From 32c4b2507cf9b5ea71ae7dd76d5dda1e295edc7e Mon Sep 17 00:00:00 2001 From: anilb Date: Wed, 8 Feb 2023 13:01:37 +0100 Subject: [PATCH 01/56] EagleEye contents with actions (#483) Co-authored-by: Joan Reyero --- backend/.env.dist.local | 6 +- .../config/custom-environment-variables.json | 4 + backend/config/default.json | 3 +- .../eagleEyeContent/eagleEyeActionCreate.ts | 11 + .../eagleEyeContent/eagleEyeActionDestroy.ts | 11 + .../eagleEyeContent/eagleEyeContentList.ts | 17 - .../eagleEyeContent/eagleEyeContentSearch.ts | 8 +- ...tentUpdate.ts => eagleEyeContentUpsert.ts} | 4 +- .../eagleEyeContent/eagleEyeSettingsUpdate.ts | 11 + backend/src/api/eagleEyeContent/index.ts | 42 +- backend/src/config/configTypes.ts | 5 + backend/src/config/index.ts | 8 + .../U1675259471__eagleEyeActions.sql | 59 +++ .../U1675702339__eagleEyeSettings.sql | 2 + .../V1675259471__eagleEyeActions.sql | 33 ++ .../V1675702339__eagleEyeSettings.sql | 2 + backend/src/database/models/eagleEyeAction.ts | 48 ++ .../src/database/models/eagleEyeContent.ts | 107 +---- backend/src/database/models/index.ts | 1 + backend/src/database/models/user.ts | 7 + .../eagleEyeActionRepository.test.ts | 63 +++ .../eagleEyeContentRepository.test.ts | 370 +++++++-------- .../repositories/eagleEyeActionRepository.ts | 125 ++++++ .../repositories/eagleEyeContentRepository.ts | 423 +++++------------- .../database/repositories/userRepository.ts | 31 ++ .../src/database/utils/sequelizeTestUtils.ts | 1 + backend/src/i18n/en.ts | 30 +- backend/src/security/permissions.ts | 15 + .../hackerNewsIntegrationService.ts | 12 +- .../integrations/types/hackerNewsTypes.ts | 53 ++- .../usecases/hackerNews/getPostsByKeywords.ts | 47 +- .../__tests__/eagleEyeContentService.test.ts | 148 ++---- backend/src/services/eagleEyeActionService.ts | 97 ++++ .../src/services/eagleEyeContentService.ts | 255 +++++------ .../src/services/eagleEyeSettingsService.ts | 158 +++++++ backend/src/types/common.ts | 7 + backend/src/types/eagleEyeTypes.ts | 93 ++++ 37 files changed, 1380 insertions(+), 937 deletions(-) create mode 100644 backend/src/api/eagleEyeContent/eagleEyeActionCreate.ts create mode 100644 backend/src/api/eagleEyeContent/eagleEyeActionDestroy.ts delete mode 100644 backend/src/api/eagleEyeContent/eagleEyeContentList.ts rename backend/src/api/eagleEyeContent/{eagleEyeContentUpdate.ts => eagleEyeContentUpsert.ts} (77%) create mode 100644 backend/src/api/eagleEyeContent/eagleEyeSettingsUpdate.ts create mode 100644 backend/src/database/migrations/U1675259471__eagleEyeActions.sql create mode 100644 backend/src/database/migrations/U1675702339__eagleEyeSettings.sql create mode 100644 backend/src/database/migrations/V1675259471__eagleEyeActions.sql create mode 100644 backend/src/database/migrations/V1675702339__eagleEyeSettings.sql create mode 100644 backend/src/database/models/eagleEyeAction.ts create mode 100644 backend/src/database/repositories/__tests__/eagleEyeActionRepository.test.ts create mode 100644 backend/src/database/repositories/eagleEyeActionRepository.ts create mode 100644 backend/src/services/eagleEyeActionService.ts create mode 100644 backend/src/services/eagleEyeSettingsService.ts create mode 100644 backend/src/types/eagleEyeTypes.ts diff --git a/backend/.env.dist.local b/backend/.env.dist.local index dbec134ba0..ad0575574e 100755 --- a/backend/.env.dist.local +++ b/backend/.env.dist.local @@ -133,4 +133,8 @@ CROWD_QDRANT_PORT=6333 # Enrichment settings CROWD_ENRICHMENT_URL= -CROWD_ENRICHMENT_API_KEY= \ No newline at end of file +CROWD_ENRICHMENT_API_KEY= + +# EagleEye settings +CROWD_EAGLE_EYE_URL= +CROWD_EAGLE_EYE_API_KEY= \ No newline at end of file diff --git a/backend/config/custom-environment-variables.json b/backend/config/custom-environment-variables.json index 56b8645816..862d9e9fb9 100644 --- a/backend/config/custom-environment-variables.json +++ b/backend/config/custom-environment-variables.json @@ -135,5 +135,9 @@ "enrichment": { "url": "CROWD_ENRICHMENT_URL", "apiKey": "CROWD_ENRICHMENT_API_KEY" + }, + "eagleEye": { + "url": "CROWD_EAGLE_EYE_URL", + "apiKey": "CROWD_EAGLE_EYE_API_KEY" } } diff --git a/backend/config/default.json b/backend/config/default.json index c31da9bcbb..13dfcfeaed 100644 --- a/backend/config/default.json +++ b/backend/config/default.json @@ -34,5 +34,6 @@ "maxRetrospectInSeconds": 3600 }, "github": {}, - "enrichment": {} + "enrichment": {}, + "eagleEye": {} } diff --git a/backend/src/api/eagleEyeContent/eagleEyeActionCreate.ts b/backend/src/api/eagleEyeContent/eagleEyeActionCreate.ts new file mode 100644 index 0000000000..8d25a39212 --- /dev/null +++ b/backend/src/api/eagleEyeContent/eagleEyeActionCreate.ts @@ -0,0 +1,11 @@ +import Permissions from '../../security/permissions' +import EagleEyeActionService from '../../services/eagleEyeActionService' +import PermissionChecker from '../../services/user/permissionChecker' + +export default async (req, res) => { + new PermissionChecker(req).validateHas(Permissions.values.eagleEyeActionCreate) + + const payload = await new EagleEyeActionService(req).create(req.body, req.params.contentId) + + await req.responseHandler.success(req, res, payload) +} diff --git a/backend/src/api/eagleEyeContent/eagleEyeActionDestroy.ts b/backend/src/api/eagleEyeContent/eagleEyeActionDestroy.ts new file mode 100644 index 0000000000..7684b74174 --- /dev/null +++ b/backend/src/api/eagleEyeContent/eagleEyeActionDestroy.ts @@ -0,0 +1,11 @@ +import Permissions from '../../security/permissions' +import EagleEyeActionService from '../../services/eagleEyeActionService' +import PermissionChecker from '../../services/user/permissionChecker' + +export default async (req, res) => { + new PermissionChecker(req).validateHas(Permissions.values.eagleEyeActionDestroy) + + const payload = await new EagleEyeActionService(req).destroy(req.params.actionId) + + await req.responseHandler.success(req, res, payload) +} diff --git a/backend/src/api/eagleEyeContent/eagleEyeContentList.ts b/backend/src/api/eagleEyeContent/eagleEyeContentList.ts deleted file mode 100644 index 40fd0fb9c9..0000000000 --- a/backend/src/api/eagleEyeContent/eagleEyeContentList.ts +++ /dev/null @@ -1,17 +0,0 @@ -import Permissions from '../../security/permissions' -import track from '../../segment/track' -import EagleEyeContentService from '../../services/eagleEyeContentService' -import PermissionChecker from '../../services/user/permissionChecker' - -export default async (req, res) => { - new PermissionChecker(req).validateHas(Permissions.values.eagleEyeContentRead) - const payload = await new EagleEyeContentService(req).findAndCountAll(req.query) - - if (req.query.filter && Object.keys(req.query.filter).length > 0) { - const platforms = req.query.filter.platforms ? req.query.filter.platforms.split(',') : [] - const nDays = req.query.filter.nDays - track('Eagle Eye Filter', { filter: req.query.filter, platforms, nDays }, { ...req }) - } - - await req.responseHandler.success(req, res, payload) -} diff --git a/backend/src/api/eagleEyeContent/eagleEyeContentSearch.ts b/backend/src/api/eagleEyeContent/eagleEyeContentSearch.ts index 278459e1c3..88659e218a 100644 --- a/backend/src/api/eagleEyeContent/eagleEyeContentSearch.ts +++ b/backend/src/api/eagleEyeContent/eagleEyeContentSearch.ts @@ -4,11 +4,9 @@ import EagleEyeContentService from '../../services/eagleEyeContentService' import PermissionChecker from '../../services/user/permissionChecker' export default async (req, res) => { - new PermissionChecker(req).validateHas(Permissions.values.eagleEyeContentSearch) - - const payload = await new EagleEyeContentService(req).search(req.body) - - track('EagleEyeSearch', { ...req.body }, { ...req }) + new PermissionChecker(req).validateHas(Permissions.values.eagleEyeActionCreate) + const payload = await new EagleEyeContentService(req).search() + track('EagleEye backend search', { ...req.body }, { ...req }) await req.responseHandler.success(req, res, payload) } diff --git a/backend/src/api/eagleEyeContent/eagleEyeContentUpdate.ts b/backend/src/api/eagleEyeContent/eagleEyeContentUpsert.ts similarity index 77% rename from backend/src/api/eagleEyeContent/eagleEyeContentUpdate.ts rename to backend/src/api/eagleEyeContent/eagleEyeContentUpsert.ts index b1d3c0854e..2acfcc5e2d 100644 --- a/backend/src/api/eagleEyeContent/eagleEyeContentUpdate.ts +++ b/backend/src/api/eagleEyeContent/eagleEyeContentUpsert.ts @@ -3,9 +3,9 @@ import EagleEyeContentService from '../../services/eagleEyeContentService' import PermissionChecker from '../../services/user/permissionChecker' export default async (req, res) => { - new PermissionChecker(req).validateHas(Permissions.values.eagleEyeContentEdit) + new PermissionChecker(req).validateHas(Permissions.values.eagleEyeContentCreate) - const payload = await new EagleEyeContentService(req).update(req.params.id, req.body) + const payload = await new EagleEyeContentService(req).upsert(req.body) await req.responseHandler.success(req, res, payload) } diff --git a/backend/src/api/eagleEyeContent/eagleEyeSettingsUpdate.ts b/backend/src/api/eagleEyeContent/eagleEyeSettingsUpdate.ts new file mode 100644 index 0000000000..635e4a7411 --- /dev/null +++ b/backend/src/api/eagleEyeContent/eagleEyeSettingsUpdate.ts @@ -0,0 +1,11 @@ +import Permissions from '../../security/permissions' +import EagleEyeSettingsService from '../../services/eagleEyeSettingsService' +import PermissionChecker from '../../services/user/permissionChecker' + +export default async (req, res) => { + new PermissionChecker(req).validateHas(Permissions.values.eagleEyeActionCreate) + + const payload = await new EagleEyeSettingsService(req).update(req.body) + + await req.responseHandler.success(req, res, payload) +} diff --git a/backend/src/api/eagleEyeContent/index.ts b/backend/src/api/eagleEyeContent/index.ts index 33928e9148..7fd10c716c 100644 --- a/backend/src/api/eagleEyeContent/index.ts +++ b/backend/src/api/eagleEyeContent/index.ts @@ -1,21 +1,47 @@ import { safeWrap } from '../../middlewares/errorMiddleware' +import { featureFlagMiddleware } from '../../middlewares/featureFlagMiddleware' +import { FeatureFlag } from '../../types/common' export default (app) => { - app.post( - `/tenant/:tenantId/eagleEyeContent`, - safeWrap(require('./eagleEyeContentSearch').default), - ) app.post( `/tenant/:tenantId/eagleEyeContent/query`, + featureFlagMiddleware(FeatureFlag.EAGLE_EYE, 'entities.eagleEye.errors.planLimitExceeded'), safeWrap(require('./eagleEyeContentQuery').default), ) - app.put( - `/tenant/:tenantId/eagleEyeContent/:id`, - safeWrap(require('./eagleEyeContentUpdate').default), + + app.post( + `/tenant/:tenantId/eagleEyeContent`, + featureFlagMiddleware(FeatureFlag.EAGLE_EYE, 'entities.eagleEye.errors.planLimitExceeded'), + safeWrap(require('./eagleEyeContentUpsert').default), + ) + + app.get( + `/tenant/:tenantId/eagleEyeContent/search`, + featureFlagMiddleware(FeatureFlag.EAGLE_EYE, 'entities.eagleEye.errors.planLimitExceeded'), + safeWrap(require('./eagleEyeContentSearch').default), ) - app.get(`/tenant/:tenantId/eagleEyeContent`, safeWrap(require('./eagleEyeContentList').default)) + app.get( `/tenant/:tenantId/eagleEyeContent/:id`, + featureFlagMiddleware(FeatureFlag.EAGLE_EYE, 'entities.eagleEye.errors.planLimitExceeded'), safeWrap(require('./eagleEyeContentFind').default), ) + + app.post( + `/tenant/:tenantId/eagleEyeContent/:contentId/action`, + featureFlagMiddleware(FeatureFlag.EAGLE_EYE, 'entities.eagleEye.errors.planLimitExceeded'), + safeWrap(require('./eagleEyeActionCreate').default), + ) + + app.put( + `/tenant/:tenantId/eagleEyeContent/settings`, + featureFlagMiddleware(FeatureFlag.EAGLE_EYE, 'entities.eagleEye.errors.planLimitExceeded'), + safeWrap(require('./eagleEyeSettingsUpdate').default), + ) + + app.delete( + `/tenant/:tenantId/eagleEyeContent/:contentId/action/:actionId`, + featureFlagMiddleware(FeatureFlag.EAGLE_EYE, 'entities.eagleEye.errors.planLimitExceeded'), + safeWrap(require('./eagleEyeActionDestroy').default), + ) } diff --git a/backend/src/config/configTypes.ts b/backend/src/config/configTypes.ts index c0949978df..f6ec20d69b 100644 --- a/backend/src/config/configTypes.ts +++ b/backend/src/config/configTypes.ts @@ -179,3 +179,8 @@ export interface EnrichmentConfiguration { url: string apiKey: string } + +export interface EagleEyeConfiguration { + url: string + apiKey: string +} diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 6d32e96932..69ad9c6f72 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -24,6 +24,7 @@ import { PosthogConfiguration, PizzlyConfiguration, EnrichmentConfiguration, + EagleEyeConfiguration, } from './configTypes' // TODO-kube @@ -233,3 +234,10 @@ export const ENRICHMENT_CONFIG: EnrichmentConfiguration = KUBE_MODE url: process.env.ENRICHMENT_URL, apiKey: process.env.ENRICHMENT_SECRET_KEY, } + +export const EAGLE_EYE_CONFIG: EagleEyeConfiguration = KUBE_MODE + ? config.get('eagleEye') + : { + url: process.env.EAGLE_EYE_URL, + apiKey: process.env.EAGLE_EYE_SECRET_KEY, + } diff --git a/backend/src/database/migrations/U1675259471__eagleEyeActions.sql b/backend/src/database/migrations/U1675259471__eagleEyeActions.sql new file mode 100644 index 0000000000..30b8b2c037 --- /dev/null +++ b/backend/src/database/migrations/U1675259471__eagleEyeActions.sql @@ -0,0 +1,59 @@ +DROP TABLE IF EXISTS "eagleEyeContents"; + +DROP TYPE "eagleEyeContents_actions_type"; + +create table "eagleEyeContents"; +( + id uuid not null primary key, + "sourceId" text not null, + "vectorId" text not null, + status varchar(255) default NULL::character varying, + title text not null, + username text not null, + url text not null, + text text, + timestamp timestamp with time zone not null, + platform text not null, + keywords text [], + "similarityScore" double precision, + "userAttributes" jsonb, + "postAttributes" jsonb, + "importHash" varchar(255), + "createdAt" timestamp with time zone not null, + "updatedAt" timestamp with time zone not null, + "deletedAt" timestamp with time zone, + "tenantId" uuid not null references tenants on update cascade, + "createdById" uuid references users on update cascade on delete + set null, + "updatedById" uuid references users on update cascade on delete + set null, + "exactKeywords" text [] +); + +alter table "eagleEyeContents" owner to postgres; + +create index discord on "eagleEyeContents" ("vectorId", status); + +create index members_email_tenant_id on "eagleEyeContents" (id) +where ("deletedAt" IS NULL); + +create index members_joined_at_tenant_id on "eagleEyeContents" (id) +where ("deletedAt" IS NULL); + +create index members_username on "eagleEyeContents" using gin (id); + +create index slack on "eagleEyeContents" (id); + +create index twitter on "eagleEyeContents" (id); + +create unique index eagle_eye_contents_import_hash_tenant_id on "eagleEyeContents" ("importHash", "tenantId") +where ("deletedAt" IS NULL); + +create index eagle_eye_contents_platform_tenant_id_timestamp on "eagleEyeContents" (platform, "tenantId", timestamp) +where ("deletedAt" IS NULL); + +create index eagle_eye_contents_status_tenant_id_timestamp on "eagleEyeContents" (status, "tenantId", timestamp) +where ("deletedAt" IS NULL); + +create index eagle_eye_contents_tenant_id_timestamp on "eagleEyeContents" ("tenantId", timestamp) +where ("deletedAt" IS NULL); \ No newline at end of file diff --git a/backend/src/database/migrations/U1675702339__eagleEyeSettings.sql b/backend/src/database/migrations/U1675702339__eagleEyeSettings.sql new file mode 100644 index 0000000000..e3a0f4fe1e --- /dev/null +++ b/backend/src/database/migrations/U1675702339__eagleEyeSettings.sql @@ -0,0 +1,2 @@ +ALTER TABLE public."users" +DROP COLUMN "eagleEyeSettings"; \ No newline at end of file diff --git a/backend/src/database/migrations/V1675259471__eagleEyeActions.sql b/backend/src/database/migrations/V1675259471__eagleEyeActions.sql new file mode 100644 index 0000000000..9183281bc1 --- /dev/null +++ b/backend/src/database/migrations/V1675259471__eagleEyeActions.sql @@ -0,0 +1,33 @@ +DROP TABLE IF EXISTS "eagleEyeContents"; + +CREATE TABLE public."eagleEyeContents" ( + "id" uuid NOT NULL, + "platform" text NOT NULL, + "url" text NOT NULL, + "post" jsonb NOT NULL, + "tenantId" uuid NOT NULL, + "postedAt" timestamptz NOT NULL, + "createdAt" timestamptz NOT NULL, + "updatedAt" timestamptz NOT NULL, + CONSTRAINT "eagleEyeContents_pkey" PRIMARY KEY ("id") +); + +ALTER TABLE public."eagleEyeContents" ADD CONSTRAINT "eagleEyeContents_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES public.tenants(id) ON DELETE NO ACTION ON UPDATE NO ACTION; + +CREATE TYPE public."eagleEyeActionTypes_type" AS ENUM ('thumbs-up', 'thumbs-down', 'bookmark'); + +CREATE TABLE public."eagleEyeActions" ( + "id" uuid NOT NULL, + "type" public."eagleEyeActionTypes_type" NOT NULL, + "timestamp" timestamptz NOT NULL, + "contentId" uuid NOT NULL, + "tenantId" uuid NOT NULL, + "actionById" uuid NOT NULL, + "createdAt" timestamptz NOT NULL, + "updatedAt" timestamptz NOT NULL, + CONSTRAINT "eagleEyeActions_pkey" PRIMARY KEY ("id") +); + +ALTER TABLE public."eagleEyeActions" ADD CONSTRAINT "eagleEyeActions_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES public.tenants(id) ON DELETE NO ACTION ON UPDATE NO ACTION; +ALTER TABLE public."eagleEyeActions" ADD CONSTRAINT "eagleEyeActions_actionBy_fkey" FOREIGN KEY ("actionById") REFERENCES public.users(id) ON DELETE NO ACTION ON UPDATE NO ACTION; +ALTER TABLE public."eagleEyeActions" ADD CONSTRAINT "eagleEyeActions_contentId_fkey" FOREIGN KEY ("contentId") REFERENCES public."eagleEyeContents"(id) ON DELETE CASCADE ON UPDATE NO ACTION; diff --git a/backend/src/database/migrations/V1675702339__eagleEyeSettings.sql b/backend/src/database/migrations/V1675702339__eagleEyeSettings.sql new file mode 100644 index 0000000000..7e8e46fbf2 --- /dev/null +++ b/backend/src/database/migrations/V1675702339__eagleEyeSettings.sql @@ -0,0 +1,2 @@ +ALTER TABLE public."users" +ADD COLUMN "eagleEyeSettings" JSONB DEFAULT '{"onboarded": false}'; diff --git a/backend/src/database/models/eagleEyeAction.ts b/backend/src/database/models/eagleEyeAction.ts new file mode 100644 index 0000000000..116b069fb2 --- /dev/null +++ b/backend/src/database/models/eagleEyeAction.ts @@ -0,0 +1,48 @@ +import { DataTypes } from 'sequelize' + +const eagleEyeActionModel = { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + type: { + type: DataTypes.TEXT, + validate: { + isIn: [['thumbs-up', 'thumbs-down', 'bookmark']], + }, + defaultValue: null, + }, + timestamp: { + type: DataTypes.DATE, + allowNull: false, + }, +} + +export default (sequelize) => { + const eagleEyeAction = sequelize.define('eagleEyeAction', eagleEyeActionModel, { + timestamps: true, + paranoid: false, + }) + + eagleEyeAction.associate = (models) => { + models.eagleEyeAction.belongsTo(models.tenant, { + as: 'tenant', + foreignKey: { + allowNull: false, + }, + }) + + models.eagleEyeAction.belongsTo(models.user, { + as: 'actionBy', + }) + + models.eagleEyeAction.belongsTo(models.eagleEyeContent, { + as: 'content', + }) + } + + return eagleEyeAction +} + +export { eagleEyeActionModel } diff --git a/backend/src/database/models/eagleEyeContent.ts b/backend/src/database/models/eagleEyeContent.ts index bfee48a92e..9b00bc070c 100644 --- a/backend/src/database/models/eagleEyeContent.ts +++ b/backend/src/database/models/eagleEyeContent.ts @@ -6,40 +6,16 @@ const eagleEyeContentModel = { defaultValue: DataTypes.UUIDV4, primaryKey: true, }, - sourceId: { - type: DataTypes.TEXT, - allowNull: false, - validate: { - notEmpty: true, - }, - }, - vectorId: { - type: DataTypes.TEXT, - allowNull: false, - validate: { - notEmpty: true, - }, - }, - status: { - type: DataTypes.STRING(255), - validate: { - isIn: [['engaged', 'rejected']], - }, - defaultValue: null, - }, - title: { + platform: { type: DataTypes.TEXT, allowNull: false, validate: { notEmpty: true, }, }, - username: { - type: DataTypes.TEXT, + post: { + type: DataTypes.JSONB, allowNull: false, - validate: { - notEmpty: true, - }, }, url: { type: DataTypes.TEXT, @@ -48,79 +24,16 @@ const eagleEyeContentModel = { notEmpty: true, }, }, - text: { - type: DataTypes.TEXT, - }, - timestamp: { + postedAt: { type: DataTypes.DATE, allowNull: false, }, - platform: { - type: DataTypes.TEXT, - allowNull: false, - validate: { - notEmpty: true, - }, - }, - keywords: { - type: DataTypes.ARRAY(DataTypes.TEXT), - default: [], - }, - exactKeywords: { - type: DataTypes.ARRAY(DataTypes.TEXT), - default: [], - }, - similarityScore: { - type: DataTypes.FLOAT, - }, - userAttributes: { - type: DataTypes.JSONB, - default: {}, - }, - postAttributes: { - type: DataTypes.JSONB, - default: {}, - }, - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - validate: { - len: [0, 255], - }, - }, } export default (sequelize) => { const eagleEyeContent = sequelize.define('eagleEyeContent', eagleEyeContentModel, { - indexes: [ - { - unique: true, - fields: ['importHash', 'tenantId'], - where: { - deletedAt: null, - }, - }, - { - fields: ['platform', 'tenantId', 'timestamp'], - where: { - deletedAt: null, - }, - }, - { - fields: ['status', 'tenantId', 'timestamp'], - where: { - deletedAt: null, - }, - }, - { - fields: ['tenantId', 'timestamp'], - where: { - deletedAt: null, - }, - }, - ], timestamps: true, - paranoid: true, + paranoid: false, }) eagleEyeContent.associate = (models) => { @@ -130,13 +43,9 @@ export default (sequelize) => { allowNull: false, }, }) - - models.eagleEyeContent.belongsTo(models.user, { - as: 'createdBy', - }) - - models.eagleEyeContent.belongsTo(models.user, { - as: 'updatedBy', + models.eagleEyeContent.hasMany(models.eagleEyeAction, { + as: 'actions', + foreignKey: 'contentId', }) } diff --git a/backend/src/database/models/index.ts b/backend/src/database/models/index.ts index 9a1dcc704c..4e0b3bcc09 100644 --- a/backend/src/database/models/index.ts +++ b/backend/src/database/models/index.ts @@ -102,6 +102,7 @@ function models() { require('./conversation').default, require('./conversationSettings').default, require('./eagleEyeContent').default, + require('./eagleEyeAction').default, require('./automation').default, require('./automationExecution').default, require('./organization').default, diff --git a/backend/src/database/models/user.ts b/backend/src/database/models/user.ts index a64482691b..3e9990465e 100644 --- a/backend/src/database/models/user.ts +++ b/backend/src/database/models/user.ts @@ -102,6 +102,13 @@ export default (sequelize, DataTypes) => { len: [0, 255], }, }, + eagleEyeSettings: { + type: DataTypes.JSONB, + allowNull: false, + defaultValue: { + onboarded: false, + }, + }, }, { indexes: [ diff --git a/backend/src/database/repositories/__tests__/eagleEyeActionRepository.test.ts b/backend/src/database/repositories/__tests__/eagleEyeActionRepository.test.ts new file mode 100644 index 0000000000..f3a64fa6ec --- /dev/null +++ b/backend/src/database/repositories/__tests__/eagleEyeActionRepository.test.ts @@ -0,0 +1,63 @@ +import EagleEyeContentRepository from '../eagleEyeContentRepository' +import SequelizeTestUtils from '../../utils/sequelizeTestUtils' +import { EagleEyeAction, EagleEyeActionType, EagleEyeContent } from '../../../types/eagleEyeTypes' +import EagleEyeActionRepository from '../eagleEyeActionRepository' + +const db = null + +describe('eagleEyeActionRepository tests', () => { + beforeEach(async () => { + await SequelizeTestUtils.wipeDatabase(db) + }) + + afterAll((done) => { + // Closing the DB connection allows Jest to exit successfully. + SequelizeTestUtils.closeConnection(db) + done() + }) + + describe('createActionForContent method', () => { + it('Should create a an action for a content succesfully', async () => { + const mockIRepositoryOptions = await SequelizeTestUtils.getTestIRepositoryOptions(db) + + const content = { + platform: 'reddit', + url: 'https://some-post-url', + post: { + title: 'post title', + body: 'post body', + }, + postedAt: '2020-05-27T15:13:30Z', + tenantId: mockIRepositoryOptions.currentTenant.id, + } as EagleEyeContent + + const contentCreated = await EagleEyeContentRepository.create(content, mockIRepositoryOptions) + + const action: EagleEyeAction = { + type: EagleEyeActionType.BOOKMARK, + timestamp: '2022-07-27T19:13:30Z', + } + + const actionCreated = await EagleEyeActionRepository.createActionForContent( + action, + contentCreated.id, + mockIRepositoryOptions, + ) + + actionCreated.createdAt = (actionCreated.createdAt as Date).toISOString().split('T')[0] + actionCreated.updatedAt = (actionCreated.updatedAt as Date).toISOString().split('T')[0] + + const expectedAction = { + id: actionCreated.id, + ...action, + timestamp: new Date(actionCreated.timestamp), + contentId: contentCreated.id, + actionById: mockIRepositoryOptions.currentUser.id, + tenantId: mockIRepositoryOptions.currentTenant.id, + createdAt: SequelizeTestUtils.getNowWithoutTime(), + updatedAt: SequelizeTestUtils.getNowWithoutTime(), + } + expect(expectedAction).toStrictEqual(actionCreated) + }) + }) +}) diff --git a/backend/src/database/repositories/__tests__/eagleEyeContentRepository.test.ts b/backend/src/database/repositories/__tests__/eagleEyeContentRepository.test.ts index bffec870ca..96666a7148 100644 --- a/backend/src/database/repositories/__tests__/eagleEyeContentRepository.test.ts +++ b/backend/src/database/repositories/__tests__/eagleEyeContentRepository.test.ts @@ -1,86 +1,10 @@ -import lodash from 'lodash' -import moment from 'moment' import EagleEyeContentRepository from '../eagleEyeContentRepository' import SequelizeTestUtils from '../../utils/sequelizeTestUtils' -import Error404 from '../../../errors/Error404' -import Error400 from '../../../errors/Error400' -import EagleEyeContentService from '../../../services/eagleEyeContentService' -import { PlatformType } from '../../../types/integrationEnums' +import { EagleEyeActionType, EagleEyeContent } from '../../../types/eagleEyeTypes' +import EagleEyeActionRepository from '../eagleEyeActionRepository' const db = null -const toCreate = { - sourceId: 'sourceId', - vectorId: '123', - status: null, - platform: 'hacker_news', - title: 'title', - userAttributes: { [PlatformType.GITHUB]: 'hey', [PlatformType.TWITTER]: 'ho' }, - text: 'text', - postAttributes: { - score: 10, - }, - url: 'url', - exactKeywords: null, - timestamp: new Date(), - username: 'username', - keywords: ['keyword1', 'keyword2'], - similarityScore: 0.9, -} - -const toCreateMinimal = { - sourceId: 'sourceIdMinimal', - vectorId: '456', - platform: 'hacker_news', - url: 'url', - title: 'title minimal', - timestamp: new Date(), - username: 'username', - keywords: 'keyword', -} - -const forFiltering = [ - toCreate, - toCreateMinimal, - { - sourceId: 'devto123', - vectorId: '123123', - status: 'engaged', - url: 'devto url', - username: 'devtousername1', - platform: 'devto', - timestamp: moment().toDate(), - title: 'title devto 1', - }, - { - sourceId: 'devto456', - vectorId: '123456', - url: 'url devto 2', - username: 'devtousername2', - status: 'rejected', - platform: 'devto', - timestamp: moment().subtract(1, 'week').toDate(), - title: 'title devto 2', - keywords: ['keyword1', 'keyword2'], - score: 40, - }, - { - sourceId: 'devto789', - vectorId: '123456', - url: 'url devto 3', - username: 'devtousername3', - status: null, - platform: 'devto', - timestamp: moment().subtract(1, 'week').toDate(), - keywords: ['keyword3', 'keyword2'], - title: 'title devto 3', - }, -] - -async function addAll(options) { - await Promise.all(forFiltering.map((item) => EagleEyeContentRepository.upsert(item, options))) -} - describe('eagleEyeContentRepository tests', () => { beforeEach(async () => { await SequelizeTestUtils.wipeDatabase(db) @@ -92,29 +16,40 @@ describe('eagleEyeContentRepository tests', () => { done() }) - describe('upserts method', () => { - it('Should create a complete content succesfully', async () => { + describe('create method', () => { + it('Should create a content succesfully', async () => { const mockIRepositoryOptions = await SequelizeTestUtils.getTestIRepositoryOptions(db) - const created = await EagleEyeContentRepository.upsert(toCreate, mockIRepositoryOptions) + const content = { + platform: 'reddit', + url: 'https://some-post-url', + post: { + title: 'post title', + body: 'post body', + }, + postedAt: '2020-05-27T15:13:30Z', + tenantId: mockIRepositoryOptions.currentTenant.id, + } as EagleEyeContent - created.createdAt = created.createdAt.toISOString().split('T')[0] - created.updatedAt = created.updatedAt.toISOString().split('T')[0] + const created = await EagleEyeContentRepository.create(content, mockIRepositoryOptions) + + created.createdAt = (created.createdAt as Date).toISOString().split('T')[0] + created.updatedAt = (created.updatedAt as Date).toISOString().split('T')[0] const expectedCreated = { id: created.id, - ...toCreate, - importHash: null, + ...content, + postedAt: new Date(content.postedAt), + actions: [], createdAt: SequelizeTestUtils.getNowWithoutTime(), updatedAt: SequelizeTestUtils.getNowWithoutTime(), - deletedAt: null, tenantId: mockIRepositoryOptions.currentTenant.id, - createdById: mockIRepositoryOptions.currentUser.id, - updatedById: mockIRepositoryOptions.currentUser.id, } expect(created).toStrictEqual(expectedCreated) }) + /* + it('Should create a content with unix timestamp', async () => { const mockIRepositoryOptions = await SequelizeTestUtils.getTestIRepositoryOptions(db) @@ -157,130 +92,9 @@ describe('eagleEyeContentRepository tests', () => { expect(created).toStrictEqual(expectedCreated) }) - it('Should not add it the record already exists', async () => { - const mockIRepositoryOptions = await SequelizeTestUtils.getTestIRepositoryOptions(db) - - await EagleEyeContentRepository.upsert(toCreate, mockIRepositoryOptions) - - await EagleEyeContentRepository.upsert(toCreate, mockIRepositoryOptions) - - const count = await mockIRepositoryOptions.database.eagleEyeContent.count() - expect(count).toBe(1) - }) - - it('Should update keywords and similarity score if the item already exists', async () => { - const mockIRepositoryOptions = await SequelizeTestUtils.getTestIRepositoryOptions(db) - - await EagleEyeContentRepository.upsert(toCreate, mockIRepositoryOptions) - - const toCreateNewKeywords = { ...toCreate } - toCreateNewKeywords.keywords = ['1', '2', 'keyword1'] - toCreateNewKeywords.similarityScore = 0.95 - - const allKeywords = ['1', '2', 'keyword1', 'keyword2'] - - const created = await EagleEyeContentRepository.upsert( - toCreateNewKeywords, - mockIRepositoryOptions, - ) - - const count = await mockIRepositoryOptions.database.eagleEyeContent.count() - expect(count).toBe(1) - expect(lodash.isEqual(created.keywords.sort(), allKeywords.sort())) - expect(created.similarityScore).toBe(0.95) - }) - - it('Should create a minimal content succesfully', async () => { - const mockIRepositoryOptions = await SequelizeTestUtils.getTestIRepositoryOptions(db) - - const created = await EagleEyeContentRepository.upsert( - toCreateMinimal, - mockIRepositoryOptions, - ) - - created.createdAt = created.createdAt.toISOString().split('T')[0] - created.updatedAt = created.updatedAt.toISOString().split('T')[0] - - const expectedCreated = { - id: created.id, - ...toCreateMinimal, - text: null, - status: null, - userAttributes: null, - postAttributes: null, - similarityScore: null, - exactKeywords: null, - importHash: null, - createdAt: SequelizeTestUtils.getNowWithoutTime(), - updatedAt: SequelizeTestUtils.getNowWithoutTime(), - deletedAt: null, - tenantId: mockIRepositoryOptions.currentTenant.id, - createdById: mockIRepositoryOptions.currentUser.id, - updatedById: mockIRepositoryOptions.currentUser.id, - } - expect(created).toStrictEqual(expectedCreated) - expect(created.status).toBe(null) - }) - - it('Should create with rejected status', async () => { - const mockIRepositoryOptions = await SequelizeTestUtils.getTestIRepositoryOptions(db) - const newStatus = { ...toCreate } - newStatus.status = 'rejected' - - const created = await EagleEyeContentRepository.upsert(newStatus, mockIRepositoryOptions) - - created.createdAt = created.createdAt.toISOString().split('T')[0] - created.updatedAt = created.updatedAt.toISOString().split('T')[0] + - const expectedCreated = { - id: created.id, - ...newStatus, - importHash: null, - createdAt: SequelizeTestUtils.getNowWithoutTime(), - updatedAt: SequelizeTestUtils.getNowWithoutTime(), - deletedAt: null, - tenantId: mockIRepositoryOptions.currentTenant.id, - createdById: mockIRepositoryOptions.currentUser.id, - updatedById: mockIRepositoryOptions.currentUser.id, - } - expect(created).toStrictEqual(expectedCreated) - expect(created.status).toBe('rejected') - }) - - it('Should create with engaged status', async () => { - const mockIRepositoryOptions = await SequelizeTestUtils.getTestIRepositoryOptions(db) - const newStatus = { ...toCreate } - newStatus.status = 'engaged' - - const created = await EagleEyeContentRepository.upsert(newStatus, mockIRepositoryOptions) - - created.createdAt = created.createdAt.toISOString().split('T')[0] - created.updatedAt = created.updatedAt.toISOString().split('T')[0] - - const expectedCreated = { - id: created.id, - ...newStatus, - importHash: null, - createdAt: SequelizeTestUtils.getNowWithoutTime(), - updatedAt: SequelizeTestUtils.getNowWithoutTime(), - deletedAt: null, - tenantId: mockIRepositoryOptions.currentTenant.id, - createdById: mockIRepositoryOptions.currentUser.id, - updatedById: mockIRepositoryOptions.currentUser.id, - } - expect(created).toStrictEqual(expectedCreated) - expect(created.status).toBe('engaged') - }) - - it('Should throw an error for an invalid status', async () => { - const mockIRepositoryOptions = await SequelizeTestUtils.getTestIRepositoryOptions(db) - const newStatus = { ...toCreate } - newStatus.status = 'smth else' - - await expect(() => - EagleEyeContentRepository.upsert(newStatus, mockIRepositoryOptions), - ).rejects.toThrowError(new Error400('en', 'errors.invalidEagleEyeStatus.message')) - }) + }) describe('find by id method', () => { @@ -601,4 +415,138 @@ describe('eagleEyeContentRepository tests', () => { expect(updated.keywords).toStrictEqual(created.keywords) }) }) + */ + }) + + describe('findAndCountAll method', () => { + it('Should find eagle eye contant, various cases', async () => { + // create random tenant with one user + const mockIRepositoryOptions = await SequelizeTestUtils.getTestIRepositoryOptions(db) + + // create additional users for same tenant to test out actionBy filtering + const randomUser = await SequelizeTestUtils.getRandomUser() + + console.log('random user: ') + console.log(randomUser) + + const user2 = await mockIRepositoryOptions.database.user.create(randomUser) + + await mockIRepositoryOptions.database.tenantUser.create({ + roles: ['admin'], + status: 'active', + tenantId: mockIRepositoryOptions.currentTenant.id, + userId: user2.id, + }) + + // create few content + // one without any actions + await EagleEyeContentRepository.create( + { + platform: 'reddit', + url: 'https://some-reddit-url', + post: { + title: 'post title', + body: 'post body', + }, + postedAt: '2020-05-27T15:13:30Z', + tenantId: mockIRepositoryOptions.currentTenant.id, + }, + mockIRepositoryOptions, + ) + + // one with a bookmark action + let c2 = await EagleEyeContentRepository.create( + { + platform: 'hackernews', + url: 'https://some-hackernews-url', + post: { + title: 'post title', + body: 'post body', + }, + postedAt: '2022-06-27T19:14:44Z', + tenantId: mockIRepositoryOptions.currentTenant.id, + }, + mockIRepositoryOptions, + ) + + // add bookmark action + await EagleEyeActionRepository.createActionForContent( + { + type: EagleEyeActionType.BOOKMARK, + timestamp: '2022-07-27T19:13:30Z', + }, + c2.id, + mockIRepositoryOptions, + ) + + c2 = await EagleEyeContentRepository.findById(c2.id, mockIRepositoryOptions) + + // another content with a thumbs-up(user1) and a bookmark(user2) action + let c3 = await EagleEyeContentRepository.create( + { + platform: 'devto', + url: 'https://some-devto-url', + post: { + title: 'post title', + body: 'post body', + }, + postedAt: '2022-06-27T19:14:44Z', + tenantId: mockIRepositoryOptions.currentTenant.id, + }, + mockIRepositoryOptions, + ) + + // add the thumbs up action + await EagleEyeActionRepository.createActionForContent( + { + type: EagleEyeActionType.THUMBS_UP, + timestamp: '2022-09-30T23:11:10Z', + }, + c3.id, + mockIRepositoryOptions, + ) + + // also add bookmark from user2 + await EagleEyeActionRepository.createActionForContent( + { + type: EagleEyeActionType.BOOKMARK, + timestamp: '2022-09-30T23:11:10Z', + }, + c3.id, + { ...mockIRepositoryOptions, currentUser: user2 }, + ) + + c3 = await EagleEyeContentRepository.findById(c3.id, mockIRepositoryOptions) + + // filter by action type + let res = await EagleEyeContentRepository.findAndCountAll( + { + advancedFilter: { + action: { + type: EagleEyeActionType.BOOKMARK, + }, + }, + }, + mockIRepositoryOptions, + ) + + expect(res.count).toBe(2) + expect(res.rows.sort((a, b) => (a.createdAt > b.createdAt ? 1 : -1))).toStrictEqual([c2, c3]) + + // filter by actionBy + res = await EagleEyeContentRepository.findAndCountAll( + { + advancedFilter: { + action: { + actionById: user2.id, + }, + }, + }, + mockIRepositoryOptions, + ) + + expect(res.count).toBe(1) + expect(res.rows).toStrictEqual([c3]) + }) + }) }) diff --git a/backend/src/database/repositories/eagleEyeActionRepository.ts b/backend/src/database/repositories/eagleEyeActionRepository.ts new file mode 100644 index 0000000000..cc7932b257 --- /dev/null +++ b/backend/src/database/repositories/eagleEyeActionRepository.ts @@ -0,0 +1,125 @@ +import lodash from 'lodash' +import Error404 from '../../errors/Error404' +import { EagleEyeAction, EagleEyeActionType } from '../../types/eagleEyeTypes' +import { IRepositoryOptions } from './IRepositoryOptions' +import SequelizeRepository from './sequelizeRepository' + +export default class EagleEyeActionRepository { + static async createActionForContent( + data: EagleEyeAction, + contentId: string, + options: IRepositoryOptions, + ): Promise { + const currentUser = SequelizeRepository.getCurrentUser(options) + + const transaction = SequelizeRepository.getTransaction(options) + + const currentTenant = SequelizeRepository.getCurrentTenant(options) + + const record = await options.database.eagleEyeAction.create( + { + ...lodash.pick(data, ['type', 'timestamp']), + actionById: currentUser.id, + contentId, + tenantId: currentTenant.id, + }, + { + transaction, + }, + ) + + return this.findById(record.id, options) + } + + static async removeActionFromContent( + action: EagleEyeActionType, + contentId: string, + options: IRepositoryOptions, + ) { + const currentUser = SequelizeRepository.getCurrentUser(options) + + const currentTenant = SequelizeRepository.getCurrentTenant(options) + + const transaction = SequelizeRepository.getTransaction(options) + + const record = await options.database.eagleEyeAction.findOne({ + where: { + contentId, + action, + actionById: currentUser.id, + tenantId: currentTenant.id, + }, + transaction, + }) + + if (record) { + await record.destroy({ + transaction, + force: true, + }) + } + } + + static async destroy(id: string, options: IRepositoryOptions): Promise { + const transaction = SequelizeRepository.getTransaction(options) + + const currentTenant = SequelizeRepository.getCurrentTenant(options) + + const record = await options.database.eagleEyeAction.findOne({ + where: { + id, + tenantId: currentTenant.id, + }, + transaction, + }) + + if (record) { + await record.destroy({ + transaction, + force: true, + }) + } + } + + static async findById(id: string, options: IRepositoryOptions) { + const transaction = SequelizeRepository.getTransaction(options) + + const include = [] + + const currentTenant = SequelizeRepository.getCurrentTenant(options) + + const record = await options.database.eagleEyeAction.findOne({ + where: { + id, + tenantId: currentTenant.id, + }, + include, + transaction, + }) + + if (!record) { + throw new Error404() + } + + return this._populateRelations(record) + } + + static async create(data: EagleEyeAction, options: IRepositoryOptions): Promise { + const currentTenant = SequelizeRepository.getCurrentTenant(options) + + const record = options.database.eagleEyeContent.create({ + ...lodash.pick(data, ['type', 'timestamp']), + tenantId: currentTenant.id, + }) + + return this.findById(record.id, options) + } + + static async _populateRelations(record) { + if (!record) { + return record + } + + return record.get({ plain: true }) + } +} diff --git a/backend/src/database/repositories/eagleEyeContentRepository.ts b/backend/src/database/repositories/eagleEyeContentRepository.ts index 56de3e60f0..9a34d4d9d4 100644 --- a/backend/src/database/repositories/eagleEyeContentRepository.ts +++ b/backend/src/database/repositories/eagleEyeContentRepository.ts @@ -1,101 +1,56 @@ -import moment from 'moment' import lodash from 'lodash' +import { Op } from 'sequelize' import SequelizeRepository from './sequelizeRepository' import Error404 from '../../errors/Error404' -import Error400 from '../../errors/Error400' -import AuditLogRepository from './auditLogRepository' import { IRepositoryOptions } from './IRepositoryOptions' +import { EagleEyeContent } from '../../types/eagleEyeTypes' import QueryParser from './filters/queryParser' import { QueryOutput } from './filters/queryTypes' +import EagleEyeActionRepository from './eagleEyeActionRepository' export default class EagleEyeContentRepository { - /** - * Create an eagle eye shown content record. - * @param data Data to a new EagleEyeContent record. - * @param options Repository options. - * @returns Created EagleEyeContent record. - */ - static async upsert(data, options: IRepositoryOptions) { - const currentUser = SequelizeRepository.getCurrentUser(options) + static async create( + data: EagleEyeContent, + options: IRepositoryOptions, + ): Promise { + const currentTenant = SequelizeRepository.getCurrentTenant(options) + + const record = await options.database.eagleEyeContent.create({ + ...lodash.pick(data, ['platform', 'post', 'url', 'postedAt']), + tenantId: currentTenant.id, + }) + + if (data.actions) { + for (const action of data.actions) { + await EagleEyeActionRepository.createActionForContent(action, record.id, options) + } + } + + return this.findById(record.id, options) + } - const tenant = SequelizeRepository.getCurrentTenant(options) + static async update(id, data, options: IRepositoryOptions) { + const currentUser = SequelizeRepository.getCurrentUser(options) const transaction = SequelizeRepository.getTransaction(options) - if (data.status && ![null, 'rejected', 'engaged'].includes(data.status)) { - throw new Error400('en', 'errors.invalidEagleEyeStatus.message') - } + const currentTenant = SequelizeRepository.getCurrentTenant(options) - const existing = await options.database.eagleEyeContent.findOne({ + let record = await options.database.eagleEyeContent.findOne({ where: { - tenantId: tenant.id, - sourceId: data.sourceId, + id, + tenantId: currentTenant.id, }, + transaction, }) - // If the content is already shown, we don't need to add it again - if (existing) { - // If the content comes from a different kewword, we also add it - if (!lodash.isEqual(data.keywords.sort(), existing.keywords.sort())) { - const keywords = lodash.uniq([...existing.keywords, ...data.keywords]) - let exactKeywords = null - if (data.exactKeywords && !existing.exactKeywords) { - exactKeywords = data.exactKeywords - } else if (!data.exactKeywords && existing.exactKeywords) { - exactKeywords = existing.exactKeywords - } - if (data.exactKeywords && existing.exactKeywords) { - exactKeywords = lodash.uniq([...existing.exactKeywords, ...data.exactKeywords]) - } - const similarityScore = data.similarityScore - return existing.update( - { - keywords, - similarityScore, - exactKeywords, - }, - { - transaction, - }, - ) - } - return existing - } - - if (typeof data.keywords === 'string') { - data.keywords = [data.keywords] - } - - if (typeof data.exactKeywords === 'string') { - data.exactKeywords = [data.exactKeywords] - } - - if (typeof data.timestamp === 'number') { - data.timestamp = moment.unix(data.timestamp).toDate() + if (!record) { + throw new Error404() } - const record = await options.database.eagleEyeContent.create( + record = await record.update( { - ...lodash.pick(data, [ - 'sourceId', - 'vectorId', - 'status', - 'postAttributes', - 'title', - 'username', - 'url', - 'text', - 'timestamp', - 'userAttributes', - 'platform', - 'keywords', - 'exactKeywords', - 'similarityScore', - 'importHash', - ]), - - tenantId: tenant.id, - createdById: currentUser.id, + ...lodash.pick(data, ['platform', 'post', 'postedAt', 'url']), updatedById: currentUser.id, }, { @@ -103,192 +58,87 @@ export default class EagleEyeContentRepository { }, ) - await AuditLogRepository.log( - { - entityName: 'eagleEyeContent', - entityId: record.id, - action: AuditLogRepository.CREATE, - values: data, - }, - options, - ) - return this.findById(record.id, options) } - /** - * EagleEyeContent find all records matching given criteria. - * @returns Records found. - */ - static async findAndCountAll( - { filter = {} as any, advancedFilter = null as any, limit = 0, offset = 0, orderBy = '' }, - options: IRepositoryOptions, - ) { - // If the advanced filter is empty, we construct it from the query parameter filter - if (!advancedFilter) { - advancedFilter = { and: [] } - - if (filter.id) { - advancedFilter.and.push({ - id: filter.id, - }) - } + static async findById(id: string, options: IRepositoryOptions) { + const transaction = SequelizeRepository.getTransaction(options) - if (filter.sourceId) { - advancedFilter.and.push({ - sourceId: filter.sourceId, - }) - } + const include = [ + { + model: options.database.eagleEyeAction, + as: 'actions', + }, + ] - if (filter.vectorId) { - advancedFilter.and.push({ - vectorId: filter.vectorId, - }) - } + const currentTenant = SequelizeRepository.getCurrentTenant(options) - if (filter.status) { - if (filter.status === 'NULL') { - advancedFilter.and.push({ - status: 'NULL', - }) - } else if (filter.status === 'NOT_NULL') { - advancedFilter.and.push({ - status: { - not: null, - }, - }) - } else { - advancedFilter.and.push({ - status: { - textContains: filter.status, - }, - }) - } - } + const record = await options.database.eagleEyeContent.findOne({ + where: { + id, + tenantId: currentTenant.id, + }, + include, + transaction, + }) - if (filter.timestampRange) { - const [start, end] = filter.timestampRange - - if (start !== undefined && start !== null && start !== '') { - advancedFilter.and.push({ - timestamp: { - gte: start, - }, - }) - } - - if (end !== undefined && end !== null && end !== '') { - advancedFilter.and.push({ - timestamp: { - lte: end, - }, - }) - } - } + if (!record) { + throw new Error404() + } - if (filter.platforms) { - advancedFilter.and.push({ - platform: { - or: filter.platforms.split(','), - }, - }) - } + return this._populateRelations(record) + } - if (filter.nDays) { - advancedFilter.and.push({ - timestamp: { - gte: moment().subtract(filter.nDays, 'days').toDate(), - }, - }) - } + static async destroy(id: string, options: IRepositoryOptions): Promise { + const transaction = SequelizeRepository.getTransaction(options) - if (filter.title) { - advancedFilter.and.push({ - title: { - textContains: filter.title, - }, - }) - } + const currentTenant = SequelizeRepository.getCurrentTenant(options) - if (filter.text) { - advancedFilter.and.push({ - text: { - textContains: filter.text, - }, - }) - } + const record = await options.database.eagleEyeContent.findOne({ + where: { + id, + tenantId: currentTenant.id, + }, + transaction, + }) - if (filter.url) { - advancedFilter.and.push({ - url: { - textContains: filter.url, - }, - }) - } + if (record) { + await record.destroy({ + transaction, + force: true, + }) + } + } - if (filter.username) { - advancedFilter.and.push({ - username: { - textContains: filter.username, - }, - }) - } + static async findAndCountAll( + { advancedFilter = null as any, limit = 0, offset = 0, orderBy = '' }, + options: IRepositoryOptions, + ) { + const actionsSequelizeInclude = { + model: options.database.eagleEyeAction, + as: 'actions', + where: {}, + } - if (filter.keywords) { - // Overlap will take a post where any keyword matches any of the filter keywords - advancedFilter.and.push({ - keywords: { - overlap: filter.keywords.split(','), - }, - }) - } + if (advancedFilter && advancedFilter.action) { + const actionQueryParser = new QueryParser({}, options) - if (filter.similarityScoreRange) { - const [start, end] = filter.similarityScoreRange - - if (start !== undefined && start !== null && start !== '') { - advancedFilter.and.push({ - similarityScore: { - gte: start, - }, - }) - } - - if (end !== undefined && end !== null && end !== '') { - advancedFilter.and.push({ - similarityScore: { - lte: end, - }, - }) - } - } + const parsedActionQuery: QueryOutput = actionQueryParser.parse({ + filter: advancedFilter.action, + orderBy: 'timestamp_DESC', + }) - if (filter.createdAtRange) { - const [start, end] = filter.createdAtRange - - if (start !== undefined && start !== null && start !== '') { - advancedFilter.and.push({ - createdAt: { - gte: start, - }, - }) - } - - if (end !== undefined && end !== null && end !== '') { - advancedFilter.and.push({ - createdAt: { - lte: end, - }, - }) - } - } + actionsSequelizeInclude.where = parsedActionQuery.where ?? {} + delete advancedFilter.action } - const parser = new QueryParser({}, options) + const include = [actionsSequelizeInclude] + + const contentParser = new QueryParser({}, options) - const parsed: QueryOutput = parser.parse({ + const parsed: QueryOutput = contentParser.parse({ filter: advancedFilter, - orderBy: orderBy || ['createdAt_DESC'], + orderBy: orderBy || ['postedAt_DESC'], limit, offset, }) @@ -297,79 +147,38 @@ export default class EagleEyeContentRepository { rows, count, // eslint-disable-line prefer-const } = await options.database.eagleEyeContent.findAndCountAll({ + include, ...(parsed.where ? { where: parsed.where } : {}), - ...(parsed.having ? { having: parsed.having } : {}), order: parsed.order, limit: parsed.limit, offset: parsed.offset, transaction: SequelizeRepository.getTransaction(options), + subQuery: false, }) - rows = await this._populateRelationsForRows(rows) - - return { rows, count, limit: parsed.limit, offset: parsed.offset } - } - - static async update(id, data, options: IRepositoryOptions) { - const currentUser = SequelizeRepository.getCurrentUser(options) - - const transaction = SequelizeRepository.getTransaction(options) - - const currentTenant = SequelizeRepository.getCurrentTenant(options) - - let record = await options.database.eagleEyeContent.findOne({ - where: { - id, - tenantId: currentTenant.id, - }, - transaction, - }) - - if (!record) { - throw new Error404() - } - - if (data.status && ![null, 'rejected', 'engaged'].includes(data.status)) { - throw new Error400('en', 'errors.invalidEagleEyeStatus.message') + // If we have an actions filter, we should query again to eager + // load the all actions on a content because previous query will + // omit actions that don't match the given action filter + if (Object.keys(actionsSequelizeInclude.where).length !== 0) { + rows = ( + await options.database.eagleEyeContent.findAndCountAll({ + include: [{ ...actionsSequelizeInclude, where: {} }], + where: { id: { [Op.in]: rows.map((i) => i.id) } }, + order: parsed.order, + limit: parsed.limit, + offset: parsed.offset, + transaction: SequelizeRepository.getTransaction(options), + subQuery: false, + }) + ).rows } - record = await record.update( - { - ...lodash.pick(data, [ - 'sourceId', - 'vectorId', - 'status', - 'title', - 'username', - 'url', - 'text', - 'postAttributes', - 'timestamp', - 'platform', - 'userAttributes', - 'importHash', - // Missing keywords on purpose - ]), - updatedById: currentUser.id, - }, - { - transaction, - }, - ) + rows = await this._populateRelationsForRows(rows) - await AuditLogRepository.log( - { - entityName: 'eagleEyeContent', - entityId: record.id, - action: AuditLogRepository.UPDATE, - values: data, - }, - options, - ) - return this.findById(record.id, options) + return { rows, count, limit: parsed.limit, offset: parsed.offset } } - static async findById(id, options: IRepositoryOptions) { + static async findByUrl(url: string, options: IRepositoryOptions) { const transaction = SequelizeRepository.getTransaction(options) const include = [] @@ -378,7 +187,7 @@ export default class EagleEyeContentRepository { const record = await options.database.eagleEyeContent.findOne({ where: { - id, + url, tenantId: currentTenant.id, }, include, @@ -386,7 +195,7 @@ export default class EagleEyeContentRepository { }) if (!record) { - throw new Error404() + return null } return this._populateRelations(record) diff --git a/backend/src/database/repositories/userRepository.ts b/backend/src/database/repositories/userRepository.ts index 8b80aee5ed..781e93d1cf 100644 --- a/backend/src/database/repositories/userRepository.ts +++ b/backend/src/database/repositories/userRepository.ts @@ -320,6 +320,37 @@ export default class UserRepository { return this.findById(user.id, options) } + static async updateEagleEyeSettings(id: string, data, options: IRepositoryOptions) { + const currentUser = SequelizeRepository.getCurrentUser(options) + const transaction = SequelizeRepository.getTransaction(options) + + const user = await options.database.user.findByPk(id, { + transaction, + }) + + await user.update( + { + eagleEyeSettings: data, + updatedById: currentUser.id, + }, + { transaction }, + ) + + await AuditLogRepository.log( + { + entityName: 'user', + entityId: user.id, + action: AuditLogRepository.UPDATE, + values: { + ...user.get({ plain: true }), + eagleEyeSettings: data, + }, + }, + options, + ) + return this.findById(user.id, options) + } + static async findByEmail(email, options: IRepositoryOptions) { const transaction = SequelizeRepository.getTransaction(options) diff --git a/backend/src/database/utils/sequelizeTestUtils.ts b/backend/src/database/utils/sequelizeTestUtils.ts index 7b103981f4..83e813d9a2 100644 --- a/backend/src/database/utils/sequelizeTestUtils.ts +++ b/backend/src/database/utils/sequelizeTestUtils.ts @@ -34,6 +34,7 @@ export default class SequelizeTestUtils { files, microservices, "eagleEyeContents", + "eagleEyeActions", "auditLogs", "memberEnrichmentCache" cascade; diff --git a/backend/src/i18n/en.ts b/backend/src/i18n/en.ts index 0a41b33134..7df609a98f 100644 --- a/backend/src/i18n/en.ts +++ b/backend/src/i18n/en.ts @@ -102,19 +102,29 @@ const en = { activityDup: { message: 'This activity has already been linked to this member', }, - invalidEagleEyeStatus: { - message: 'Possible statuses are: "shown", "rejected", "engaged"', - }, - eagleEyeSearchFailed: { - message: 'Search failed in EagleEye', - }, OrganizationNameRequired: { message: 'Organization Name is required', }, projectNotFound: { message: 'Project not found', }, - + eagleEye: { + urlRequiredWhenUpserting: 'URL field is mandatory when upserting eagleEyeContent', + contentNotFound: 'Eagle eye content not found. Action will not be created.', + feedSettingsMissing: 'Feed settings are missing. Settings not updated.', + keywordsMissing: + 'Either keywords or exactKeywords are required in feeds. Settings not updated.', + platformMissing: + 'feed.platforms is required and must be a non-empty list. Settings not updated.', + platformInvalid: `feed.platforms contains {0}, which is not in [{1}]. Settings not updated.`, + publishedDateMissing: + 'feed.publishedDate is missing or invalid. It should be one of [{0}]. Settings not updated.', + emailInvalid: 'emailDigest.email needs a valid email address. Settings not updated.', + frequencyInvalid: + 'emailDigest.frequency needs to be one of daily, weekly. Settings not updated.', + timeInvalid: 'emailDigest.time needs to be a valid time. Settings not updated.', + notOnboarded: 'Eagle eye is not set up yet.', + }, integrations: { badEndpoint: 'Bad endpoint: {0}', }, @@ -195,6 +205,12 @@ const en = { planLimitExceeded: 'You have exceeded # of automations you can have in your plan.', }, }, + eagleEye: { + errors: { + planLimitExceeded: + 'EagleEye is only available in the Growth and Custom plans. Please upgrade your plan.', + }, + }, }, communityHelpCenter: { diff --git a/backend/src/security/permissions.ts b/backend/src/security/permissions.ts index 3c75df4c2b..ec28c71024 100644 --- a/backend/src/security/permissions.ts +++ b/backend/src/security/permissions.ts @@ -422,6 +422,21 @@ class Permissions { allowedRoles: [roles.admin, roles.readonly], allowedPlans: [plans.essential, plans.growth], }, + eagleEyeActionCreate: { + id: 'eagleEyeActionCreate', + allowedRoles: [roles.admin], + allowedPlans: [plans.growth], + }, + eagleEyeActionDestroy: { + id: 'eagleEyeActionDestroy', + allowedRoles: [roles.admin], + allowedPlans: [plans.growth], + }, + eagleEyeContentCreate: { + id: 'eagleEyeContentCreate', + allowedRoles: [roles.admin], + allowedPlans: [plans.growth], + }, eagleEyeContentRead: { id: 'eagleEyeContentRead', allowedRoles: [roles.admin, roles.readonly], diff --git a/backend/src/serverless/integrations/services/integrations/hackerNewsIntegrationService.ts b/backend/src/serverless/integrations/services/integrations/hackerNewsIntegrationService.ts index f454b6171b..254125c88e 100644 --- a/backend/src/serverless/integrations/services/integrations/hackerNewsIntegrationService.ts +++ b/backend/src/serverless/integrations/services/integrations/hackerNewsIntegrationService.ts @@ -1,4 +1,5 @@ import sanitizeHtml from 'sanitize-html' +import moment from 'moment' import { MemberAttributeName } from '../../../../database/attributes/member/enums' import { HackerNewsMemberAttributes } from '../../../../database/attributes/member/hackerNews' import MemberAttributeSettingsService from '../../../../services/memberAttributeSettingsService' @@ -13,9 +14,9 @@ import Operations from '../../../dbOperations/operations' import getPost from '../../usecases/hackerNews/getPost' import { HackerNewsGrid } from '../../grid/hackerNewsGrid' import { - EagleEyeResponse, HackerNewsResponse, HackerNewsIntegrationSettings, + HackerNewsSearchResult, } from '../../types/hackerNewsTypes' import { AddActivitiesSingle } from '../../types/messageTypes' import getPostsByKeywords from '../../usecases/hackerNews/getPostsByKeywords' @@ -43,7 +44,10 @@ export class HackerNewsIntegrationService extends IntegrationServiceBase { const keywords = Array.from(new Set([...settings.keywords, ...settings.urls])) this.logger(context).info(`Fetching posts for keywords: ${keywords}`) const posts = await getPostsByKeywords( - { keywords, nDays: context.onboarding ? 1000000 : 3 }, + { + keywords, + after: context.onboarding ? 0 : moment().subtract(30, 'days').unix(), + }, context.serviceContext, this.logger(context), ) @@ -55,8 +59,8 @@ export class HackerNewsIntegrationService extends IntegrationServiceBase { } async getStreams(context: IStepContext): Promise { - return context.pipelineData.posts.map((a: EagleEyeResponse) => ({ - value: a.sourceId.slice(a.sourceId.lastIndexOf(':') + 1), + return context.pipelineData.posts.map((a: HackerNewsSearchResult) => ({ + value: a.postId, metadata: { channel: a.keywords[0], }, diff --git a/backend/src/serverless/integrations/types/hackerNewsTypes.ts b/backend/src/serverless/integrations/types/hackerNewsTypes.ts index 89bc808f3a..5093679316 100644 --- a/backend/src/serverless/integrations/types/hackerNewsTypes.ts +++ b/backend/src/serverless/integrations/types/hackerNewsTypes.ts @@ -1,22 +1,37 @@ -export interface EagleEyeResponse { - vectorId: number - sourceId: string - title: string - url: string - createdAt: string - text: string - username: string - platform: string - timestamp: string - userAttributes: any - postAttributes: { - commentsCount: number - score: number - } - keywords: string[] +export interface HackerNewsSearchResponseRaw { + hits: [ + { + created_at: string + title: string + url: string + author: string + points: number + story_text: string + comment_text: string | null + num_comments: number + story_id: string | null + story_title: string | null + story_url: string | null + parent_id: string | null + created_at_i: number + _tags: string[] + objectID: string + _highlightResult: { + [key: string]: { + value: string + matchLevel: string + matchedWords: string[] + fullyHighlighted?: boolean + } + } + }, + ] } -export type EagleEyeResponses = EagleEyeResponse[] +export interface HackerNewsSearchResult { + keywords: string[] + postId: number +} export interface HackerNewsPost { by: string @@ -49,7 +64,7 @@ export interface HackerNewsIntegrationSettings { urls: string[] } -export interface EagleEyeInput { +export interface HackerNewsKeywordSearchInput { keywords: string[] - nDays: number + after: number } diff --git a/backend/src/serverless/integrations/usecases/hackerNews/getPostsByKeywords.ts b/backend/src/serverless/integrations/usecases/hackerNews/getPostsByKeywords.ts index 0e19a3ac5e..6a3563b131 100644 --- a/backend/src/serverless/integrations/usecases/hackerNews/getPostsByKeywords.ts +++ b/backend/src/serverless/integrations/usecases/hackerNews/getPostsByKeywords.ts @@ -1,23 +1,50 @@ +import axios from 'axios' import { IServiceOptions } from '../../../../services/IServiceOptions' -import { EagleEyeResponses, EagleEyeInput } from '../../types/hackerNewsTypes' +import { + HackerNewsKeywordSearchInput, + HackerNewsSearchResponseRaw, + HackerNewsSearchResult, +} from '../../types/hackerNewsTypes' import { Logger } from '../../../../utils/logging' import { timeout } from '../../../../utils/timing' -import EagleEyeContentService from '../../../../services/eagleEyeContentService' async function getPostsByKeyword( - input: EagleEyeInput, + input: HackerNewsKeywordSearchInput, options: IServiceOptions, logger: Logger, -): Promise { +): Promise { await timeout(2000) try { - const eagleEyeService = new EagleEyeContentService(options) - return await eagleEyeService.keywordMatch({ - keywords: input.keywords, - nDays: input.nDays, - platform: 'hacker_news', - }) + const out = [] + const existing = new Set() + for (const keyword of input.keywords) { + const config = { + method: 'get', + maxBodyLength: Infinity, + url: 'http://hn.algolia.com/api/v1/search', + params: { + query: keyword, + numericFilters: `created_at_i>${input.after}`, + tags: '(story,ask_hn,show_hn,poll)', + }, + headers: {}, + } + + const response = await axios(config) + const data = response.data as HackerNewsSearchResponseRaw + + for (const item of data.hits) { + if (!existing.has(item.objectID)) { + out.push({ + keywords: [keyword], + postId: item.objectID, + }) + existing.add(item.objectID) + } + } + } + return out } catch (err) { logger.error({ err, input }, 'Error while getting posts by keyword in EagleEye') throw err diff --git a/backend/src/services/__tests__/eagleEyeContentService.test.ts b/backend/src/services/__tests__/eagleEyeContentService.test.ts index 46b7d51a8b..9170b4a645 100644 --- a/backend/src/services/__tests__/eagleEyeContentService.test.ts +++ b/backend/src/services/__tests__/eagleEyeContentService.test.ts @@ -1,44 +1,9 @@ -import moment from 'moment' import SequelizeTestUtils from '../../database/utils/sequelizeTestUtils' -import { PlatformType } from '../../types/integrationEnums' +import { EagleEyeActionType, EagleEyeContent } from '../../types/eagleEyeTypes' import EagleEyeContentService from '../eagleEyeContentService' const db = null -const toUpsert = { - keywords: ['keyword'], - similarityScore: 1, - userAttributes: { - [PlatformType.GITHUB]: 'github', - }, - username: 'username', - timestamp: moment().unix(), - url: 'url', - title: 'title', - text: 'text', - platform: 'platform', - sourceId: 'sourceId', - vectorId: '1234', - status: null, -} - -const toUpsert2 = { - keywords: ['keyword'], - similarityScore: 1, - userAttributes: { - [PlatformType.GITHUB]: 'github', - }, - username: 'username', - timestamp: moment().subtract(1, 'days').unix(), - url: 'url', - title: 'title', - text: 'text', - platform: 'platform', - sourceId: 'sourceId2', - vectorId: '12345', - status: null, -} - describe('EagleEyeContentService tests', () => { beforeEach(async () => { await SequelizeTestUtils.wipeDatabase(db) @@ -49,91 +14,54 @@ describe('EagleEyeContentService tests', () => { await SequelizeTestUtils.closeConnection(db) }) - describe('bulk upsert method', () => { - it('Should upsert a single record', async () => { - const mockIRepositoryOptions = await SequelizeTestUtils.getTestIRepositoryOptions(db) - const service = new EagleEyeContentService(mockIRepositoryOptions) - await service.bulkUpsert([toUpsert]) - const result = await service.findAndCountAll({}) - expect(result.count).toBe(1) - }) - - it('Should upsert a single record', async () => { - const mockIRepositoryOptions = await SequelizeTestUtils.getTestIRepositoryOptions(db) - const service = new EagleEyeContentService(mockIRepositoryOptions) - await service.bulkUpsert([toUpsert]) - await service.bulkUpsert([toUpsert2]) - const result = await service.findAndCountAll({}) - expect(result.count).toBe(2) - }) - }) - - describe('findAndCount all method', () => { - it('Should find records', async () => { + describe('upsert method', () => { + it('Should create or update a single content using URL field', async () => { const mockIRepositoryOptions = await SequelizeTestUtils.getTestIRepositoryOptions(db) - const service = new EagleEyeContentService(mockIRepositoryOptions) - await service.bulkUpsert([toUpsert]) - await service.bulkUpsert([toUpsert2]) - const result = await service.findAndCountAll({}) - expect(result.count).toBe(2) - expect(result.rows[1].vectorId).toBe(toUpsert.vectorId) - expect(result.rows[0].vectorId).toBe(toUpsert2.vectorId) - }) + const content: EagleEyeContent = { + platform: 'reddit', + url: 'https://some-post-url', + post: { + title: 'post title', + body: 'post body', + }, + postedAt: '2020-05-27T15:13:30Z', + tenantId: mockIRepositoryOptions.currentTenant.id, + actions: [ + { + type: EagleEyeActionType.BOOKMARK, + timestamp: '2022-06-27T14:13:30Z', + }, + ], + } - it('Should work when no records', async () => { - const mockIRepositoryOptions = await SequelizeTestUtils.getTestIRepositoryOptions(db) const service = new EagleEyeContentService(mockIRepositoryOptions) - const result = await service.findAndCountAll({}) - expect(result.count).toBe(0) - }) - }) + const c1 = await service.upsert(content) - describe('findNotInbox method', () => { - it('4 records: 2 have status null, one is too old. Return 1', async () => { - const mockIRepositoryOptions = await SequelizeTestUtils.getTestIRepositoryOptions(db) - const service = new EagleEyeContentService(mockIRepositoryOptions) + let contents = await service.query({}) - const nInbox1 = { - keywords: ['keyword'], - similarityScore: 1, - userAttributes: { - [PlatformType.GITHUB]: 'github', - }, - username: 'username', - timestamp: moment().unix(), - url: 'url', - title: 'title', - text: 'text', - platform: 'platform', - sourceId: 'p-321', - vectorId: '321', - status: 'rejected', - } + expect(contents.count).toBe(1) + expect(contents.rows).toStrictEqual([c1]) - const nInbox2 = { - keywords: ['keyword'], - similarityScore: 1, - userAttributes: { - [PlatformType.GITHUB]: 'github', + // upsert previous url with some new fields + const contentWithSameUrl: EagleEyeContent = { + platform: 'reddit', + url: 'https://some-post-url', + post: { + title: 'a brand new post title', + body: 'better post body', }, - username: 'username', - timestamp: moment().subtract(31, 'days').unix(), - url: 'url', - title: 'title', - text: 'text', - platform: 'platform', - sourceId: 'p-4321', - vectorId: '4321', - status: 'engaged', + postedAt: '2020-05-27T15:13:30Z', + tenantId: mockIRepositoryOptions.currentTenant.id, } - await service.bulkUpsert([toUpsert, nInbox1, nInbox2, toUpsert2]) - - const result = await service.findNotInbox() + const c1Upserted = await service.upsert(contentWithSameUrl) - expect(result.length).toBe(1) - expect(result[0]).toBe(nInbox1.vectorId) + contents = await service.query({}) + expect(contents.count).toBe(1) + expect(contents.rows).toStrictEqual([c1Upserted]) + expect(c1Upserted.id).toEqual(c1.id) + expect(contents.rows[0].post).toStrictEqual(contentWithSameUrl.post) }) }) }) diff --git a/backend/src/services/eagleEyeActionService.ts b/backend/src/services/eagleEyeActionService.ts new file mode 100644 index 0000000000..75b71c9178 --- /dev/null +++ b/backend/src/services/eagleEyeActionService.ts @@ -0,0 +1,97 @@ +import EagleEyeActionRepository from '../database/repositories/eagleEyeActionRepository' +import EagleEyeContentRepository from '../database/repositories/eagleEyeContentRepository' +import SequelizeRepository from '../database/repositories/sequelizeRepository' +import Error404 from '../errors/Error404' +import { EagleEyeAction, EagleEyeActionType } from '../types/eagleEyeTypes' +import { IServiceOptions } from './IServiceOptions' +import { LoggingBase } from './loggingBase' + +export default class EagleEyeActionService extends LoggingBase { + options: IServiceOptions + + constructor(options) { + super(options) + this.options = options + } + + async create(data: EagleEyeAction, contentId: string): Promise { + const transaction = await SequelizeRepository.createTransaction(this.options) + + // find content + const content = await EagleEyeContentRepository.findById(contentId, this.options) + + if (!content) { + throw new Error404(this.options.language, 'errors.eagleEye.contentNotFound') + } + + const existingUserActions: EagleEyeAction[] = content.actions.filter( + (a) => a.actionById === this.options.currentUser.id, + ) + + const existingUserActionTypes = existingUserActions.map((a) => a.type) + + try { + // check if already bookmarked - if yes ignore the new action and return existing + if ( + data.type === EagleEyeActionType.BOOKMARK && + existingUserActionTypes.includes(EagleEyeActionType.BOOKMARK) + ) { + return existingUserActions.find((a) => a.type === EagleEyeActionType.BOOKMARK) + } + + // thumbs up and down should be mutually exclusive + if ( + data.type === EagleEyeActionType.THUMBS_DOWN && + existingUserActionTypes.includes(EagleEyeActionType.THUMBS_UP) + ) { + await EagleEyeActionRepository.removeActionFromContent( + EagleEyeActionType.THUMBS_UP, + contentId, + this.options, + ) + } else if ( + data.type === EagleEyeActionType.THUMBS_UP && + existingUserActionTypes.includes(EagleEyeActionType.THUMBS_DOWN) + ) { + await EagleEyeActionRepository.removeActionFromContent( + EagleEyeActionType.THUMBS_DOWN, + contentId, + this.options, + ) + } + + // add new action + const record = await EagleEyeActionRepository.createActionForContent( + data, + contentId, + this.options, + ) + + await SequelizeRepository.commitTransaction(transaction) + + return record + } catch (error) { + await SequelizeRepository.rollbackTransaction(transaction) + + SequelizeRepository.handleUniqueFieldError(error, this.options.language, 'EagleEyeContent') + + throw error + } + } + + async destroy(id: string) { + const action = await EagleEyeActionRepository.findById(id, this.options) + + const contentId = action.contentId + + await EagleEyeActionRepository.destroy(id, this.options) + + // find content + const content = await EagleEyeContentRepository.findById(contentId, this.options) + + // if content no longer has any actions attached to it, also delete the content + if (content.actions.length === 0) { + await EagleEyeContentRepository.destroy(contentId, this.options) + } + } +} diff --git a/backend/src/services/eagleEyeContentService.ts b/backend/src/services/eagleEyeContentService.ts index e42de0de9a..3220cef2f1 100644 --- a/backend/src/services/eagleEyeContentService.ts +++ b/backend/src/services/eagleEyeContentService.ts @@ -1,30 +1,25 @@ import moment from 'moment' -import request from 'superagent' -import { API_CONFIG } from '../config' -import SequelizeRepository from '../database/repositories/sequelizeRepository' +import axios from 'axios' +import { EAGLE_EYE_CONFIG } from '../config' import { IServiceOptions } from './IServiceOptions' import EagleEyeContentRepository from '../database/repositories/eagleEyeContentRepository' -import Error400 from '../errors/Error400' -import track from '../segment/track' import { LoggingBase } from './loggingBase' +import { + EagleEyeContent, + EagleEyeAction, + EagleEyeSettings, + EagleEyePublishedDates, + EagleEyeRawPost, + EagleEyePostWithActions, +} from '../types/eagleEyeTypes' +import { PageData, QueryData } from '../types/common' +import Error400 from '../errors/Error400' +import UserRepository from '../database/repositories/userRepository' -interface EagleEyeSearchPoint { - vectorId: string - sourceId: string - title: string - text?: string - url: string - timestamp: number - username: string - similarityScore: number - userAttributes: { - [platform: string]: string - } - keywords: string[] +export interface EagleEyeContentUpsertData extends EagleEyeAction { + content: EagleEyeContent } -type EagleEyeSearchOutput = EagleEyeSearchPoint[] - export default class EagleEyeContentService extends LoggingBase { options: IServiceOptions @@ -33,51 +28,36 @@ export default class EagleEyeContentService extends LoggingBase { this.options = options } - async upsert(data) { - const transaction = await SequelizeRepository.createTransaction(this.options) - - try { - const record = await EagleEyeContentRepository.upsert(data, { - ...this.options, - transaction, - }) - - await SequelizeRepository.commitTransaction(transaction) + /** + * Create an eagle eye shown content record. + * @param data Data to a new EagleEyeContent record. + * @param options Repository options. + * @returns Created EagleEyeContent record. + */ + async upsert(data: EagleEyeContent): Promise { + if (!data.url) { + throw new Error400(this.options.language, 'errors.eagleEye.urlRequiredWhenUpserting') + } - return record - } catch (error) { - await SequelizeRepository.rollbackTransaction(transaction) + // find by url + const existing = await EagleEyeContentRepository.findByUrl(data.url, this.options) - SequelizeRepository.handleUniqueFieldError(error, this.options.language, 'EagleEyeContent') + let record - throw error + if (existing) { + record = await EagleEyeContentRepository.update(existing.id, data, this.options) + } else { + record = await EagleEyeContentRepository.create(data, this.options) } - } - async findNotInbox() { - const shown = ( - await EagleEyeContentRepository.findAndCountAll( - { - filter: { - timestampRange: [ - moment().subtract(30, 'days').toDate(), - moment().add(1, 'hour').toDate(), - ], - status: 'NOT_NULL', - }, - }, - this.options, - ) - ).rows - // Slicing results such that lambda payload will not be too big - return shown.map((record) => record.vectorId).slice(0, 20000) + return record } - async findAndCountAll(args) { - return EagleEyeContentRepository.findAndCountAll(args, this.options) + async findById(id: string): Promise { + return EagleEyeContentRepository.findById(id, this.options) } - async query(data) { + async query(data: QueryData): Promise> { const advancedFilter = data.filter const orderBy = data.orderBy const limit = data.limit @@ -88,99 +68,102 @@ export default class EagleEyeContentService extends LoggingBase { ) } - async bulkUpsert(data: EagleEyeSearchOutput) { - for (const point of data) { - await this.upsert(point) + /** + * Convert a relative string date to a Date. For example, 30 days ago -> 2020-01-01 + * @param date String date. Can be one of EagleEyePublishedDates + * @returns The corresponding Date + */ + static switchDate(date: string, offset = 0) { + let dateMoment + switch (date) { + case EagleEyePublishedDates.LAST_24_HOURS: + dateMoment = moment().subtract(1, 'days') + break + case EagleEyePublishedDates.LAST_7_DAYS: + dateMoment = moment().subtract(7, 'days') + break + case EagleEyePublishedDates.LAST_14_DAYS: + dateMoment = moment().subtract(14, 'days') + break + case EagleEyePublishedDates.LAST_30_DAYS: + dateMoment = moment().subtract(30, 'days') + break + case EagleEyePublishedDates.LAST_90_DAYS: + dateMoment = moment().subtract(90, 'days') + break + default: + return null } + return dateMoment.add(offset, 'days').format('YYYY-MM-DD') } - async search(args) { - const { keywords, nDays, exactKeywords } = args - // We do not want what we have already accepted or rejected - const filters = await this.findNotInbox() - if (API_CONFIG.premiumApiUrl) { - const response = await request - .post(`${API_CONFIG.premiumApiUrl}/search`) - .send({ queries: keywords, nDays, filters, exactKeywords }) - const fromEagleEye: EagleEyeSearchOutput = JSON.parse(response.text) - await this.bulkUpsert(fromEagleEye) - return fromEagleEye + async search(email = false) { + const eagleEyeSettings: EagleEyeSettings = ( + await UserRepository.findById(this.options.currentUser.id, this.options) + ).eagleEyeSettings + + if (!eagleEyeSettings.onboarded) { + throw new Error400(this.options.language, 'errors.eagleEye.notOnboarded') } - return [] as EagleEyeSearchOutput - } - async keywordMatch(args) { - const { keywords, nDays, platform } = args - - if (API_CONFIG.premiumApiUrl) { - const response = await request - .post(`${API_CONFIG.premiumApiUrl}/keyword-match`) - .send({ exactKeywords: keywords, nDays, platform }) - try { - return JSON.parse(response.text) - } catch (error) { - this.log.error({ error: response.error }, 'error while calling eagle eye server!') - throw new Error400('en', 'errors.eagleEyeSearchFailed.message') - } - } else { - return [] as EagleEyeSearchOutput + const feedSettings = email ? eagleEyeSettings.emailDigest.feed : eagleEyeSettings.feed + + const keywords = feedSettings.keywords ? feedSettings.keywords.join(',') : '' + const exactKeywords = feedSettings.exactKeywords ? feedSettings.exactKeywords.join(',') : '' + const excludedKeywords = feedSettings.excludedKeywords + ? feedSettings.excludedKeywords.join(',') + : '' + + const afterDate = EagleEyeContentService.switchDate(feedSettings.publishedDate) + + const config = { + method: 'get', + maxBodyLength: Infinity, + url: `${EAGLE_EYE_CONFIG.url}`, + params: { + platforms: feedSettings.platforms.join(','), + keywords, + exact_keywords: exactKeywords, + exclude_keywords: excludedKeywords, + after_date: afterDate, + }, + headers: { + Authorization: `Bearer ${EAGLE_EYE_CONFIG.apiKey}`, + }, } - } - async update(id, data) { - const transaction = await SequelizeRepository.createTransaction(this.options) + const response = await axios(config) - try { - const recordBeforeUpdate = await EagleEyeContentRepository.findById(id, { ...this.options }) - const record = await EagleEyeContentRepository.update(id, data, { - ...this.options, - transaction, + const interacted = ( + await this.query({ + filter: { + postedAt: { gt: EagleEyeContentService.switchDate(feedSettings.publishedDate, 15) }, + }, }) + ).rows - // If we are updating status we want to track it - if (data.status !== recordBeforeUpdate.status) { - // If we are going from null to status, we are either accepting or rejecting - if (data.status && data.status !== null && data.status !== undefined) { - track( - `EagleEye ${data.status}`, - { - ...data, - platform: record.platform, - keywords: record.keywords, - title: record.title, - url: record.url, - }, - { ...this.options }, - ) - // Here we are bringing back a rejected post to the Inbox - } else if (recordBeforeUpdate.status === 'rejected' && data.status === null) { - track( - `EagleEye post from rejected to Inbox`, - { - ...data, - platform: record.platform, - keywords: record.keywords, - title: record.title, - url: record.url, - }, - { ...this.options }, - ) - } - } - - await SequelizeRepository.commitTransaction(transaction) - - return record - } catch (error) { - await SequelizeRepository.rollbackTransaction(transaction) + const interactedMap = {} - SequelizeRepository.handleUniqueFieldError(error, this.options.language, 'EagleEyeContent') + for (const item of interacted) { + interactedMap[item.url] = item + } - throw error + const out: EagleEyePostWithActions[] = [] + for (const item of response.data as EagleEyeRawPost[]) { + const post = { + description: item.description, + thumbnail: item.thumbnail, + title: item.title, + } + out.push({ + url: item.url, + postedAt: item.date, + post, + platform: item.platform, + actions: interactedMap[item.url] ? interactedMap[item.url].actions : [], + }) } - } - async findById(id) { - return EagleEyeContentRepository.findById(id, this.options) + return out } } diff --git a/backend/src/services/eagleEyeSettingsService.ts b/backend/src/services/eagleEyeSettingsService.ts new file mode 100644 index 0000000000..7753f2f13d --- /dev/null +++ b/backend/src/services/eagleEyeSettingsService.ts @@ -0,0 +1,158 @@ +import lodash from 'lodash' +import SequelizeRepository from '../database/repositories/sequelizeRepository' +import UserRepository from '../database/repositories/userRepository' +import Error400 from '../errors/Error400' +import { + EagleEyeSettings, + EagleEyeFeedSettings, + EagleEyePlatforms, + EagleEyePublishedDates, + EagleEyeEmailDigestSettings, +} from '../types/eagleEyeTypes' +import { IServiceOptions } from './IServiceOptions' +import { LoggingBase } from './loggingBase' + +export default class EagleEyeSettingsService extends LoggingBase { + options: IServiceOptions + + constructor(options) { + super(options) + this.options = options + } + + /** + * Validate and normalize feed settings. + * @param data Feed data of type EagleEyeFeedSettings + * @returns Normalized feed data if the input is valid. Otherwise a 400 Error + */ + getFeed(data: EagleEyeFeedSettings) { + // Feed is compulsory + if (!data) { + throw new Error400(this.options.language, 'errors.eagleEye.feedSettingsMissing') + } + + // We need at least one of keywords or exactKeywords + if (!data.keywords && !data.exactKeywords) { + throw new Error400(this.options.language, 'errors.eagleEye.keywordsMissing') + } + + // We need at least one platform + if (!data.platforms || data.platforms.length === 0) { + throw new Error400(this.options.language, 'errors.eagleEye.platformMissing') + } + + // Make sure platforms are in the allowed list + const platforms = Object.values(EagleEyePlatforms) as string[] + data.platforms.forEach((platform) => { + if (!platforms.includes(platform)) { + throw new Error400( + this.options.language, + 'errors.eagleEye.platformInvalid', + platform, + platforms.join(', '), + ) + } + }) + + // We need a date. Make sure it's in the allowed list. + const publishedDates = Object.values(EagleEyePublishedDates) as string[] + if (publishedDates.indexOf(data.publishedDate) === -1) { + throw new Error400( + this.options.language, + 'errors.eagleEye.publishedDateMissing', + publishedDates.join(', '), + ) + } + + // Remove any extra fields + return lodash.pick(data, [ + 'keywords', + 'exactKeywords', + 'excludedKeywords', + 'publishedDate', + 'platforms', + ]) + } + + /** + * Validate and normalize email digest settings. + * @param data Email digest settings of type EagleEyeEmailDigestSettings + * @param feed Standard feed settings of type EagleEyeFeedSettings + * @returns The normalized email digest settings if the input is valid. Otherwise a 400 Error. + */ + getEmailDigestSettings(data: EagleEyeEmailDigestSettings, feed: EagleEyeFeedSettings) { + // If the matchFeedSettings option is toggled, we set the email feed settings to the standard feed settings. + // Otherwise, we validate and normalize the email feed settings. + if (!data.matchFeedSettings) { + data.feed = this.getFeed(data.feed) + } else { + data.feed = feed + } + + // Make sure the email exists and is valid + const emailRegex = + /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ + if (!emailRegex.test(data.email)) { + throw new Error400(this.options.language, 'errors.eagleEye.emailInvalid') + } + + // Make sure the frequency exists and is valid + if (['daily', 'weekly'].indexOf(data.frequency) === -1) { + throw new Error400(this.options.language, 'errors.eagleEye.frequencyInvalid') + } + + // Make sure the time exists and is valid + const timeRegex = /^([0-1]?[0-9]|2[0-3]):[0-5][0-9]?$/ + if (!timeRegex.test(data.time)) { + throw new Error400(this.options.language, 'errors.eagleEye.timeInvalid') + } + + // Remove any extra fields + return lodash.pick(data, ['email', 'frequency', 'time', 'matchFeedSettings', 'feed']) + } + + /** + * Validate, normalize and update EagleEye settings. + * @param data Input of type EagleEyeSettings + * @returns Normalized EagleEyeSettings if the input is valid. Otherwise a 400 Error. + */ + async update(data: EagleEyeSettings): Promise { + const transaction = await SequelizeRepository.createTransaction(this.options) + try { + // At this point onboarded is true always + data.onboarded = true + + // Validate and normalize feed settings + data.feed = this.getFeed(data.feed) + + // If an email digest was sent, validate and normalize email digest settings + // Otherwise, set email digest to false + if (data.emailDigest || data.emailDigestActive) { + data.emailDigestActive = true + data.emailDigest = this.getEmailDigestSettings(data.emailDigest, data.feed) + } else { + data.emailDigestActive = false + } + + // Remove any extra fields + data = lodash.pick(data, ['onboarded', 'feed', 'emailDigestActive', 'emailDigest']) + + // Update the user's EagleEye settings + const userOut = await UserRepository.updateEagleEyeSettings( + this.options.currentUser.id, + data, + { ...this.options, transaction }, + ) + + await SequelizeRepository.commitTransaction(transaction) + + return userOut.eagleEyeSettings + } catch (error) { + await SequelizeRepository.rollbackTransaction(transaction) + + SequelizeRepository.handleUniqueFieldError(error, this.options.language, 'EagleEyeContent') + + throw error + } + } +} diff --git a/backend/src/types/common.ts b/backend/src/types/common.ts index 1eb58e2dc9..d7b4b7a253 100644 --- a/backend/src/types/common.ts +++ b/backend/src/types/common.ts @@ -5,6 +5,13 @@ export interface PageData { offset: number } +export interface QueryData { + filter?: any + orderBy?: string + limit?: number + offset?: number +} + export interface SearchCriteria { limit?: number offset?: number diff --git a/backend/src/types/eagleEyeTypes.ts b/backend/src/types/eagleEyeTypes.ts new file mode 100644 index 0000000000..2dccce7703 --- /dev/null +++ b/backend/src/types/eagleEyeTypes.ts @@ -0,0 +1,93 @@ +export enum EagleEyeActionType { + THUMBS_UP = 'thumbs-up', + THUMBS_DOWN = 'thumbs-down', + BOOKMARK = 'bookmark', +} + +export interface EagleEyeAction { + id?: string + type: EagleEyeActionType + timestamp: Date | string + createdAt?: Date | string + updatedAt?: Date | string +} + +export interface EagleEyeContent { + id?: string + platform: string + post: any + url: string + actions?: EagleEyeAction[] + tenantId: string + postedAt: string + createdAt?: Date | string + updatedAt?: Date | string +} + +export interface EagleEyeFeedSettings { + keywords: string[] + exactKeywords: string[] + excludedKeywords: string[] + publishedDate: string + platforms: string[] +} + +export interface EagleEyeEmailDigestSettings { + email: string + frequency: 'daily' | 'weekly' + time: string + feed: EagleEyeFeedSettings + matchFeedSettings: boolean +} + +export interface EagleEyeSettings { + onboarded: boolean + feed: EagleEyeFeedSettings + emailDigestActive: boolean + emailDigest?: EagleEyeEmailDigestSettings +} + +// Enum for EagleEyePlatforms +export enum EagleEyePlatforms { + GITHUB = 'github', + HACKERNEWS = 'hackernews', + DEVTO = 'devto', + REDDIT = 'reddit', + MEDIUM = 'medium', + STACKOVERFLOW = 'stackoverflow', + TWITTER = 'twitter', + YOUTUBE = 'youtube', + PRODUCTHUNT = 'producthunt', + KAGGLE = 'kaggle', + HASHNODE = 'hashnode', + LINKEDIN = 'linkedin', +} + +export enum EagleEyePublishedDates { + LAST_24_HOURS = 'Last 24h', + LAST_7_DAYS = 'Last 7d', + LAST_14_DAYS = 'Last 14d', + LAST_30_DAYS = 'Last 30d', + LAST_90_DAYS = 'Last 90d', +} + +export interface EagleEyeRawPost { + description: string + title: string + thumbnail?: string + url: string + platform: string + date: string +} + +export interface EagleEyePostWithActions { + post: { + description: string + title: string + thumbnail?: string + } + url: string + platform: string + postedAt: string + actions: EagleEyeAction[] +} From 536ef3f77479ea1f7149c322cca787674de11475 Mon Sep 17 00:00:00 2001 From: joanagmaia Date: Thu, 9 Feb 2023 09:15:11 +0000 Subject: [PATCH 02/56] Eagle eye onboarding (#496) --- frontend/public/images/eagle-eye/banner.png | Bin 0 -> 143325 bytes .../images/eagle-eye/onboard-discover.png | Bin 0 -> 4111 bytes .../images/eagle-eye/onboard-engage.png | Bin 0 -> 4593 bytes .../public/images/eagle-eye/onboard-grow.png | Bin 0 -> 5418 bytes .../public/images/integrations/kaggle.png | Bin 0 -> 376 bytes .../images/integrations/producthunt.png | Bin 0 -> 7354 bytes frontend/src/assets/scss/buttons.scss | 5 +- .../src/modules/layout/layout-page-content.js | 47 ++++++ .../src/modules/layout/pages/paywall-page.vue | 49 +----- .../components/onboard/eagle-eye-banner.vue | 42 +++++ .../components/onboard/eagle-eye-footer.vue | 63 +++++++ .../components/onboard/eagle-eye-intro.vue | 45 +++++ .../components/onboard/eagle-eye-keywords.vue | 100 +++++++++++ .../onboard/eagle-eye-platforms.vue | 158 ++++++++++++++++++ .../components/onboard/eagle-eye-summary.vue | 68 ++++++++ .../premium/eagle-eye/eagle-eye-constants.js | 75 +++++++++ .../src/premium/eagle-eye/eagle-eye-routes.js | 34 ++++ .../premium/eagle-eye/eagle-eye-service.js | 11 ++ .../pages/eagle-eye-onboard-page.vue | 146 ++++++++++++++++ .../src/premium/eagle-eye/store/actions.js | 17 ++ .../src/premium/eagle-eye/store/mutations.js | 12 +- frontend/src/premium/eagle-eye/store/state.js | 3 +- 22 files changed, 823 insertions(+), 52 deletions(-) create mode 100644 frontend/public/images/eagle-eye/banner.png create mode 100644 frontend/public/images/eagle-eye/onboard-discover.png create mode 100644 frontend/public/images/eagle-eye/onboard-engage.png create mode 100644 frontend/public/images/eagle-eye/onboard-grow.png create mode 100644 frontend/public/images/integrations/kaggle.png create mode 100644 frontend/public/images/integrations/producthunt.png create mode 100644 frontend/src/modules/layout/layout-page-content.js create mode 100644 frontend/src/premium/eagle-eye/components/onboard/eagle-eye-banner.vue create mode 100644 frontend/src/premium/eagle-eye/components/onboard/eagle-eye-footer.vue create mode 100644 frontend/src/premium/eagle-eye/components/onboard/eagle-eye-intro.vue create mode 100644 frontend/src/premium/eagle-eye/components/onboard/eagle-eye-keywords.vue create mode 100644 frontend/src/premium/eagle-eye/components/onboard/eagle-eye-platforms.vue create mode 100644 frontend/src/premium/eagle-eye/components/onboard/eagle-eye-summary.vue create mode 100644 frontend/src/premium/eagle-eye/eagle-eye-constants.js create mode 100644 frontend/src/premium/eagle-eye/pages/eagle-eye-onboard-page.vue diff --git a/frontend/public/images/eagle-eye/banner.png b/frontend/public/images/eagle-eye/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..63eee00d9935c8a56e3296f6679baed249bc084b GIT binary patch literal 143325 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 N002ovPDHLkV1k;i$1?x` literal 0 HcmV?d00001 diff --git a/frontend/public/images/eagle-eye/onboard-engage.png b/frontend/public/images/eagle-eye/onboard-engage.png new file mode 100644 index 0000000000000000000000000000000000000000..18395aa0f91a9961274b58b5e1ac1c2d04bc043e GIT binary patch literal 4593 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 b8NmMmih14QYLIyxY9b+|J(Y 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 nES z>BhlM+OI;oUwY}K>$qLgI3V4oWV1>a(#^J8NVhy7MYi?-iUTbIu zapLTxNi`0Fx7dyZl~sDoc34z6G!liAL7N7eVw=B`Qdo UKEB1oJ+40KSVtp1Iuo!~geRB1<90fpvEbk@KtFqudnC8M|eqm-n65c_}_6rNoq5^V};yjFx zq_^W@0ya9`MHbwC9h|*XrMnspkZZk-6;?b4aowe@hoy-DlYCpKXEUvlC?} za1}2fGEm@bv-@=caFJy@?TG||5=I@rxK%F|^lnZXJ-rTMeyOw+h< zHh>0!tZd`hG)5>hN{7x2434ly&b4(Rb%On^kscN<7#Fq!Gbq?8p2OS~@9M^g4`q=2 zk+wEER&iv2K{zvtrV|$)77Kpjt)?K%!D4pWC< zibXLn7>o{qWa>|&(-?HRiH;e@42#C#&{!M_gCU!f$T*zNj}Hm_& ziqKi+NTai&qpXpDs(;xK&i=(VBJziy0FR;LXlyjr6tis8cc4Gx7mgjx3HvVGpMhqE zF~gY=QIP-^`wI)W$;IUt{BPNYhyOxHMmfd+8vU^CZ_$x%``JwNPG%%4n!{i^#sCu6 z{!}b7YA5qwuK5S#0Q?s*JBSs$wBRFE2wb8PkKd6`#S`^b72_P&`7&DX^&JBwvTVTjo5(+~kV=#X~U4T^b zr$y0zf`QOtF(@;<8%nPQCuR5c9__9tU87(5Z#MxL(%a>9Eye~;VjIFOgxIMSN@qsf3b}X zVggM6L#Y3PMX~~-Vrd+vT_E7Wf0j?^e`i4?E#^P#Pa+ZtIGQ;YWr1a4P&g99A4MXW z`J-qwI*CqX5ChEofgJn~`eVsB%+FN)f9wB403(PN5y%93E*km&x9Fec>HoCo-`3MV zvdGNb6!SmJ`!BNpWe$3|*Z!4l=>MIFe?3!}oM0ec8#%0Sz#~9YBL7{=kq9)r1(r@n z1(2`-D4dxY2}L6Ul|VB0$1xdLCN_YCUk=$az5jnJ#J>g;umTk0zeqpQ=N5PR&FKE)ZZAvw-?9h_qb3qarN{kg_i|j0-weo(G)T$4pP8>= zHVDQU3{E=_6bnzl({9RMMJ3cJ3S?&_IzdgtORb27>e&yvbE zGt!!Fr@!>ztb150m$=PB{e>d;5#NkzBsTr1uaj%Uk7$72m)a;HnGEL3Zn)NaigQ`Q z^-2QMk{f=Z2$Yq)hhHLa_qDG8rJq+}!!hz2aCzidc@n89eL$t9Wp*y49`gYDN}?8A zqWQ3JJ(CQDQ_QI{m{l4Od4qWGkuzE#bqVw2m3#?m*U%AVC-BE@TTJR0+*+{KvqBY; zH`jw3m|VoQj=19tg|y&K2-H9B6xz>Fj^n}&#S&uGrZnC@Z`VX4e&0%1;tI>Jp;Ik| zEl=TA(pI3mkv>~yD&DkIt7>uAfaj=&!TsmOi)T?7_~)(T-~-ukTUaHC5H2Iu6U$=M z+T4x1iE0a|k9%x0lRo|~10gnZgh*jD)do|zb}p-d!rv9&Ns*p=KFaVKAMkuC~Q6DNh0UfBCY(kHnz z+Y9_fdwRA>(`ZAi@IY9pi_TbV!wHibuxW2@eWBz~oitQ$Z?3d<&+v24u+mD`RgzXR z3zjj3SDPojDxx~-qd$?GB6jJ!fM-*Z7+qeMOKzv=g9~6@?<~wck5*M6W^M1eQ8mHpJT+M5{9kDnK5fW_n=pXClw>+(pG3vwlJHKlqaJ(SNy1!JWM0%}TH&@2&Q=p+#Opq8y_~Tk zyuR~22A>;a(r3Z9uHPaxsX3zimH;nK{cu^3$>2Wd-AL4&Zh<@JCJS1Ir%1fst1XZ? zq!_u1(p^cDh?Baux^^K*c{T(vlyZWJ(6M1{Y+EY5Zb(F;+z)# z#y;DTv=%rU9rpW_YpzJ??G=^b*o12)Jxp#JBk*Hxv}dZ5QEnfvm{>B{yPNAxGjEt@ zKkUr#Yn>E-$;ko{BrDI~0PB+$8A;?nrFDFy7Ged7wMb_UVz}8sEr!bi9Z=$wAZee# z;$xWA^5*<0aO`10S%zG!(!@<|8l+`KZZ3ji?|v}X@c5lAG^rLfu{_>C(`l8ag4Gt8 zz{*}3vGsKJ)rtq8u%NOH5G^38Z^6yF%DX3J;-)8cB%c*2btY4gv)U4xgKIB=n)&b- zYi-vRJMq03dx8+xds1QI8bKWqN#C=uUr7#*7R@KXiy)5ropNTHe^ z+@w{QymL1$9sg!#_uPwag@XY@7sazB;`PWf;1#ISw7TPtdyu9X={Mf7cSU*}W3#%aMjg1ujkTPfJK!^wnL-yLoruA9Bw zg9S&(ehI|pIB!02qWksQ=edT$BeFK*3a2%`r7`auqf318JrjzUJJw)qocjDc?T<wC=fTM~GUh-Q2TR(h44))Q9eHP4%;e zr7pJc^wzgd?2{*r0q^J&hzihLLhz81vtEzyIC|b_B5QE`aJS(#Ue5`Gt0QjQbjgd0yRw|}dF@6uv0&O*n+CS!b@`Su*1%2DrG5#kRY9Tz z60)!L&r`Tut1LEUghh7Xu`jEoO3^xf;DLIs?bqEHo$IkbJYfxq=>;v@*2?6 zEoE+J;v~}@Zj5)olAH~Z8P^bQOaI2?fe6y~<=Qnf^W^I;tK(}@9IL2{LjyHx*^BD( z){3`Niw!#wOeVWKRycU0Cw!!4hbMk@w$Dk?u{Gd^J8$Qa>DA*3iY}=lbQ<%0FYDm+ zNDphMCI$fAR1>yetai+;Qz#}wv=<;VRkF3C>L-HRO%o~jNC+|7FMJ}EP}uWAwr(j) z{6y1ceS6cn=NVzz+CnsVsrRy@a$xV?;>6u?y0hl|T-eZg+rq(AxT2U8^qZMcUyRUW z#LgvJ9KM{OODQZv^6k28?Wj2J19*+9GjChf^ZbH~ov6Ef+Vch#Ex%h|QzcBgi@Qut zUmZ%4hK_G+$iDm4A%^>u_F&DC1;!IqqLTQY`Ws7o5w#?vc-PI=yCqseT~%A}vp4gb z!0-3MJ4+|yrN%c#9Y1D)j*X#OJUza^dbK8%b$(N=@M%V2>YjUWF<&e?dfmHgHNIM| zDTlGE5puY?IzXDZdumdjvgH-D?ThQ>64o5mT_pKz6>-o7RS;*aF5UL!qYJ$JG|u|+ z>Q}Wk{G~xz6WQCXiYdMaN*-D#?1G+#rrTGI2Fl*AT)W0(Jrd47^JYX$tT0{J4utOKFr=(@gef4sK$C(S0biG^g zQi+F}BE9SGdw!@>MeAD#YEW?EJXOfOT zL9q=Xo+;*E7lnc0g4UHWkf)SGTD#y;YydQH@}m8>t3cGI4NK3x(a@62`qt{!eW*Nb zXn2BKZjsvrf4L!HWVcgF1LQzF!Oa~q?rtE-Ld$iQPKWq`8Dn5#QAK za0EU{mv`;9D?8ccXho{B&F(^+N?!<@eWtXrJ-ew;El3Y;v`;pnGRTvh3e=G;o^a*hr6U z29jv&=e#AE9o+LFPt1A78N9y8lr@3I22o#(-xl2B@0!2HL#~f0l(h8m(A`=0*qq8} zt<_>a_Jd1VC7sUL7W0OCV@-^&<8ikl$%JLd(TlTbUL%f_%`T*)w-McX0q$LLS68(1 zkRc&=l52QXO2KaTv|B!_kL;!le&pyhu1#^?Y8BV!+W4yJf~H`i6_(!~ur)nx4iI~# z>9}NxuZM2I(9^5JlT$!bWR|E=Gb?xB5tg+94I;WEO5SAfY5?Tf+sKjK*Sia0)bpbC z6u4KXQsuMPtw&k}p5W?zzG*TbxxH!Q<8!S?hHB}&+zKDwt<a zg@0g6w=}}wIXCN{&~yvbPs-mdmEE>AHDsjk`q*Zos?aSj7p3coTV2+vh@YktN`}3i<={&^^!e5+axYvXJUM* ze`s300Lqsx6rC+XUUSiyY?a95^?m5NW%H_Z#Q`nk&O_hJTLO2z+UX&)u3ADtvR%Pb zJD!A`=;N4F@$-vv0@A#*GUEP>|F{O|P~#3J6iR#O(ZOEHFRPmJP{_e!-DdFv&%t9L z6NRc(h`0VmKr7>nk}qF=;CSwJM%XKuI9myZK+NUd4B&wt7>IC<8I&HpNr}P>nAk@6 zl79z*K=1AU?eT`r8`9;nP3nlZ>jDklLl*RB5DtiaEW^TEYhTETBZO)E+sjCu2M#4U zIsCU#n8u8ZP5ZA3Jh_3Or%Sbt6e|Jz?%nyk97qdv;n>{EjEofrEA#E*N>*K;)jb%B zK;(TL07jOYkTkuLhVUq4th`%wl;*#B396LOw-P*5R8&ATFQEV8@Xg3NN;It@Ss9ERrDKoXA}QJ1cl+071yY8$JP0Zj5uECzNT<(fkE>`uW!x) zDUF%enQ1ntEqbrjCx(WS4nX2;+4_!UuocevUM9w$mpqI8z)(;5t#9}3M>^vmcaEUH z$YTTtme!XS85O8ji9aRgkAr#8{>h=)WT%uFX@h~ACUSjZOFmU{hlnPfe>g%i;B&`- z4q%=fPNvMMloY0eP5t!XJbiw*PAVYh zq0*`6+kX#PB@Q~OAf-j+hH{(jgEr}HR;MS~ZU=s!Ll>ZRMu(ax=cp>fQ%N2E$G2#J zp$i(8M@K%;oLiSX{l2Zs?(czN_<7Ck-7K?s)wN>+C?8&JxJnEY5aJNJeo7aRkgk`!q+q9=-?J^f-h zBWJ5XsY^GyU}5a#eF+{kHNkdxVaBIkwfrJi_jsQca&LJ5B5!DF+*ev-W`TyQyBDpC zggiO?25)Jbr;-Lr9SzwJu6qhBx(F1$7>g@K_Bv!RbhQjsHC}4RxlqI5O-TnaU7kAt z156q$QG*Q%a&smlY5rMW-0r69Q|Hpx=#lZ@Z`mL2Ic3th;4$d^e(e;ceXkkS=#89- zluJ+zp*3|~-OXs-0!PLc^f#AldtXn|xiiF7EM>@L|DX*84T@Ju;4GBpJKEPv}GO zK?fnw^U3e7+p=g$f7J5i-mcFD7&h7}E9^18kRT)4Qs3^sas=@DLae@c4L=6hpMD9u zv3UQ)Axymg_6bd4d>%M;z-Q~u76NyuzEdUCSq3A(nXXMPR~gX6705Jtu372K9V$I! zWCVtKlL(T2V0SXG>kiZhcHIVce(#)N?2c>v4MMnb!?}u}Mt-Shd9kQT^_xDH4@%&c zaLor_R^k%mM3TqqZ1RcD3ha(P!M$mMQtH!*>jcYs%PWWJNjmif+SEGVOKn^mK~$df zv%ZMxeDj)ArD22d*dy<^w(r2413MEzBu|#eRZ?`Cha?1$YF3(JaxLNCM1y z?amN!H1JB4D;0p~l~gj@EXMHus*8`Dur@uzqt1fXyDg|2IStU3y{H&;nBNS-%;ke} zlBhoVk+gSgrtSUkt-w1G7W$)7EK8Wchc&-+f*aQfKlTql+S~k+k}C0RyM-9UhKX5} zFqy&Qr_yS&cGU?D-o;1Ms|ugNsqZ_=6cSf1tld7@a4za{x6OMrLnPcE^$BeVX$h9& z)^8wCkz&Q>mwHbU1cA@AKHpu@f-+oG74{^-xAw)n+z84$Gj(*SPV%$KCb|ct@|^B5 zm^;u|GDWKr?HR5cKiPvnKG3d?w2{L}9;SLv?GSK-gDrhXT$fE|Do<~l>KHgQ z_GiYN?H!aQN?XQg!{v4M`;|5FmBS?J9`i$kQd;@Tuig4h^RxN=@BdId4LW|!CnRA zjxoCj9-C4mG_@@2H%)MIc#qQ@XtNTUa#8)R#~W)C8v8q?PK_*eIu3u1-8Vhli~j9v sMChnUjw&hMGb(a0X}G-K1kL-p=4jD1r->QX@_&*bXGd2G&z_p{Uj(675C8xG literal 0 HcmV?d00001 diff --git a/frontend/src/assets/scss/buttons.scss b/frontend/src/assets/scss/buttons.scss index ae8706edd8..8c62c4990e 100644 --- a/frontend/src/assets/scss/buttons.scss +++ b/frontend/src/assets/scss/buttons.scss @@ -93,8 +93,9 @@ &:active { @apply bg-gray-200 text-gray-600 border-2 border-gray-200 border-solid; } - &[disabled] { - @apply cursor-not-allowed bg-white text-gray-400 border-2 border-gray-100 border-solid; + &[disabled], + &.disabled { + @apply cursor-not-allowed bg-white text-gray-400 border-none; } } diff --git a/frontend/src/modules/layout/layout-page-content.js b/frontend/src/modules/layout/layout-page-content.js new file mode 100644 index 0000000000..286aff748c --- /dev/null +++ b/frontend/src/modules/layout/layout-page-content.js @@ -0,0 +1,47 @@ +export const pageContent = { + organizations: { + icon: 'ri-community-line', + headerTitle: 'Organizations', + title: + 'Get a pulse of the organizations represented in your community', + mainContent: + 'Get a complete organization directory that you can search, filter, and sort instantly. Each organization also has its own profile page, which highlights key information about that organization and all the community members that belong to it. Keeping a pulse of which organizations your members are representing is extremely important for a successful bottom-up growth strategy.', + imageSrc: '/images/paywall/organizations.png', + imageClass: 'mt-8', + secondaryContent: + 'Organizations are companies or entities within your community. If a member that works at a certain company joins your community, that company will be added as an organization.', + featuresList: [] + }, + eagleEye: { + icon: 'ri-search-eye-line', + headerTitle: 'Eagle Eye', + title: 'Locate & engage with the right content', + mainContent: + "Our Eagle Eye app allows you to monitor different community platforms to find relevant content to engage with, helping you to gain developers' mindshare and grow your community organically.", + imageSrc: '/images/paywall/eagle-eye.png', + imageClass: '', + featuresList: [ + { + icon: 'ri-eye-2-line', + title: + 'Keep an Eagle Eye view on relevant content & posts to grow', + content: + "On top of monitoring everything going on within your community, crowd.dev's Eagle Eye application is focused on helping you engage with relevant content outside of your community to help grow it further." + }, + { + icon: 'ri-apps-2-line', + title: + 'Identify and engage with content across platforms', + content: + 'All you need to do is type in a few keywords and Eagle Eye will give you the most recent and relevant content to enage with accross platforms like HackerNews and Dev to connect you with like-minded people.' + }, + { + icon: 'ri-character-recognition-line', + title: + 'Search powered by Natural Language Processing', + content: + "The search engine behind Eagle Eye is based on a semantic model that delivers the most relevant content even when it doesn't match your keywords." + } + ] + } +} diff --git a/frontend/src/modules/layout/pages/paywall-page.vue b/frontend/src/modules/layout/pages/paywall-page.vue index d52939b219..f0a2358a07 100644 --- a/frontend/src/modules/layout/pages/paywall-page.vue +++ b/frontend/src/modules/layout/pages/paywall-page.vue @@ -97,6 +97,7 @@ import config from '@/config' import AppPageWrapper from '@/shared/layout/page-wrapper.vue' import { defineProps, computed } from 'vue' import { premiumFeatureCopy } from '@/utils/posthog' +import { pageContent } from '@/modules/layout/layout-page-content' const props = defineProps({ module: { @@ -109,54 +110,6 @@ const page = computed(() => pageContent[props.module]) const computedFeaturePlan = computed(() => { return config.isCommunityVersion ? 'Custom' : 'Growth' }) - -const pageContent = { - organizations: { - icon: 'ri-community-line', - headerTitle: 'Organizations', - title: - 'Get a pulse of the organizations represented in your community', - mainContent: - 'Get a complete organization directory that you can search, filter, and sort instantly. Each organization also has its own profile page, which highlights key information about that organization and all the community members that belong to it. Keeping a pulse of which organizations your members are representing is extremely important for a successful bottom-up growth strategy.', - imageSrc: '/images/paywall/organizations.png', - imageClass: 'mt-8', - secondaryContent: - 'Organizations are companies or entities within your community. If a member that works at a certain company joins your community, that company will be added as an organization.', - featuresList: [] - }, - eagleEye: { - icon: 'ri-search-eye-line', - headerTitle: 'Eagle Eye', - title: 'Locate & engage with the right content', - mainContent: - 'Our Eagle Eye app allows you to monitor different community platforms to find relevant content to engage with, helping you to gain developers’ mindshare and grow your community organically', - imageSrc: '/images/paywall/eagle-eye.png', - imageClass: '', - featuresList: [ - { - icon: 'ri-eye-2-line', - title: - 'Keep an Eagle Eye view on relevant content & posts to grow', - content: - 'On top of monitoring everything going on within your community, crowd.dev’s Eagle Eye application is focused on helping you engage with relevant content outside of your community to help grow it further.' - }, - { - icon: 'ri-apps-2-line', - title: - 'Identify and engage with content across platforms', - content: - 'All you need to do is type in a few keywords and Eagle Eye will give you the most recent and relevant content to enage with accross platforms like HackerNews and Dev to connect you with like-minded people.' - }, - { - icon: 'ri-character-recognition-line', - title: - 'Search powered by Natural Language Processing', - content: - 'The search engine behind Eagle Eye is based on a semantic model that delivers the most relevant content even when it doesn’t match your keywords.' - } - ] - } -} diff --git a/frontend/src/premium/eagle-eye/components/onboard/eagle-eye-platforms.vue b/frontend/src/premium/eagle-eye/components/onboard/eagle-eye-platforms.vue new file mode 100644 index 0000000000..114b246f49 --- /dev/null +++ b/frontend/src/premium/eagle-eye/components/onboard/eagle-eye-platforms.vue @@ -0,0 +1,158 @@ + + + + + diff --git a/frontend/src/premium/eagle-eye/components/onboard/eagle-eye-summary.vue b/frontend/src/premium/eagle-eye/components/onboard/eagle-eye-summary.vue new file mode 100644 index 0000000000..28963beeb9 --- /dev/null +++ b/frontend/src/premium/eagle-eye/components/onboard/eagle-eye-summary.vue @@ -0,0 +1,68 @@ + + + diff --git a/frontend/src/premium/eagle-eye/eagle-eye-constants.js b/frontend/src/premium/eagle-eye/eagle-eye-constants.js new file mode 100644 index 0000000000..74759895e0 --- /dev/null +++ b/frontend/src/premium/eagle-eye/eagle-eye-constants.js @@ -0,0 +1,75 @@ +export const publishedDateOptions = [ + { + label: 'Last 24h' + }, + { + label: 'Last 7d' + }, + { + label: 'Last 14d' + }, + { + label: 'Last 30d' + }, + { + label: 'Last 90d' + } +] + +export const platformOptions = { + devto: { + enabled: false, + label: 'DEV', + img: 'https://cdn-icons-png.flaticon.com/512/5969/5969051.png' + }, + github: { + enabled: false, + label: 'GitHub', + img: 'https://cdn-icons-png.flaticon.com/512/25/25231.png' + }, + hackernews: { + enabled: false, + label: 'Hacker News', + img: '/images/integrations/hackernews.svg' + }, + hashnode: { + enabled: false, + label: 'Hashnode', + img: 'https://cdn.hashnode.com/res/hashnode/image/upload/v1611902473383/CDyAuTy75.png?auto=compress' + }, + kaggle: { + enabled: false, + label: 'Kaggle', + img: '/images/integrations/kaggle.png' + }, + medium: { + enabled: false, + label: 'Medium', + img: 'https://cdn-icons-png.flaticon.com/512/5968/5968885.png' + }, + producthunt: { + enabled: false, + label: 'Product Hunt', + img: '/images/integrations/producthunt.png' + }, + reddit: { + enabled: false, + label: 'Reddit', + img: '/images/integrations/reddit.svg' + }, + stackoverflow: { + enabled: false, + label: 'Stack Overflow', + img: 'https://cdn-icons-png.flaticon.com/512/2111/2111628.png' + }, + twitter: { + enabled: false, + label: 'Twitter', + img: 'https://cdn-icons-png.flaticon.com/512/733/733579.png' + }, + youtube: { + enabled: false, + label: 'YouTube', + img: 'https://cdn-icons-png.flaticon.com/512/1384/1384060.png' + } +} diff --git a/frontend/src/premium/eagle-eye/eagle-eye-routes.js b/frontend/src/premium/eagle-eye/eagle-eye-routes.js index 3434056dae..a1c9137c36 100644 --- a/frontend/src/premium/eagle-eye/eagle-eye-routes.js +++ b/frontend/src/premium/eagle-eye/eagle-eye-routes.js @@ -22,6 +22,11 @@ const EagleEyeMainPage = async () => { return EagleEyePage() } +const EagleEyeOnboardPage = () => + import( + '@/premium/eagle-eye/pages/eagle-eye-onboard-page.vue' + ) + const EagleEyePage = () => import('@/premium/eagle-eye/pages/eagle-eye-page.vue') @@ -49,6 +54,15 @@ export default [ module: 'eagleEye' }, beforeEnter: async (to, _from, next) => { + // Redirect to onboard page if user is not onboarded + if (await isEagleEyeFeatureEnabled()) { + const currentUser = + store.getters['auth/currentUser'] + if (!currentUser.eagleEyeSettings?.onboarded) { + next('/eagle-eye/onboard') + } + } + if ( to.query.activeTab !== undefined && store.getters['eagleEye/activeView'].id !== @@ -60,6 +74,26 @@ export default [ ) } + next() + } + }, + { + name: 'eagleEyeOnboard', + path: '/eagle-eye/onboard', + component: EagleEyeOnboardPage, + exact: true, + meta: { + auth: true, + permission: Permissions.values.eagleEyeRead + }, + beforeEnter: async (to, _from, next) => { + const currentUser = + store.getters['auth/currentUser'] + // Redirect to onboard page if user is not onboarded + if (currentUser.eagleEyeSettings?.onboarded) { + next('/eagle-eye') + } + next() } } diff --git a/frontend/src/premium/eagle-eye/eagle-eye-service.js b/frontend/src/premium/eagle-eye/eagle-eye-service.js index 96f34aaa28..158cb40bcf 100644 --- a/frontend/src/premium/eagle-eye/eagle-eye-service.js +++ b/frontend/src/premium/eagle-eye/eagle-eye-service.js @@ -89,4 +89,15 @@ export class EagleEyeService { return response.data } + + static async updateSettings(data) { + const tenantId = AuthCurrentTenant.get() + + const response = await authAxios.put( + `/tenant/${tenantId}/eagleEyeContent/settings`, + data + ) + + return response.data + } } diff --git a/frontend/src/premium/eagle-eye/pages/eagle-eye-onboard-page.vue b/frontend/src/premium/eagle-eye/pages/eagle-eye-onboard-page.vue new file mode 100644 index 0000000000..4e147c0f00 --- /dev/null +++ b/frontend/src/premium/eagle-eye/pages/eagle-eye-onboard-page.vue @@ -0,0 +1,146 @@ + + + diff --git a/frontend/src/premium/eagle-eye/store/actions.js b/frontend/src/premium/eagle-eye/store/actions.js index f553065983..d87613a17d 100644 --- a/frontend/src/premium/eagle-eye/store/actions.js +++ b/frontend/src/premium/eagle-eye/store/actions.js @@ -101,5 +101,22 @@ export default { Errors.handle(error) commit('ENGAGE_ERROR') } + }, + + async doUpdateSettings({ commit, dispatch }, data) { + try { + commit('UPDATE_EAGLE_EYE_SETTINGS_STARTED') + + await EagleEyeService.updateSettings(data) + + await dispatch(`auth/doRefreshCurrentUser`, null, { + root: true + }) + + commit('UPDATE_EAGLE_EYE_SETTINGS_SUCCESS') + } catch (error) { + Errors.handle(error) + commit('UPDATE_EAGLE_EYE_SETTINGS_ERROR') + } } } diff --git a/frontend/src/premium/eagle-eye/store/mutations.js b/frontend/src/premium/eagle-eye/store/mutations.js index 71ccae9b85..c16f62b013 100644 --- a/frontend/src/premium/eagle-eye/store/mutations.js +++ b/frontend/src/premium/eagle-eye/store/mutations.js @@ -55,5 +55,15 @@ export default { state.records[recordId].status = null state.count-- }, - REVERT_EXCLUDE_ERROR() {} + REVERT_EXCLUDE_ERROR() {}, + + UPDATE_EAGLE_EYE_SETTINGS_STARTED(state) { + state.loadingUpdateSettings = true + }, + UPDATE_EAGLE_EYE_SETTINGS_SUCCESS(state) { + state.loadingUpdateSettings = false + }, + UPDATE_EAGLE_EYE_SETTINGS_ERROR(state) { + state.loadingUpdateSettings = false + } } diff --git a/frontend/src/premium/eagle-eye/store/state.js b/frontend/src/premium/eagle-eye/store/state.js index dbe210cf10..64259ebfcc 100644 --- a/frontend/src/premium/eagle-eye/store/state.js +++ b/frontend/src/premium/eagle-eye/store/state.js @@ -151,6 +151,7 @@ export default () => { ids: [], loading: false }, - count: 0 + count: 0, + loadingUpdateSettings: false } } From b845b7c16cb80170f525418187a9ea09c419e9d5 Mon Sep 17 00:00:00 2001 From: Joan Reyero Date: Thu, 9 Feb 2023 17:32:52 +0100 Subject: [PATCH 03/56] Fixes --- .../src/database/repositories/eagleEyeContentRepository.ts | 2 ++ backend/src/services/eagleEyeActionService.ts | 5 ++++- backend/src/services/eagleEyeContentService.ts | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/backend/src/database/repositories/eagleEyeContentRepository.ts b/backend/src/database/repositories/eagleEyeContentRepository.ts index 9a34d4d9d4..25949a10bd 100644 --- a/backend/src/database/repositories/eagleEyeContentRepository.ts +++ b/backend/src/database/repositories/eagleEyeContentRepository.ts @@ -126,6 +126,8 @@ export default class EagleEyeContentRepository { const parsedActionQuery: QueryOutput = actionQueryParser.parse({ filter: advancedFilter.action, orderBy: 'timestamp_DESC', + limit, + offset, }) actionsSequelizeInclude.where = parsedActionQuery.where ?? {} diff --git a/backend/src/services/eagleEyeActionService.ts b/backend/src/services/eagleEyeActionService.ts index 75b71c9178..05ad1e0c27 100644 --- a/backend/src/services/eagleEyeActionService.ts +++ b/backend/src/services/eagleEyeActionService.ts @@ -18,7 +18,10 @@ export default class EagleEyeActionService extends LoggingBase { const transaction = await SequelizeRepository.createTransaction(this.options) // find content - const content = await EagleEyeContentRepository.findById(contentId, this.options) + const content = await EagleEyeContentRepository.findById(contentId, { + ...this.options, + transaction, + }) if (!content) { throw new Error404(this.options.language, 'errors.eagleEye.contentNotFound') diff --git a/backend/src/services/eagleEyeContentService.ts b/backend/src/services/eagleEyeContentService.ts index 3220cef2f1..3af1d492ed 100644 --- a/backend/src/services/eagleEyeContentService.ts +++ b/backend/src/services/eagleEyeContentService.ts @@ -94,7 +94,7 @@ export default class EagleEyeContentService extends LoggingBase { default: return null } - return dateMoment.add(offset, 'days').format('YYYY-MM-DD') + return dateMoment.subtract(offset, 'days').format('YYYY-MM-DD') } async search(email = false) { @@ -137,7 +137,7 @@ export default class EagleEyeContentService extends LoggingBase { const interacted = ( await this.query({ filter: { - postedAt: { gt: EagleEyeContentService.switchDate(feedSettings.publishedDate, 15) }, + postedAt: { gt: EagleEyeContentService.switchDate(feedSettings.publishedDate, 90) }, }, }) ).rows From f11dec3c78bcf6cc222bb8e00061939f97f269dd Mon Sep 17 00:00:00 2001 From: Joan Reyero Date: Thu, 9 Feb 2023 17:59:43 +0100 Subject: [PATCH 04/56] Transactions in upsert content --- .../src/services/eagleEyeContentService.ts | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/backend/src/services/eagleEyeContentService.ts b/backend/src/services/eagleEyeContentService.ts index 3af1d492ed..698ec9d98a 100644 --- a/backend/src/services/eagleEyeContentService.ts +++ b/backend/src/services/eagleEyeContentService.ts @@ -15,6 +15,7 @@ import { import { PageData, QueryData } from '../types/common' import Error400 from '../errors/Error400' import UserRepository from '../database/repositories/userRepository' +import SequelizeRepository from '../database/repositories/sequelizeRepository' export interface EagleEyeContentUpsertData extends EagleEyeAction { content: EagleEyeContent @@ -38,19 +39,36 @@ export default class EagleEyeContentService extends LoggingBase { if (!data.url) { throw new Error400(this.options.language, 'errors.eagleEye.urlRequiredWhenUpserting') } + const transaction = await SequelizeRepository.createTransaction(this.options) - // find by url - const existing = await EagleEyeContentRepository.findByUrl(data.url, this.options) + try { + // find by url + const existing = await EagleEyeContentRepository.findByUrl(data.url, { + ...this.options, + transaction, + }) + + let record + + if (existing) { + record = await EagleEyeContentRepository.update(existing.id, data, { + ...this.options, + transaction, + }) + } else { + record = await EagleEyeContentRepository.create(data, { + ...this.options, + transaction, + }) + } - let record + await SequelizeRepository.commitTransaction(transaction) - if (existing) { - record = await EagleEyeContentRepository.update(existing.id, data, this.options) - } else { - record = await EagleEyeContentRepository.create(data, this.options) + return record + } catch (error) { + await SequelizeRepository.rollbackTransaction(transaction) + throw error } - - return record } async findById(id: string): Promise { From 4512a32c704893cf151d1326b37058fa284492c4 Mon Sep 17 00:00:00 2001 From: joanagmaia Date: Mon, 13 Feb 2023 09:16:03 +0000 Subject: [PATCH 05/56] First version of eagle eye feed (#507) --- frontend/package-lock.json | 76 +++++ frontend/package.json | 2 + frontend/src/assets/scss/layout.scss | 31 -- frontend/src/jsons/eagle-eye-sources.json | 38 --- frontend/src/main.js | 3 + .../components/conversation-reply.vue | 2 +- .../src/modules/layout/components/layout.vue | 92 ++---- .../src/modules/task/components/task-item.vue | 8 +- frontend/src/modules/tenant/store/getters.js | 80 ++++- .../components/eagle-eye-counter.vue | 45 --- .../eagle-eye/components/eagle-eye-filter.vue | 61 ---- .../components/eagle-eye-list-item.vue | 184 ------------ .../eagle-eye/components/eagle-eye-list.vue | 113 ------- .../eagle-eye/components/eagle-eye-search.vue | 80 ----- .../eagle-eye/components/eagle-eye-sorter.vue | 65 ---- .../eagle-eye/components/eagle-eye-tabs.vue | 53 ---- .../list/eagle-eye-email-digest-card.vue | 71 +++++ .../components/list/eagle-eye-list.vue | 83 ++++++ .../list/eagle-eye-loading-card.vue | 42 +++ .../list/eagle-eye-loading-state.vue | 20 ++ .../components/list/eagle-eye-result-card.vue | 280 ++++++++++++++++++ .../components/list/eagle-eye-settings.vue | 112 +++++++ .../components/list/eagle-eye-tabs.vue | 103 +++++++ .../premium/eagle-eye/eagle-eye-service.js | 64 ++-- .../premium/eagle-eye/eagle-eye-storage.js | 77 +++++ .../eagle-eye/pages/eagle-eye-page.vue | 113 +++---- .../src/premium/eagle-eye/store/actions.js | 194 ++++++++---- .../src/premium/eagle-eye/store/getters.js | 11 +- .../src/premium/eagle-eye/store/mutations.js | 93 +++--- frontend/src/premium/eagle-eye/store/state.js | 143 +-------- .../src/shared/form/inline-select-input.vue | 15 +- frontend/src/shared/image/image.vue | 35 +++ frontend/src/shared/shared-module.js | 4 +- frontend/tailwind.config.js | 2 +- 34 files changed, 1298 insertions(+), 1097 deletions(-) delete mode 100644 frontend/src/jsons/eagle-eye-sources.json delete mode 100644 frontend/src/premium/eagle-eye/components/eagle-eye-counter.vue delete mode 100644 frontend/src/premium/eagle-eye/components/eagle-eye-filter.vue delete mode 100644 frontend/src/premium/eagle-eye/components/eagle-eye-list-item.vue delete mode 100644 frontend/src/premium/eagle-eye/components/eagle-eye-list.vue delete mode 100644 frontend/src/premium/eagle-eye/components/eagle-eye-search.vue delete mode 100644 frontend/src/premium/eagle-eye/components/eagle-eye-sorter.vue delete mode 100644 frontend/src/premium/eagle-eye/components/eagle-eye-tabs.vue create mode 100644 frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-card.vue create mode 100644 frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue create mode 100644 frontend/src/premium/eagle-eye/components/list/eagle-eye-loading-card.vue create mode 100644 frontend/src/premium/eagle-eye/components/list/eagle-eye-loading-state.vue create mode 100644 frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue create mode 100644 frontend/src/premium/eagle-eye/components/list/eagle-eye-settings.vue create mode 100644 frontend/src/premium/eagle-eye/components/list/eagle-eye-tabs.vue create mode 100644 frontend/src/premium/eagle-eye/eagle-eye-storage.js create mode 100644 frontend/src/shared/image/image.vue diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 53621fb10a..2c2861b579 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -49,12 +49,14 @@ "vue-json-pretty": "^2.2.2", "vue-router": "^4.1.5", "vue3-click-away": "^1.2.4", + "vue3-lazyload": "^0.3.6", "vuedraggable": "^4.1.0", "vuex": "^4.0.2", "xlsx": "^0.17.2", "yup": "^0.32.11" }, "devDependencies": { + "@tailwindcss/line-clamp": "^0.4.2", "@tiptap/extension-link": "^2.0.0-beta.202", "@vue/cli-plugin-babel": "^5.0.8", "@vue/cli-plugin-eslint": "^5.0.1", @@ -2602,6 +2604,15 @@ "integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==", "dev": true }, + "node_modules/@tailwindcss/line-clamp": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/line-clamp/-/line-clamp-0.4.2.tgz", + "integrity": "sha512-HFzAQuqYCjyy/SX9sLGB1lroPzmcnWv1FHkIpmypte10hptf4oPUfucryMKovZh2u0uiS9U5Ty3GghWfEJGwVw==", + "dev": true, + "peerDependencies": { + "tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1" + } + }, "node_modules/@tiptap/core": { "version": "2.0.0-beta.199", "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.0.0-beta.199.tgz", @@ -14787,6 +14798,48 @@ "resolved": "https://registry.npmjs.org/vue3-click-away/-/vue3-click-away-1.2.4.tgz", "integrity": "sha512-O9Z2KlvIhJT8OxaFy04eiZE9rc1Mk/bp+70dLok68ko3Kr8AW5dU+j8avSk4GDQu94FllSr4m5ul4BpzlKOw1A==" }, + "node_modules/vue3-lazyload": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/vue3-lazyload/-/vue3-lazyload-0.3.6.tgz", + "integrity": "sha512-UcVnEN9JzxeFBa7nNAPWKXHTtvVAzWYhBSvRU+Gmx9MdTGLWKwjZiNSyB1Os25jr9HaFHWY0DaU8uugXkGu9Gw==", + "dependencies": { + "vue-demi": "^0.12.5" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^2.0.0 || >=3.0.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/vue3-lazyload/node_modules/vue-demi": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.12.5.tgz", + "integrity": "sha512-BREuTgTYlUr0zw0EZn3hnhC3I6gPWv+Kwh4MCih6QcAeaTlaIX0DwOVN0wHej7hSvDPecz4jygy/idsgKfW58Q==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, "node_modules/vuedraggable": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-4.1.0.tgz", @@ -17627,6 +17680,13 @@ "integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==", "dev": true }, + "@tailwindcss/line-clamp": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/line-clamp/-/line-clamp-0.4.2.tgz", + "integrity": "sha512-HFzAQuqYCjyy/SX9sLGB1lroPzmcnWv1FHkIpmypte10hptf4oPUfucryMKovZh2u0uiS9U5Ty3GghWfEJGwVw==", + "dev": true, + "requires": {} + }, "@tiptap/core": { "version": "2.0.0-beta.199", "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.0.0-beta.199.tgz", @@ -26765,6 +26825,22 @@ "resolved": "https://registry.npmjs.org/vue3-click-away/-/vue3-click-away-1.2.4.tgz", "integrity": "sha512-O9Z2KlvIhJT8OxaFy04eiZE9rc1Mk/bp+70dLok68ko3Kr8AW5dU+j8avSk4GDQu94FllSr4m5ul4BpzlKOw1A==" }, + "vue3-lazyload": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/vue3-lazyload/-/vue3-lazyload-0.3.6.tgz", + "integrity": "sha512-UcVnEN9JzxeFBa7nNAPWKXHTtvVAzWYhBSvRU+Gmx9MdTGLWKwjZiNSyB1Os25jr9HaFHWY0DaU8uugXkGu9Gw==", + "requires": { + "vue-demi": "^0.12.5" + }, + "dependencies": { + "vue-demi": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.12.5.tgz", + "integrity": "sha512-BREuTgTYlUr0zw0EZn3hnhC3I6gPWv+Kwh4MCih6QcAeaTlaIX0DwOVN0wHej7hSvDPecz4jygy/idsgKfW58Q==", + "requires": {} + } + } + }, "vuedraggable": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-4.1.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 028372b35d..afcb4f6ee6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -59,12 +59,14 @@ "vue-json-pretty": "^2.2.2", "vue-router": "^4.1.5", "vue3-click-away": "^1.2.4", + "vue3-lazyload": "^0.3.6", "vuedraggable": "^4.1.0", "vuex": "^4.0.2", "xlsx": "^0.17.2", "yup": "^0.32.11" }, "devDependencies": { + "@tailwindcss/line-clamp": "^0.4.2", "@tiptap/extension-link": "^2.0.0-beta.202", "@vue/cli-plugin-babel": "^5.0.8", "@vue/cli-plugin-eslint": "^5.0.1", diff --git a/frontend/src/assets/scss/layout.scss b/frontend/src/assets/scss/layout.scss index dc15dd8a00..7c06b09504 100644 --- a/frontend/src/assets/scss/layout.scss +++ b/frontend/src/assets/scss/layout.scss @@ -79,37 +79,6 @@ hr { flex-wrap: wrap; } -[class^='text-limit'], -[class*=' text-limit'] { - overflow: hidden; - text-overflow: ellipsis; - display: -webkit-box; - -webkit-box-orient: vertical; -} - -// Limits text to 1 line -.text-limit-1 { - -webkit-line-clamp: 1; - line-clamp: 1; -} - -// Limits text to 1 line -.text-limit-2 { - -webkit-line-clamp: 2; - line-clamp: 2; -} -// Limits text to 1 line -.text-limit-3 { - -webkit-line-clamp: 3; - line-clamp: 3; -} - -// Limits text to 4 lines -.text-limit-4 { - -webkit-line-clamp: 4; - line-clamp: 4; -} - // Disable autocomplete background input:-webkit-autofill, input:-webkit-autofill:hover, diff --git a/frontend/src/jsons/eagle-eye-sources.json b/frontend/src/jsons/eagle-eye-sources.json deleted file mode 100644 index db8fcc6970..0000000000 --- a/frontend/src/jsons/eagle-eye-sources.json +++ /dev/null @@ -1,38 +0,0 @@ -[ - { - "platform": "hacker_news", - "name": "Hacker News", - "image": - "https://directory-cdn.anymailfinder.com/a644fc61-3287-4d9e-9b7f-c9859fa50a8f" - }, - { - "platform": "devto", - "name": "DEV", - "image": - "https://i.pinimg.com/originals/23/49/2d/23492d49eefc1794c50377c2613baa00.jpg" - }, - { - "platform": "github", - "name": "GitHub", - "image": - "https://cdn-icons-png.flaticon.com/512/25/25231.png" - }, - { - "platform": "twitter", - "name": "Twitter", - "image": - "https://cdn-icons-png.flaticon.com/512/733/733579.png" - }, - { - "platform": "stackoverflow", - "name": "Stack Overflow", - "image": - "https://cdn-icons-png.flaticon.com/512/2111/2111628.png" - }, - { - "platform": "reddit", - "name": "Reddit", - "image": - "https://cdn-icons-png.flaticon.com/512/2111/2111589.png" - } -] \ No newline at end of file diff --git a/frontend/src/main.js b/frontend/src/main.js index a09bf0ce01..6f8baa2962 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -24,6 +24,7 @@ import App from '@/app.vue' import { vueSanitizeOptions } from '@/plugins/sanitize' import marked from '@/plugins/marked' import posthog from 'posthog-js' +import VueLazyLoad from 'vue3-lazyload' i18nInit() /** @@ -57,6 +58,8 @@ i18nInit() app.use(Vue3Sanitize, vueSanitizeOptions) app.use(VueClickAway) app.use(marked) + app.use(VueLazyLoad) + app.config.productionTip = process.env.NODE_ENV === 'production' diff --git a/frontend/src/modules/conversation/components/conversation-reply.vue b/frontend/src/modules/conversation/components/conversation-reply.vue index 00a8394697..6369bcb90b 100644 --- a/frontend/src/modules/conversation/components/conversation-reply.vue +++ b/frontend/src/modules/conversation/components/conversation-reply.vue @@ -44,7 +44,7 @@ :display-title="false" class="text-sm" :class="{ - 'text-limit-1': !displayContent && !showMore + 'line-clamp-1': !displayContent && !showMore }" :show-more="showMore" :limit="limit" diff --git a/frontend/src/modules/layout/components/layout.vue b/frontend/src/modules/layout/components/layout.vue index 4a8bc472fb..3faf577579 100644 --- a/frontend/src/modules/layout/components/layout.vue +++ b/frontend/src/modules/layout/components/layout.vue @@ -3,9 +3,13 @@ -
+
- +
@@ -129,7 +130,6 @@ import { mapActions, mapGetters } from 'vuex' import Banner from '@/shared/banner/banner.vue' import identify from '@/shared/monitoring/identify' import ConfirmDialog from '@/shared/dialog/confirm-dialog.js' -import moment from 'moment' import config from '@/config' export default { @@ -160,7 +160,16 @@ export default { currentUser: 'auth/currentUser', currentTenant: 'auth/currentTenant', integrationsInProgress: 'integration/inProgress', - integrationsWithErrors: 'integration/withErrors' + integrationsWithErrors: 'integration/withErrors', + showSampleDataAlert: 'tenant/showSampleDataAlert', + showIntegrationsErrorAlert: + 'tenant/showIntegrationsErrorAlert', + showIntegrationsInProgressAlert: + 'tenant/showIntegrationsInProgressAlert', + showTenantCreatingAlert: + 'tenant/showTenantCreatingAlert', + showPMFSurveyAlert: 'tenant/showPMFSurveyAlert', + showBanner: 'tenant/showBanner' }), integrationsInProgressToString() { const arr = this.integrationsInProgress.map( @@ -178,43 +187,6 @@ export default { ) } }, - shouldShowIntegrationsInProgressAlert() { - return this.integrationsInProgress.length > 0 - }, - shouldShowIntegrationsErrorAlert() { - return ( - this.integrationsWithErrors.length > 0 && - this.$route.name !== 'integration' - ) - }, - shouldShowSampleDataAlert() { - return this.currentTenant.hasSampleData - }, - shouldShowPMFSurveyAlert() { - return ( - config.typeformId && - config.typeformTitle && - !this.hideTypeformBanner - ) - }, - shouldShowTenantCreatingAlert() { - return ( - moment().diff( - moment(this.currentTenant.createdAt), - 'minutes' - ) <= 2 - ) - }, - computedBannerWrapperClass() { - return { - 'pt-16': - this.shouldShowSampleDataAlert || - this.shouldShowIntegrationsErrorAlert || - this.shouldShowIntegrationsInProgressAlert || - this.shouldShowTenantCreatingAlert || - this.shouldShowPMFSurveyAlert - } - }, elMainStyle() { if (this.isMobile && !this.collapsed) { return { @@ -280,30 +252,6 @@ export default { // as long as it's not one of the above reserved names. }, - account: { - id: this.currentTenant.id, // Required if using Pendo Feedback, default uses the value 'ACCOUNT-UNIQUE-ID' - name: this.currentTenant.name, // Optional - is_paying: this.currentTenant.plan !== 'Essential' // Recommended if using Pendo Feedback - // monthly_value:// Recommended if using Pendo Feedback - // planLevel: // Optional - // planPrice: // Optional - // creationDate: // Optional - - // You can add any additional account level key-values here, - // as long as it's not one of the above reserved names. - } - }) - console.log({ - visitor: { - id: this.currentUser.id, // Required if user is logged in, default creates anonymous ID - email: this.currentUser.email, // Recommended if using Pendo Feedback, or NPS Email - full_name: this.currentUser.fullName // Recommended if using Pendo Feedback - // role: // Optional - - // You can add any additional visitor level key-values here, - // as long as it's not one of the above reserved names. - }, - account: { id: this.currentTenant.id, // Required if using Pendo Feedback, default uses the value 'ACCOUNT-UNIQUE-ID' name: this.currentTenant.name, // Optional diff --git a/frontend/src/modules/task/components/task-item.vue b/frontend/src/modules/task/components/task-item.vue index 9d2055f426..0a27702b5b 100644 --- a/frontend/src/modules/task/components/task-item.vue +++ b/frontend/src/modules/task/components/task-item.vue @@ -90,11 +90,9 @@
{ + const currentTenant = rootGetters['auth/currentTenant'] + + return currentTenant.hasSampleData + }, + + showIntegrationsErrorAlert: ( + _state, + _getters, + _rootState, + rootGetters + ) => { + const integrationsWithErrors = + rootGetters['integration/withErrors'] + + return ( + integrationsWithErrors.length > 0 && + router.currentRoute.value.name !== 'integration' + ) + }, + + showIntegrationsInProgressAlert: ( + _state, + _getters, + _rootState, + rootGetters + ) => { + const integrationsInProgress = + rootGetters['integration/inProgress'] + + return integrationsInProgress.length > 0 + }, + + showTenantCreatingAlert: ( + _state, + _getters, + _rootState, + rootGetters + ) => { + const currentTenant = rootGetters['auth/currentTenant'] + + return ( + moment().diff( + moment(currentTenant.createdAt), + 'minutes' + ) <= 2 + ) + }, + + showPMFSurveyAlert: () => { + const hideTypeformBanner = localStorage.getItem( + `hideTypeformBanner-${config.typeformId}` + ) + + return ( + config.typeformId && + config.typeformTitle && + !hideTypeformBanner + ) + }, + + showBanner: (_state, getters) => { + return ( + getters.showSampleDataAlert || + getters.showIntegrationsErrorAlert || + getters.showIntegrationsInProgressAlert || + getters.showTenantCreatingAlert || + getters.showPMFSurveyAlert + ) + } } diff --git a/frontend/src/premium/eagle-eye/components/eagle-eye-counter.vue b/frontend/src/premium/eagle-eye/components/eagle-eye-counter.vue deleted file mode 100644 index 7fa76bdf28..0000000000 --- a/frontend/src/premium/eagle-eye/components/eagle-eye-counter.vue +++ /dev/null @@ -1,45 +0,0 @@ - - - diff --git a/frontend/src/premium/eagle-eye/components/eagle-eye-filter.vue b/frontend/src/premium/eagle-eye/components/eagle-eye-filter.vue deleted file mode 100644 index b3e4dee0a8..0000000000 --- a/frontend/src/premium/eagle-eye/components/eagle-eye-filter.vue +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - diff --git a/frontend/src/premium/eagle-eye/components/eagle-eye-list-item.vue b/frontend/src/premium/eagle-eye/components/eagle-eye-list-item.vue deleted file mode 100644 index 251cbcbe1d..0000000000 --- a/frontend/src/premium/eagle-eye/components/eagle-eye-list-item.vue +++ /dev/null @@ -1,184 +0,0 @@ - - - - - diff --git a/frontend/src/premium/eagle-eye/components/eagle-eye-list.vue b/frontend/src/premium/eagle-eye/components/eagle-eye-list.vue deleted file mode 100644 index 72d1fbf0e0..0000000000 --- a/frontend/src/premium/eagle-eye/components/eagle-eye-list.vue +++ /dev/null @@ -1,113 +0,0 @@ - - - - - diff --git a/frontend/src/premium/eagle-eye/components/eagle-eye-search.vue b/frontend/src/premium/eagle-eye/components/eagle-eye-search.vue deleted file mode 100644 index ead673db3e..0000000000 --- a/frontend/src/premium/eagle-eye/components/eagle-eye-search.vue +++ /dev/null @@ -1,80 +0,0 @@ - - - diff --git a/frontend/src/premium/eagle-eye/components/eagle-eye-sorter.vue b/frontend/src/premium/eagle-eye/components/eagle-eye-sorter.vue deleted file mode 100644 index f551718a79..0000000000 --- a/frontend/src/premium/eagle-eye/components/eagle-eye-sorter.vue +++ /dev/null @@ -1,65 +0,0 @@ - - - diff --git a/frontend/src/premium/eagle-eye/components/eagle-eye-tabs.vue b/frontend/src/premium/eagle-eye/components/eagle-eye-tabs.vue deleted file mode 100644 index 92d7be79d7..0000000000 --- a/frontend/src/premium/eagle-eye/components/eagle-eye-tabs.vue +++ /dev/null @@ -1,53 +0,0 @@ - - - - - diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-card.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-card.vue new file mode 100644 index 0000000000..3184a31043 --- /dev/null +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-card.vue @@ -0,0 +1,71 @@ + + + diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue new file mode 100644 index 0000000000..7757e0cd1c --- /dev/null +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue @@ -0,0 +1,83 @@ + + + diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-loading-card.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-loading-card.vue new file mode 100644 index 0000000000..8a7103a82e --- /dev/null +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-loading-card.vue @@ -0,0 +1,42 @@ + + + diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-loading-state.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-loading-state.vue new file mode 100644 index 0000000000..56c81ea4b9 --- /dev/null +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-loading-state.vue @@ -0,0 +1,20 @@ + + + diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue new file mode 100644 index 0000000000..29038d380e --- /dev/null +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue @@ -0,0 +1,280 @@ + + + + + diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings.vue new file mode 100644 index 0000000000..37f16e51d0 --- /dev/null +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings.vue @@ -0,0 +1,112 @@ + + + + + diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-tabs.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-tabs.vue new file mode 100644 index 0000000000..9095dcfff8 --- /dev/null +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-tabs.vue @@ -0,0 +1,103 @@ + + + + + diff --git a/frontend/src/premium/eagle-eye/eagle-eye-service.js b/frontend/src/premium/eagle-eye/eagle-eye-service.js index 158cb40bcf..7582cbfd3c 100644 --- a/frontend/src/premium/eagle-eye/eagle-eye-service.js +++ b/frontend/src/premium/eagle-eye/eagle-eye-service.js @@ -1,21 +1,10 @@ import authAxios from '@/shared/axios/auth-axios' import AuthCurrentTenant from '@/modules/auth/auth-current-tenant' -import buildApiPayload from '@/shared/filter/helpers/build-api-payload' export class EagleEyeService { - static async find(id) { - const tenantId = AuthCurrentTenant.get() - - const response = await authAxios.get( - `/tenant/${tenantId}/eagleEyeContent/${id}` - ) - - return response.data - } - - static async list(filter, orderBy, limit, offset) { + static async query(filter, orderBy, limit, offset) { const body = { - filter: buildApiPayload(filter), + filter, orderBy, limit, offset @@ -31,60 +20,43 @@ export class EagleEyeService { return response.data } - static async populate(keywords) { - const data = { - exactKeywords: keywords - .filter((k) => { - return k[0] === '"' && k[k.length - 1] === '"' - }) - .map((s) => s.replaceAll('"', '')), - keywords: keywords.filter((k) => { - return k[0] !== '"' && k[k.length - 1] !== '"' - }) - } - + static async search() { const tenantId = AuthCurrentTenant.get() - await authAxios.post( - `/tenant/${tenantId}/eagleEyeContent`, - data + const response = await authAxios.get( + `/tenant/${tenantId}/eagleEyeContent/search` ) + + return response.data } - static async exclude(id) { + static async createContent({ post }) { const tenantId = AuthCurrentTenant.get() - const response = await authAxios.put( - `/tenant/${tenantId}/eagleEyeContent/${id}`, - { - status: 'rejected' - } + const response = await authAxios.post( + `/tenant/${tenantId}/eagleEyeContent`, + post ) return response.data } - static async engage(id) { + static async addAction({ postId, actionData }) { const tenantId = AuthCurrentTenant.get() - const response = await authAxios.put( - `/tenant/${tenantId}/eagleEyeContent/${id}`, - { - status: 'engaged' - } + const response = await authAxios.post( + `/tenant/${tenantId}/eagleEyeContent/${postId}/action`, + actionData ) return response.data } - static async revertExclude(id) { + static async deleteAction({ postId, actionId }) { const tenantId = AuthCurrentTenant.get() - const response = await authAxios.put( - `/tenant/${tenantId}/eagleEyeContent/${id}`, - { - status: null - } + const response = await authAxios.delete( + `/tenant/${tenantId}/eagleEyeContent/${postId}/action/${actionId}` ) return response.data diff --git a/frontend/src/premium/eagle-eye/eagle-eye-storage.js b/frontend/src/premium/eagle-eye/eagle-eye-storage.js new file mode 100644 index 0000000000..a54aa7347a --- /dev/null +++ b/frontend/src/premium/eagle-eye/eagle-eye-storage.js @@ -0,0 +1,77 @@ +/** + * Storage Object + * [tenantId]: { + * [userId]: { + * posts: [] + * storageDate: '' + * } + * } + */ + +import moment from 'moment' + +export const shouldFetchNewResults = ({ + tenantId, + userId +}) => { + const storage = localStorage.getItem('eagleEyeResults') + const currentDay = moment() + + // Fetch new results if it is a new day from the previous stored one, + // or if storage is not set or if user is not set in storage + if ( + !storage || + !JSON.parse(storage)[tenantId]?.[userId] || + !currentDay.isSame( + JSON.parse(storage)[tenantId][userId].storageDate, + 'd' + ) + ) { + return true + } + + return false +} + +// Get posts from local storage +export const getResultsFromStorage = ({ + tenantId, + userId +}) => { + const storage = localStorage.getItem('eagleEyeResults') + + if (!storage) { + return null + } + + return JSON.parse(storage)[tenantId][userId].posts +} + +// Set results in storage for the given tenant and user id +export const setResultsInStorage = ({ + posts, + tenantId, + userId +}) => { + const storage = JSON.parse( + localStorage.getItem('eagleEyeResults') || '{}' + ) + const payload = { + posts, + storageDate: moment() + } + + // Add/update user posts in tenantId + if (storage[tenantId]) { + storage[tenantId][userId] = payload + } else { + storage[tenantId] = { + [userId]: payload + } + } + + localStorage.setItem( + 'eagleEyeResults', + JSON.stringify(storage) + ) +} diff --git a/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue b/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue index 359cc59a13..43624b9c48 100644 --- a/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue +++ b/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue @@ -1,43 +1,32 @@ diff --git a/frontend/src/premium/eagle-eye/store/actions.js b/frontend/src/premium/eagle-eye/store/actions.js index d87613a17d..6cfdefcc7f 100644 --- a/frontend/src/premium/eagle-eye/store/actions.js +++ b/frontend/src/premium/eagle-eye/store/actions.js @@ -1,40 +1,81 @@ import sharedActions from '@/shared/store/actions' import { EagleEyeService } from '@/premium/eagle-eye/eagle-eye-service' import Errors from '@/shared/error/errors' +import moment from 'moment' +import { + getResultsFromStorage, + setResultsInStorage, + shouldFetchNewResults +} from '@/premium/eagle-eye/eagle-eye-storage' export default { ...sharedActions('eagleEye'), async doFetch( - { commit, getters }, - { keepPagination = false } + { commit, getters, rootGetters }, + { keepPagination = false, resetStorage = false } ) { try { - commit('FETCH_STARTED', { - keepPagination - }) - - const response = await EagleEyeService.list( - getters.activeView.filter, - getters.orderBy, - getters.limit, - getters.offset - ) - - if ( - getters.activeView.filter.attributes.keywords && - getters.activeView.filter.attributes.keywords.value - ?.length > 0 - ) { - localStorage.setItem( - 'eagleEye_keywords', - getters.activeView.filter.attributes.keywords - .value + const currentUser = rootGetters['auth/currentUser'] + const currentTenant = + rootGetters['auth/currentTenant'] + let list = [], + count, + appendToList + + commit('FETCH_STARTED', { keepPagination }) + + // Bookmarks View + if (getters.activeView.id === 'bookmarked') { + const { sorter } = getters.activeView + const response = await EagleEyeService.query( + { + action: { + type: 'bookmark', + ...(sorter === 'individualBookmarks' && { + actionById: currentUser.id + }) + } + }, + getters.orderBy, + getters.limit, + getters.offset ) + + list = response.rows + count = response.count + + if (getters.offset !== 0) { + appendToList = true + } + } + // Feed view + else { + const fetchNewResults = + shouldFetchNewResults({ + tenantId: currentTenant.id, + userId: currentUser.id + }) || resetStorage + + if (fetchNewResults) { + list = await EagleEyeService.search() + + setResultsInStorage({ + posts: list, + tenantId: currentTenant.id, + userId: currentUser.id + }) + } else { + list = getResultsFromStorage({ + tenantId: currentTenant.id, + userId: currentUser.id + }) + } } commit('FETCH_SUCCESS', { - rows: response.rows, - count: response.count + list, + ...(count && { count }), + ...(appendToList && { appendToList }) }) } catch (error) { Errors.handle(error) @@ -42,64 +83,91 @@ export default { } }, - async doPopulate( - { commit, getters }, - { keepPagination = false } + async doAddAction( + { state, commit, rootGetters }, + { post, action, index } ) { try { - commit('POPULATE_STARTED', { - keepPagination + commit('UPDATE_ACTION_LOADING', { + index }) - const keywords = - getters.activeView.filter.attributes.keywords.value - await EagleEyeService.populate(keywords) + // Create content in database + const postResponse = + await EagleEyeService.createContent({ + post + }) - commit('POPULATE_SUCCESS', { - keywords + commit('CREATE_CONTENT_SUCCESS', { + post: postResponse, + index }) - } catch (error) { - Errors.handle(error) - commit('POPULATE_ERROR') - } - }, - - async doExclude({ commit }, recordId) { - try { - commit('EXCLUDE_STARTED', recordId) - await EagleEyeService.exclude(recordId) + // Add action to db content + const actionData = { + type: action, + timestamp: moment().utc().format('YYYY-MM-DD') + } - commit('EXCLUDE_SUCCESS', recordId) - } catch (error) { - Errors.handle(error) - commit('EXCLUDE_ERROR') - } - }, + const actionResponse = + await EagleEyeService.addAction({ + postId: postResponse.id, + actionData + }) - async doRevertExclude({ commit }, recordId) { - try { - commit('REVERT_EXCLUDE_STARTED', recordId) + commit('CREATE_ACTION_SUCCESS', { + action: actionResponse, + index + }) - await EagleEyeService.revertExclude(recordId) + // Update local storage with updated action + const currentUser = rootGetters['auth/currentUser'] + const currentTenant = + rootGetters['auth/currentTenant'] - commit('REVERT_EXCLUDE_SUCCESS', recordId) + setResultsInStorage({ + posts: state.list.posts, + tenantId: currentTenant.id, + userId: currentUser.id + }) } catch (error) { - Errors.handle(error) - commit('REVERT_EXCLUDE_ERROR') + commit('UPDATE_ACTION_ERROR') } }, - async doEngage({ commit }, recordId) { + async doRemoveAction( + { state, commit, getters, rootGetters }, + { postId, actionId, actionType, index } + ) { try { - commit('ENGAGE_STARTED', recordId) + commit('UPDATE_ACTION_LOADING', { + index + }) + + await EagleEyeService.deleteAction({ + postId, + actionId + }) - await EagleEyeService.engage(recordId) + commit('DELETE_ACTION_SUCCESS', { + actionId, + actionType, + index, + activeView: getters.activeView.id + }) - commit('ENGAGE_SUCCESS', recordId) + // Update local storage with updated action + const currentUser = rootGetters['auth/currentUser'] + const currentTenant = + rootGetters['auth/currentTenant'] + + setResultsInStorage({ + posts: state.list.posts, + tenantId: currentTenant.id, + userId: currentUser.id + }) } catch (error) { - Errors.handle(error) - commit('ENGAGE_ERROR') + commit('UPDATE_ACTION_ERROR') } }, diff --git a/frontend/src/premium/eagle-eye/store/getters.js b/frontend/src/premium/eagle-eye/store/getters.js index 7cb7d233c0..14e3426340 100644 --- a/frontend/src/premium/eagle-eye/store/getters.js +++ b/frontend/src/premium/eagle-eye/store/getters.js @@ -1,14 +1,5 @@ import sharedGetters from '@/shared/store/getters' export default { - ...sharedGetters(), - rows: (state, getters) => { - return state.list.ids - .map((r) => state.records[r]) - .filter((r) => { - return getters.activeView.id === 'inbox' - ? r.status === null - : r.status === getters.activeView.id - }) - } + ...sharedGetters() } diff --git a/frontend/src/premium/eagle-eye/store/mutations.js b/frontend/src/premium/eagle-eye/store/mutations.js index c16f62b013..17c762c1d6 100644 --- a/frontend/src/premium/eagle-eye/store/mutations.js +++ b/frontend/src/premium/eagle-eye/store/mutations.js @@ -2,67 +2,92 @@ import sharedMutations from '@/shared/store/mutations' export default { ...sharedMutations(), - FETCH_SUCCESS(state, { rows, count }) { - state.list.loading = false + FETCH_STARTED(state, payload) { + state.list.loading = true - for (const record of rows) { - state.records[record.id] = record - if (!state.list.ids.includes(record.id)) { - state.list.ids.push(record.id) - } + if (state.table) { + state.list.table.clearSelection() } + if (!payload.keepPagination) { + state.list.posts.length = 0 + } + + state.pagination = + payload && payload.keepPagination + ? state.pagination + : { + currentPage: 1, + pageSize: + state.pagination && state.pagination.pageSize + } + }, + + FETCH_SUCCESS(state, { list, count, appendToList }) { + state.list.loading = false + if (appendToList) { + state.list.posts.concat(list) + } else { + state.list.posts = list + } state.count = count }, - POPULATE_STARTED(state, { keepPagination }) { - state.list.loading = true + UPDATE_ACTION_LOADING(state, { index }) { + state.list.posts[index].loading = true + }, - if (!keepPagination) { - state.list.ids.length = 0 + CREATE_CONTENT_SUCCESS(state, { post, index }) { + state.list.posts[index] = { + ...state.list.posts[index], + ...post } }, - POPULATE_SUCCESS(state) { - state.list.loading = true + CREATE_ACTION_SUCCESS(state, { action, index }) { + state.list.posts[index].loading = false + state.list.posts[index].actions.push(action) }, - POPULATE_ERROR(state) { - state.list.loading = false - }, + DELETE_ACTION_SUCCESS( + state, + { actionId, actionType, index, activeView } + ) { + state.list.posts[index].loading = false - ENGAGE_STARTED() {}, + // Remove post from bookmarks view + if ( + actionType === 'bookmark' && + activeView === 'bookmarked' + ) { + state.list.posts.splice(index, 1) + // Remove action from post + } else { + const deleteIndex = state.list.posts[ + index + ].actions.findIndex((a) => a.id === actionId) - ENGAGE_SUCCESS(state, recordId) { - if (state.records[recordId].status !== 'engaged') { - state.count-- + state.list.posts[index].actions.splice(deleteIndex, 1) } - state.records[recordId].status = 'engaged' }, - ENGAGE_ERROR() {}, - EXCLUDE_STARTED() {}, - - EXCLUDE_SUCCESS(state, recordId) { - state.records[recordId].status = 'rejected' - state.count-- + UPDATE_ACTION_ERROR(state, { index }) { + state.list.posts[index].loading = false }, - EXCLUDE_ERROR() {}, - - REVERT_EXCLUDE_STARTED() {}, - REVERT_EXCLUDE_SUCCESS(state, recordId) { - state.records[recordId].status = null - state.count-- + SORTER_CHANGED(state, payload) { + const { activeView, sorter } = payload + state.views[activeView.id].sorter = sorter }, - REVERT_EXCLUDE_ERROR() {}, UPDATE_EAGLE_EYE_SETTINGS_STARTED(state) { state.loadingUpdateSettings = true }, + UPDATE_EAGLE_EYE_SETTINGS_SUCCESS(state) { state.loadingUpdateSettings = false }, + UPDATE_EAGLE_EYE_SETTINGS_ERROR(state) { state.loadingUpdateSettings = false } diff --git a/frontend/src/premium/eagle-eye/store/state.js b/frontend/src/premium/eagle-eye/store/state.js index 64259ebfcc..524f22a1f5 100644 --- a/frontend/src/premium/eagle-eye/store/state.js +++ b/frontend/src/premium/eagle-eye/store/state.js @@ -1,154 +1,27 @@ import { INITIAL_PAGE_SIZE } from './constants' -const savedKeywords = localStorage.getItem( - 'eagleEye_keywords' -) - -const savedKeywordsArray = - savedKeywords && savedKeywords !== '' - ? savedKeywords.split(',') - : [] - export default () => { return { records: {}, views: { - inbox: { - id: 'inbox', - label: 'Inbox', - initialFilter: { - operator: 'and', - attributes: { - keywords: { - name: 'keywords', - label: 'Keywords', - show: false, - operator: 'overlap', - defaultOperator: 'overlap', - type: 'custom', - value: savedKeywordsArray, - defaultValue: savedKeywordsArray - } - } - }, - filter: { - operator: 'and', - attributes: { - keywords: { - name: 'keywords', - label: 'Keywords', - show: false, - operator: 'overlap', - defaultOperator: 'overlap', - type: 'custom', - value: savedKeywordsArray, - defaultValue: savedKeywordsArray - } - } - }, - pagination: { - currentPage: 1, - pageSize: INITIAL_PAGE_SIZE - }, - initialSorter: { - prop: 'similarityScore', - order: 'descending' - }, - sorter: { - prop: 'similarityScore', - order: 'descending' - }, + feed: { + id: 'feed', + label: 'Feed', active: true }, - engaged: { - id: 'engaged', - label: 'Engaged', - initialFilter: { - operator: 'and', - attributes: { - status: { - name: 'status', - operator: 'eq', - defaultOperator: 'eq', - defaultValue: 'engaged', - value: 'engaged', - show: false - } - } - }, - filter: { - operator: 'and', - attributes: { - status: { - name: 'status', - operator: 'eq', - defaultOperator: 'eq', - defaultValue: 'engaged', - value: 'engaged', - show: false - } - } - }, - pagination: { - currentPage: 1, - pageSize: INITIAL_PAGE_SIZE - }, - initialSorter: { - prop: 'similarityScore', - order: 'descending' - }, - sorter: { - prop: 'similarityScore', - order: 'descending' - }, - active: false - }, - rejected: { - id: 'rejected', - label: 'Excluded', - initialFilter: { - operator: 'and', - attributes: { - status: { - name: 'status', - operator: 'eq', - defaultOperator: 'eq', - defaultValue: 'rejected', - value: 'rejected', - show: false - } - } - }, - filter: { - operator: 'and', - attributes: { - status: { - name: 'status', - operator: 'eq', - defaultOperator: 'eq', - defaultValue: 'rejected', - value: 'rejected', - show: false - } - } - }, + bookmarked: { + id: 'bookmarked', + label: 'Bookmarked', pagination: { currentPage: 1, pageSize: INITIAL_PAGE_SIZE }, - initialSorter: { - prop: 'similarityScore', - order: 'descending' - }, - sorter: { - prop: 'similarityScore', - order: 'descending' - }, + sorter: 'individualBookmarks', active: false } }, list: { - ids: [], + posts: [], loading: false }, count: 0, diff --git a/frontend/src/shared/form/inline-select-input.vue b/frontend/src/shared/form/inline-select-input.vue index aefd0212b9..3c426f7103 100644 --- a/frontend/src/shared/form/inline-select-input.vue +++ b/frontend/src/shared/form/inline-select-input.vue @@ -26,10 +26,21 @@ - {{ option.label }} +
+ {{ option.label }} + + {{ option.description }} + +
diff --git a/frontend/src/shared/image/image.vue b/frontend/src/shared/image/image.vue new file mode 100644 index 0000000000..7419ab11a4 --- /dev/null +++ b/frontend/src/shared/image/image.vue @@ -0,0 +1,35 @@ + + + + + + + diff --git a/frontend/src/shared/shared-module.js b/frontend/src/shared/shared-module.js index 7bb593e9ee..ec90ae0ff1 100644 --- a/frontend/src/shared/shared-module.js +++ b/frontend/src/shared/shared-module.js @@ -46,6 +46,7 @@ import Platform from '@/shared/platform/platform' import Drawer from '@/shared/drawer/drawer' import AppLoader from '@/shared/loading/loader' import AppPageWrapper from '@/shared/layout/page-wrapper' +import Image from '@/shared/image/image' /** * All shared components are globally registered, so there's no need to import them from other components @@ -101,6 +102,7 @@ export default { 'app-platform': Platform, 'app-drawer': Drawer, 'app-loader': AppLoader, - 'app-page-wrapper': AppPageWrapper + 'app-page-wrapper': AppPageWrapper, + 'app-image': Image } } diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index 5fc3cb2f4f..1268b7a783 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -1107,5 +1107,5 @@ module.exports = { 'active', 'disabled' ], - plugins: [] + plugins: [require('@tailwindcss/line-clamp')] } From 514adc4b72fbfe19328075a14ea8db9b918e608e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C5=A1per=20Grom?= Date: Mon, 13 Feb 2023 11:07:05 +0100 Subject: [PATCH 06/56] Eagle eye feed settings drawer (#517) --- frontend/src/assets/scss/form/form.scss | 12 + frontend/src/assets/scss/form/radio.scss | 6 + .../components/list/eagle-eye-result-card.vue | 2 +- .../list/eagle-eye-settings-drawer.vue | 434 ++++++++++++++++++ .../components/list/eagle-eye-settings.vue | 11 +- .../onboard/eagle-eye-platforms.vue | 2 +- .../constants/eagle-eye-date-published.json | 17 + .../constants/eagle-eye-platforms.json | 46 ++ .../premium/eagle-eye/eagle-eye-constants.js | 75 --- .../pages/eagle-eye-onboard-page.vue | 6 +- .../eagle-eye/pages/eagle-eye-page.vue | 3 +- .../src/premium/eagle-eye/store/actions.js | 3 + 12 files changed, 533 insertions(+), 84 deletions(-) create mode 100644 frontend/src/premium/eagle-eye/components/list/eagle-eye-settings-drawer.vue create mode 100644 frontend/src/premium/eagle-eye/constants/eagle-eye-date-published.json create mode 100644 frontend/src/premium/eagle-eye/constants/eagle-eye-platforms.json delete mode 100644 frontend/src/premium/eagle-eye/eagle-eye-constants.js diff --git a/frontend/src/assets/scss/form/form.scss b/frontend/src/assets/scss/form/form.scss index b84b805a5e..29709f5bb2 100644 --- a/frontend/src/assets/scss/form/form.scss +++ b/frontend/src/assets/scss/form/form.scss @@ -30,3 +30,15 @@ @apply flex flex-row-reverse gap-1 mb-1 text-xs text-gray-900 font-semibold; } } + +.el-form-item.no-margin .el-form-item__content{ + @apply mb-0; +} + +.el-form-item.is-error-relative .el-form-item__error{ + position: relative; + top: 0%; +} +.el-form-item.is-error-above .el-form-item__error{ + top: -1rem; +} \ No newline at end of file diff --git a/frontend/src/assets/scss/form/radio.scss b/frontend/src/assets/scss/form/radio.scss index 5ef6d6b367..0ec8d38638 100644 --- a/frontend/src/assets/scss/form/radio.scss +++ b/frontend/src/assets/scss/form/radio.scss @@ -18,6 +18,12 @@ @apply text-brand-500; } } + + &.is-small { + .el-radio-button__inner { + @apply p-2; + } + } } &.radio-chips { diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue index 29038d380e..8fef282ce8 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue @@ -163,7 +163,7 @@ diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings.vue index 37f16e51d0..749a514908 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings.vue @@ -58,6 +58,7 @@ Feed settings +
diff --git a/frontend/src/premium/eagle-eye/components/eagle-eye-published-date.vue b/frontend/src/premium/eagle-eye/components/eagle-eye-published-date.vue new file mode 100644 index 0000000000..cda221bbdb --- /dev/null +++ b/frontend/src/premium/eagle-eye/components/eagle-eye-published-date.vue @@ -0,0 +1,65 @@ + + + + + diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings-drawer.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings-drawer.vue index 21610f50da..b8f51d70fd 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings-drawer.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings-drawer.vue @@ -6,12 +6,7 @@ Keywords - +

-
- -
+ +

-

- -
+ +

- - - - - +
- -
-
-
-
- -
-

- {{ platform.label }} -

-
-
- -
-
-
-
+ />
@@ -235,7 +187,6 @@ diff --git a/frontend/src/premium/eagle-eye/components/onboard/eagle-eye-platforms.vue b/frontend/src/premium/eagle-eye/components/onboard/eagle-eye-platforms.vue deleted file mode 100644 index 73467a1887..0000000000 --- a/frontend/src/premium/eagle-eye/components/onboard/eagle-eye-platforms.vue +++ /dev/null @@ -1,158 +0,0 @@ - - - - - diff --git a/frontend/src/premium/eagle-eye/components/onboard/eagle-eye-summary.vue b/frontend/src/premium/eagle-eye/components/onboard/eagle-eye-summary-step.vue similarity index 100% rename from frontend/src/premium/eagle-eye/components/onboard/eagle-eye-summary.vue rename to frontend/src/premium/eagle-eye/components/onboard/eagle-eye-summary-step.vue diff --git a/frontend/src/premium/eagle-eye/eagle-eye-storage.js b/frontend/src/premium/eagle-eye/eagle-eye-storage.js index a54aa7347a..ea972ddc09 100644 --- a/frontend/src/premium/eagle-eye/eagle-eye-storage.js +++ b/frontend/src/premium/eagle-eye/eagle-eye-storage.js @@ -3,13 +3,26 @@ * [tenantId]: { * [userId]: { * posts: [] - * storageDate: '' + * storageDate: '', * } * } */ import moment from 'moment' +export const isStorageUpdating = ({ tenantId, userId }) => { + const storage = localStorage.getItem('eagleEyeResults') + + if ( + !storage || + !JSON.parse(storage)?.[tenantId]?.[userId] + ) { + return null + } + + return !JSON.parse(storage)[tenantId][userId].storageDate +} + export const shouldFetchNewResults = ({ tenantId, userId @@ -49,6 +62,7 @@ export const getResultsFromStorage = ({ // Set results in storage for the given tenant and user id export const setResultsInStorage = ({ + storageDate, posts, tenantId, userId @@ -58,7 +72,7 @@ export const setResultsInStorage = ({ ) const payload = { posts, - storageDate: moment() + storageDate } // Add/update user posts in tenantId diff --git a/frontend/src/premium/eagle-eye/pages/eagle-eye-onboard-page.vue b/frontend/src/premium/eagle-eye/pages/eagle-eye-onboard-page.vue index fe84cbf5b1..c2a478230c 100644 --- a/frontend/src/premium/eagle-eye/pages/eagle-eye-onboard-page.vue +++ b/frontend/src/premium/eagle-eye/pages/eagle-eye-onboard-page.vue @@ -16,13 +16,13 @@ /> { if (step.value === 1) { return { @@ -75,15 +86,8 @@ const headerContent = computed(() => { } }) -const keywords = reactive([ - { - value: null - } -]) -const publishedDate = ref(publishedDateOptions[0].label) const wasFormSubmittedSuccessfuly = ref(false) const storeUnsubscribe = ref(() => {}) -const platforms = reactive(platformOptions) // Prevent lost data on route change onBeforeRouteLeave((to) => { @@ -126,9 +130,11 @@ const onStepChange = (increment) => { } const onSubmit = async () => { - const formattedKeywords = keywords.map((k) => k.value) - const formattedPlatforms = Object.entries(platforms) - .filter(([, value]) => value.enabled) + const formattedKeywords = form.keywords.map( + (s) => s.value + ) + const formattedPlatforms = Object.entries(form.platforms) + .filter(([, value]) => value) .map(([key]) => key) await doUpdateSettings({ @@ -136,7 +142,7 @@ const onSubmit = async () => { keywords: formattedKeywords, exactKeywords: [], excludedKeywords: [], - publishedDate: publishedDate.value, + publishedDate: form.datePublished, platforms: formattedPlatforms } }) diff --git a/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue b/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue index 2a71f20696..218099dc21 100644 --- a/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue +++ b/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue @@ -15,11 +15,9 @@ class="basis-9/12 overflow-auto overscroll-contain" > - + store.state.eagleEye.list.posts) -const loading = computed( - () => store.state.eagleEye.list.loading +const { activeView, activeViewList } = + mapGetters('eagleEye') + +const list = computed(() => activeViewList.value.posts) +const isLoading = computed(() => { + if (activeView.value.id === 'feed') { + return activeViewList.value.loading + } + + return activeViewList.value.loading && !list.value.length +}) +const showEmptyState = computed( + () => !activeViewList.value.loading && !list.value.length ) -const { activeView } = mapGetters('eagleEye') const emptyStateContent = computed(() => { if (activeView.value.id === 'feed') { return { @@ -70,9 +77,12 @@ const emptyStateContent = computed(() => { }) onMounted(async () => { - await store.dispatch('eagleEye/doFetch', { - keepPagination: true, - resetStorage: false - }) + // Prevent new fetch if it still loading results from onboarding + if (!activeViewList.value.loading) { + await store.dispatch('eagleEye/doFetch', { + keepPagination: true, + resetStorage: false + }) + } }) diff --git a/frontend/src/premium/eagle-eye/store/actions.js b/frontend/src/premium/eagle-eye/store/actions.js index da2949771d..0c84e6314a 100644 --- a/frontend/src/premium/eagle-eye/store/actions.js +++ b/frontend/src/premium/eagle-eye/store/actions.js @@ -5,27 +5,46 @@ import moment from 'moment' import { getResultsFromStorage, setResultsInStorage, - shouldFetchNewResults + shouldFetchNewResults, + isStorageUpdating } from '@/premium/eagle-eye/eagle-eye-storage' export default { ...sharedActions('eagleEye'), async doFetch( - { commit, getters, rootGetters }, + { state, commit, getters, rootGetters }, { keepPagination = false, resetStorage = false } ) { - try { - const currentUser = rootGetters['auth/currentUser'] - const currentTenant = - rootGetters['auth/currentTenant'] - let list = [], - count, - appendToList + const currentUser = rootGetters['auth/currentUser'] + const currentTenant = rootGetters['auth/currentTenant'] + const activeView = getters.activeView.id + let list = [], + count = 0, + appendToList = false + + // Edge case where new results were fetched but user changed tabs + // This is to prevent a new fetch until the previous results were loaded + if ( + activeView === 'feed' && + state.views[activeView].list.loading && + isStorageUpdating({ + tenantId: currentTenant.id, + userId: currentUser.id + }) + ) { + return + } - commit('FETCH_STARTED', { keepPagination }) + try { + commit('FETCH_STARTED', { + keepPagination: resetStorage + ? false + : keepPagination, + activeView + }) // Bookmarks View - if (getters.activeView.id === 'bookmarked') { + if (activeView === 'bookmarked') { const { sorter } = getters.activeView const response = await EagleEyeService.query( { @@ -44,27 +63,49 @@ export default { list = response.rows count = response.count + // Append to existing list if offset is not 0 + // User clicked on load more button if (getters.offset !== 0) { appendToList = true } } // Feed view else { + // Fetch for new results when + // resetStorage = true (settings were updated) + // or criteria to fetch new results = true (new day) + // or storage is waiting for results const fetchNewResults = + resetStorage || shouldFetchNewResults({ tenantId: currentTenant.id, userId: currentUser.id - }) || resetStorage + }) || + isStorageUpdating({ + tenantId: currentTenant.id, + userId: currentUser.id + }) if (fetchNewResults) { + // Set storage to be in updating state + setResultsInStorage({ + posts: [], + storageDate: null, + tenantId: currentTenant.id, + userId: currentUser.id + }) + list = await EagleEyeService.search() + // Set new results in local storage setResultsInStorage({ posts: list, + storageDate: moment(), tenantId: currentTenant.id, userId: currentUser.id }) } else { + // Get results from local storage list = getResultsFromStorage({ tenantId: currentTenant.id, userId: currentUser.id @@ -72,24 +113,32 @@ export default { } } + // Only update view list results if active view is the same from the initial request + // This is to prevent the user changing between tabs and the request was still loading commit('FETCH_SUCCESS', { list, ...(count && { count }), - ...(appendToList && { appendToList }) + ...(appendToList && { appendToList }), + activeView }) } catch (error) { Errors.handle(error) - commit('FETCH_ERROR') + commit('FETCH_ERROR', { + activeView + }) } }, async doAddAction( - { state, commit, rootGetters }, + { state, commit, getters, rootGetters }, { post, action, index } ) { + const activeView = getters.activeView.id + try { commit('UPDATE_ACTION_LOADING', { - index + index, + activeView }) // Create content in database @@ -100,7 +149,8 @@ export default { commit('CREATE_CONTENT_SUCCESS', { post: postResponse, - index + index, + activeView }) // Add action to db content @@ -117,7 +167,8 @@ export default { commit('CREATE_ACTION_SUCCESS', { action: actionResponse, - index + index, + activeView }) // Update local storage with updated action @@ -131,7 +182,10 @@ export default { userId: currentUser.id }) } catch (error) { - commit('UPDATE_ACTION_ERROR') + commit('UPDATE_ACTION_ERROR', { + index, + activeView + }) } }, @@ -139,9 +193,12 @@ export default { { state, commit, getters, rootGetters }, { postId, actionId, actionType, index } ) { + const activeView = getters.activeView.id + try { commit('UPDATE_ACTION_LOADING', { - index + index, + activeView }) await EagleEyeService.deleteAction({ @@ -153,7 +210,7 @@ export default { actionId, actionType, index, - activeView: getters.activeView.id + activeView }) // Update local storage with updated action @@ -167,7 +224,7 @@ export default { userId: currentUser.id }) } catch (error) { - commit('UPDATE_ACTION_ERROR') + commit('UPDATE_ACTION_ERROR', { index, activeView }) } }, diff --git a/frontend/src/premium/eagle-eye/store/getters.js b/frontend/src/premium/eagle-eye/store/getters.js index 14e3426340..2ebedde6fe 100644 --- a/frontend/src/premium/eagle-eye/store/getters.js +++ b/frontend/src/premium/eagle-eye/store/getters.js @@ -1,5 +1,11 @@ import sharedGetters from '@/shared/store/getters' export default { - ...sharedGetters() + ...sharedGetters(), + + activeViewList: (state) => { + const activeView = sharedGetters().activeView(state) + + return state.views[activeView.id].list + } } diff --git a/frontend/src/premium/eagle-eye/store/mutations.js b/frontend/src/premium/eagle-eye/store/mutations.js index 17c762c1d6..2a2552f21f 100644 --- a/frontend/src/premium/eagle-eye/store/mutations.js +++ b/frontend/src/premium/eagle-eye/store/mutations.js @@ -2,77 +2,99 @@ import sharedMutations from '@/shared/store/mutations' export default { ...sharedMutations(), - FETCH_STARTED(state, payload) { - state.list.loading = true + FETCH_STARTED(state, { keepPagination, activeView }) { + state.views[activeView].list.loading = true - if (state.table) { - state.list.table.clearSelection() + if (!keepPagination) { + state.views[activeView].list.posts.length = 0 } - if (!payload.keepPagination) { - state.list.posts.length = 0 - } - - state.pagination = - payload && payload.keepPagination - ? state.pagination - : { - currentPage: 1, - pageSize: - state.pagination && state.pagination.pageSize - } + state.pagination = keepPagination + ? state.pagination + : { + currentPage: 1, + pageSize: + state.pagination && state.pagination.pageSize + } }, - FETCH_SUCCESS(state, { list, count, appendToList }) { - state.list.loading = false + FETCH_SUCCESS( + state, + { list, count, appendToList, activeView } + ) { + state.views[activeView].list.loading = false if (appendToList) { - state.list.posts.concat(list) + state.views[activeView].list.posts.concat(list) } else { - state.list.posts = list + state.views[activeView].list.posts = list } state.count = count }, - UPDATE_ACTION_LOADING(state, { index }) { - state.list.posts[index].loading = true + FETCH_ERROR(state, { activeView }) { + state.views[activeView].list.loading = false + state.views[activeView].list.posts = [] + state.views[activeView].count = 0 + }, + + UPDATE_ACTION_LOADING(state, { index, activeView }) { + state.views[activeView].list.posts[index].loading = true }, - CREATE_CONTENT_SUCCESS(state, { post, index }) { - state.list.posts[index] = { - ...state.list.posts[index], + CREATE_CONTENT_SUCCESS( + state, + { post, index, activeView } + ) { + state.views[activeView].list.posts[index] = { + ...state.views[activeView].list.posts[index], ...post } }, - CREATE_ACTION_SUCCESS(state, { action, index }) { - state.list.posts[index].loading = false - state.list.posts[index].actions.push(action) + CREATE_ACTION_SUCCESS( + state, + { action, index, activeView } + ) { + state.views[activeView].list.posts[ + index + ].loading = false + state.views[activeView].list.posts[index].actions.push( + action + ) }, DELETE_ACTION_SUCCESS( state, { actionId, actionType, index, activeView } ) { - state.list.posts[index].loading = false + state.views[activeView].list.posts[ + index + ].loading = false // Remove post from bookmarks view if ( actionType === 'bookmark' && activeView === 'bookmarked' ) { - state.list.posts.splice(index, 1) + state.views[activeView].list.posts.splice(index, 1) // Remove action from post } else { - const deleteIndex = state.list.posts[ - index - ].actions.findIndex((a) => a.id === actionId) + const deleteIndex = state.views[ + activeView + ].list.posts[index].actions.findIndex( + (a) => a.id === actionId + ) - state.list.posts[index].actions.splice(deleteIndex, 1) + state.views[activeView].list.posts[ + index + ].actions.splice(deleteIndex, 1) } }, - UPDATE_ACTION_ERROR(state, { index }) { - state.list.posts[index].loading = false + UPDATE_ACTION_ERROR(state, { index, activeView }) { + state.views[activeView].list.posts[ + index + ].loading = false }, SORTER_CHANGED(state, payload) { diff --git a/frontend/src/premium/eagle-eye/store/state.js b/frontend/src/premium/eagle-eye/store/state.js index 524f22a1f5..8a37deec75 100644 --- a/frontend/src/premium/eagle-eye/store/state.js +++ b/frontend/src/premium/eagle-eye/store/state.js @@ -7,11 +7,21 @@ export default () => { feed: { id: 'feed', label: 'Feed', + list: { + posts: [], + loading: false + }, + count: 0, active: true }, bookmarked: { id: 'bookmarked', label: 'Bookmarked', + list: { + posts: [], + loading: false + }, + count: 0, pagination: { currentPage: 1, pageSize: INITIAL_PAGE_SIZE @@ -20,11 +30,6 @@ export default () => { active: false } }, - list: { - posts: [], - loading: false - }, - count: 0, loadingUpdateSettings: false } } From 44fc4130052a1a13bf64294e3ece13a3e86de9d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C5=A1per=20Grom?= Date: Tue, 14 Feb 2023 11:00:05 +0100 Subject: [PATCH 09/56] [C-750] Email digest settings (#498) --- .../database/repositories/userRepository.ts | 2 +- .../src/services/eagleEyeSettingsService.ts | 5 +- frontend/src/i18n/en.js | 7 + .../list/eagle-eye-email-digest-card.vue | 18 +- .../list/eagle-eye-email-digest-drawer.vue | 402 ++++++++++++++++++ .../list/eagle-eye-settings-drawer.vue | 11 +- .../src/premium/eagle-eye/store/actions.js | 34 +- frontend/src/shared/drawer/drawer.vue | 15 +- 8 files changed, 452 insertions(+), 42 deletions(-) create mode 100644 frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-drawer.vue diff --git a/backend/src/database/repositories/userRepository.ts b/backend/src/database/repositories/userRepository.ts index 781e93d1cf..7331bc3862 100644 --- a/backend/src/database/repositories/userRepository.ts +++ b/backend/src/database/repositories/userRepository.ts @@ -330,7 +330,7 @@ export default class UserRepository { await user.update( { - eagleEyeSettings: data, + eagleEyeSettings: { ...user.eagleEyeSettings, ...data }, updatedById: currentUser.id, }, { transaction }, diff --git a/backend/src/services/eagleEyeSettingsService.ts b/backend/src/services/eagleEyeSettingsService.ts index 7753f2f13d..471f4fad21 100644 --- a/backend/src/services/eagleEyeSettingsService.ts +++ b/backend/src/services/eagleEyeSettingsService.ts @@ -127,11 +127,8 @@ export default class EagleEyeSettingsService extends LoggingBase { // If an email digest was sent, validate and normalize email digest settings // Otherwise, set email digest to false - if (data.emailDigest || data.emailDigestActive) { - data.emailDigestActive = true + if (data.emailDigestActive && data.emailDigest) { data.emailDigest = this.getEmailDigestSettings(data.emailDigest, data.feed) - } else { - data.emailDigestActive = false } // Remove any extra fields diff --git a/frontend/src/i18n/en.js b/frontend/src/i18n/en.js index 96cde6057b..82fa29f5e6 100644 --- a/frontend/src/i18n/en.js +++ b/frontend/src/i18n/en.js @@ -133,6 +133,13 @@ const en = { } }, + emailDigest: { + fields: { + email: 'Email', + frequency: 'Frequency', + time: 'Time' + } + }, member: { name: 'member', label: 'Members', diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-card.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-card.vue index 3184a31043..7e59452032 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-card.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-card.vue @@ -15,7 +15,9 @@ to 10 most relevant results from Eagle Eye.
- Activate Email Digest
@@ -45,18 +47,28 @@
- +
+ + + + diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings-drawer.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings-drawer.vue index b8f51d70fd..83db052560 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings-drawer.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings-drawer.vue @@ -354,7 +354,7 @@ const fillForm = (user) => { const onSubmit = async (formEl) => { if (!formEl) return - await formEl.validate(async (valid) => { + await formEl.validate((valid) => { if (valid) { const data = { keywords: form.include @@ -371,12 +371,13 @@ const onSubmit = async (formEl) => { .filter(([, enabled]) => enabled) .map(([platform]) => platform) } - await doUpdateSettings({ - ...currentUser.eagleEyeSettings, + doUpdateSettings({ + ...currentUser.value.eagleEyeSettings, feed: data + }).then(() => { + Message.success('Feed settings updated!') + emit('update:modelValue', false) }) - Message.success('Feed settings updated!') - emit('update:modelValue', false) } }) } diff --git a/frontend/src/premium/eagle-eye/store/actions.js b/frontend/src/premium/eagle-eye/store/actions.js index 0c84e6314a..91dee43de2 100644 --- a/frontend/src/premium/eagle-eye/store/actions.js +++ b/frontend/src/premium/eagle-eye/store/actions.js @@ -229,22 +229,26 @@ export default { }, async doUpdateSettings({ commit, dispatch }, data) { - try { - commit('UPDATE_EAGLE_EYE_SETTINGS_STARTED') - - await EagleEyeService.updateSettings(data) - - await dispatch(`auth/doRefreshCurrentUser`, null, { - root: true + commit('UPDATE_EAGLE_EYE_SETTINGS_STARTED') + return EagleEyeService.updateSettings(data) + .then(() => + dispatch(`auth/doRefreshCurrentUser`, null, { + root: true + }) + ) + .then(() => + dispatch(`doFetch`, { + resetStorage: true + }) + ) + .then(() => { + commit('UPDATE_EAGLE_EYE_SETTINGS_SUCCESS') + return Promise.resolve() }) - dispatch(`doFetch`, { - resetStorage: true + .catch((error) => { + Errors.handle(error) + commit('UPDATE_EAGLE_EYE_SETTINGS_ERROR') + return Promise.reject() }) - - commit('UPDATE_EAGLE_EYE_SETTINGS_SUCCESS') - } catch (error) { - Errors.handle(error) - commit('UPDATE_EAGLE_EYE_SETTINGS_ERROR') - } } } diff --git a/frontend/src/shared/drawer/drawer.vue b/frontend/src/shared/drawer/drawer.vue index 12d8472519..bb51f10707 100644 --- a/frontend/src/shared/drawer/drawer.vue +++ b/frontend/src/shared/drawer/drawer.vue @@ -20,12 +20,7 @@ {{ preTitle }}
- +
true }, - preTitleImgSrc: { - type: String, - default: () => null - }, - preTitleImgAlt: { - type: String, - default: () => null - }, hasBorder: { type: Boolean, default: () => false From e6b28aa719d88a5915804cd727b2278d04ead4b2 Mon Sep 17 00:00:00 2001 From: joanagmaia Date: Tue, 14 Feb 2023 10:46:22 +0000 Subject: [PATCH 10/56] Fix settings update action (#526) --- .../src/premium/eagle-eye/store/actions.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/frontend/src/premium/eagle-eye/store/actions.js b/frontend/src/premium/eagle-eye/store/actions.js index 91dee43de2..4aabde6c87 100644 --- a/frontend/src/premium/eagle-eye/store/actions.js +++ b/frontend/src/premium/eagle-eye/store/actions.js @@ -231,19 +231,17 @@ export default { async doUpdateSettings({ commit, dispatch }, data) { commit('UPDATE_EAGLE_EYE_SETTINGS_STARTED') return EagleEyeService.updateSettings(data) - .then(() => + .then(() => { dispatch(`auth/doRefreshCurrentUser`, null, { root: true + }).then(() => { + commit('UPDATE_EAGLE_EYE_SETTINGS_SUCCESS') + + dispatch(`doFetch`, { + resetStorage: true + }) + return Promise.resolve() }) - ) - .then(() => - dispatch(`doFetch`, { - resetStorage: true - }) - ) - .then(() => { - commit('UPDATE_EAGLE_EYE_SETTINGS_SUCCESS') - return Promise.resolve() }) .catch((error) => { Errors.handle(error) From 7bf8c5e90ab8cf2ae2ee36d654e4f549ff17a63b Mon Sep 17 00:00:00 2001 From: Joan Reyero Date: Tue, 14 Feb 2023 14:54:13 +0100 Subject: [PATCH 11/56] Event tracking for the new EagleEye (#525) --- .../eagleEyeContent/eagleEyeContentTrack.ts | 21 +++++++++ backend/src/api/eagleEyeContent/index.ts | 6 +++ backend/src/services/eagleEyeActionService.ts | 44 ++++++++++++++++--- .../src/services/eagleEyeSettingsService.ts | 36 +++++++++++++++ .../enrichment/memberEnrichmentService.ts | 2 +- .../components/list/eagle-eye-result-card.vue | 8 +++- .../premium/eagle-eye/eagle-eye-service.js | 12 +++++ 7 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 backend/src/api/eagleEyeContent/eagleEyeContentTrack.ts diff --git a/backend/src/api/eagleEyeContent/eagleEyeContentTrack.ts b/backend/src/api/eagleEyeContent/eagleEyeContentTrack.ts new file mode 100644 index 0000000000..c3ccdac065 --- /dev/null +++ b/backend/src/api/eagleEyeContent/eagleEyeContentTrack.ts @@ -0,0 +1,21 @@ +import Permissions from '../../security/permissions' +import PermissionChecker from '../../services/user/permissionChecker' +import track from '../../segment/track' + +export default async (req, res) => { + new PermissionChecker(req).validateHas(Permissions.values.eagleEyeContentRead) + track( + 'Eagle Eye post clicked', + { + url: req.body.url, + platform: req.body.platform, + }, + { ...req }, + ) + + const out = { + Success: true, + } + + await req.responseHandler.success(req, res, out) +} diff --git a/backend/src/api/eagleEyeContent/index.ts b/backend/src/api/eagleEyeContent/index.ts index 7fd10c716c..3a1321ab59 100644 --- a/backend/src/api/eagleEyeContent/index.ts +++ b/backend/src/api/eagleEyeContent/index.ts @@ -15,6 +15,12 @@ export default (app) => { safeWrap(require('./eagleEyeContentUpsert').default), ) + app.post( + `/tenant/:tenantId/eagleEyeContent/track`, + featureFlagMiddleware(FeatureFlag.EAGLE_EYE, 'entities.eagleEye.errors.planLimitExceeded'), + safeWrap(require('./eagleEyeContentTrack').default), + ) + app.get( `/tenant/:tenantId/eagleEyeContent/search`, featureFlagMiddleware(FeatureFlag.EAGLE_EYE, 'entities.eagleEye.errors.planLimitExceeded'), diff --git a/backend/src/services/eagleEyeActionService.ts b/backend/src/services/eagleEyeActionService.ts index 05ad1e0c27..79a5bbd956 100644 --- a/backend/src/services/eagleEyeActionService.ts +++ b/backend/src/services/eagleEyeActionService.ts @@ -5,6 +5,7 @@ import Error404 from '../errors/Error404' import { EagleEyeAction, EagleEyeActionType } from '../types/eagleEyeTypes' import { IServiceOptions } from './IServiceOptions' import { LoggingBase } from './loggingBase' +import track from '../segment/track' export default class EagleEyeActionService extends LoggingBase { options: IServiceOptions @@ -27,6 +28,18 @@ export default class EagleEyeActionService extends LoggingBase { throw new Error404(this.options.language, 'errors.eagleEye.contentNotFound') } + // Tracking here so we have access to url and platform + track( + `Eagle Eye post ${data.type === EagleEyeActionType.BOOKMARK ? 'bookmarked' : 'voted'}`, + { + type: data.type, + url: content.url, + platform: content.platform, + action: 'create', + }, + { ...this.options }, + ) + const existingUserActions: EagleEyeAction[] = content.actions.filter( (a) => a.actionById === this.options.currentUser.id, ) @@ -50,7 +63,10 @@ export default class EagleEyeActionService extends LoggingBase { await EagleEyeActionRepository.removeActionFromContent( EagleEyeActionType.THUMBS_UP, contentId, - this.options, + { + ...this.options, + transaction, + }, ) } else if ( data.type === EagleEyeActionType.THUMBS_UP && @@ -59,16 +75,18 @@ export default class EagleEyeActionService extends LoggingBase { await EagleEyeActionRepository.removeActionFromContent( EagleEyeActionType.THUMBS_DOWN, contentId, - this.options, + { + ...this.options, + transaction, + }, ) } // add new action - const record = await EagleEyeActionRepository.createActionForContent( - data, - contentId, - this.options, - ) + const record = await EagleEyeActionRepository.createActionForContent(data, contentId, { + ...this.options, + transaction, + }) await SequelizeRepository.commitTransaction(transaction) @@ -96,5 +114,17 @@ export default class EagleEyeActionService extends LoggingBase { if (content.actions.length === 0) { await EagleEyeContentRepository.destroy(contentId, this.options) } + + // Tracking here so we have access to url and platform + track( + `Eagle Eye post ${action.type === EagleEyeActionType.BOOKMARK ? 'bookmarked' : 'voted'}`, + { + type: action.type, + url: content.url, + platform: content.platform, + action: 'destroy', + }, + { ...this.options }, + ) } } diff --git a/backend/src/services/eagleEyeSettingsService.ts b/backend/src/services/eagleEyeSettingsService.ts index 471f4fad21..4db3d58327 100644 --- a/backend/src/services/eagleEyeSettingsService.ts +++ b/backend/src/services/eagleEyeSettingsService.ts @@ -2,6 +2,7 @@ import lodash from 'lodash' import SequelizeRepository from '../database/repositories/sequelizeRepository' import UserRepository from '../database/repositories/userRepository' import Error400 from '../errors/Error400' +import track from '../segment/track' import { EagleEyeSettings, EagleEyeFeedSettings, @@ -143,6 +144,41 @@ export default class EagleEyeSettingsService extends LoggingBase { await SequelizeRepository.commitTransaction(transaction) + // Track the events in Segment + const settingsOut: EagleEyeSettings = userOut.eagleEyeSettings + + if (data.emailDigestActive) { + track( + 'Eagle Eye email settings updated', + { + email: settingsOut.emailDigest.email, + frequency: settingsOut.emailDigest.frequency, + time: settingsOut.emailDigest.time, + matchFeedSettings: settingsOut.emailDigest.matchFeedSettings, + platforms: settingsOut.emailDigest.feed.platforms, + publishedDate: settingsOut.emailDigest.feed.publishedDate, + keywords: settingsOut.emailDigest.feed.keywords, + exactKeywords: settingsOut.emailDigest.feed.exactKeywords, + excludeKeywords: settingsOut.emailDigest.feed.excludedKeywords, + }, + { ...this.options }, + ) + } else { + track( + 'Eagle Eye settings updated', + { + onboarded: settingsOut.onboarded, + emailDigestActive: settingsOut.emailDigestActive, + platforms: settingsOut.feed.platforms, + publishedDate: settingsOut.feed.publishedDate, + keywords: settingsOut.feed.keywords, + exactKeywords: settingsOut.feed.exactKeywords, + excludeKeywords: settingsOut.feed.excludedKeywords, + }, + { ...this.options }, + ) + } + return userOut.eagleEyeSettings } catch (error) { await SequelizeRepository.rollbackTransaction(transaction) diff --git a/backend/src/services/premium/enrichment/memberEnrichmentService.ts b/backend/src/services/premium/enrichment/memberEnrichmentService.ts index 93b3075795..3c529eea67 100644 --- a/backend/src/services/premium/enrichment/memberEnrichmentService.ts +++ b/backend/src/services/premium/enrichment/memberEnrichmentService.ts @@ -29,7 +29,7 @@ import RedisPubSubEmitter from '../../../utils/redis/pubSubEmitter' import { createRedisClient } from '../../../utils/redis' import { ApiWebsocketMessage } from '../../../types/mq/apiWebsocketMessage' import MemberEnrichmentCacheRepository from '../../../database/repositories/memberEnrichmentCacheRepository' -import track from '../../../segment/telemetryTrack' +import track from '../../../segment/track' export default class MemberEnrichmentService extends LoggingBase { options: IServiceOptions diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue index 8fef282ce8..caafbc80f1 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue @@ -164,6 +164,7 @@ import { formatDateToTimeAgo } from '@/utils/date' import { computed, defineProps } from 'vue' import platformOptions from '@/premium/eagle-eye/constants/eagle-eye-platforms.json' +import { EagleEyeService } from '../../eagle-eye-service' import { withHttp } from '@/utils/string' import { mapActions, @@ -217,12 +218,17 @@ const bookmarkTooltip = computed(() => { }) // Open post in origin url -const onCardClick = (e) => { +const onCardClick = async (e) => { if (!props.result.url || e.target.localName === 'a') { return } window.open(withHttp(props.result.url), '_blank') + + await EagleEyeService.trackClick({ + url: props.result.url, + platform: props.result.platform + }) } // If opposite thumbs up is set, remove before creating the new action diff --git a/frontend/src/premium/eagle-eye/eagle-eye-service.js b/frontend/src/premium/eagle-eye/eagle-eye-service.js index 7582cbfd3c..bbc15f1f7a 100644 --- a/frontend/src/premium/eagle-eye/eagle-eye-service.js +++ b/frontend/src/premium/eagle-eye/eagle-eye-service.js @@ -41,6 +41,18 @@ export class EagleEyeService { return response.data } + static async trackClick({ url, platform }) { + const tenantId = AuthCurrentTenant.get() + const response = await authAxios.post( + `/tenant/${tenantId}/eagleEyeContent/track`, + { + url, + platform + } + ) + return response.data + } + static async addAction({ postId, actionData }) { const tenantId = AuthCurrentTenant.get() From 7da758780c05c90bb933ea8604a521e1f85f3c62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C5=A1per=20Grom?= Date: Wed, 15 Feb 2023 16:57:58 +0100 Subject: [PATCH 12/56] Eagle eye drawers fixes (#536) --- frontend/package-lock.json | 118 +++++++++ frontend/package.json | 2 + frontend/src/assets/scss/form/select.scss | 5 +- .../eagle-eye-platforms-drawers.vue | 80 +++++++ .../form/eagle-eye-settings-include.vue | 94 ++++++++ .../list/eagle-eye-email-digest-drawer.vue | 224 ++++++++---------- .../list/eagle-eye-settings-drawer.vue | 175 +++----------- .../onboard/eagle-eye-platforms-step.vue | 6 +- .../src/premium/eagle-eye/eagle-eye-routes.js | 2 + .../pages/eagle-eye-onboard-page.vue | 9 +- frontend/src/shared/form/form-change.js | 19 ++ frontend/src/shared/form/form-item.vue | 84 +++++++ 12 files changed, 555 insertions(+), 263 deletions(-) create mode 100644 frontend/src/premium/eagle-eye/components/eagle-eye-platforms-drawers.vue create mode 100644 frontend/src/premium/eagle-eye/components/form/eagle-eye-settings-include.vue create mode 100644 frontend/src/shared/form/form-change.js create mode 100644 frontend/src/shared/form/form-item.vue diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 2c2861b579..5bda31163a 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -15,6 +15,8 @@ "@tiptap/extension-placeholder": "^2.0.0-beta.199", "@tiptap/starter-kit": "^2.0.0-beta.199", "@tiptap/vue-3": "^2.0.0-beta.199", + "@vuelidate/core": "^2.0.0", + "@vuelidate/validators": "^2.0.0", "@vueuse/core": "^9.7.0", "apollo-boost": "^0.4.9", "axios": "^0.22.0", @@ -4055,6 +4057,90 @@ "integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==", "dev": true }, + "node_modules/@vuelidate/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@vuelidate/core/-/core-2.0.0.tgz", + "integrity": "sha512-xIFgdQlScO0aaSZ0wTGPJh8YcTMNAj5veI8yPgiAyxOT+GV7vNQFiU1vpYWCL4cklkkhYvRRSC2OEX7YOZNmPQ==", + "dependencies": { + "vue-demi": "^0.13.11" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^2.0.0 || >=3.0.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vuelidate/core/node_modules/vue-demi": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz", + "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vuelidate/validators": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@vuelidate/validators/-/validators-2.0.0.tgz", + "integrity": "sha512-fQQcmDWfz7pyH5/JPi0Ng2GEgNK1pUHn/Z/j5rG/Q+HwhgIXvJblTPcZwKOj1ABL7V4UVuGKECvZCDHNGOwdrg==", + "dependencies": { + "vue-demi": "^0.13.11" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^2.0.0 || >=3.0.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vuelidate/validators/node_modules/vue-demi": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz", + "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, "node_modules/@vueuse/core": { "version": "9.7.0", "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.7.0.tgz", @@ -18790,6 +18876,38 @@ "integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==", "dev": true }, + "@vuelidate/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@vuelidate/core/-/core-2.0.0.tgz", + "integrity": "sha512-xIFgdQlScO0aaSZ0wTGPJh8YcTMNAj5veI8yPgiAyxOT+GV7vNQFiU1vpYWCL4cklkkhYvRRSC2OEX7YOZNmPQ==", + "requires": { + "vue-demi": "^0.13.11" + }, + "dependencies": { + "vue-demi": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz", + "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==", + "requires": {} + } + } + }, + "@vuelidate/validators": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@vuelidate/validators/-/validators-2.0.0.tgz", + "integrity": "sha512-fQQcmDWfz7pyH5/JPi0Ng2GEgNK1pUHn/Z/j5rG/Q+HwhgIXvJblTPcZwKOj1ABL7V4UVuGKECvZCDHNGOwdrg==", + "requires": { + "vue-demi": "^0.13.11" + }, + "dependencies": { + "vue-demi": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz", + "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==", + "requires": {} + } + } + }, "@vueuse/core": { "version": "9.7.0", "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.7.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index afcb4f6ee6..a795fbbfd1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -25,6 +25,8 @@ "@tiptap/extension-placeholder": "^2.0.0-beta.199", "@tiptap/starter-kit": "^2.0.0-beta.199", "@tiptap/vue-3": "^2.0.0-beta.199", + "@vuelidate/core": "^2.0.0", + "@vuelidate/validators": "^2.0.0", "@vueuse/core": "^9.7.0", "apollo-boost": "^0.4.9", "axios": "^0.22.0", diff --git a/frontend/src/assets/scss/form/select.scss b/frontend/src/assets/scss/form/select.scss index ae28831194..92f6a185dd 100644 --- a/frontend/src/assets/scss/form/select.scss +++ b/frontend/src/assets/scss/form/select.scss @@ -69,8 +69,7 @@ } // Selected icon for single selection -.el-select-dropdown - .el-select-dropdown__item.selected::after { +.el-select-dropdown .el-select-dropdown__item:not(.no-checkmark).selected::after { content: ''; position: absolute; top: 50%; @@ -117,7 +116,7 @@ } // Select dropdown item selected - &.selected { + &.selected, &.selected.hover { @apply font-medium bg-brand-50 text-gray-900; } diff --git a/frontend/src/premium/eagle-eye/components/eagle-eye-platforms-drawers.vue b/frontend/src/premium/eagle-eye/components/eagle-eye-platforms-drawers.vue new file mode 100644 index 0000000000..379a25d679 --- /dev/null +++ b/frontend/src/premium/eagle-eye/components/eagle-eye-platforms-drawers.vue @@ -0,0 +1,80 @@ + + + diff --git a/frontend/src/premium/eagle-eye/components/form/eagle-eye-settings-include.vue b/frontend/src/premium/eagle-eye/components/form/eagle-eye-settings-include.vue new file mode 100644 index 0000000000..b89ac5b8a4 --- /dev/null +++ b/frontend/src/premium/eagle-eye/components/form/eagle-eye-settings-include.vue @@ -0,0 +1,94 @@ + + + + + diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-drawer.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-drawer.vue index 7836f32a1b..ed539ebf87 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-drawer.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-drawer.vue @@ -20,103 +20,94 @@

- +
-
+
- - - - -
- + + + - + Daily + +

+ From Monday to Friday (results from + previous day) +

+
+ - -
- Daily -
-

- From Monday to Friday (results from - previous day) -

-
- +

-

- Weekly -
-

- Every Monday (results from previous - week) -

-
-
-
-
- + Every Monday (results from previous + week) +

+ + + +
-
-
+ Update email results based on your current @@ -222,7 +213,8 @@ type="primary" class="btn btn--md btn--primary" :loading="loadingUpdateSettings" - @click="doSubmit(formRef)" + :disabled="$v.$invalid || !hasFormChanged" + @click="doSubmit()" >Update
@@ -248,6 +240,10 @@ import { } from '@/shared/vuex/vuex.helpers' import Message from '@/shared/message/message' import platformOptions from '@/premium/eagle-eye/constants/eagle-eye-platforms.json' +import { email, required } from '@vuelidate/validators' +import useVuelidate from '@vuelidate/core' +import AppFormItem from '@/shared/form/form-item.vue' +import formChangeDetector from '@/shared/form/form-change' const props = defineProps({ modelValue: { @@ -263,36 +259,24 @@ const { loadingUpdateSettings } = mapState('eagleEye') const emit = defineEmits(['update:modelValue']) const rules = { - email: [ - { - required: true, - message: 'This field is required', - trigger: 'blur' - } - ], - frequency: [ - { - required: true, - message: 'This field is required', - trigger: 'blur' - } - ], - time: [ - { - required: true, - message: 'This field is required', - trigger: 'blur' - } - ] + email: { + required, + email + } } -const model = reactive({ +const form = reactive({ + active: false, + email: '', frequency: 'daily', time: '09:00', updateResults: true }) +const { hasFormChanged, formSnapshot } = + formChangeDetector(form) + +const $v = useVuelidate(rules, form) -const active = ref(false) const formRef = ref() const drawerModel = computed({ @@ -307,7 +291,7 @@ const drawerModel = computed({ const feed = ref(null) const results = computed(() => { - if (!model.updateResults) { + if (!form.updateResults) { if (currentUser.value && feed.value) { return feed.value } @@ -316,7 +300,7 @@ const results = computed(() => { }) const displayFeedWarning = computed(() => { - if (model.updateResults) { + if (form.updateResults) { return false } if ( @@ -348,40 +332,40 @@ const updateFeed = () => { const fillForm = (user) => { const { eagleEyeSettings } = user - active.value = eagleEyeSettings.emailDigestActive || false - model.email = + form.active = eagleEyeSettings.emailDigestActive || false + form.email = eagleEyeSettings.emailDigest?.email || user.email - model.frequency = + form.frequency = eagleEyeSettings.emailDigest?.frequency || 'daily' - model.time = eagleEyeSettings.emailDigest?.time || '09:00' - model.updateResults = !eagleEyeSettings.emailDigest + form.time = eagleEyeSettings.emailDigest?.time || '09:00' + form.updateResults = !eagleEyeSettings.emailDigest ? true : eagleEyeSettings.emailDigest?.matchFeedSettings feed.value = user.eagleEyeSettings.emailDigest.feed + + formSnapshot() } -const doSubmit = async (formEl) => { - if (!formEl) return - await formEl.validate((valid) => { - if (valid) { - const data = { - email: model.email, - frequency: model.frequency, - time: model.time, - matchFeedSettings: model.updateResults, - feed: !model.updateResults ? feed.value : undefined - } - doUpdateSettings({ - ...currentUser.value.eagleEyeSettings, - emailDigestActive: active.value, - emailDigest: data - }).then(() => { - Message.success( - 'Email Digest settings successfully updated' - ) - emit('update:modelValue', false) - }) +const doSubmit = async () => { + $v.value.$touch() + if (!$v.value.$invalid) { + const data = { + email: form.email, + frequency: form.frequency, + time: form.time, + matchFeedSettings: form.updateResults, + feed: !form.updateResults ? feed.value : undefined } - }) + doUpdateSettings({ + ...currentUser.value.eagleEyeSettings, + emailDigestActive: form.active, + emailDigest: data + }).then(() => { + Message.success( + 'Email Digest settings successfully updated' + ) + emit('update:modelValue', false) + }) + } } const handleCancel = () => { diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings-drawer.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings-drawer.vue index 83db052560..a44b7dd21d 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings-drawer.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings-drawer.vue @@ -6,7 +6,7 @@ Keywords - +

*

-
-
- - - - + - - -
- Semantic match -
-

- Results semantically related -

-
- -
- Exact match -
-

- Results containing the keyword -

-
-
-
-
- - - -
+ + + +

- - + Date published -

+
@@ -156,9 +101,12 @@
+

+ For better results, we recommend choosing at + least 3 platforms. +

@@ -172,12 +120,11 @@ @click="emit('update:modelValue', false)" >Cancel - Update @@ -187,7 +134,6 @@ diff --git a/frontend/src/premium/eagle-eye/components/onboard/eagle-eye-platforms-step.vue b/frontend/src/premium/eagle-eye/components/onboard/eagle-eye-platforms-step.vue index b06138f996..e7e08b4fbb 100644 --- a/frontend/src/premium/eagle-eye/components/onboard/eagle-eye-platforms-step.vue +++ b/frontend/src/premium/eagle-eye/components/onboard/eagle-eye-platforms-step.vue @@ -20,12 +20,16 @@
-
+
Platforms *
+

+ For better results, we recommend choosing at least 3 + platforms. +

{ + a[b] = true + return a + }, {}) }) const headerContent = computed(() => { diff --git a/frontend/src/shared/form/form-change.js b/frontend/src/shared/form/form-change.js new file mode 100644 index 0000000000..b159178e9e --- /dev/null +++ b/frontend/src/shared/form/form-change.js @@ -0,0 +1,19 @@ +import { ref, computed } from 'vue' + +export default function formChangeDetector(form) { + const temporaryForm = ref('') + + function formSnapshot() { + temporaryForm.value = JSON.stringify(form) + } + + const hasFormChanged = computed(() => { + return temporaryForm.value !== JSON.stringify(form) + }) + + return { + temporaryForm, + formSnapshot, + hasFormChanged + } +} diff --git a/frontend/src/shared/form/form-item.vue b/frontend/src/shared/form/form-item.vue new file mode 100644 index 0000000000..ce6a022b26 --- /dev/null +++ b/frontend/src/shared/form/form-item.vue @@ -0,0 +1,84 @@ + + + + + From 5a4a08b49831d19396f79d164d02f7e1856e056a Mon Sep 17 00:00:00 2001 From: anilb Date: Wed, 15 Feb 2023 18:11:02 +0100 Subject: [PATCH 13/56] Eagle eye content wrong results with offset and limit (#537) --- .../repositories/eagleEyeContentRepository.ts | 62 ++++++++++++------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/backend/src/database/repositories/eagleEyeContentRepository.ts b/backend/src/database/repositories/eagleEyeContentRepository.ts index 25949a10bd..203fcfdc2c 100644 --- a/backend/src/database/repositories/eagleEyeContentRepository.ts +++ b/backend/src/database/repositories/eagleEyeContentRepository.ts @@ -117,7 +117,10 @@ export default class EagleEyeContentRepository { const actionsSequelizeInclude = { model: options.database.eagleEyeAction, as: 'actions', + required: true, where: {}, + limit: null, + offset: 0, } if (advancedFilter && advancedFilter.action) { @@ -126,8 +129,8 @@ export default class EagleEyeContentRepository { const parsedActionQuery: QueryOutput = actionQueryParser.parse({ filter: advancedFilter.action, orderBy: 'timestamp_DESC', - limit, - offset, + limit: 0, + offset: 0, }) actionsSequelizeInclude.where = parsedActionQuery.where ?? {} @@ -145,39 +148,54 @@ export default class EagleEyeContentRepository { offset, }) - let { - rows, - count, // eslint-disable-line prefer-const - } = await options.database.eagleEyeContent.findAndCountAll({ + const hasActionFilter = Object.keys(actionsSequelizeInclude.where).length !== 0 + + let rows = await options.database.eagleEyeContent.findAll({ include, ...(parsed.where ? { where: parsed.where } : {}), order: parsed.order, - limit: parsed.limit, - offset: parsed.offset, + limit: hasActionFilter ? null : parsed.limit, + offset: hasActionFilter ? 0 : parsed.offset, transaction: SequelizeRepository.getTransaction(options), - subQuery: false, + subQuery: true, + distinct: true, }) + // count query will group by content id and create a response with action counts + // ie: it returns a payload similar to this + // [ contentId1: #ofActionsForContent1, contentId2: #ofActionsForContent2 ] + // To get the content count, we need to get the length of the response. + const count = ( + await options.database.eagleEyeContent.count({ + include, + ...(parsed.where ? { where: parsed.where } : {}), + transaction: SequelizeRepository.getTransaction(options), + distinct: true, + group: ['eagleEyeContent.id'], + }) + ).length + // If we have an actions filter, we should query again to eager // load the all actions on a content because previous query will // omit actions that don't match the given action filter - if (Object.keys(actionsSequelizeInclude.where).length !== 0) { - rows = ( - await options.database.eagleEyeContent.findAndCountAll({ - include: [{ ...actionsSequelizeInclude, where: {} }], - where: { id: { [Op.in]: rows.map((i) => i.id) } }, - order: parsed.order, - limit: parsed.limit, - offset: parsed.offset, - transaction: SequelizeRepository.getTransaction(options), - subQuery: false, - }) - ).rows + if (hasActionFilter) { + rows = await options.database.eagleEyeContent.findAll({ + include: [ + { ...actionsSequelizeInclude, where: {}, limit: null, offset: 0, required: true }, + ], + where: { id: { [Op.in]: rows.map((i) => i.id) } }, + order: parsed.order, + transaction: SequelizeRepository.getTransaction(options), + subQuery: true, + limit: parsed.limit, + offset: parsed.offset, + distinct: true, + }) } rows = await this._populateRelationsForRows(rows) - return { rows, count, limit: parsed.limit, offset: parsed.offset } + return { rows: rows ?? [], count, limit: parsed.limit, offset: parsed.offset } } static async findByUrl(url: string, options: IRepositoryOptions) { From 3aedbcb2841ff7dc91e3193b96ee9407bf045ab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C5=A1per=20Grom?= Date: Thu, 16 Feb 2023 08:52:05 +0100 Subject: [PATCH 14/56] Fix feed settings saving issues (#539) --- .../list/eagle-eye-email-digest-drawer.vue | 3 - .../list/eagle-eye-settings-drawer.vue | 57 ++++++++----------- 2 files changed, 25 insertions(+), 35 deletions(-) diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-drawer.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-drawer.vue index ed539ebf87..3d81d34279 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-drawer.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-drawer.vue @@ -25,7 +25,6 @@
- +

Update

@@ -142,7 +142,6 @@ import { defineProps, onMounted, reactive, - ref, watch, defineExpose } from 'vue' @@ -171,8 +170,6 @@ const { currentUser } = mapGetters('auth') const { doUpdateSettings } = mapActions('eagleEye') const { loadingUpdateSettings } = mapState('eagleEye') -const formRef = ref() - const form = reactive({ include: [], exclude: [], @@ -249,34 +246,30 @@ const fillForm = (user) => { formSnapshot() } -const onSubmit = async (formEl) => { - if (!formEl) return - await formEl.validate((valid) => { - if (valid) { - const data = { - keywords: form.include - .filter((i) => i.match === 'semantic') - .map((i) => i.keyword), - exactKeywords: form.include - .filter((i) => i.match === 'exact') - .map((i) => i.keyword), - excludedKeywords: form.exclude - .filter((e) => e.keyword.trim().length > 0) - .map((e) => e.keyword), - publishedDate: form.datePublished, - platforms: Object.entries(form.platforms) - .filter(([, enabled]) => enabled) - .map(([platform]) => platform) - } - doUpdateSettings({ - ...currentUser.value.eagleEyeSettings, - feed: data - }).then(() => { - Message.success('Feed settings updated!') - emit('update:modelValue', false) - }) +const onSubmit = async () => { + $v.value.$touch() + if (!$v.value.$invalid) { + const data = { + keywords: form.include + .filter((i) => i.match === 'semantic') + .map((i) => i.keyword), + exactKeywords: form.include + .filter((i) => i.match === 'exact') + .map((i) => i.keyword), + excludedKeywords: form.exclude + .filter((e) => e.keyword.trim().length > 0) + .map((e) => e.keyword), + publishedDate: form.datePublished, + platforms: form.platforms } - }) + doUpdateSettings({ + ...currentUser.value.eagleEyeSettings, + feed: data + }).then(() => { + Message.success('Feed settings updated!') + emit('update:modelValue', false) + }) + } } onMounted(() => { From 04da5b5e793d806f030566861e500e2261f3a39d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C5=A1per=20Grom?= Date: Thu, 16 Feb 2023 10:02:56 +0100 Subject: [PATCH 15/56] Fix email digest disable button state (#540) --- .../list/eagle-eye-email-digest-drawer.vue | 19 +++++++++++----- frontend/src/shared/form/element-change.js | 22 +++++++++++++++++++ 2 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 frontend/src/shared/form/element-change.js diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-drawer.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-drawer.vue index 3d81d34279..2f4fe6ca58 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-drawer.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-drawer.vue @@ -212,7 +212,10 @@ type="primary" class="btn btn--md btn--primary" :loading="loadingUpdateSettings" - :disabled="$v.$invalid || !hasFormChanged" + :disabled=" + $v.$invalid || + (!hasFormChanged && !hasElementChanged) + " @click="doSubmit()" >Update @@ -243,6 +246,7 @@ import { email, required } from '@vuelidate/validators' import useVuelidate from '@vuelidate/core' import AppFormItem from '@/shared/form/form-item.vue' import formChangeDetector from '@/shared/form/form-change' +import elementChangeDetector from '@/shared/form/element-change' const props = defineProps({ modelValue: { @@ -274,6 +278,10 @@ const form = reactive({ const { hasFormChanged, formSnapshot } = formChangeDetector(form) +const feed = ref(null) +const { elementSnapshot, hasElementChanged } = + elementChangeDetector(feed) + const $v = useVuelidate(rules, form) const drawerModel = computed({ @@ -285,8 +293,6 @@ const drawerModel = computed({ } }) -const feed = ref(null) - const results = computed(() => { if (!form.updateResults) { if (currentUser.value && feed.value) { @@ -338,9 +344,12 @@ const fillForm = (user) => { form.updateResults = !eagleEyeSettings.emailDigest ? true : eagleEyeSettings.emailDigest?.matchFeedSettings - feed.value = user.eagleEyeSettings.emailDigest.feed - formSnapshot() + feed.value = + eagleEyeSettings?.emailDigest?.feed || + eagleEyeSettings?.feed || + null + elementSnapshot() } const doSubmit = async () => { $v.value.$touch() diff --git a/frontend/src/shared/form/element-change.js b/frontend/src/shared/form/element-change.js new file mode 100644 index 0000000000..48c6a6408a --- /dev/null +++ b/frontend/src/shared/form/element-change.js @@ -0,0 +1,22 @@ +import { ref, computed } from 'vue' + +export default function elementChangeDetector(element) { + const temporaryElement = ref('') + + function elementSnapshot() { + temporaryElement.value = JSON.stringify(element.value) + } + + const hasElementChanged = computed(() => { + return ( + temporaryElement.value !== + JSON.stringify(element.value) + ) + }) + + return { + temporaryElement, + elementSnapshot, + hasElementChanged + } +} From 295aa6ca88d1f9ce72cb34822e5c43af6dc05276 Mon Sep 17 00:00:00 2001 From: joanagmaia Date: Thu, 16 Feb 2023 17:15:28 +0000 Subject: [PATCH 16/56] Fix issues raised in eagle eye feed (#535) --- .../list/eagle-eye-email-digest-card.vue | 4 +- .../components/list/eagle-eye-list.vue | 30 +- .../list/eagle-eye-loading-state.vue | 2 +- .../components/list/eagle-eye-result-card.vue | 191 ++++++------- .../components/list/eagle-eye-settings.vue | 185 +++++++------ .../premium/eagle-eye/eagle-eye-service.js | 4 +- .../eagle-eye/pages/eagle-eye-page.vue | 52 +++- .../src/premium/eagle-eye/store/actions.js | 256 +++++++++++++----- .../src/premium/eagle-eye/store/getters.js | 31 +++ .../src/premium/eagle-eye/store/mutations.js | 154 ++++++++--- frontend/src/premium/eagle-eye/store/state.js | 2 + 11 files changed, 621 insertions(+), 290 deletions(-) diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-card.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-card.vue index 7e59452032..9433e830c7 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-card.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-card.vue @@ -11,8 +11,8 @@
- Receive automatically in your inbox a collection of up - to 10 most relevant results from Eagle Eye. + Receive the 10 most relevant results from Eagle Eye + automatically in your inbox.
+ + +
store.getters['eagleEye/activeView'] +) const loading = computed( - () => store.state.eagleEye.list.loading + () => + store.state.eagleEye.views[activeView.value.id].list + .loading +) +const count = computed( + () => + store.state.eagleEye.views[activeView.value.id].count ) -const count = computed(() => store.state.eagleEye.count) const pagination = computed( () => store.getters['eagleEye/pagination'] ) const isLoadMoreVisible = computed(() => { + if (activeView.value.id === 'feed') { + return false + } + return ( pagination.value.currentPage * pagination.value.pageSize < @@ -80,4 +100,8 @@ const onLoadMore = () => { pagination.value.currentPage + 1 ) } + +const showBottomFeedMessage = computed(() => { + return activeView.value.id === 'feed' +}) diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-loading-state.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-loading-state.vue index 56c81ea4b9..2dde923cfe 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-loading-state.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-loading-state.vue @@ -1,6 +1,6 @@ @@ -83,37 +113,40 @@ const { currentUser } = mapGetters('auth') const settingsDrawerOpen = ref(false) -const keywords = computed(() => { - const { eagleEyeSettings } = currentUser.value - - if (!eagleEyeSettings?.feed) { - return [] - } - - return eagleEyeSettings.feed.keywords +const eagleEyeFeedSettings = computed(() => { + return currentUser.value.eagleEyeSettings?.feed }) -const exactKeywords = computed(() => { - const { eagleEyeSettings } = currentUser.value +const keywords = computed( + () => eagleEyeFeedSettings.value.keywords +) - if (!eagleEyeSettings?.feed) { - return [] - } +const exactKeywords = computed( + () => eagleEyeFeedSettings.value.exactKeywords +) - return eagleEyeSettings.feed.exactKeywords -}) -const platforms = computed(() => { - const { eagleEyeSettings } = currentUser.value +const excludedKeywords = computed( + () => eagleEyeFeedSettings.value.excludedKeywords +) - if (!eagleEyeSettings?.feed) { - return [] - } +const platforms = computed( + () => eagleEyeFeedSettings.value.platforms +) - return eagleEyeSettings.feed.platforms -}) +const publishedDate = computed( + () => eagleEyeFeedSettings.value.publishedDate +) diff --git a/frontend/src/premium/eagle-eye/eagle-eye-service.js b/frontend/src/premium/eagle-eye/eagle-eye-service.js index bbc15f1f7a..bbc7620013 100644 --- a/frontend/src/premium/eagle-eye/eagle-eye-service.js +++ b/frontend/src/premium/eagle-eye/eagle-eye-service.js @@ -53,12 +53,12 @@ export class EagleEyeService { return response.data } - static async addAction({ postId, actionData }) { + static async addAction({ postId, action }) { const tenantId = AuthCurrentTenant.get() const response = await authAxios.post( `/tenant/${tenantId}/eagleEyeContent/${postId}/action`, - actionData + action ) return response.data diff --git a/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue b/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue index 218099dc21..26243af5ae 100644 --- a/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue +++ b/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue @@ -2,27 +2,30 @@
- - - - +
+ + + + +
@@ -49,6 +52,15 @@ const store = useStore() const { activeView, activeViewList } = mapGetters('eagleEye') +const cssVars = computed(() => { + const isMenuCollapsed = + store.getters['layout/menuCollapsed'] + const menuWidth = isMenuCollapsed ? '64px' : '260px' + + return { + '--eagle-eye-padding': menuWidth + } +}) const list = computed(() => activeViewList.value.posts) const isLoading = computed(() => { if (activeView.value.id === 'feed') { @@ -86,3 +98,19 @@ onMounted(async () => { } }) + + diff --git a/frontend/src/premium/eagle-eye/store/actions.js b/frontend/src/premium/eagle-eye/store/actions.js index 4aabde6c87..761500db41 100644 --- a/frontend/src/premium/eagle-eye/store/actions.js +++ b/frontend/src/premium/eagle-eye/store/actions.js @@ -8,6 +8,7 @@ import { shouldFetchNewResults, isStorageUpdating } from '@/premium/eagle-eye/eagle-eye-storage' +import Message from '@/shared/message/message' export default { ...sharedActions('eagleEye'), @@ -129,105 +130,232 @@ export default { } }, + // Add temporary actions to post so that UI updates immeadiately + async doAddTemporaryPostAction( + { commit, getters }, + { index, storeActionType, action } + ) { + const activeView = getters.activeView.id + + // Add new action + if (storeActionType === 'add') { + commit('CREATE_TEMPORARY_ACTION', { + action, + activeView, + index + }) + // Remove action + } else { + commit('REMOVE_TEMPORARY_ACTION', { + action, + activeView, + index + }) + } + }, + + // Add or remove actions from the database depending on the action type + async doUpdatePostAction( + { state, dispatch, getters }, + { post, index, storeActionType, actionType } + ) { + const activeView = getters.activeView.id + const action = state.views[activeView].list.posts[ + index + ].actions.find((a) => a.type === actionType) || { + type: actionType, + timestamp: moment() + } + // Add new action + if (storeActionType === 'add') { + await dispatch('doAddAction', { + post, + action, + index + }) + // Remove action + } else { + await dispatch('doRemoveAction', { + postId: post.id, + action, + index + }) + } + }, + async doAddAction( { state, commit, getters, rootGetters }, { post, action, index } ) { const activeView = getters.activeView.id + const oppositeActionTypes = { + ['thumbs-up']: 'thumbs-down', + ['thumbs-down']: 'thumbs-up' + } + const oppositeAction = state.views[ + activeView + ].list.posts[index].actions.find( + (a) => a.type === oppositeActionTypes[action.type] + ) - try { - commit('UPDATE_ACTION_LOADING', { - index, - activeView + // If action is thumbs, delete opposite thumbs from post + if ( + oppositeActionTypes[action.type] && + oppositeAction + ) { + commit('REMOVE_TEMPORARY_ACTION', { + action: oppositeAction, + activeView, + index }) - // Create content in database - const postResponse = - await EagleEyeService.createContent({ - post - }) - - commit('CREATE_CONTENT_SUCCESS', { - post: postResponse, - index, - activeView + await EagleEyeService.deleteAction({ + postId: post.id, + actionId: oppositeAction.id }) + } - // Add action to db content - const actionData = { - type: action, - timestamp: moment().utc().format('YYYY-MM-DD') + const postDb = await EagleEyeService.createContent({ + post: { + actions: [], + platform: post.platform, + post: post.post, + postedAt: post.postedAt, + url: post.url } + }) - const actionResponse = - await EagleEyeService.addAction({ - postId: postResponse.id, - actionData - }) + const actionDb = await EagleEyeService.addAction({ + postId: postDb.id, + action + }) - commit('CREATE_ACTION_SUCCESS', { - action: actionResponse, - index, - activeView - }) + commit('CREATE_ACTION_SUCCESS', { + post: postDb, + action: actionDb, + index, + activeView + }) - // Update local storage with updated action - const currentUser = rootGetters['auth/currentUser'] - const currentTenant = - rootGetters['auth/currentTenant'] + // Update posts with new actions in local storage + const currentUser = rootGetters['auth/currentUser'] + const currentTenant = rootGetters['auth/currentTenant'] - setResultsInStorage({ - posts: state.list.posts, - tenantId: currentTenant.id, - userId: currentUser.id - }) - } catch (error) { - commit('UPDATE_ACTION_ERROR', { - index, - activeView - }) - } + setResultsInStorage({ + posts: state.views['feed'].list.posts, + storageDate: moment(), + tenantId: currentTenant.id, + userId: currentUser.id + }) }, async doRemoveAction( { state, commit, getters, rootGetters }, - { postId, actionId, actionType, index } + { postId, action, index } ) { const activeView = getters.activeView.id + const actionId = action.id + const deleteImmeadiately = + activeView === 'bookmarked' && + action.type === 'bookmark' - try { - commit('UPDATE_ACTION_LOADING', { + if (deleteImmeadiately) { + commit('REMOVE_ACTION_SUCCESS', { + postId, + action, index, activeView }) + } - await EagleEyeService.deleteAction({ - postId, - actionId - }) + await EagleEyeService.deleteAction({ + postId, + actionId + }) - commit('DELETE_ACTION_SUCCESS', { - actionId, - actionType, + if (!deleteImmeadiately) { + commit('REMOVE_ACTION_SUCCESS', { + postId, + action, index, activeView }) + } - // Update local storage with updated action - const currentUser = rootGetters['auth/currentUser'] - const currentTenant = - rootGetters['auth/currentTenant'] + // Update posts with new actions in local storage + const currentUser = rootGetters['auth/currentUser'] + const currentTenant = rootGetters['auth/currentTenant'] - setResultsInStorage({ - posts: state.list.posts, - tenantId: currentTenant.id, - userId: currentUser.id - }) - } catch (error) { - commit('UPDATE_ACTION_ERROR', { index, activeView }) + setResultsInStorage({ + posts: state.views['feed'].list.posts, + storageDate: moment(), + tenantId: currentTenant.id, + userId: currentUser.id + }) + }, + + doAddActionQueue({ commit, state, dispatch }, job) { + commit('ADD_PENDING_ACTION', job) + + // If there are no actions active, start the next one in the queue + if (Object.keys(state.activeAction).length == 0) { + dispatch('doStartActionQueue') } }, + async doStartActionQueue({ + commit, + dispatch, + state, + getters, + rootGetters + }) { + if (state.pendingActions.length > 0) { + commit('SET_ACTIVE_ACTION', state.pendingActions[0]) + + const pendingAction = { ...state.pendingActions[0] } + + commit('POP_CURRENT_ACTION') + + try { + await pendingAction.handler() + await dispatch('doStartActionQueue') + } catch (error) { + // In case of an error, create post again and update it in UI + EagleEyeService.createContent({ + post: pendingAction.post + }).then((response) => { + const activeView = getters.activeView.id + const currentUser = + rootGetters['auth/currentUser'] + const currentTenant = + rootGetters['auth/currentTenant'] + + commit('UPDATE_POST', { + activeView, + index: pendingAction.index, + post: response + }) + + // Update posts with new actions in local storage + setResultsInStorage({ + posts: state.views['feed'].list.posts, + storageDate: moment(), + tenantId: currentTenant.id, + userId: currentUser.id + }) + }) + + Message.error( + 'Something went wrong. Please try again' + ) + commit('SET_ACTIVE_ACTION', {}) + } + } + + commit('SET_ACTIVE_ACTION', {}) + }, + async doUpdateSettings({ commit, dispatch }, data) { commit('UPDATE_EAGLE_EYE_SETTINGS_STARTED') return EagleEyeService.updateSettings(data) diff --git a/frontend/src/premium/eagle-eye/store/getters.js b/frontend/src/premium/eagle-eye/store/getters.js index 2ebedde6fe..b52596f2df 100644 --- a/frontend/src/premium/eagle-eye/store/getters.js +++ b/frontend/src/premium/eagle-eye/store/getters.js @@ -1,4 +1,5 @@ import sharedGetters from '@/shared/store/getters' +import { INITIAL_PAGE_SIZE } from './constants' export default { ...sharedGetters(), @@ -7,5 +8,35 @@ export default { const activeView = sharedGetters().activeView(state) return state.views[activeView.id].list + }, + + pagination: (state, getters) => { + return { + ...getters.activeView.pagination, + total: getters.activeView.count, + showSizeChanger: true + } + }, + + limit: (state, getters) => { + const { pagination } = getters.activeView + + if (!pagination?.pageSize) { + return INITIAL_PAGE_SIZE + } + + return pagination.pageSize + }, + + offset: (state, getters) => { + const { pagination } = getters.activeView + + if (!pagination?.pageSize) { + return 0 + } + + const { currentPage = 1 } = pagination + + return (currentPage - 1) * pagination.pageSize } } diff --git a/frontend/src/premium/eagle-eye/store/mutations.js b/frontend/src/premium/eagle-eye/store/mutations.js index 2a2552f21f..a1d399bb2a 100644 --- a/frontend/src/premium/eagle-eye/store/mutations.js +++ b/frontend/src/premium/eagle-eye/store/mutations.js @@ -24,11 +24,11 @@ export default { ) { state.views[activeView].list.loading = false if (appendToList) { - state.views[activeView].list.posts.concat(list) + state.views[activeView].list.posts.push(...list) } else { state.views[activeView].list.posts = list } - state.count = count + state.views[activeView].count = count }, FETCH_ERROR(state, { activeView }) { @@ -37,64 +37,128 @@ export default { state.views[activeView].count = 0 }, - UPDATE_ACTION_LOADING(state, { index, activeView }) { - state.views[activeView].list.posts[index].loading = true - }, - - CREATE_CONTENT_SUCCESS( + CREATE_ACTION_SUCCESS( state, - { post, index, activeView } + { post, action, index, activeView } ) { - state.views[activeView].list.posts[index] = { - ...state.views[activeView].list.posts[index], - ...post + // Update feed post if bookmark action is updated + if (activeView === 'bookmarked') { + const feedPost = state.views['feed'].list.posts.find( + (p) => p.url === post.url + ) + + if (feedPost) { + const indexAction = feedPost.actions.findIndex( + (a) => a.type === action.type + ) + + if (indexAction === -1) { + feedPost.actions.push(action) + } else { + feedPost.actions[indexAction] = { + ...action, + id: action.id + } + } + } } - }, - CREATE_ACTION_SUCCESS( - state, - { action, index, activeView } - ) { - state.views[activeView].list.posts[ - index - ].loading = false - state.views[activeView].list.posts[index].actions.push( - action + const { actions } = + state.views[activeView].list.posts[index] + const indexAction = actions.findIndex( + (a) => a.type === action.type ) + + // Update store post with new one, except for actions + state.views[activeView].list.posts[index] = { + ...post, + actions + } + + if (indexAction === -1) { + actions.push(action) + } else { + actions[indexAction] = { + ...action, + id: action.id + } + } }, - DELETE_ACTION_SUCCESS( + REMOVE_ACTION_SUCCESS( state, - { actionId, actionType, index, activeView } + { postId, action, index, activeView } ) { - state.views[activeView].list.posts[ - index - ].loading = false + // Update feed post if bookmark action is updated + if (activeView === 'bookmarked') { + const feedPost = state.views['feed'].list.posts.find( + (p) => p.id === postId + ) + + if (feedPost) { + const deleteIndex = feedPost.actions.findIndex( + (a) => a.type === action.type + ) + + if (deleteIndex !== -1) { + feedPost.actions.splice(deleteIndex, 1) + console.log(feedPost.actions) + } + } + } // Remove post from bookmarks view if ( - actionType === 'bookmark' && + action.type === 'bookmark' && activeView === 'bookmarked' ) { state.views[activeView].list.posts.splice(index, 1) - // Remove action from post } else { - const deleteIndex = state.views[ - activeView - ].list.posts[index].actions.findIndex( - (a) => a.id === actionId + // Remove action from post + const { actions } = + state.views[activeView].list.posts[index] + const deleteIndex = actions.findIndex( + (a) => a.type === action.type ) - state.views[activeView].list.posts[ - index - ].actions.splice(deleteIndex, 1) + if (deleteIndex !== -1) { + actions.splice(deleteIndex, 1) + } } }, - UPDATE_ACTION_ERROR(state, { index, activeView }) { - state.views[activeView].list.posts[ - index - ].loading = false + CREATE_TEMPORARY_ACTION( + state, + { action, activeView, index } + ) { + const { actions } = + state.views[activeView].list.posts[index] + const indexAction = actions.findIndex( + (a) => a.type === action.type + ) + + if (indexAction === -1) { + actions.push(action) + } else { + actions[indexAction] = action + } + }, + + REMOVE_TEMPORARY_ACTION( + state, + { action, activeView, index } + ) { + const { actions } = + state.views[activeView].list.posts[index] + const deleteIndex = actions.findIndex( + (a) => a.type === action.type + ) + + actions[deleteIndex].toRemove = true + }, + + UPDATE_POST(state, { activeView, index, post }) { + state.views[activeView].list.posts[index] = post }, SORTER_CHANGED(state, payload) { @@ -112,5 +176,17 @@ export default { UPDATE_EAGLE_EYE_SETTINGS_ERROR(state) { state.loadingUpdateSettings = false + }, + + ADD_PENDING_ACTION(state, job) { + state.pendingActions.push(job) + }, + + SET_ACTIVE_ACTION(state, job) { + state.activeAction = job + }, + + POP_CURRENT_ACTION(state) { + state.pendingActions.shift() } } diff --git a/frontend/src/premium/eagle-eye/store/state.js b/frontend/src/premium/eagle-eye/store/state.js index 8a37deec75..8e92f374b2 100644 --- a/frontend/src/premium/eagle-eye/store/state.js +++ b/frontend/src/premium/eagle-eye/store/state.js @@ -30,6 +30,8 @@ export default () => { active: false } }, + pendingActions: [], + activeAction: {}, loadingUpdateSettings: false } } From fbb731d3a2c0423320217a3b6e69f2e503f34faf Mon Sep 17 00:00:00 2001 From: joanagmaia Date: Mon, 20 Feb 2023 09:19:11 +0000 Subject: [PATCH 17/56] Eagle eye email digest drawer on update (#546) --- .../list/eagle-eye-email-digest-drawer.vue | 9 ++++++--- .../components/list/eagle-eye-settings-drawer.vue | 6 ++++-- .../eagle-eye/pages/eagle-eye-onboard-page.vue | 14 ++++++++------ frontend/src/premium/eagle-eye/store/actions.js | 13 +++++++++---- 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-drawer.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-drawer.vue index 2f4fe6ca58..8a138f4f7f 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-drawer.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-drawer.vue @@ -362,9 +362,12 @@ const doSubmit = async () => { feed: !form.updateResults ? feed.value : undefined } doUpdateSettings({ - ...currentUser.value.eagleEyeSettings, - emailDigestActive: form.active, - emailDigest: data + data: { + ...currentUser.value.eagleEyeSettings, + emailDigestActive: form.active, + emailDigest: data + }, + fetchNewResults: false }).then(() => { Message.success( 'Email Digest settings successfully updated' diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings-drawer.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings-drawer.vue index fd2683a423..789d6a96ad 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings-drawer.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings-drawer.vue @@ -263,8 +263,10 @@ const onSubmit = async () => { platforms: form.platforms } doUpdateSettings({ - ...currentUser.value.eagleEyeSettings, - feed: data + data: { + ...currentUser.value.eagleEyeSettings, + feed: data + } }).then(() => { Message.success('Feed settings updated!') emit('update:modelValue', false) diff --git a/frontend/src/premium/eagle-eye/pages/eagle-eye-onboard-page.vue b/frontend/src/premium/eagle-eye/pages/eagle-eye-onboard-page.vue index 29bc5b3093..62b531e2d5 100644 --- a/frontend/src/premium/eagle-eye/pages/eagle-eye-onboard-page.vue +++ b/frontend/src/premium/eagle-eye/pages/eagle-eye-onboard-page.vue @@ -143,12 +143,14 @@ const onSubmit = async () => { .map(([key]) => key) await doUpdateSettings({ - feed: { - keywords: formattedKeywords, - exactKeywords: [], - excludedKeywords: [], - publishedDate: form.datePublished, - platforms: formattedPlatforms + data: { + feed: { + keywords: formattedKeywords, + exactKeywords: [], + excludedKeywords: [], + publishedDate: form.datePublished, + platforms: formattedPlatforms + } } }) } diff --git a/frontend/src/premium/eagle-eye/store/actions.js b/frontend/src/premium/eagle-eye/store/actions.js index 761500db41..4e9efbdd20 100644 --- a/frontend/src/premium/eagle-eye/store/actions.js +++ b/frontend/src/premium/eagle-eye/store/actions.js @@ -356,7 +356,10 @@ export default { commit('SET_ACTIVE_ACTION', {}) }, - async doUpdateSettings({ commit, dispatch }, data) { + async doUpdateSettings( + { commit, dispatch }, + { data, fetchNewResults = true } + ) { commit('UPDATE_EAGLE_EYE_SETTINGS_STARTED') return EagleEyeService.updateSettings(data) .then(() => { @@ -365,9 +368,11 @@ export default { }).then(() => { commit('UPDATE_EAGLE_EYE_SETTINGS_SUCCESS') - dispatch(`doFetch`, { - resetStorage: true - }) + if (fetchNewResults) { + dispatch(`doFetch`, { + resetStorage: true + }) + } return Promise.resolve() }) }) From cae493f108911c96ad4f84745670fb5b982992a9 Mon Sep 17 00:00:00 2001 From: joanagmaia Date: Wed, 8 Feb 2023 12:23:24 +0000 Subject: [PATCH 18/56] Fix reach filter (#491) --- .../src/shared/filter/components/filter-list-item.vue | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/frontend/src/shared/filter/components/filter-list-item.vue b/frontend/src/shared/filter/components/filter-list-item.vue index 50101a0f8c..6db4d531f4 100644 --- a/frontend/src/shared/filter/components/filter-list-item.vue +++ b/frontend/src/shared/filter/components/filter-list-item.vue @@ -256,9 +256,11 @@ const clickOutsideListener = (event) => { // we need the following condition to validate clicks // on popovers that are not DOM children of this component, // since popper is adding fixed components to the body directly - event.path?.some( - (o) => o.className?.includes('el-popper') || false - ) + event + .composedPath() + .some( + (o) => o.className?.includes('el-popper') || false + ) ) ) { emit('change', { From 6d372b83291859b0f809dd0ccaf8ac41f893b5ab Mon Sep 17 00:00:00 2001 From: joanagmaia Date: Wed, 8 Feb 2023 12:23:41 +0000 Subject: [PATCH 19/56] Fix filters for custom attributes (#492) --- .../member/member-array-attributes-field.js | 42 +++++++++++++++++++ frontend/src/modules/member/store/actions.js | 4 +- .../shared/fields/get-custom-attributes.js | 30 ++++++++++--- 3 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 frontend/src/modules/member/member-array-attributes-field.js diff --git a/frontend/src/modules/member/member-array-attributes-field.js b/frontend/src/modules/member/member-array-attributes-field.js new file mode 100644 index 0000000000..7dbc7e6384 --- /dev/null +++ b/frontend/src/modules/member/member-array-attributes-field.js @@ -0,0 +1,42 @@ +import StringField from '@/shared/fields/string-field' + +export default class MemberArrayAttributesField extends StringField { + constructor(name, label, config = {}) { + super(name, label) + + this.placeholder = config.placeholder + this.hint = config.hint + this.required = config.required + this.matches = config.matches + this.filterable = config.filterable || false + this.custom = config.custom || false + this.options = config.options + } + + dropdownOptions() { + return this.options.sort((x, y) => { + return x.label < y.label + ? -1 + : x.label > y.label + ? 1 + : 0 + }) + } + + forFilter() { + return { + name: this.name, + label: this.label, + custom: this.custom, + props: { + options: this.dropdownOptions(), + multiple: true + }, + defaultValue: [], + value: [], + defaultOperator: 'contains', + operator: 'contains', + type: 'select-multi' + } + } +} diff --git a/frontend/src/modules/member/store/actions.js b/frontend/src/modules/member/store/actions.js index bc8b056c68..90084f707d 100644 --- a/frontend/src/modules/member/store/actions.js +++ b/frontend/src/modules/member/store/actions.js @@ -366,7 +366,7 @@ export default { } }, - async doBulkEnrich({ rootGetters }, ids) { + async doBulkEnrich({ rootGetters, dispatch }, ids) { try { const currentTenant = rootGetters['auth/currentTenant'] @@ -403,6 +403,8 @@ export default { showEnrichmentLoadingMessage({ isBulk: true }) await MemberService.enrichMemberBulk(ids) + + await dispatch('doFetchCustomAttributes') } catch (error) { Message.closeAll() Errors.handle(error) diff --git a/frontend/src/shared/fields/get-custom-attributes.js b/frontend/src/shared/fields/get-custom-attributes.js index 209e825271..b0c7c632ed 100644 --- a/frontend/src/shared/fields/get-custom-attributes.js +++ b/frontend/src/shared/fields/get-custom-attributes.js @@ -2,12 +2,22 @@ import StringField from '@/shared/fields/string-field' import BooleanField from '@/shared/fields/boolean-field' import IntegerField from '@/shared/fields/integer-field' import DateField from '@/shared/fields/date-field' -import ArrayField from '@/shared/fields/array-field' +import MemberArrayAttributesField from '@/modules/member/member-array-attributes-field' export default (customAttributes) => { return ( Object.values(customAttributes) - .filter((a) => a.show) + .filter((a) => { + // Don't render special filters that do not have available options + if ( + a.type === 'multiSelect' || + a.type === 'special' + ) { + return a.options.length && a.show + } + + return a.show + }) .map((customAttribute) => { switch (customAttribute.type) { case 'boolean': @@ -30,12 +40,20 @@ export default (customAttributes) => { ) case 'multiSelect': - case 'special': - return new ArrayField( - customAttribute.name, - customAttribute.label + case 'special': { + const options = customAttribute.options.map( + (o) => ({ + value: o, + label: o + }) ) + return new MemberArrayAttributesField( + customAttribute.name, + customAttribute.label, + { options } + ) + } default: return new StringField( customAttribute.name, From 904707110d4250524f260632b67be9811c891bdf Mon Sep 17 00:00:00 2001 From: Joan Reyero Date: Wed, 8 Feb 2023 18:03:31 +0100 Subject: [PATCH 20/56] Fix sample data permissions (#497) --- .../src/api/tenant/tenantDeleteSampleData.ts | 4 ++++ .../src/api/tenant/tenantGenerateSampleData.ts | 5 +++++ .../src/modules/layout/components/layout.vue | 18 ++++++++++++++---- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/backend/src/api/tenant/tenantDeleteSampleData.ts b/backend/src/api/tenant/tenantDeleteSampleData.ts index 0a5572b21a..9067fb1941 100644 --- a/backend/src/api/tenant/tenantDeleteSampleData.ts +++ b/backend/src/api/tenant/tenantDeleteSampleData.ts @@ -2,12 +2,16 @@ import Error403 from '../../errors/Error403' import { i18n } from '../../i18n' import track from '../../segment/track' import SampleDataService from '../../services/sampleDataService' +import Permissions from '../../security/permissions' +import PermissionChecker from '../../services/user/permissionChecker' export default async (req, res) => { if (!req.currentUser || !req.currentUser.id) { throw new Error403(req.language) } + new PermissionChecker(req).validateHas(Permissions.values.memberDestroy) + await new SampleDataService(req).deleteSampleData() track('Delete sample data', {}, { ...req }) diff --git a/backend/src/api/tenant/tenantGenerateSampleData.ts b/backend/src/api/tenant/tenantGenerateSampleData.ts index 33044fa427..623998a251 100644 --- a/backend/src/api/tenant/tenantGenerateSampleData.ts +++ b/backend/src/api/tenant/tenantGenerateSampleData.ts @@ -2,6 +2,8 @@ import Error403 from '../../errors/Error403' import { i18n } from '../../i18n' import SampleDataService from '../../services/sampleDataService' import track from '../../segment/track' +import Permissions from '../../security/permissions' +import PermissionChecker from '../../services/user/permissionChecker' const fs = require('fs') const path = require('path') @@ -10,6 +12,9 @@ export default async (req, res) => { if (!req.currentUser || !req.currentUser.id) { throw new Error403(req.language) } + + new PermissionChecker(req).validateHas(Permissions.values.memberCreate) + const sampleMembersActivities = JSON.parse( fs.readFileSync( path.resolve(__dirname, '../../database/initializers/sample-data.json'), diff --git a/frontend/src/modules/layout/components/layout.vue b/frontend/src/modules/layout/components/layout.vue index 3faf577579..2a6e9ee8b3 100644 --- a/frontend/src/modules/layout/components/layout.vue +++ b/frontend/src/modules/layout/components/layout.vue @@ -131,6 +131,7 @@ import Banner from '@/shared/banner/banner.vue' import identify from '@/shared/monitoring/identify' import ConfirmDialog from '@/shared/dialog/confirm-dialog.js' import config from '@/config' +import Message from '@/shared/message/message' export default { name: 'AppLayout', @@ -279,10 +280,19 @@ export default { }) this.loading = true - await TenantService.deleteSampleData( - this.currentTenant.id - ) - window.location.reload() + try { + await TenantService.deleteSampleData( + this.currentTenant.id + ) + window.location.reload() + } catch (e) { + if (e.response.status === 403) { + Message.error( + 'You do not have permission to delete sample data' + ) + this.loading = false + } + } } } } From 464b554bfa8de426ede226377aae42f27c4126d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Fri, 10 Feb 2023 13:04:26 +0100 Subject: [PATCH 21/56] Move organizations to essential/free tier. --- .../src/feature-flags/ensureFlagUpdated.ts | 1 - .../workers/stripeWebhookWorker.ts | 5 --- backend/src/types/common.ts | 1 - .../components/dashboard-organizations.vue | 21 ++------- .../dashboard-organization-item.vue | 21 ++------- .../components/member-organizations.vue | 21 ++------- .../organization/organization-routes.js | 44 +------------------ 7 files changed, 14 insertions(+), 100 deletions(-) diff --git a/backend/src/feature-flags/ensureFlagUpdated.ts b/backend/src/feature-flags/ensureFlagUpdated.ts index 51e25058e5..f6f88f524c 100644 --- a/backend/src/feature-flags/ensureFlagUpdated.ts +++ b/backend/src/feature-flags/ensureFlagUpdated.ts @@ -54,7 +54,6 @@ export default async ( break } case FeatureFlag.EAGLE_EYE: - case FeatureFlag.ORGANIZATIONS: case FeatureFlag.COMMUNITY_HELP_CENTER_PRO: { expectedFlag = payload.plan === Plans.values.growth break diff --git a/backend/src/serverless/integrations/workers/stripeWebhookWorker.ts b/backend/src/serverless/integrations/workers/stripeWebhookWorker.ts index ab6531308f..b7ffc172c7 100644 --- a/backend/src/serverless/integrations/workers/stripeWebhookWorker.ts +++ b/backend/src/serverless/integrations/workers/stripeWebhookWorker.ts @@ -93,11 +93,6 @@ export const processWebhook = async (message: any) => { await timeout(2000) - // Ensure a growth specific flag is available before sending websocket message - await ensureFlagUpdated(FeatureFlag.ORGANIZATIONS, tenantId, posthog, { - plan: Plans.values.growth, - }) - log.info('Emitting to redis pubsub for websocket forwarding from api..') // Wait few more seconds to ensure redirect is completed diff --git a/backend/src/types/common.ts b/backend/src/types/common.ts index d7b4b7a253..a21669f9eb 100644 --- a/backend/src/types/common.ts +++ b/backend/src/types/common.ts @@ -21,7 +21,6 @@ export enum FeatureFlag { AUTOMATIONS = 'automations', COMMUNITY_HELP_CENTER_PRO = 'community-help-center-pro', EAGLE_EYE = 'eagle-eye', - ORGANIZATIONS = 'organizations', CSV_EXPORT = 'csv-export', LINKEDIN = 'linkedin', MEMBER_ENRICHMENT = 'member-enrichment', diff --git a/frontend/src/modules/dashboard/components/dashboard-organizations.vue b/frontend/src/modules/dashboard/components/dashboard-organizations.vue index 616cae7084..a58ab9f744 100644 --- a/frontend/src/modules/dashboard/components/dashboard-organizations.vue +++ b/frontend/src/modules/dashboard/components/dashboard-organizations.vue @@ -205,11 +205,6 @@ import { import AppDashboardOrganizationItem from '@/modules/dashboard/components/organization/dashboard-organization-item.vue' import AppDashboardCount from '@/modules/dashboard/components/dashboard-count.vue' import { formatNumberToCompact } from '@/utils/number' -import { - isFeatureEnabled, - featureFlags -} from '@/utils/posthog' -import config from '@/config' import AppPaywallModal from '@/modules/layout/components/paywall-modal.vue' export default { @@ -270,18 +265,10 @@ export default { }, formatNumberToCompact, async onViewMoreClick() { - const isFlagEnabled = await isFeatureEnabled( - featureFlags.organizations - ) - - if (config.hasPremiumModules && isFlagEnabled) { - this.$router.push({ - name: 'organization', - query: { activeTab: 'new-and-active' } - }) - } else { - this.isUpgradeModalOpen = true - } + this.$router.push({ + name: 'organization', + query: { activeTab: 'new-and-active' } + }) } } } diff --git a/frontend/src/modules/dashboard/components/organization/dashboard-organization-item.vue b/frontend/src/modules/dashboard/components/organization/dashboard-organization-item.vue index 59bb73e141..88e8ef1645 100644 --- a/frontend/src/modules/dashboard/components/organization/dashboard-organization-item.vue +++ b/frontend/src/modules/dashboard/components/organization/dashboard-organization-item.vue @@ -40,11 +40,6 @@ diff --git a/frontend/src/modules/organization/organization-routes.js b/frontend/src/modules/organization/organization-routes.js index b5c714b7e1..786797193f 100644 --- a/frontend/src/modules/organization/organization-routes.js +++ b/frontend/src/modules/organization/organization-routes.js @@ -1,30 +1,11 @@ import Layout from '@/modules/layout/components/layout.vue' import Permissions from '@/security/permissions' import { store } from '@/store' -import config from '@/config' -import { - isFeatureEnabled, - featureFlags -} from '@/utils/posthog' - -const isOrganizationsFeatureEnabled = async () => { - return ( - config.hasPremiumModules && - (await isFeatureEnabled(featureFlags.organizations)) - ) -} const OrganizationsMainPage = async () => { - if (!(await isOrganizationsFeatureEnabled())) { - return OrganizationPaywallPage() - } - return OrganizationListPage() } -const OrganizationPaywallPage = () => - import('@/modules/layout/pages/paywall-page') - const OrganizationListPage = () => import( '@/modules/organization/pages/organization-list-page' @@ -77,13 +58,6 @@ export default [ meta: { auth: true, permission: Permissions.values.organizationCreate - }, - beforeEnter: async (_to, _from, next) => { - if (!(await isOrganizationsFeatureEnabled())) { - next({ name: 'organization' }) - } - - next() } }, { @@ -94,14 +68,7 @@ export default [ auth: true, permission: Permissions.values.organizationEdit }, - props: true, - beforeEnter: async (_to, _from, next) => { - if (!(await isOrganizationsFeatureEnabled())) { - next({ name: 'organization' }) - } - - next() - } + props: true }, { name: 'organizationView', @@ -111,14 +78,7 @@ export default [ auth: true, permission: Permissions.values.organizationRead }, - props: true, - beforeEnter: async (_to, _from, next) => { - if (!(await isOrganizationsFeatureEnabled())) { - next({ name: 'organization' }) - } - - next() - } + props: true } ] } From 6d31ad992c243ecdde08de9a6d602dd545856572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Fri, 10 Feb 2023 13:04:26 +0100 Subject: [PATCH 22/56] Revert "Move organizations to essential/free tier." This reverts commit 615956335802843b76cc73b6b6d7e033ef712c50. --- .../src/feature-flags/ensureFlagUpdated.ts | 1 + .../workers/stripeWebhookWorker.ts | 5 +++ backend/src/types/common.ts | 1 + .../components/dashboard-organizations.vue | 21 +++++++-- .../dashboard-organization-item.vue | 21 +++++++-- .../components/member-organizations.vue | 21 +++++++-- .../organization/organization-routes.js | 44 ++++++++++++++++++- 7 files changed, 100 insertions(+), 14 deletions(-) diff --git a/backend/src/feature-flags/ensureFlagUpdated.ts b/backend/src/feature-flags/ensureFlagUpdated.ts index f6f88f524c..51e25058e5 100644 --- a/backend/src/feature-flags/ensureFlagUpdated.ts +++ b/backend/src/feature-flags/ensureFlagUpdated.ts @@ -54,6 +54,7 @@ export default async ( break } case FeatureFlag.EAGLE_EYE: + case FeatureFlag.ORGANIZATIONS: case FeatureFlag.COMMUNITY_HELP_CENTER_PRO: { expectedFlag = payload.plan === Plans.values.growth break diff --git a/backend/src/serverless/integrations/workers/stripeWebhookWorker.ts b/backend/src/serverless/integrations/workers/stripeWebhookWorker.ts index b7ffc172c7..ab6531308f 100644 --- a/backend/src/serverless/integrations/workers/stripeWebhookWorker.ts +++ b/backend/src/serverless/integrations/workers/stripeWebhookWorker.ts @@ -93,6 +93,11 @@ export const processWebhook = async (message: any) => { await timeout(2000) + // Ensure a growth specific flag is available before sending websocket message + await ensureFlagUpdated(FeatureFlag.ORGANIZATIONS, tenantId, posthog, { + plan: Plans.values.growth, + }) + log.info('Emitting to redis pubsub for websocket forwarding from api..') // Wait few more seconds to ensure redirect is completed diff --git a/backend/src/types/common.ts b/backend/src/types/common.ts index a21669f9eb..d7b4b7a253 100644 --- a/backend/src/types/common.ts +++ b/backend/src/types/common.ts @@ -21,6 +21,7 @@ export enum FeatureFlag { AUTOMATIONS = 'automations', COMMUNITY_HELP_CENTER_PRO = 'community-help-center-pro', EAGLE_EYE = 'eagle-eye', + ORGANIZATIONS = 'organizations', CSV_EXPORT = 'csv-export', LINKEDIN = 'linkedin', MEMBER_ENRICHMENT = 'member-enrichment', diff --git a/frontend/src/modules/dashboard/components/dashboard-organizations.vue b/frontend/src/modules/dashboard/components/dashboard-organizations.vue index a58ab9f744..616cae7084 100644 --- a/frontend/src/modules/dashboard/components/dashboard-organizations.vue +++ b/frontend/src/modules/dashboard/components/dashboard-organizations.vue @@ -205,6 +205,11 @@ import { import AppDashboardOrganizationItem from '@/modules/dashboard/components/organization/dashboard-organization-item.vue' import AppDashboardCount from '@/modules/dashboard/components/dashboard-count.vue' import { formatNumberToCompact } from '@/utils/number' +import { + isFeatureEnabled, + featureFlags +} from '@/utils/posthog' +import config from '@/config' import AppPaywallModal from '@/modules/layout/components/paywall-modal.vue' export default { @@ -265,10 +270,18 @@ export default { }, formatNumberToCompact, async onViewMoreClick() { - this.$router.push({ - name: 'organization', - query: { activeTab: 'new-and-active' } - }) + const isFlagEnabled = await isFeatureEnabled( + featureFlags.organizations + ) + + if (config.hasPremiumModules && isFlagEnabled) { + this.$router.push({ + name: 'organization', + query: { activeTab: 'new-and-active' } + }) + } else { + this.isUpgradeModalOpen = true + } } } } diff --git a/frontend/src/modules/dashboard/components/organization/dashboard-organization-item.vue b/frontend/src/modules/dashboard/components/organization/dashboard-organization-item.vue index 88e8ef1645..59bb73e141 100644 --- a/frontend/src/modules/dashboard/components/organization/dashboard-organization-item.vue +++ b/frontend/src/modules/dashboard/components/organization/dashboard-organization-item.vue @@ -40,6 +40,11 @@ diff --git a/frontend/src/modules/organization/organization-routes.js b/frontend/src/modules/organization/organization-routes.js index 786797193f..b5c714b7e1 100644 --- a/frontend/src/modules/organization/organization-routes.js +++ b/frontend/src/modules/organization/organization-routes.js @@ -1,11 +1,30 @@ import Layout from '@/modules/layout/components/layout.vue' import Permissions from '@/security/permissions' import { store } from '@/store' +import config from '@/config' +import { + isFeatureEnabled, + featureFlags +} from '@/utils/posthog' + +const isOrganizationsFeatureEnabled = async () => { + return ( + config.hasPremiumModules && + (await isFeatureEnabled(featureFlags.organizations)) + ) +} const OrganizationsMainPage = async () => { + if (!(await isOrganizationsFeatureEnabled())) { + return OrganizationPaywallPage() + } + return OrganizationListPage() } +const OrganizationPaywallPage = () => + import('@/modules/layout/pages/paywall-page') + const OrganizationListPage = () => import( '@/modules/organization/pages/organization-list-page' @@ -58,6 +77,13 @@ export default [ meta: { auth: true, permission: Permissions.values.organizationCreate + }, + beforeEnter: async (_to, _from, next) => { + if (!(await isOrganizationsFeatureEnabled())) { + next({ name: 'organization' }) + } + + next() } }, { @@ -68,7 +94,14 @@ export default [ auth: true, permission: Permissions.values.organizationEdit }, - props: true + props: true, + beforeEnter: async (_to, _from, next) => { + if (!(await isOrganizationsFeatureEnabled())) { + next({ name: 'organization' }) + } + + next() + } }, { name: 'organizationView', @@ -78,7 +111,14 @@ export default [ auth: true, permission: Permissions.values.organizationRead }, - props: true + props: true, + beforeEnter: async (_to, _from, next) => { + if (!(await isOrganizationsFeatureEnabled())) { + next({ name: 'organization' }) + } + + next() + } } ] } From 4c85b443f30a5d2478b2c85b8ee45d7b96326501 Mon Sep 17 00:00:00 2001 From: Uros Marolt Date: Fri, 10 Feb 2023 15:19:00 +0100 Subject: [PATCH 23/56] Move organizations to essential/free tier. (#514) --- .../src/feature-flags/ensureFlagUpdated.ts | 1 - .../workers/stripeWebhookWorker.ts | 7 --- backend/src/types/common.ts | 1 - .../components/dashboard-organizations.vue | 21 ++------- .../dashboard-organization-item.vue | 21 ++------- .../components/member-organizations.vue | 21 ++------- .../organization/organization-routes.js | 44 +------------------ 7 files changed, 14 insertions(+), 102 deletions(-) diff --git a/backend/src/feature-flags/ensureFlagUpdated.ts b/backend/src/feature-flags/ensureFlagUpdated.ts index 51e25058e5..f6f88f524c 100644 --- a/backend/src/feature-flags/ensureFlagUpdated.ts +++ b/backend/src/feature-flags/ensureFlagUpdated.ts @@ -54,7 +54,6 @@ export default async ( break } case FeatureFlag.EAGLE_EYE: - case FeatureFlag.ORGANIZATIONS: case FeatureFlag.COMMUNITY_HELP_CENTER_PRO: { expectedFlag = payload.plan === Plans.values.growth break diff --git a/backend/src/serverless/integrations/workers/stripeWebhookWorker.ts b/backend/src/serverless/integrations/workers/stripeWebhookWorker.ts index ab6531308f..52a19a7ab4 100644 --- a/backend/src/serverless/integrations/workers/stripeWebhookWorker.ts +++ b/backend/src/serverless/integrations/workers/stripeWebhookWorker.ts @@ -3,10 +3,8 @@ import { PostHog } from 'posthog-node' import { Stripe } from 'stripe' import { PLANS_CONFIG, POSTHOG_CONFIG } from '../../../config' import SequelizeRepository from '../../../database/repositories/sequelizeRepository' -import ensureFlagUpdated from '../../../feature-flags/ensureFlagUpdated' import setPosthogTenantProperties from '../../../feature-flags/setTenantProperties' import Plans from '../../../security/plans' -import { FeatureFlag } from '../../../types/common' import { ApiWebsocketMessage } from '../../../types/mq/apiWebsocketMessage' import { NodeWorkerMessageBase } from '../../../types/mq/nodeWorkerMessageBase' import { createServiceChildLogger } from '../../../utils/logging' @@ -93,11 +91,6 @@ export const processWebhook = async (message: any) => { await timeout(2000) - // Ensure a growth specific flag is available before sending websocket message - await ensureFlagUpdated(FeatureFlag.ORGANIZATIONS, tenantId, posthog, { - plan: Plans.values.growth, - }) - log.info('Emitting to redis pubsub for websocket forwarding from api..') // Wait few more seconds to ensure redirect is completed diff --git a/backend/src/types/common.ts b/backend/src/types/common.ts index d7b4b7a253..a21669f9eb 100644 --- a/backend/src/types/common.ts +++ b/backend/src/types/common.ts @@ -21,7 +21,6 @@ export enum FeatureFlag { AUTOMATIONS = 'automations', COMMUNITY_HELP_CENTER_PRO = 'community-help-center-pro', EAGLE_EYE = 'eagle-eye', - ORGANIZATIONS = 'organizations', CSV_EXPORT = 'csv-export', LINKEDIN = 'linkedin', MEMBER_ENRICHMENT = 'member-enrichment', diff --git a/frontend/src/modules/dashboard/components/dashboard-organizations.vue b/frontend/src/modules/dashboard/components/dashboard-organizations.vue index 616cae7084..a58ab9f744 100644 --- a/frontend/src/modules/dashboard/components/dashboard-organizations.vue +++ b/frontend/src/modules/dashboard/components/dashboard-organizations.vue @@ -205,11 +205,6 @@ import { import AppDashboardOrganizationItem from '@/modules/dashboard/components/organization/dashboard-organization-item.vue' import AppDashboardCount from '@/modules/dashboard/components/dashboard-count.vue' import { formatNumberToCompact } from '@/utils/number' -import { - isFeatureEnabled, - featureFlags -} from '@/utils/posthog' -import config from '@/config' import AppPaywallModal from '@/modules/layout/components/paywall-modal.vue' export default { @@ -270,18 +265,10 @@ export default { }, formatNumberToCompact, async onViewMoreClick() { - const isFlagEnabled = await isFeatureEnabled( - featureFlags.organizations - ) - - if (config.hasPremiumModules && isFlagEnabled) { - this.$router.push({ - name: 'organization', - query: { activeTab: 'new-and-active' } - }) - } else { - this.isUpgradeModalOpen = true - } + this.$router.push({ + name: 'organization', + query: { activeTab: 'new-and-active' } + }) } } } diff --git a/frontend/src/modules/dashboard/components/organization/dashboard-organization-item.vue b/frontend/src/modules/dashboard/components/organization/dashboard-organization-item.vue index 59bb73e141..88e8ef1645 100644 --- a/frontend/src/modules/dashboard/components/organization/dashboard-organization-item.vue +++ b/frontend/src/modules/dashboard/components/organization/dashboard-organization-item.vue @@ -40,11 +40,6 @@ diff --git a/frontend/src/modules/organization/organization-routes.js b/frontend/src/modules/organization/organization-routes.js index b5c714b7e1..786797193f 100644 --- a/frontend/src/modules/organization/organization-routes.js +++ b/frontend/src/modules/organization/organization-routes.js @@ -1,30 +1,11 @@ import Layout from '@/modules/layout/components/layout.vue' import Permissions from '@/security/permissions' import { store } from '@/store' -import config from '@/config' -import { - isFeatureEnabled, - featureFlags -} from '@/utils/posthog' - -const isOrganizationsFeatureEnabled = async () => { - return ( - config.hasPremiumModules && - (await isFeatureEnabled(featureFlags.organizations)) - ) -} const OrganizationsMainPage = async () => { - if (!(await isOrganizationsFeatureEnabled())) { - return OrganizationPaywallPage() - } - return OrganizationListPage() } -const OrganizationPaywallPage = () => - import('@/modules/layout/pages/paywall-page') - const OrganizationListPage = () => import( '@/modules/organization/pages/organization-list-page' @@ -77,13 +58,6 @@ export default [ meta: { auth: true, permission: Permissions.values.organizationCreate - }, - beforeEnter: async (_to, _from, next) => { - if (!(await isOrganizationsFeatureEnabled())) { - next({ name: 'organization' }) - } - - next() } }, { @@ -94,14 +68,7 @@ export default [ auth: true, permission: Permissions.values.organizationEdit }, - props: true, - beforeEnter: async (_to, _from, next) => { - if (!(await isOrganizationsFeatureEnabled())) { - next({ name: 'organization' }) - } - - next() - } + props: true }, { name: 'organizationView', @@ -111,14 +78,7 @@ export default [ auth: true, permission: Permissions.values.organizationRead }, - props: true, - beforeEnter: async (_to, _from, next) => { - if (!(await isOrganizationsFeatureEnabled())) { - next({ name: 'organization' }) - } - - next() - } + props: true } ] } From fdeb6edfa8403240be35509b15529e75acd2466c Mon Sep 17 00:00:00 2001 From: Igor Kotua <36304232+garrrikkotua@users.noreply.github.com> Date: Fri, 10 Feb 2023 22:48:11 +0800 Subject: [PATCH 24/56] add demo link to Readme (#508) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index cac2c2da68..8b0f0cad03 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@
Cloud Version (Beta) | + Demo + | Docs | Discord From b395c49c131a178b2de3e2e9a8a3f3a49fb7b06e Mon Sep 17 00:00:00 2001 From: Joan Reyero Date: Fri, 10 Feb 2023 15:58:51 +0100 Subject: [PATCH 25/56] Removed left server activity type for filters (#516) --- backend/src/types/prettyActivityTypes.ts | 1 - frontend/src/i18n/en.js | 3 +-- frontend/src/jsons/activity-types.json | 3 +-- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/backend/src/types/prettyActivityTypes.ts b/backend/src/types/prettyActivityTypes.ts index fdb2d68a6d..c13e586c4e 100644 --- a/backend/src/types/prettyActivityTypes.ts +++ b/backend/src/types/prettyActivityTypes.ts @@ -30,7 +30,6 @@ export const prettyActivityTypes = { thread_started: 'started a new thread', started_thread: 'started a new thread', joined_guild: 'joined server', - left_guild: 'left server', }, [PlatformType.SLACK]: { contributed_to_community: 'contributed to community', diff --git a/frontend/src/i18n/en.js b/frontend/src/i18n/en.js index 82fa29f5e6..4b4a22790a 100644 --- a/frontend/src/i18n/en.js +++ b/frontend/src/i18n/en.js @@ -358,8 +358,7 @@ const en = { replied: 'replied to a message', replied_thread: 'replied to a thread', started_thread: 'started a new thread', - joined_guild: 'joined server', - left_guild: 'left server' + joined_guild: 'joined server' }, slack: { contributed_to_community: diff --git a/frontend/src/jsons/activity-types.json b/frontend/src/jsons/activity-types.json index 42a1f356c8..8d709e7758 100644 --- a/frontend/src/jsons/activity-types.json +++ b/frontend/src/jsons/activity-types.json @@ -16,8 +16,7 @@ "message", "replied", "replied_thread", - "joined_guild", - "left_guild" + "joined_guild" ], "slack": [ "message", From a60f4818396957b30a7730dfac789d6af544c1b4 Mon Sep 17 00:00:00 2001 From: Uros Marolt Date: Mon, 13 Feb 2023 12:42:37 +0100 Subject: [PATCH 26/56] Organizations in essential plan (#523) --- backend/src/security/permissions.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/src/security/permissions.ts b/backend/src/security/permissions.ts index ec28c71024..d3b57a7810 100644 --- a/backend/src/security/permissions.ts +++ b/backend/src/security/permissions.ts @@ -222,35 +222,35 @@ class Permissions { organizationImport: { id: 'organizationImport', allowedRoles: [roles.admin], - allowedPlans: [plans.growth], + allowedPlans: [plans.essential, plans.growth], }, organizationCreate: { id: 'organizationCreate', allowedRoles: [roles.admin], - allowedPlans: [plans.growth], + allowedPlans: [plans.essential, plans.growth], allowedStorage: [], }, organizationEdit: { id: 'organizationEdit', allowedRoles: [roles.admin], - allowedPlans: [plans.growth], + allowedPlans: [plans.essential, plans.growth], allowedStorage: [], }, organizationDestroy: { id: 'organizationDestroy', allowedRoles: [roles.admin], - allowedPlans: [plans.growth], + allowedPlans: [plans.essential, plans.growth], allowedStorage: [], }, organizationRead: { id: 'organizationRead', allowedRoles: [roles.admin, roles.readonly], - allowedPlans: [plans.growth], + allowedPlans: [plans.essential, plans.growth], }, organizationAutocomplete: { id: 'organizationAutocomplete', allowedRoles: [roles.admin, roles.readonly], - allowedPlans: [plans.growth], + allowedPlans: [plans.essential, plans.growth], }, widgetImport: { id: 'widgetImport', From 0e34100fa4e8876d93228825d63a0532ea326fe7 Mon Sep 17 00:00:00 2001 From: joanreyero Date: Mon, 13 Feb 2023 16:33:27 +0000 Subject: [PATCH 27/56] Update CHANGELOG --- CHANGELOG.md | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74c254b531..50bc29b52d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ All notable changes to this project will be documented in this file. +## v0.19.0 - 2023-02-13 + +### Changes + +### ✨ Improvements + +- Added LinkedIn to sample data @joanreyero (#481) +- Moved the organizations' module to the essential plan @themarolt (#514) + +### 🐞 Bug Fixes + +- Fix global attributes not showing in the Edit attributes drawer. @joanagmaia (#488) +- Fix filters for custom attributes. @joanagmaia (#492) +- Fix the reach filter on the members' page. @joanagmaia (#491) +- Share button visible on custom reports page @gaspergrom (#484) + ## v0.18.0 - 2023-02-06 ### Changes @@ -20,7 +36,6 @@ Introducing our member enrichment feature! With it you can populate your communi - Added the special type for member attributes @joanreyero (#431) - Multi-select attribute type for members @joanreyero (#426) - Tweak error messages when enriching in bulk @joanagmaia (#477) - #### Detailed report drawers You can now get a detailed view of the members returned by widgets in default reports. For example, you can see exactly which members were active this month, as well as the total count. @@ -28,7 +43,6 @@ You can now get a detailed view of the members returned by widgets in default re Screenshot 2023-02-06 at 16 34 00 - Report detailed drawers @joanagmaia (#461) - Find active members endpoint @themarolt (#449) - ### ✨ Improvements - Optimizations in the LinkedIn integration. @themarolt (#464) @@ -58,7 +72,6 @@ Introduction the LinkedIn integration! With it, you can bring the comments and r Linkedin - Linkedin integration @mariobalca (#442) ### ✨ Improvements - - Add global filters to Default Reports. @joanagmaia (#425) - Added a Stripe integration for payment so we can automatically upgrade new Growth workspaces. @epipav (#419) - Show the current date's value differently in reports. @joanagmaia (#443) @@ -93,7 +106,6 @@ Introducing our newest feature: Default Reports! These specially crafted reports Our first external code contribution! @mattinannt and the [Formbricks](https://formbricks.com/) team added an in-app feedback box to our menu. If you have an idea, something needs to be fixed, or want to point out which features you like, you can leave us feedback there! Screenshot 2023-01-16 at 14 04 37 - Add formbricks feedback @mattinannt (#411) - ### ✨ Improvements - Added the capability of filtering members by the types of activities they performed. @joanreyero (#421) @@ -128,7 +140,6 @@ For example, imagine you want to search for content that talks about *generatice #### Discord forum channels Forum channels are now supported as part of the Discord integration. We will get posts and all comments on those channels. If you already have a Discord integration connected, we will get posts in public forum channels automatically. You'll need to add the bot to the forum channels that you want if they are private. - Get forum channels from Discord @joanreyero (#405) - ### ✨ Improvements - Preventing that an automation is executed twice. @themarolt (#401) @@ -174,7 +185,6 @@ You can now export your community members as CSV. You can export all members or - Update the "Read more" URL for custom integrations. @dende (#372) - Notes and tasks were being unlinked when updating tags in a member. @joanreyero (#370) - Fix the sorting in the dashboard's *active members* widget. @joanagmaia (#369) - ## v0.13.0 - 2022-12-19 ### Changes @@ -209,7 +219,6 @@ We are advancing in making premium plans possible. This week we introduced a *Pl - Fix a copy in the pricing page @joanagmaia (#353) - Fix a copy error in the Hacker News integration's connection page. @jonathimer (#343) ## v0.12.0 - 2022-12-13 - ### Changes - Fix identities for hackernews integration @joanagmaia (#313) @@ -274,7 +283,6 @@ The Hacker News integration will detect any post that mentions your community in ### Changes This release introduces three new features: organizations, tasks, and notes. Furthermore, we added a bunch of bug fixes and improvements based on your feedback. ### :rocket: Features - #### Organizations You can now track how organizations are adopting your community. With the organizations' list, you can have an overview of all organizations. You can also have several views and perform filtering. For each organization, there is an organization page with all its background information, a list of all the members that belong to the organization, and their activities. @@ -318,7 +326,6 @@ We’ve added social sign-in to make signing up and logging into [crowd.dev](htt #### Breaking changes This version introduces breaking API changes. While the API has vastly improved and it is now much more powerful, previous scripts written with the API will need to be adjusted. For more information, refer to the [API docs](https://docs.crowd.dev/reference). ## v0.8.0 - 2022-10-07 - ### Changes ### ✨ Enhancements @@ -355,6 +362,7 @@ This version introduces breaking API changes. While the API has vastly improved - - - +- - - When a new activity is created - - @@ -368,6 +376,7 @@ This version introduces breaking API changes. While the API has vastly improved - - - +- - With some additional optional filters. - @@ -433,7 +442,6 @@ This version introduces breaking API changes. While the API has vastly improved - EagleEye events @joanreyero (#6) ## v0.0.3 - 2022-08-24 ### Changes - ### 🚀 Features - Eagle Eye backend @joanreyero From 6944317fb8f8d9f0208ce11c9e4963d5903e703b Mon Sep 17 00:00:00 2001 From: Jonathan Reimer <41432658+jonathimer@users.noreply.github.com> Date: Mon, 13 Feb 2023 21:32:06 +0100 Subject: [PATCH 28/56] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8b0f0cad03..f77c3cdbe7 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ -

The community-led growth platform, built with developers in mind.

+

Grow your Developer Tool through Community


From 9927f53a35ef7a1e894afce3232e4bbdace18224 Mon Sep 17 00:00:00 2001 From: Uros Marolt Date: Tue, 14 Feb 2023 07:46:51 +0100 Subject: [PATCH 29/56] Discord with WebSockets (#486) Co-authored-by: Gasper Grom --- .github/workflows/production-deploy.yaml | 22 + .github/workflows/staging-deploy-backend.yaml | 17 + backend/Dockerfile.kube | 11 +- backend/package-lock.json | 622 ++++++++++++++++- backend/package.json | 11 +- backend/src/api/webhooks/github.ts | 48 +- backend/src/bin/discord-ws.ts | 170 +++++ backend/src/bin/nodejs-worker.ts | 3 +- backend/src/bin/scripts/process-webhook.ts | 12 +- backend/src/bin/worker/integrations.ts | 15 + .../services/integrationProcessor.ts | 106 +++ .../services/integrationServiceBase.ts | 20 +- .../integrations/devtoIntegrationService.ts | 4 +- .../integrations/discordIntegrationService.ts | 424 +++++++----- .../integrations/githubIntegrationService.ts | 468 ++++++++++++- .../hackerNewsIntegrationService.ts | 7 +- .../premium/linkedinIntegrationService.ts | 36 +- .../integrations/redditIntegrationService.ts | 26 +- .../integrations/slackIntegrationService.ts | 10 +- .../integrations/twitterIntegrationService.ts | 6 +- .../twitterReachIntegrationService.ts | 2 +- .../integrations/types/discordTypes.ts | 153 +++-- .../usecases/discord/errorHandler.ts | 33 + .../usecases/discord/getChannel.ts | 26 + .../usecases/discord/getChannels.ts | 43 +- .../usecases/discord/getMember.ts | 27 + .../usecases/discord/getMembers.ts | 6 +- .../usecases/discord/getMessage.ts | 26 + .../usecases/discord/getMessages.ts | 4 +- .../usecases/discord/getThreads.ts | 13 +- .../webhooks/__tests__/github.test.ts | 641 +++++++----------- .../integrations/webhooks/github.ts | 549 --------------- .../workers/githubWebhookWorker.ts | 104 --- backend/src/types/integration/stepResult.ts | 14 + .../mq/nodeWorkerProcessWebhookMessage.ts | 6 +- backend/src/types/webhooks.ts | 13 + .../activity/discord-activity-message.vue | 40 +- .../activity/components/activity-content.vue | 11 +- .../activity/components/activity-item.vue | 201 +++--- .../activity/components/activity-list.vue | 10 +- scripts/cli | 2 + scripts/services/discord-ws.yaml | 46 ++ 42 files changed, 2461 insertions(+), 1547 deletions(-) create mode 100644 backend/src/bin/discord-ws.ts create mode 100644 backend/src/serverless/integrations/usecases/discord/errorHandler.ts create mode 100644 backend/src/serverless/integrations/usecases/discord/getChannel.ts create mode 100644 backend/src/serverless/integrations/usecases/discord/getMember.ts create mode 100644 backend/src/serverless/integrations/usecases/discord/getMessage.ts delete mode 100644 backend/src/serverless/integrations/webhooks/github.ts delete mode 100644 backend/src/serverless/integrations/workers/githubWebhookWorker.ts create mode 100644 scripts/services/discord-ws.yaml diff --git a/.github/workflows/production-deploy.yaml b/.github/workflows/production-deploy.yaml index 1cb2a13ab4..2020e8b4d9 100644 --- a/.github/workflows/production-deploy.yaml +++ b/.github/workflows/production-deploy.yaml @@ -15,6 +15,10 @@ on: description: Deploy nodejs-worker service? required: true type: boolean + deploy_discord_ws: + description: Deploy discord-ws service? + required: true + type: boolean deploy_python_worker: description: Deploy python-worker service? required: true @@ -187,6 +191,24 @@ jobs: image: ${{ needs.build-and-push-backend.outputs.image }} cluster: ${{ env.CROWD_CLUSTER }} + deploy-discord-ws: + needs: build-and-push-backend + runs-on: ubuntu-latest + if: ${{ inputs.deploy_discord_ws }} + defaults: + run: + shell: bash + + steps: + - name: Check out repository code + uses: actions/checkout@v2 + + - uses: ./.github/actions/deploy-service + with: + service: discord-ws + image: ${{ needs.build-and-push-backend.outputs.image }} + cluster: ${{ env.CROWD_CLUSTER }} + deploy-job-generator: needs: build-and-push-backend runs-on: ubuntu-latest diff --git a/.github/workflows/staging-deploy-backend.yaml b/.github/workflows/staging-deploy-backend.yaml index 1972431a11..ca3ce56119 100644 --- a/.github/workflows/staging-deploy-backend.yaml +++ b/.github/workflows/staging-deploy-backend.yaml @@ -90,3 +90,20 @@ jobs: service: job-generator image: ${{ needs.build-and-push.outputs.image }} cluster: ${{ env.CROWD_CLUSTER }} + + deploy-discord-ws: + needs: build-and-push + runs-on: ubuntu-latest + defaults: + run: + shell: bash + + steps: + - name: Check out repository code + uses: actions/checkout@v2 + + - uses: ./.github/actions/deploy-service + with: + service: discord-ws + image: ${{ needs.build-and-push.outputs.image }} + cluster: ${{ env.CROWD_CLUSTER }} diff --git a/backend/Dockerfile.kube b/backend/Dockerfile.kube index 4c42a5d5bb..ac6c992565 100644 --- a/backend/Dockerfile.kube +++ b/backend/Dockerfile.kube @@ -1,9 +1,16 @@ -# syntax = docker/dockerfile:experimental -FROM node:16-alpine +FROM node:16-alpine as builder + +ENV PYTHONUNBUFFERED=1 +RUN apk add --update --no-cache python3 build-base && ln -sf python3 /usr/bin/python +RUN python3 -m ensurepip +RUN pip3 install --no-cache --upgrade pip setuptools WORKDIR /usr/crowd/backend COPY package-lock.json package.json ./ RUN npm install +FROM node:16-alpine + +COPY --from=builder /usr/crowd/backend/node_modules ./node_modules COPY . . \ No newline at end of file diff --git a/backend/package-lock.json b/backend/package-lock.json index 88056001b8..67cc011be5 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -28,6 +28,7 @@ "axios": "^0.27.2", "bcrypt": "5.0.0", "body-parser": "^1.20.1", + "bufferutil": "^4.0.7", "bunyan": "^1.8.15", "bunyan-format": "^0.2.1", "bunyan-middleware": "^1.0.2", @@ -40,9 +41,11 @@ "cron": "^2.1.0", "cron-time-generator": "^1.3.0", "crypto-js": "^4.1.1", + "discord.js": "^14.7.1", "dotenv": "8.2.0", "dotenv-expand": "^8.0.3", "emoji-dictionary": "^1.0.11", + "erlpack": "^0.1.4", "express": "4.17.1", "express-rate-limit": "6.5.1", "formidable-serverless": "1.1.1", @@ -75,9 +78,11 @@ "stripe": "^10.0.0", "superagent": "^8.0.0", "swagger-ui-dist": "4.1.3", + "utf-8-validate": "^5.0.10", "uuid": "^8.3.2", "validator": "^13.7.0", - "verify-github-webhook": "^1.0.1" + "verify-github-webhook": "^1.0.1", + "zlib-sync": "^0.1.8" }, "devDependencies": { "@babel/plugin-transform-runtime": "^7.18.10", @@ -3744,6 +3749,66 @@ "uuid": "^8.3.2" } }, + "node_modules/@discordjs/builders": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.4.0.tgz", + "integrity": "sha512-nEeTCheTTDw5kO93faM1j8ZJPonAX86qpq/QVoznnSa8WWcCgJpjlu6GylfINTDW6o7zZY0my2SYdxx2mfNwGA==", + "dependencies": { + "@discordjs/util": "^0.1.0", + "@sapphire/shapeshift": "^3.7.1", + "discord-api-types": "^0.37.20", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.2", + "tslib": "^2.4.1" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@discordjs/builders/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, + "node_modules/@discordjs/collection": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.3.0.tgz", + "integrity": "sha512-ylt2NyZ77bJbRij4h9u/wVy7qYw/aDqQLWnadjvDqW/WoWCxrsX6M3CIw9GVP5xcGCDxsrKj5e0r5evuFYwrKg==", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@discordjs/rest": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.5.0.tgz", + "integrity": "sha512-lXgNFqHnbmzp5u81W0+frdXN6Etf4EUi8FAPcWpSykKd8hmlWh1xy6BmE0bsJypU1pxohaA8lQCgp70NUI3uzA==", + "dependencies": { + "@discordjs/collection": "^1.3.0", + "@discordjs/util": "^0.1.0", + "@sapphire/async-queue": "^1.5.0", + "@sapphire/snowflake": "^3.2.2", + "discord-api-types": "^0.37.23", + "file-type": "^18.0.0", + "tslib": "^2.4.1", + "undici": "^5.13.0" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@discordjs/rest/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, + "node_modules/@discordjs/util": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-0.1.0.tgz", + "integrity": "sha512-e7d+PaTLVQav6rOc2tojh2y6FE8S7REkqLldq1XF4soCx74XB/DIjbVbVLtBemf0nLW77ntz0v+o5DytKwFNLQ==", + "engines": { + "node": ">=16.9.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", @@ -5519,6 +5584,37 @@ "@redis/client": "^1.0.0" } }, + "node_modules/@sapphire/async-queue": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", + "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/shapeshift": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.8.1.tgz", + "integrity": "sha512-xG1oXXBhCjPKbxrRTlox9ddaZTvVpOhYLmKmApD/vIWOV1xEYXnpoFs68zHIZBGbqztq6FrUPNPerIrO1Hqeaw==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/snowflake": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.4.0.tgz", + "integrity": "sha512-zZxymtVO6zeXVMPds+6d7gv/OfnCc25M1Z+7ZLB0oPmeMTPeRWVPQSS16oDJy5ZsyCOLj7M6mbZml5gWXcVRNw==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, "node_modules/@segment/loosely-validate-event": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz", @@ -5753,6 +5849,11 @@ "node": ">=6" } }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" + }, "node_modules/@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -6092,6 +6193,14 @@ "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.4.tgz", "integrity": "sha512-uAaSWegu2lymY18l+s5nmcXu3sFeeTOl1zhSGoYzcr6T3wz1M+3OcW4UjfPhIhHGd13tIMRDsEpR+d8w/MexwQ==" }, + "node_modules/@types/ws": { + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/yargs": { "version": "16.0.4", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", @@ -7132,6 +7241,19 @@ "node": ">=8" } }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bindings/node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -7541,6 +7663,18 @@ "node": ">=4" } }, + "node_modules/bufferutil": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", + "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/bunyan": { "version": "1.8.15", "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.15.tgz", @@ -7594,6 +7728,17 @@ "uuid": "^8.3.2" } }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -8994,6 +9139,58 @@ "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==" }, + "node_modules/discord-api-types": { + "version": "0.37.31", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.31.tgz", + "integrity": "sha512-k9DQQ7Wv+ehiF7901qk/FnP47k6O2MHm3meQFee4gUzi5dfGAVLf7SfLNtb4w7G2dmukJyWQtVJEDF9oMb9yuQ==" + }, + "node_modules/discord.js": { + "version": "14.7.1", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.7.1.tgz", + "integrity": "sha512-1FECvqJJjjeYcjSm0IGMnPxLqja/pmG1B0W2l3lUY2Gi4KXiyTeQmU1IxWcbXHn2k+ytP587mMWqva2IA87EbA==", + "dependencies": { + "@discordjs/builders": "^1.4.0", + "@discordjs/collection": "^1.3.0", + "@discordjs/rest": "^1.4.0", + "@discordjs/util": "^0.1.0", + "@sapphire/snowflake": "^3.2.2", + "@types/ws": "^8.5.3", + "discord-api-types": "^0.37.20", + "fast-deep-equal": "^3.1.3", + "lodash.snakecase": "^4.1.1", + "tslib": "^2.4.1", + "undici": "^5.13.0", + "ws": "^8.11.0" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/discord.js/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, + "node_modules/discord.js/node_modules/ws": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz", + "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -9400,6 +9597,16 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/erlpack": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/erlpack/-/erlpack-0.1.4.tgz", + "integrity": "sha512-CJYbkEvsB5FqCCu2tLxF1eYKi28PvemC12oqzJ9oO6mDFrFO9G9G7nNJUHhiAyyL9zfXTOJx/tOcrQk+ncD65w==", + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.15.0" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -10465,6 +10672,22 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-type": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-18.2.0.tgz", + "integrity": "sha512-M3RQMWY3F2ykyWZ+IHwNCjpnUmukYhtdkGGC1ZVEUb0ve5REGF7NNJ4Q9ehCUabtQKtSVFOMbFTXgJlFb0DQIg==", + "dependencies": { + "readable-web-to-node-stream": "^3.0.2", + "strtok3": "^7.0.0", + "token-types": "^5.0.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, "node_modules/file-uri-to-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", @@ -14504,6 +14727,11 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" + }, "node_modules/log-driver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", @@ -15352,8 +15580,7 @@ "node_modules/nan": { "version": "2.17.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", - "optional": true + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" }, "node_modules/nanoid": { "version": "3.3.4", @@ -15519,6 +15746,16 @@ "node": ">= 6.13.0" } }, + "node_modules/node-gyp-build": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", + "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -16896,6 +17133,18 @@ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, + "node_modules/peek-readable": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", + "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/pg": { "version": "8.7.3", "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.3.tgz", @@ -18262,6 +18511,21 @@ "node": ">= 6" } }, + "node_modules/readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", + "dependencies": { + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/readdirp": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", @@ -19379,6 +19643,14 @@ "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -19568,6 +19840,22 @@ "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" }, + "node_modules/strtok3": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", + "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/stubs": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", @@ -20210,6 +20498,41 @@ "node": ">=0.6" } }, + "node_modules/token-types": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", + "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/token-types/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/toposort-class": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", @@ -20335,6 +20658,11 @@ "node": ">=10" } }, + "node_modules/ts-mixer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.2.tgz", + "integrity": "sha512-zvHx3VM83m2WYCE8XL99uaM7mFwYSkjR2OZti98fabHrwkjsCvgwChda5xctein3xGOyaQhtTeDq/1H/GNvF3A==" + }, "node_modules/ts-node": { "version": "10.6.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.6.0.tgz", @@ -20585,6 +20913,17 @@ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", "dev": true }, + "node_modules/undici": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.16.0.tgz", + "integrity": "sha512-KWBOXNv6VX+oJQhchXieUznEmnJMqgXMbs0xxH2t8q/FUAWSJvOSr/rMaZKnX5RIVq7JDn0JbP4BOnKG2SGXLQ==", + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=12.18" + } + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -20833,6 +21172,18 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -21663,6 +22014,15 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zlib-sync": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/zlib-sync/-/zlib-sync-0.1.8.tgz", + "integrity": "sha512-Xbu4odT5SbLsa1HFz8X/FvMgUbJYWxJYKB2+bqxJ6UOIIPaVGrqHEB3vyXDltSA6tTqBhSGYLgiVpzPQHYi3lA==", + "hasInstallScript": true, + "dependencies": { + "nan": "^2.17.0" + } } }, "dependencies": { @@ -24580,6 +24940,58 @@ "uuid": "^8.3.2" } }, + "@discordjs/builders": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.4.0.tgz", + "integrity": "sha512-nEeTCheTTDw5kO93faM1j8ZJPonAX86qpq/QVoznnSa8WWcCgJpjlu6GylfINTDW6o7zZY0my2SYdxx2mfNwGA==", + "requires": { + "@discordjs/util": "^0.1.0", + "@sapphire/shapeshift": "^3.7.1", + "discord-api-types": "^0.37.20", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.2", + "tslib": "^2.4.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + } + } + }, + "@discordjs/collection": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.3.0.tgz", + "integrity": "sha512-ylt2NyZ77bJbRij4h9u/wVy7qYw/aDqQLWnadjvDqW/WoWCxrsX6M3CIw9GVP5xcGCDxsrKj5e0r5evuFYwrKg==" + }, + "@discordjs/rest": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.5.0.tgz", + "integrity": "sha512-lXgNFqHnbmzp5u81W0+frdXN6Etf4EUi8FAPcWpSykKd8hmlWh1xy6BmE0bsJypU1pxohaA8lQCgp70NUI3uzA==", + "requires": { + "@discordjs/collection": "^1.3.0", + "@discordjs/util": "^0.1.0", + "@sapphire/async-queue": "^1.5.0", + "@sapphire/snowflake": "^3.2.2", + "discord-api-types": "^0.37.23", + "file-type": "^18.0.0", + "tslib": "^2.4.1", + "undici": "^5.13.0" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + } + } + }, + "@discordjs/util": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-0.1.0.tgz", + "integrity": "sha512-e7d+PaTLVQav6rOc2tojh2y6FE8S7REkqLldq1XF4soCx74XB/DIjbVbVLtBemf0nLW77ntz0v+o5DytKwFNLQ==" + }, "@eslint/eslintrc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", @@ -25988,6 +26400,25 @@ "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", "requires": {} }, + "@sapphire/async-queue": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", + "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==" + }, + "@sapphire/shapeshift": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.8.1.tgz", + "integrity": "sha512-xG1oXXBhCjPKbxrRTlox9ddaZTvVpOhYLmKmApD/vIWOV1xEYXnpoFs68zHIZBGbqztq6FrUPNPerIrO1Hqeaw==", + "requires": { + "fast-deep-equal": "^3.1.3", + "lodash": "^4.17.21" + } + }, + "@sapphire/snowflake": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.4.0.tgz", + "integrity": "sha512-zZxymtVO6zeXVMPds+6d7gv/OfnCc25M1Z+7ZLB0oPmeMTPeRWVPQSS16oDJy5ZsyCOLj7M6mbZml5gWXcVRNw==" + }, "@segment/loosely-validate-event": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz", @@ -26188,6 +26619,11 @@ "defer-to-connect": "^1.0.1" } }, + "@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" + }, "@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -26524,6 +26960,14 @@ "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.4.tgz", "integrity": "sha512-uAaSWegu2lymY18l+s5nmcXu3sFeeTOl1zhSGoYzcr6T3wz1M+3OcW4UjfPhIhHGd13tIMRDsEpR+d8w/MexwQ==" }, + "@types/ws": { + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", + "requires": { + "@types/node": "*" + } + }, "@types/yargs": { "version": "16.0.4", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", @@ -27289,6 +27733,21 @@ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "requires": { + "file-uri-to-path": "1.0.0" + }, + "dependencies": { + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + } + } + }, "bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -27597,6 +28056,14 @@ "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" }, + "bufferutil": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", + "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", + "requires": { + "node-gyp-build": "^4.3.0" + } + }, "bunyan": { "version": "1.8.15", "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.15.tgz", @@ -27643,6 +28110,14 @@ "uuid": "^8.3.2" } }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "requires": { + "streamsearch": "^1.1.0" + } + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -28725,6 +29200,43 @@ "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==" }, + "discord-api-types": { + "version": "0.37.31", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.31.tgz", + "integrity": "sha512-k9DQQ7Wv+ehiF7901qk/FnP47k6O2MHm3meQFee4gUzi5dfGAVLf7SfLNtb4w7G2dmukJyWQtVJEDF9oMb9yuQ==" + }, + "discord.js": { + "version": "14.7.1", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.7.1.tgz", + "integrity": "sha512-1FECvqJJjjeYcjSm0IGMnPxLqja/pmG1B0W2l3lUY2Gi4KXiyTeQmU1IxWcbXHn2k+ytP587mMWqva2IA87EbA==", + "requires": { + "@discordjs/builders": "^1.4.0", + "@discordjs/collection": "^1.3.0", + "@discordjs/rest": "^1.4.0", + "@discordjs/util": "^0.1.0", + "@sapphire/snowflake": "^3.2.2", + "@types/ws": "^8.5.3", + "discord-api-types": "^0.37.20", + "fast-deep-equal": "^3.1.3", + "lodash.snakecase": "^4.1.1", + "tslib": "^2.4.1", + "undici": "^5.13.0", + "ws": "^8.11.0" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, + "ws": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz", + "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==", + "requires": {} + } + } + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -29055,6 +29567,15 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" }, + "erlpack": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/erlpack/-/erlpack-0.1.4.tgz", + "integrity": "sha512-CJYbkEvsB5FqCCu2tLxF1eYKi28PvemC12oqzJ9oO6mDFrFO9G9G7nNJUHhiAyyL9zfXTOJx/tOcrQk+ncD65w==", + "requires": { + "bindings": "^1.5.0", + "nan": "^2.15.0" + } + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -29905,6 +30426,16 @@ "flat-cache": "^3.0.4" } }, + "file-type": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-18.2.0.tgz", + "integrity": "sha512-M3RQMWY3F2ykyWZ+IHwNCjpnUmukYhtdkGGC1ZVEUb0ve5REGF7NNJ4Q9ehCUabtQKtSVFOMbFTXgJlFb0DQIg==", + "requires": { + "readable-web-to-node-stream": "^3.0.2", + "strtok3": "^7.0.0", + "token-types": "^5.0.1" + } + }, "file-uri-to-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", @@ -32954,6 +33485,11 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" }, + "lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" + }, "log-driver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", @@ -33613,8 +34149,7 @@ "nan": { "version": "2.17.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", - "optional": true + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" }, "nanoid": { "version": "3.3.4", @@ -33738,6 +34273,11 @@ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" }, + "node-gyp-build": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", + "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==" + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -34803,6 +35343,11 @@ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, + "peek-readable": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", + "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==" + }, "pg": { "version": "8.7.3", "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.3.tgz", @@ -35804,6 +36349,14 @@ "util-deprecate": "^1.0.1" } }, + "readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", + "requires": { + "readable-stream": "^3.6.0" + } + }, "readdirp": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", @@ -36674,6 +37227,11 @@ "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" + }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -36807,6 +37365,15 @@ "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" }, + "strtok3": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", + "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", + "requires": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^5.0.0" + } + }, "stubs": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", @@ -37288,6 +37855,22 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, + "token-types": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", + "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", + "requires": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "dependencies": { + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + } + } + }, "toposort-class": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", @@ -37366,6 +37949,11 @@ } } }, + "ts-mixer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.2.tgz", + "integrity": "sha512-zvHx3VM83m2WYCE8XL99uaM7mFwYSkjR2OZti98fabHrwkjsCvgwChda5xctein3xGOyaQhtTeDq/1H/GNvF3A==" + }, "ts-node": { "version": "10.6.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.6.0.tgz", @@ -37547,6 +38135,14 @@ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", "dev": true }, + "undici": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.16.0.tgz", + "integrity": "sha512-KWBOXNv6VX+oJQhchXieUznEmnJMqgXMbs0xxH2t8q/FUAWSJvOSr/rMaZKnX5RIVq7JDn0JbP4BOnKG2SGXLQ==", + "requires": { + "busboy": "^1.6.0" + } + }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -37732,6 +38328,14 @@ "resolved": "https://registry.npmjs.org/url-search-params-polyfill/-/url-search-params-polyfill-7.0.1.tgz", "integrity": "sha512-bAw7L2E+jn9XHG5P9zrPnHdO0yJub4U+yXJOdpcpkr7OBd9T8oll4lUos0iSGRcDvfZoLUKfx9a6aNmIhJ4+mQ==" }, + "utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "requires": { + "node-gyp-build": "^4.3.0" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -38389,6 +38993,14 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + }, + "zlib-sync": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/zlib-sync/-/zlib-sync-0.1.8.tgz", + "integrity": "sha512-Xbu4odT5SbLsa1HFz8X/FvMgUbJYWxJYKB2+bqxJ6UOIIPaVGrqHEB3vyXDltSA6tTqBhSGYLgiVpzPQHYi3lA==", + "requires": { + "nan": "^2.17.0" + } } } } diff --git a/backend/package.json b/backend/package.json index f59ec8f59a..9b60be2813 100644 --- a/backend/package.json +++ b/backend/package.json @@ -11,6 +11,9 @@ "start:nodejs-worker": "ts-node --transpile-only ./src/bin/nodejs-worker.ts", "start:nodejs-worker:dev": "nodemon --watch \"src/**/*.ts\" -e ts,json --exec \"ts-node --transpile-only ./src/bin/nodejs-worker.ts\"", "start:nodejs-worker:dev:local": "set -a && . ./.env.dist.local && . ./.env.override.local && set +a && SERVICE=nodejs-worker nodemon --signal SIGKILL --watch \"src/**/*.ts\" -e ts,json --exec \"node --inspect=0.0.0.0:9229 -r ts-node/register ./src/bin/nodejs-worker.ts --transpile-only\"", + "start:discord-ws": "ts-node --transpile-only ./src/bin/discord-ws.ts", + "start:discord-ws:dev": "nodemon --watch \"src/**/*.ts\" -e ts,json --exec \"ts-node --transpile-only ./src/bin/discord-ws.ts\"", + "start:discord-ws:dev:local": "set -a && . ./.env.dist.local && . ./.env.override.local && set +a && SERVICE=job-generator nodemon --signal SIGKILL --watch \"src/**/*.ts\" -e ts,json --exec \"ts-node --transpile-only ./src/bin/discord-ws.ts\"", "build": "tsc && npm run build:documentation && cp package*json dist/ && cp .sequelizerc dist/.sequelizerc ", "test": "../scripts/cli scaffold up-test && jest --clearCache && set -a && . ./.env.dist.local && . ./.env.test && set +a && NODE_ENV=test SERVICE=test jest --runInBand --verbose --forceExit", "build:documentation": "copyfiles --flat ./src/documentation/openapi.json ./dist/documentation/", @@ -26,6 +29,7 @@ "stripe:start": "stripe listen --forward-to localhost:8080/api/plan/stripe/webhook", "lint": "npx eslint .", "format": "npx prettier --write .", + "tsc-check": "tsc --noEmit", "script:process-integration": "SERVICE=script ts-node ./src/bin/scripts/process-integration.ts", "script:change-tenant-plan": "SERVICE=script ts-node ./src/bin/scripts/change-tenant-plan.ts", "script:process-webhook": "SERVICE=script ts-node ./src/bin/scripts/process-webhook.ts", @@ -54,6 +58,7 @@ "axios": "^0.27.2", "bcrypt": "5.0.0", "body-parser": "^1.20.1", + "bufferutil": "^4.0.7", "bunyan": "^1.8.15", "bunyan-format": "^0.2.1", "bunyan-middleware": "^1.0.2", @@ -66,9 +71,11 @@ "cron": "^2.1.0", "cron-time-generator": "^1.3.0", "crypto-js": "^4.1.1", + "discord.js": "^14.7.1", "dotenv": "8.2.0", "dotenv-expand": "^8.0.3", "emoji-dictionary": "^1.0.11", + "erlpack": "^0.1.4", "express": "4.17.1", "express-rate-limit": "6.5.1", "formidable-serverless": "1.1.1", @@ -101,9 +108,11 @@ "stripe": "^10.0.0", "superagent": "^8.0.0", "swagger-ui-dist": "4.1.3", + "utf-8-validate": "^5.0.10", "uuid": "^8.3.2", "validator": "^13.7.0", - "verify-github-webhook": "^1.0.1" + "verify-github-webhook": "^1.0.1", + "zlib-sync": "^0.1.8" }, "private": true, "devDependencies": { diff --git a/backend/src/api/webhooks/github.ts b/backend/src/api/webhooks/github.ts index 1c1f199e93..f3f7630767 100644 --- a/backend/src/api/webhooks/github.ts +++ b/backend/src/api/webhooks/github.ts @@ -1,10 +1,46 @@ -import githubWebhookWorker from '../../serverless/integrations/workers/githubWebhookWorker' +import IntegrationRepository from '../../database/repositories/integrationRepository' +import { PlatformType } from '../../types/integrationEnums' +import SequelizeRepository from '../../database/repositories/sequelizeRepository' +import IncomingWebhookRepository from '../../database/repositories/incomingWebhookRepository' +import { WebhookType } from '../../types/webhooks' +import { sendNodeWorkerMessage } from '../../serverless/utils/nodeWorkerSQS' +import { NodeWorkerProcessWebhookMessage } from '../../types/mq/nodeWorkerProcessWebhookMessage' export default async (req, res) => { - const out = await githubWebhookWorker(req) - let status = 200 - if (out.status === 204) { - status = 204 + const signature = req.headers['x-hub-signature'] + const event = req.headers['x-github-event'] + const data = req.body + + const identifier = data.installation.id.toString() + const integration = (await IntegrationRepository.findByIdentifier( + identifier, + PlatformType.GITHUB, + )) as any + + if (integration) { + req.log.info({ integrationId: integration.id }, 'Incoming GitHub Webhook!') + const options = await SequelizeRepository.getDefaultIRepositoryOptions() + const repo = new IncomingWebhookRepository(options) + + const result = await repo.create({ + tenantId: integration.tenantId, + integrationId: integration.id, + type: WebhookType.GITHUB, + payload: { + signature, + event, + data, + }, + }) + + await sendNodeWorkerMessage( + integration.tenantId, + new NodeWorkerProcessWebhookMessage(integration.tenantId, result.id), + ) + + await req.responseHandler.success(req, res, {}, 204) + } else { + req.log.error({ identifier }, 'No integration found for incoming GitHub Webhook!') + await req.responseHandler.success(req, res, {}, 200) } - await req.responseHandler.success(req, res, out, status) } diff --git a/backend/src/bin/discord-ws.ts b/backend/src/bin/discord-ws.ts new file mode 100644 index 0000000000..01de670b54 --- /dev/null +++ b/backend/src/bin/discord-ws.ts @@ -0,0 +1,170 @@ +import { Client, Events, GatewayIntentBits, MessageType } from 'discord.js' +import moment from 'moment' +import { DISCORD_CONFIG } from '../config' +import { createChildLogger, getServiceLogger } from '../utils/logging' +import SequelizeRepository from '../database/repositories/sequelizeRepository' +import IntegrationRepository from '../database/repositories/integrationRepository' +import { PlatformType } from '../types/integrationEnums' +import IncomingWebhookRepository from '../database/repositories/incomingWebhookRepository' +import { DiscordWebsocketEvent, DiscordWebsocketPayload, WebhookType } from '../types/webhooks' +import { sendNodeWorkerMessage } from '../serverless/utils/nodeWorkerSQS' +import { NodeWorkerProcessWebhookMessage } from '../types/mq/nodeWorkerProcessWebhookMessage' +import { createRedisClient } from '../utils/redis' +import { RedisCache } from '../utils/redis/redisCache' +import { DiscordIntegrationService } from '../serverless/integrations/services/integrations/discordIntegrationService' + +const log = getServiceLogger() + +async function spawnClient(name: string, token: string) { + const logger = createChildLogger('discord-ws', log, { clientName: name }) + + const repoOptions = await SequelizeRepository.getDefaultIRepositoryOptions() + const repo = new IncomingWebhookRepository(repoOptions) + + const processPayload = async ( + event: DiscordWebsocketEvent, + data: any, + guildId: string, + ): Promise => { + const payload: DiscordWebsocketPayload = { + event, + data, + } + + try { + const integration = (await IntegrationRepository.findByIdentifier( + guildId, + PlatformType.DISCORD, + )) as any + + const result = await repo.create({ + tenantId: integration.tenantId, + integrationId: integration.id, + type: WebhookType.DISCORD, + payload, + }) + + await sendNodeWorkerMessage( + integration.tenantId, + new NodeWorkerProcessWebhookMessage(integration.tenantId, result.id), + ) + } catch (err) { + if (err.code === 404) { + logger.warn({ guildId }, 'No integration found for incoming Discord WS Message!') + } else { + logger.error( + err, + { + discordPayload: JSON.stringify(payload), + guildId, + }, + 'Error processing Discord WS Message!', + ) + } + } + } + + const client = new Client({ + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMembers, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.GuildMessageReactions, + GatewayIntentBits.DirectMessages, + GatewayIntentBits.DirectMessageReactions, + GatewayIntentBits.MessageContent, + ], + }) + + // listen to client events + client.on(Events.ClientReady, () => { + logger.info('Discord WS client is ready!') + }) + + client.on(Events.Error, (err) => { + logger.error(err, 'Discord WS client error! Exiting...') + process.exit(1) + }) + + client.on(Events.Debug, (message) => { + logger.debug({ debugMsg: message }, 'Discord WS client debug message!') + }) + + client.on(Events.Warn, (message) => { + logger.warn({ warning: message }, 'Discord WS client warning!') + }) + + // listen to discord events + client.on(Events.GuildMemberAdd, async (member) => { + logger.info({ member }, 'Member joined guild!') + await processPayload(DiscordWebsocketEvent.MEMBER_ADDED, member, member.guild.id) + }) + + client.on(Events.MessageCreate, async (message) => { + if (message.type === MessageType.Default || message.type === MessageType.Reply) { + logger.info({ message }, 'Message created!') + await processPayload(DiscordWebsocketEvent.MESSAGE_CREATED, message, message.guildId) + } + }) + + client.on(Events.MessageUpdate, async (oldMessage, newMessage) => { + if (newMessage.type === MessageType.Default) { + logger.info({ oldMessage, newMessage }, 'Message updated!') + await processPayload( + DiscordWebsocketEvent.MESSAGE_UPDATED, + { + message: newMessage, + oldMessage, + }, + newMessage.guildId, + ) + } + }) + + await client.login(token) + logger.info('Discord WS client logged in!') +} + +setImmediate(async () => { + // we are saving heartbeat timestamps in redis every 2 seconds + // on boot if we detect that there has been a downtime we should trigger discord integration checks + // so we don't miss anything + const redis = await createRedisClient(true) + const cache = new RedisCache('discord-ws', redis) + + const lastHeartbeat = await cache.getValue('heartbeat') + let triggerCheck = false + if (!lastHeartbeat) { + log.info('No heartbeat found, triggering check!') + triggerCheck = true + } else { + const diff = moment().diff(lastHeartbeat, 'seconds') + // if we do rolling update deploys (kubernetes default) + // we might catch a heartbeat without the need to trigger a check + if (diff > 5) { + log.warn('Heartbeat is stale, triggering check!') + triggerCheck = true + } + } + + if (triggerCheck) { + const integrations = await IntegrationRepository.findAllActive(PlatformType.DISCORD) + if (integrations.length > 0) { + log.warn(`Found ${integrations.length} integrations to trigger check for!`) + const service = new DiscordIntegrationService() + await service.triggerIntegrationCheck(integrations) + } else { + log.warn('Found no integrations to trigger check for!') + } + } + + await spawnClient('first-app', DISCORD_CONFIG.token) + + if (DISCORD_CONFIG.token2) { + await spawnClient('second-app', DISCORD_CONFIG.token2) + } + + setInterval(async () => { + await cache.setValue('heartbeat', new Date().toISOString()) + }, 2 * 1000) +}) diff --git a/backend/src/bin/nodejs-worker.ts b/backend/src/bin/nodejs-worker.ts index cc193c4528..5ce82b9676 100644 --- a/backend/src/bin/nodejs-worker.ts +++ b/backend/src/bin/nodejs-worker.ts @@ -9,8 +9,7 @@ import { NodeWorkerMessageBase } from '../types/mq/nodeWorkerMessageBase' import { createChildLogger, getServiceLogger, Logger } from '../utils/logging' import { deleteMessage, receiveMessage, sendMessage } from '../utils/sqs' import { timeout } from '../utils/timing' -import { processIntegration, processIntegrationCheck } from './worker/integrations' -import { processWebhook } from '../serverless/integrations/workers/githubWebhookWorker' +import { processIntegration, processIntegrationCheck, processWebhook } from './worker/integrations' /* eslint-disable no-constant-condition */ diff --git a/backend/src/bin/scripts/process-webhook.ts b/backend/src/bin/scripts/process-webhook.ts index bd70afd0b9..62fb752f89 100644 --- a/backend/src/bin/scripts/process-webhook.ts +++ b/backend/src/bin/scripts/process-webhook.ts @@ -22,6 +22,14 @@ const options = [ description: 'The unique ID of webhook that you would like to process. Use comma delimiter when sending multiple webhooks.', }, + { + name: 'force', + alias: 'f', + typeLabel: '{underline force}', + type: Boolean, + defaultOption: false, + description: 'Force processing of webhooks.', + }, { name: 'help', alias: 'h', @@ -61,14 +69,14 @@ if (parameters.help || !parameters.webhook) { if (!webhook) { log.error({ webhookId }, 'Webhook not found!') process.exit(1) - } else if (webhook.state !== WebhookState.PENDING) { + } else if (!parameters.force && webhook.state !== WebhookState.PENDING) { log.error({ webhookId }, 'Webhook is not in pending state!') process.exit(1) } else { log.info({ webhookId }, 'Webhook found - triggering SQS message!') await sendNodeWorkerMessage( webhook.tenantId, - new NodeWorkerProcessWebhookMessage(webhook.tenantId, webhook.id), + new NodeWorkerProcessWebhookMessage(webhook.tenantId, webhook.id, parameters.force), ) } } diff --git a/backend/src/bin/worker/integrations.ts b/backend/src/bin/worker/integrations.ts index 502fd17b32..88a04652ce 100644 --- a/backend/src/bin/worker/integrations.ts +++ b/backend/src/bin/worker/integrations.ts @@ -5,6 +5,7 @@ import { Logger } from '../../utils/logging' import { NodeWorkerIntegrationCheckMessage } from '../../types/mq/nodeWorkerIntegrationCheckMessage' import { NodeWorkerIntegrationProcessMessage } from '../../types/mq/nodeWorkerIntegrationProcessMessage' import { createRedisClient } from '../../utils/redis' +import { NodeWorkerProcessWebhookMessage } from '../../types/mq/nodeWorkerProcessWebhookMessage' export const processIntegrationCheck = async ( msg: NodeWorkerIntegrationCheckMessage, @@ -33,3 +34,17 @@ export const processIntegration = async ( await processor.process(msg) } + +export const processWebhook = async ( + msg: NodeWorkerProcessWebhookMessage, + messageLogger: Logger, +): Promise => { + const options = (await SequelizeRepository.getDefaultIRepositoryOptions()) as IServiceOptions + options.log = messageLogger + + const redisEmitter = await createRedisClient(true) + + const processor = new IntegrationProcessor(options, redisEmitter) + + await processor.processWebhook(msg.webhookId, msg.force) +} diff --git a/backend/src/serverless/integrations/services/integrationProcessor.ts b/backend/src/serverless/integrations/services/integrationProcessor.ts index 452568b04b..3f8133582f 100644 --- a/backend/src/serverless/integrations/services/integrationProcessor.ts +++ b/backend/src/serverless/integrations/services/integrationProcessor.ts @@ -37,6 +37,11 @@ import { IRedisPubSubEmitter, RedisClient } from '../../../utils/redis' import RedisPubSubEmitter from '../../../utils/redis/pubSubEmitter' import { ApiWebsocketMessage } from '../../../types/mq/apiWebsocketMessage' import { RedisCache } from '../../../utils/redis/redisCache' +import SequelizeRepository from '../../../database/repositories/sequelizeRepository' +import { IRepositoryOptions } from '../../../database/repositories/IRepositoryOptions' +import IncomingWebhookRepository from '../../../database/repositories/incomingWebhookRepository' +import { WebhookError, WebhookState } from '../../../types/webhooks' +import { NodeWorkerProcessWebhookMessage } from '../../../types/mq/nodeWorkerProcessWebhookMessage' const MAX_STREAM_RETRIES = 5 @@ -179,6 +184,106 @@ export class IntegrationProcessor extends LoggingBase { } } + async processWebhook(webhookId: string, force?: boolean) { + let logger = createChildLogger('processWebhook', this.log, { webhookId }) + logger.debug('Processing webhook!') + + const options = (await SequelizeRepository.getDefaultIRepositoryOptions()) as IRepositoryOptions + const repo = new IncomingWebhookRepository(options) + const webhook = await repo.findById(webhookId) + + if (webhook === null || webhook === undefined) { + logger.error('Webhook not found!') + return + } + + logger = createChildLogger('processWebhook', this.log, { + type: webhook.type, + tenantId: webhook.tenantId, + integrationId: webhook.integrationId, + }) + + logger.info('Webhook found!') + + if (!(force === true) && webhook.state !== WebhookState.PENDING) { + logger.error({ state: webhook.state }, 'Webhook is not in pending state!') + return + } + + const userContext = await getUserContext(webhook.tenantId) + userContext.log = logger + + const integration = await IntegrationRepository.findById(webhook.integrationId, userContext) + const intService = singleOrDefault( + this.integrationServices, + (s) => s.type === integration.platform, + ) + if (intService === undefined) { + logger.error('No integration service configured!') + throw new Error(`No integration service configured for type '${integration.platform}'!`) + } + + const stepContext: IStepContext = { + startTimestamp: moment().utc().unix(), + limitCount: integration.limitCount || 0, + onboarding: false, + pipelineData: {}, + webhook, + integration, + serviceContext: userContext, + repoContext: userContext, + logger, + } + + if (integration.settings.updateMemberAttributes) { + logger.trace('Updating member attributes!') + + await intService.createMemberAttributes(stepContext) + + integration.settings.updateMemberAttributes = false + await IntegrationRepository.update( + integration.id, + { settings: integration.settings }, + userContext, + ) + } + + const whContext = { ...userContext } + whContext.transaction = await SequelizeRepository.createTransaction(whContext) + + try { + const result = await intService.processWebhook(webhook, stepContext) + for (const operation of result.operations) { + if (operation.records.length > 0) { + logger.trace( + { operationType: operation.type }, + `Processing bulk operation with ${operation.records.length} records!`, + ) + await bulkOperations(integration.tenantId, operation.type, operation.records) + } + } + await repo.markCompleted(webhook.id) + logger.debug('Webhook processed!') + } catch (err) { + if (err.rateLimitResetSeconds) { + logger.warn(err, 'Rate limit reached while processing webhook! Delaying...') + await sendNodeWorkerMessage( + integration.tenantId, + new NodeWorkerProcessWebhookMessage(integration.tenantId, webhookId), + err.rateLimitResetSeconds + 5, + ) + } else { + logger.error(err, 'Error processing webhook!') + await repo.markError( + webhook.id, + new WebhookError(webhook.id, 'Error processing webhook!', err), + ) + } + } finally { + await SequelizeRepository.commitTransaction(whContext.transaction) + } + } + async process(req: NodeWorkerIntegrationProcessMessage) { const logger = createChildLogger('process', this.log, { type: req.integrationType, @@ -224,6 +329,7 @@ export class IntegrationProcessor extends LoggingBase { integration, serviceContext: userContext, repoContext: userContext, + logger, } if (integration.settings.updateMemberAttributes) { diff --git a/backend/src/serverless/integrations/services/integrationServiceBase.ts b/backend/src/serverless/integrations/services/integrationServiceBase.ts index 17dad09ae2..06232f65fd 100644 --- a/backend/src/serverless/integrations/services/integrationServiceBase.ts +++ b/backend/src/serverless/integrations/services/integrationServiceBase.ts @@ -1,15 +1,11 @@ import { SuperfaceClient } from '@superfaceai/one-sdk' import moment from 'moment' import crypto from 'crypto' -import { - getServiceLogger, - createChildLogger, - createServiceChildLogger, - Logger, -} from '../../../utils/logging' +import { createServiceChildLogger } from '../../../utils/logging' import { IIntegrationStream, IProcessStreamResults, + IProcessWebhookResults, IStepContext, IStreamResultOperation, } from '../../../types/integration/stepResult' @@ -103,6 +99,10 @@ export abstract class IntegrationServiceBase { // do nothing - override if something is needed } + async processWebhook(webhook: any, context: IStepContext): Promise { + throw new Error('Not implemented') + } + static superfaceClient(): SuperfaceClient { if (IS_TEST_ENV) { return undefined @@ -172,12 +172,4 @@ export abstract class IntegrationServiceBase { } return Math.floor(unixTimestamp - timestampedDate) } - - logger(context: IStepContext): Logger { - if (context.serviceContext.log) { - return createChildLogger(this.type, context.serviceContext.log || getServiceLogger()) - } - - return createServiceChildLogger(this.type) - } } diff --git a/backend/src/serverless/integrations/services/integrations/devtoIntegrationService.ts b/backend/src/serverless/integrations/services/integrations/devtoIntegrationService.ts index a6ae2eb9f4..393b00ca2e 100644 --- a/backend/src/serverless/integrations/services/integrations/devtoIntegrationService.ts +++ b/backend/src/serverless/integrations/services/integrations/devtoIntegrationService.ts @@ -114,11 +114,9 @@ export class DevtoIntegrationService extends IntegrationServiceBase { stream: IIntegrationStream, context: IStepContext, ): Promise { - const logger = this.logger(context) - const articleId = parseInt(stream.value, 10) - logger.debug({ articleId }, 'Processing article!') + context.logger.debug({ articleId }, 'Processing article!') const comments = await getArticleComments(articleId) diff --git a/backend/src/serverless/integrations/services/integrations/discordIntegrationService.ts b/backend/src/serverless/integrations/services/integrations/discordIntegrationService.ts index bfa9e18d5a..1aff0ad8b5 100644 --- a/backend/src/serverless/integrations/services/integrations/discordIntegrationService.ts +++ b/backend/src/serverless/integrations/services/integrations/discordIntegrationService.ts @@ -1,12 +1,12 @@ import moment from 'moment/moment' import lodash from 'lodash' +import { ChannelType, MessageType } from 'discord.js' import { - DiscordMessages, - DiscordMembers, - DiscordMention, + DiscordApiChannel, + DiscordApiMember, + DiscordApiMessage, + DiscordApiUser, DiscordStreamProcessResult, - ProcessedChannel, - ProcessedChannels, } from '../../types/discordTypes' import { DISCORD_CONFIG } from '../../../../config' import { DiscordMemberAttributes } from '../../../../database/attributes/member/discord' @@ -15,6 +15,7 @@ import MemberAttributeSettingsService from '../../../../services/memberAttribute import { IIntegrationStream, IProcessStreamResults, + IProcessWebhookResults, IStepContext, IStreamResultOperation, } from '../../../../types/integration/stepResult' @@ -29,8 +30,13 @@ import { IntegrationServiceBase } from '../integrationServiceBase' import { sendNodeWorkerMessage } from '../../../utils/nodeWorkerSQS' import { NodeWorkerIntegrationProcessMessage } from '../../../../types/mq/nodeWorkerIntegrationProcessMessage' import { AddActivitiesSingle } from '../../types/messageTypes' -import { singleOrDefault } from '../../../../utils/arrays' import getThreads from '../../usecases/discord/getThreads' +import { DiscordWebsocketEvent, DiscordWebsocketPayload } from '../../../../types/webhooks' +import { getMember } from '../../usecases/discord/getMember' +import { getMessage } from '../../usecases/discord/getMessage' +import { createRedisClient } from '../../../../utils/redis' +import { RedisCache } from '../../../../utils/redis/redisCache' +import { getChannel } from '../../usecases/discord/getChannel' /* eslint class-methods-use-this: 0 */ @@ -41,23 +47,21 @@ export class DiscordIntegrationService extends IntegrationServiceBase { static readonly MAX_RETROSPECT = DISCORD_CONFIG.maxRetrospectInSeconds || 3600 - public token: string + public static token: string = `Bot ${DISCORD_CONFIG.token}` constructor() { - super(IntegrationType.DISCORD, 60) + super(IntegrationType.DISCORD, -1) this.globalLimit = DISCORD_CONFIG.globalLimit || 0 this.limitResetFrequencySeconds = (DISCORD_CONFIG.limitResetFrequencyDays || 0) * 24 * 60 * 60 - - this.token = `Bot ${DISCORD_CONFIG.token}` } - private getToken(context: IStepContext): string { + private static getToken(context: IStepContext): string { if (context.integration.token) { return `Bot ${context.integration.token}` } - return this.token + return DiscordIntegrationService.token } override async triggerIntegrationCheck(integrations: any[]): Promise { @@ -83,75 +87,54 @@ export class DiscordIntegrationService extends IntegrationServiceBase { } async preprocess(context: IStepContext): Promise { + const settingsChannels = context.integration.settings.channels || [] + + // merge forum channels and regular channels from settings + if (context.integration.settings.forumChannels) { + for (const forumChannel of context.integration.settings.forumChannels) { + settingsChannels.push({ + id: forumChannel.id, + name: forumChannel.name, + }) + } + + context.integration.settings.channels = settingsChannels + } + const guildId = context.integration.integrationIdentifier - const fromDiscordApi: ProcessedChannels = await getChannels( + const fromDiscordApi = await getChannels( { guildId, - token: this.getToken(context), + token: DiscordIntegrationService.getToken(context), }, - this.logger(context), + context.logger, ) - let channelsFromDiscordAPI: ProcessedChannel[] = fromDiscordApi.channels - - const channels = context.integration.settings.channels - ? context.integration.settings.channels - : [] - - const forumChannels = context.integration.settings.forumChannels - ? context.integration.settings.forumChannels - : [] - - // Add bool new property to new channels - channelsFromDiscordAPI = channelsFromDiscordAPI.map((c) => { - if (channels.filter((a) => a.id === c.id).length <= 0) { - return { ...c, new: true } - } - return c - }) + for (const channel of fromDiscordApi) { + await DiscordIntegrationService.cacheChannel(channel, context) + } const threads = await getThreads( { guildId, - token: this.getToken(context), + token: DiscordIntegrationService.getToken(context), }, - this.logger(context), + context.logger, ) - const forumChannelsFromDiscordAPi = [] - + // we are only interested in threads that are in a forum channel because the rest we will get normally when a message has thread property attached for (const thread of threads) { - const forumChannel: any = lodash.find(fromDiscordApi.forumChannels, { id: thread.parentId }) - if (forumChannel) { - forumChannelsFromDiscordAPi.push({ - ...forumChannel, - threadId: thread.id, - new: forumChannels.filter((c) => c.id === forumChannel.id).length <= 0, - threadName: thread.name, - }) + await DiscordIntegrationService.cacheChannel(thread, context) + const parentChannel = await DiscordIntegrationService.getChannel(thread.parent_id, context) + if (DiscordIntegrationService.isForum(parentChannel)) { + fromDiscordApi.push(thread) } } context.pipelineData = { - settingsChannels: channels, - channels: channelsFromDiscordAPI, - forumChannels: forumChannelsFromDiscordAPi, - channelsInfo: channelsFromDiscordAPI.reduce((acc, channel) => { - acc[channel.id] = { - name: channel.name, - new: !!channel.new, - } - return acc - }, {}), - forumChannelsInfo: forumChannelsFromDiscordAPi.reduce((acc, forumChannel) => { - acc[forumChannel.id] = { - name: forumChannel.name, - new: !!forumChannel.new, - } - return acc - }, {}), - guildId: context.integration.integrationIdentifier, + channels: fromDiscordApi, + guildId, } } @@ -160,6 +143,61 @@ export class DiscordIntegrationService extends IntegrationServiceBase { await service.createPredefined(DiscordMemberAttributes) } + async processWebhook(webhook: any, context: IStepContext): Promise { + const { event, data } = webhook.payload as DiscordWebsocketPayload + + let record: AddActivitiesSingle | undefined + + switch (event) { + case DiscordWebsocketEvent.MESSAGE_CREATED: { + record = await DiscordIntegrationService.parseWebhookMessage(data, context) + break + } + case DiscordWebsocketEvent.MESSAGE_UPDATED: { + record = await DiscordIntegrationService.parseWebhookMessage(data.message, context) + break + } + + case DiscordWebsocketEvent.MEMBER_ADDED: { + record = await DiscordIntegrationService.parseWebhookMember(data, context) + break + } + + case DiscordWebsocketEvent.MEMBER_UPDATED: { + record = await DiscordIntegrationService.parseWebhookMember(data.member, context) + break + } + + default: { + context.logger.error(`Unknown discord websocket event: ${event}!`) + throw new Error(`Unknown discord websocket event: ${event}!`) + } + } + + if (record === undefined) { + context.logger.warn( + { + event, + webhookId: context.webhook.id, + }, + 'No record created for event!', + ) + + return { + operations: [], + } + } + + return { + operations: [ + { + type: Operations.UPSERT_ACTIVITIES_WITH_MEMBERS, + records: [record], + }, + ], + } + } + async getStreams(context: IStepContext): Promise { const predefined: IIntegrationStream[] = [ { @@ -170,35 +208,21 @@ export class DiscordIntegrationService extends IntegrationServiceBase { }, ] - return predefined - .concat( - context.pipelineData.channels.map((c) => ({ - value: 'channel', - metadata: { - id: c.id, - page: '', - }, - })), - ) - .concat( - context.pipelineData.forumChannels.map((c) => ({ - value: 'forumChannel', - metadata: { - id: c.threadId, - page: '', - forumChannelId: c.id, - threadName: c.threadName, - }, - })), - ) + return predefined.concat( + context.pipelineData.channels.map((c) => ({ + value: 'channel', + metadata: { + id: c.id, + page: '', + }, + })), + ) } async processStream( stream: IIntegrationStream, context: IStepContext, ): Promise { - const logger = this.logger(context) - // sleep for 2 seconds for rate limit await timeout(2000) for ( @@ -214,11 +238,11 @@ export class DiscordIntegrationService extends IntegrationServiceBase { const { records, nextPage, limit, timeUntilReset } = await fn( { ...arg, - token: this.getToken(context), + token: DiscordIntegrationService.getToken(context), page: stream.metadata.page, perPage: 100, }, - logger, + context.logger, ) const nextPageStream = nextPage @@ -235,7 +259,7 @@ export class DiscordIntegrationService extends IntegrationServiceBase { } } - const { activities, newStreams } = this.parseActivities(stream, context, records) + const { activities, newStreams } = await this.parseActivities(stream, context, records) const lastRecord = activities.length > 0 ? activities[activities.length - 1] : undefined return { @@ -256,10 +280,10 @@ export class DiscordIntegrationService extends IntegrationServiceBase { ![504, 502, 500].includes(err.statusCode) || retryCount === DiscordIntegrationService.ENDPOINT_MAX_RETRY - 1 ) { - logger.error(err, `Error while processing a stream!`) + context.logger.error(err, `Error while processing a stream!`) throw err } else { - logger.error( + context.logger.error( err, `Error while processing a stream (retry #${retryCount + 1} out of ${ DiscordIntegrationService.ENDPOINT_MAX_RETRY @@ -291,7 +315,7 @@ export class DiscordIntegrationService extends IntegrationServiceBase { ) default: - if (context.pipelineData.channelsInfo[currentStream.metadata.id].new) return false + if (DiscordIntegrationService.isNew(currentStream.metadata.id, context)) return false return IntegrationServiceBase.isRetrospectOver( lastRecordTimestamp, @@ -306,35 +330,48 @@ export class DiscordIntegrationService extends IntegrationServiceBase { failedStreams?: IIntegrationStream[], remainingStreams?: IIntegrationStream[], ): Promise { - context.integration.settings.channels = context.pipelineData.channels.map((ch) => { - const { new: _, ...raw } = ch - return raw - }) - - context.integration.settings.forumChannels = lodash.uniqBy( - context.pipelineData.forumChannels.map((ch) => { - const { new: _, ...raw } = ch - delete raw.threadId - return raw - }), - (ch: any) => ch.id, - ) + context.integration.settings.channels = context.pipelineData.channels.map((c) => ({ + id: c.id, + name: c.name, + })) } - parseActivities( + async parseActivities( stream: IIntegrationStream, context: IStepContext, - records: DiscordMessages | DiscordMembers, - ): DiscordStreamProcessResult { + records: DiscordApiMessage[] | DiscordApiMember[], + ): Promise { switch (stream.value) { case 'members': - return this.parseMembers(context, records as DiscordMembers) + return DiscordIntegrationService.parseMembers(context, records as DiscordApiMember[]) default: - return this.parseMessages(context, records as DiscordMessages, stream) + return DiscordIntegrationService.parseMessages(context, records as DiscordApiMessage[]) + } + } + + public static async parseWebhookMember( + payload: any, + context: IStepContext, + ): Promise { + const discordMember = await getMember( + payload.guildId, + payload.userId, + DiscordIntegrationService.getToken(context), + context.logger, + ) + + if (!discordMember.user.bot) { + const results = await DiscordIntegrationService.parseMembers(context, [discordMember]) + if (results.activities.length > 0) return results.activities[0] } + + return undefined } - parseMembers(context: IStepContext, records: Array): DiscordStreamProcessResult { + public static async parseMembers( + context: IStepContext, + records: DiscordApiMember[], + ): Promise { // We only need the members if they are not bots const activities: AddActivitiesSingle[] = records.reduce((acc, record) => { if (!record.user.bot) { @@ -379,64 +416,76 @@ export class DiscordIntegrationService extends IntegrationServiceBase { } } - parseMessages( + public static async parseWebhookMessage( + payload: any, context: IStepContext, - records: DiscordMessages, - stream: IIntegrationStream, - ): DiscordStreamProcessResult { - const newStreams: IIntegrationStream[] = [] - const activities: AddActivitiesSingle[] = records.reduce((acc, record) => { - let parent = '' + ): Promise { + const message = await getMessage( + payload.channelId, + payload.id, + DiscordIntegrationService.getToken(context), + context.logger, + ) - const isForum = stream.metadata.forumChannelId !== undefined + const results = await DiscordIntegrationService.parseMessages(context, [message]) - let channelInfo = context.pipelineData.channelsInfo[stream.metadata.id] - if (isForum) { - channelInfo = context.pipelineData.forumChannelsInfo[stream.metadata.forumChannelId] - } + if (results.activities.length > 0) return results.activities[0] - if (!channelInfo) { - const log = this.logger(context) - log.error( - { - stream: stream.value, - streamMetadata: stream.metadata, - channelsInfo: context.pipelineData.channelsInfo, - }, - 'Channel info not found for stream!', - ) - throw new Error('Channel info not found for stream!') - } + return undefined + } - // is the message starting a thread? + public static async parseMessages( + context: IStepContext, + records: DiscordApiMessage[], + ): Promise { + const newStreams: IIntegrationStream[] = [] + const activities: AddActivitiesSingle[] = [] + + for (const record of records) { + let parent: string | undefined + let parentChannel: string | undefined + + let firstThreadMessage = false + // is the message starting a thread? if so we should get thread messages as well if (record.thread) { - parent = record.thread.id newStreams.push({ - value: 'thread', + value: 'channel', metadata: { id: record.thread.id, - forumChannelId: stream.metadata.forumChannelId, }, }) - context.pipelineData.channelsInfo[record.thread.id] = { - name: context.pipelineData.channelsInfo[record.channel_id].name, - new: - singleOrDefault( - context.pipelineData.settingsChannels, - (c) => c.id === record.thread.id, - ) === undefined, - } + firstThreadMessage = true + await DiscordIntegrationService.cacheChannel(record.thread as DiscordApiChannel, context) + } + + if (record.id === record.channel_id) { + firstThreadMessage = true } + + const channel = await DiscordIntegrationService.getChannel(record.channel_id, context) + + let isForum = false + const isThread = DiscordIntegrationService.isThread(channel) + // if we're parsing a thread, mark each message as a child of this thread - else if (stream.value === 'thread') { - parent = stream.metadata.id + if (isThread || isForum) { + if (!firstThreadMessage) { + parent = channel.id + } + + if (channel.parent_id) { + const parentChannelObj = await DiscordIntegrationService.getChannel( + channel.parent_id, + context, + ) + parentChannel = parentChannelObj.name + isForum = DiscordIntegrationService.isForum(parentChannelObj) + } } // record.parentId means that it's a reply else if (record.message_reference && record.message_reference.message_id) { parent = record.message_reference.message_id - } else if (stream.value === 'forumChannel') { - parent = stream.metadata.id } let avatarUrl: string | boolean = false @@ -444,7 +493,7 @@ export class DiscordIntegrationService extends IntegrationServiceBase { avatarUrl = `https://cdn.discordapp.com/avatars/${record.author.id}/${record.author.avatar}.png` } - if (!record.author.bot) { + if (!record.author.bot && [MessageType.Default, MessageType.Reply].includes(record.type)) { const activityObject = { tenant: context.integration.tenantId, platform: PlatformType.DISCORD, @@ -452,18 +501,15 @@ export class DiscordIntegrationService extends IntegrationServiceBase { sourceId: record.id, sourceParentId: parent, timestamp: moment(record.timestamp).utc().toDate(), - ...(stream.value === 'forumChannel' && - record.id === parent && { title: stream.metadata.threadName }), + title: isThread || isForum ? channel.name : undefined, body: record.content ? DiscordIntegrationService.replaceMentions(record.content, record.mentions) : '', - url: `https://discordapp.com/channels/${context.pipelineData.guildId}/${stream.metadata.id}/${record.id}`, - channel: channelInfo.name, + url: `https://discordapp.com/channels/${context.pipelineData.guildId}/${channel.id}/${record.id}`, + channel: channel.name, attributes: { - thread: - record.thread !== undefined || - stream.value === 'thread' || - stream.value === 'forumChannel', + parentChannel, + thread: isThread, reactions: record.reactions ? record.reactions : [], attachments: record.attachments ? record.attachments : [], forum: isForum, @@ -485,10 +531,9 @@ export class DiscordIntegrationService extends IntegrationServiceBase { isKeyAction: DiscordGrid.message.isKeyAction, } as any - acc.push(activityObject) + activities.push(activityObject) } - return acc - }, []) + } return { activities, @@ -502,7 +547,7 @@ export class DiscordIntegrationService extends IntegrationServiceBase { * @param mentions * @returns Message text, swapping mention IDs by mentions */ - private static replaceMentions(text: string, mentions: [DiscordMention] | undefined): string { + private static replaceMentions(text: string, mentions: DiscordApiUser[] | undefined): string { if (mentions === undefined) return text // Replace <@!123456789> by @username @@ -536,11 +581,60 @@ export class DiscordIntegrationService extends IntegrationServiceBase { case 'members': return { fn: getMembers, arg: { guildId } } case 'channel': - case 'thread': - case 'forumChannel': return { fn: getMessages, arg: { channelId: stream.metadata.id } } default: throw new Error(`Unknown stream ${stream.value}!`) } } + + private static async cacheChannel( + channel: DiscordApiChannel, + context: IStepContext, + ): Promise { + if (!context.pipelineData.channelCache) { + const redis = await createRedisClient(true) + context.pipelineData.channelCache = new RedisCache('discord-channels', redis) + } + + const cache = context.pipelineData.channelCache as RedisCache + + await cache.setValue(channel.id, JSON.stringify(channel), 24 * 60 * 60) + } + + private static async getChannel(id: string, context: IStepContext): Promise { + if (!context.pipelineData.channelCache) { + const redis = await createRedisClient(true) + context.pipelineData.channelCache = new RedisCache('discord-channels', redis) + } + + const cache = context.pipelineData.channelCache as RedisCache + + const cached = await cache.getValue(id) + + if (cached) { + return JSON.parse(cached) + } + + const channel = await getChannel( + id, + DiscordIntegrationService.getToken(context), + context.logger, + ) + await cache.setValue(id, JSON.stringify(channel), 24 * 60 * 60) + + return channel + } + + private static isForum(channel: DiscordApiChannel): boolean { + return channel.type === ChannelType.GuildForum + } + + private static isThread(channel: DiscordApiChannel): boolean { + return channel.type === ChannelType.PublicThread || channel.type === ChannelType.PrivateThread + } + + private static isNew(channelId: string, context: IStepContext): boolean { + const settingsChannel = context.integration.settings.channels || [] + return settingsChannel.find((c) => c.id === channelId) === undefined + } } diff --git a/backend/src/serverless/integrations/services/integrations/githubIntegrationService.ts b/backend/src/serverless/integrations/services/integrations/githubIntegrationService.ts index 2db21e7066..61fe4bbf69 100644 --- a/backend/src/serverless/integrations/services/integrations/githubIntegrationService.ts +++ b/backend/src/serverless/integrations/services/integrations/githubIntegrationService.ts @@ -1,10 +1,12 @@ import moment from 'moment/moment' import { createAppAuth } from '@octokit/auth-app' +import verifyGithubWebhook from 'verify-github-webhook' import { Repo, Repos } from '../../types/regularTypes' import { IntegrationType, PlatformType } from '../../../../types/integrationEnums' import { IIntegrationStream, IProcessStreamResults, + IProcessWebhookResults, IStepContext, } from '../../../../types/integration/stepResult' import MemberAttributeSettingsService from '../../../../services/memberAttributeSettingsService' @@ -32,6 +34,7 @@ import { AppTokenResponse, getAppToken } from '../../usecases/github/rest/getApp import getMember from '../../usecases/github/graphql/members' import { createRedisClient } from '../../../../utils/redis' import { RedisCache } from '../../../../utils/redis/redisCache' +import { gridEntry } from '../../grid/grid' /* eslint class-methods-use-this: 0 */ @@ -82,8 +85,6 @@ export class GithubIntegrationService extends IntegrationServiceBase { } async preprocess(context: IStepContext): Promise { - const log = this.logger(context) - const redis = await createRedisClient(true) const emailCache = new RedisCache('github-emails', redis) @@ -105,7 +106,7 @@ export class GithubIntegrationService extends IntegrationServiceBase { if (e.rateLimitResetSeconds) { throw e } else { - log.warn( + context.logger.warn( `Repo ${repo.name} will not be parsed. It is not available with the github token`, ) unavailableRepos.push(repo) @@ -286,6 +287,95 @@ export class GithubIntegrationService extends IntegrationServiceBase { } } + async processWebhook(webhook: any, context: IStepContext): Promise { + let record: AddActivitiesSingle | undefined + + await GithubIntegrationService.verifyWebhookSignature( + webhook.payload.signature, + webhook.payload.data, + ) + + const event = webhook.payload.event + const payload = webhook.payload.data + + switch (event) { + case 'issues': { + record = await GithubIntegrationService.parseWebhookIssue(payload, context) + break + } + + case 'discussion': { + record = await GithubIntegrationService.parseWebhookDiscussion(payload, context) + break + } + + case 'pull_request': { + record = await GithubIntegrationService.parseWebhookPullRequest(payload, context) + break + } + + case 'star': { + record = await GithubIntegrationService.parseWebhookStar(payload, context) + break + } + + case 'fork': { + record = await GithubIntegrationService.parseWebhookFork(payload, context) + break + } + + case 'discussion_comment': + case 'issue_comment': { + record = await GithubIntegrationService.parseWebhookComment(event, payload, context) + break + } + + default: + } + + if (record === undefined) { + context.logger.warn( + { + event, + action: payload.action, + }, + 'No record created for event!', + ) + + return { + operations: [], + } + } + + return { + operations: [ + { + type: Operations.UPSERT_ACTIVITIES_WITH_MEMBERS, + records: [record], + }, + ], + } + } + + private static verifyWebhookSignature(signature: string, data: any): void { + if (IS_TEST_ENV) { + return + } + + const secret = GITHUB_CONFIG.webhookSecret + + let isVerified: boolean + try { + isVerified = verifyGithubWebhook(signature, JSON.stringify(data), secret) // Returns true if verification succeeds; otherwise, false. + } catch (err) { + throw new Error(`Webhook not verified\n${err}`) + } + + if (!isVerified) { + throw new Error('Webhook not verified') + } + } + /** * Parses various activity types into crowd activities. * @param records List of activities to be parsed @@ -334,6 +424,57 @@ export class GithubIntegrationService extends IntegrationServiceBase { return activities } + public static async parseWebhookStar( + payload: any, + context: IStepContext, + ): Promise { + let type: GithubActivityType + switch (payload.action) { + case 'created': { + type = GithubActivityType.STAR + break + } + + case 'deleted': { + type = GithubActivityType.UNSTAR + break + } + + default: { + return undefined + } + } + const member = await GithubIntegrationService.parseWebhookMember( + payload.sender.login, + context.integration.token, + ) + + if (member) { + const starredAt = + type === GithubActivityType.STAR ? moment(payload.starred_at).utc() : moment().utc() + + return { + member, + type, + timestamp: starredAt.toDate(), + platform: PlatformType.GITHUB, + tenant: context.integration.tenantId, + sourceId: IntegrationServiceBase.generateSourceIdHash( + payload.sender.login, + type, + starredAt.unix().toString(), + PlatformType.GITHUB, + ), + sourceParentId: null, + channel: payload.repository.html_url, + score: type === 'star' ? GitHubGrid.star.score : GitHubGrid.unStar.score, + isKeyAction: GitHubGrid.star.isKeyAction, + } + } + + return undefined + } + private static async parseStars( records: any[], repo: Repo, @@ -362,6 +503,32 @@ export class GithubIntegrationService extends IntegrationServiceBase { return out } + public static async parseWebhookFork( + payload: any, + context: IStepContext, + ): Promise { + const member: Member = await GithubIntegrationService.parseWebhookMember( + payload.sender.login, + context.integration.token, + ) + + if (member) { + return { + member, + type: GithubActivityType.FORK, + timestamp: moment(payload.forkee.created_at).utc().toDate(), + platform: PlatformType.GITHUB, + tenant: context.integration.tenantId, + sourceId: payload.forkee.node_id.toString(), + sourceParentId: null, + channel: payload.repository.html_url, + score: GitHubGrid.fork.score, + isKeyAction: GitHubGrid.fork.isKeyAction, + } + } + return undefined + } + private static async parseForks( records: any[], repo: Repo, @@ -387,6 +554,63 @@ export class GithubIntegrationService extends IntegrationServiceBase { return out } + public static async parseWebhookPullRequest( + payload: any, + context: IStepContext, + ): Promise { + let type: GithubActivityType + let scoreGrid: gridEntry + let timestamp: string + + switch (payload.action) { + case 'edited': + case 'opened': + case 'reopened': { + type = GithubActivityType.PULL_REQUEST_OPENED + scoreGrid = GitHubGrid.pullRequestOpened + timestamp = payload.pull_request.created_at + break + } + + case 'closed': { + type = GithubActivityType.PULL_REQUEST_CLOSED + scoreGrid = GitHubGrid.pullRequestClosed + timestamp = payload.pull_request.closed_at + break + } + + default: { + return undefined + } + } + + const pull = payload.pull_request + const member = await GithubIntegrationService.parseWebhookMember( + pull.user.login, + context.integration.token, + ) + + if (member) { + return { + member, + type, + timestamp: moment(timestamp).utc().toDate(), + platform: PlatformType.GITHUB, + tenant: context.integration.tenantId, + sourceId: pull.node_id.toString(), + sourceParentId: null, + url: pull.html_url, + title: pull.title, + channel: payload.repository.html_url, + body: pull.body, + score: scoreGrid.score, + isKeyAction: scoreGrid.isKeyAction, + } + } + + return undefined + } + private static async parsePullRequests( records: any[], repo: Repo, @@ -418,6 +642,77 @@ export class GithubIntegrationService extends IntegrationServiceBase { return out } + public static async parseWebhookComment( + event: string, + payload: any, + context: IStepContext, + ): Promise { + let type: GithubActivityType + let sourceParentId: string | undefined + + switch (event) { + case 'discussion_comment': { + switch (payload.action) { + case 'created': + case 'edited': + type = GithubActivityType.DISCUSSION_COMMENT + sourceParentId = payload.discussion.node_id.toString() + break + default: + return undefined + } + break + } + + case 'issue_comment': { + switch (payload.action) { + case 'created': + case 'edited': { + if ('pull_request' in payload.issue) { + type = GithubActivityType.PULL_REQUEST_COMMENT + } else { + type = GithubActivityType.ISSUE_COMMENT + } + sourceParentId = payload.issue.node_id.toString() + break + } + + default: + return undefined + } + break + } + + default: { + return undefined + } + } + + const member = await GithubIntegrationService.parseWebhookMember( + payload.sender.login, + context.integration.token, + ) + if (member) { + const comment = payload.comment + return { + member, + type, + timestamp: moment(comment.created_at).utc().toDate(), + platform: PlatformType.GITHUB, + tenant: context.integration.tenantId, + sourceId: comment.node_id.toString(), + sourceParentId, + url: comment.html_url, + body: comment.body, + channel: payload.repository.html_url, + score: GitHubGrid.comment.score, + isKeyAction: GitHubGrid.comment.isKeyAction, + } + } + + return undefined + } + private static async parsePullRequestComments( records: any[], repo: Repo, @@ -443,6 +738,60 @@ export class GithubIntegrationService extends IntegrationServiceBase { return out } + public static async parseWebhookIssue( + payload: any, + context: IStepContext, + ): Promise { + let type: GithubActivityType + let scoreGrid: gridEntry + let timestamp: string + + switch (payload.action) { + case 'edited': + case 'opened': + case 'reopened': + type = GithubActivityType.ISSUE_OPENED + scoreGrid = GitHubGrid.issueOpened + timestamp = payload.issue.created_at + break + + case 'closed': + type = GithubActivityType.ISSUE_CLOSED + scoreGrid = GitHubGrid.issueClosed + timestamp = payload.issue.closed_at + break + + default: + return undefined + } + + const issue = payload.issue + const member = await GithubIntegrationService.parseWebhookMember(issue.user.login, context) + + if (member) { + return { + member, + type, + timestamp: moment(timestamp).utc().toDate(), + platform: PlatformType.GITHUB, + tenant: context.integration.tenantId, + sourceId: issue.node_id.toString(), + sourceParentId: null, + url: issue.html_url, + title: issue.title, + channel: payload.repository.html_url, + body: issue.body, + attributes: { + state: issue.state, + }, + score: scoreGrid.score, + isKeyAction: scoreGrid.isKeyAction, + } + } + + return undefined + } + private static async parseIssues( records: any[], repo: Repo, @@ -499,6 +848,52 @@ export class GithubIntegrationService extends IntegrationServiceBase { return out } + public static async parseWebhookDiscussion( + payload: any, + context: IStepContext, + ): Promise { + if (payload.action === 'answered') { + return this.parseWebhookDiscussionComments(payload, context) + } + + if (!['edited', 'created'].includes(payload.action)) { + return undefined + } + + const discussion = payload.discussion + const member = await GithubIntegrationService.parseWebhookMember(discussion.user.login, context) + + if (member) { + return { + member, + type: GithubActivityType.DISCUSSION_STARTED, + timestamp: moment(discussion.created_at).utc().toDate(), + platform: PlatformType.GITHUB, + tenant: context.integration.tenantId, + sourceId: discussion.node_id.toString(), + sourceParentId: null, + url: discussion.html_url, + title: discussion.title, + channel: payload.repository.html_url, + body: discussion.body, + attributes: { + category: { + id: discussion.category.node_id, + isAnswerable: discussion.category.is_answerable, + name: discussion.category.name, + slug: discussion.category.slug, + emoji: discussion.category.emoji, + description: discussion.category.description, + }, + }, + score: GitHubGrid.discussionOpened.score, + isKeyAction: GitHubGrid.discussionOpened.isKeyAction, + } + } + + return undefined + } + private static async parseDiscussions( records: any[], repo: Repo, @@ -536,6 +931,39 @@ export class GithubIntegrationService extends IntegrationServiceBase { return out } + private static async parseWebhookDiscussionComments( + payload: any, + context: IStepContext, + ): Promise { + const member: Member = await this.parseWebhookMember( + payload.sender.login, + context.integration.token, + ) + + if (member) { + const answer = payload.answer + return { + member, + type: GithubActivityType.DISCUSSION_COMMENT, + timestamp: moment(answer.created_at).utc().toDate(), + platform: PlatformType.GITHUB, + tenant: context.integration.tenantId, + sourceId: answer.node_id.toString(), + sourceParentId: payload.discussion.node_id.toString(), + attributes: { + isSelectedAnswer: true, + }, + channel: payload.repository.html_url, + body: answer.body, + url: answer.html_url, + score: GitHubGrid.selectedAnswer.score, + isKeyAction: GitHubGrid.selectedAnswer.isKeyAction, + } + } + + return undefined + } + private static async parseDiscussionComments( records: any[], repo: Repo, @@ -622,6 +1050,10 @@ export class GithubIntegrationService extends IntegrationServiceBase { } private static async getMemberEmail(context: IStepContext, login: string): Promise { + if (IS_TEST_ENV) { + return '' + } + const cache: RedisCache = context.pipelineData.emailCache const existing = await cache.getValue(login) @@ -644,7 +1076,27 @@ export class GithubIntegrationService extends IntegrationServiceBase { return '' } - private static async parseMember(memberFromApi: any, context: IStepContext): Promise { + private static async parseWebhookMember( + login: string, + context: IStepContext, + ): Promise { + if (IS_TEST_ENV) { + return { + username: { + [PlatformType.GITHUB]: 'testMember', + }, + } + } + + const member = await getMember(login, context.integration.token) + if (member) { + return GithubIntegrationService.parseMember(member, context) + } + + return undefined + } + + public static async parseMember(memberFromApi: any, context: IStepContext): Promise { const email = await this.getMemberEmail(context, memberFromApi.login) const member: Member = { @@ -670,6 +1122,12 @@ export class GithubIntegrationService extends IntegrationServiceBase { email, } + if (memberFromApi.websiteUrl) { + member.attributes[MemberAttributeName.WEBSITE_URL] = { + [PlatformType.GITHUB]: memberFromApi.websiteUrl, + } + } + if (memberFromApi.company) { if (IS_TEST_ENV) { member.organizations = [{ name: 'crowd.dev' }] @@ -705,7 +1163,7 @@ export class GithubIntegrationService extends IntegrationServiceBase { member.username[PlatformType.TWITTER] = memberFromApi.twitterUsername } - if (memberFromApi.followers.totalCount > 0) { + if (memberFromApi.followers && memberFromApi.followers.totalCount > 0) { member.reach = { [PlatformType.GITHUB]: memberFromApi.followers.totalCount } } diff --git a/backend/src/serverless/integrations/services/integrations/hackerNewsIntegrationService.ts b/backend/src/serverless/integrations/services/integrations/hackerNewsIntegrationService.ts index 254125c88e..486683a1bf 100644 --- a/backend/src/serverless/integrations/services/integrations/hackerNewsIntegrationService.ts +++ b/backend/src/serverless/integrations/services/integrations/hackerNewsIntegrationService.ts @@ -42,14 +42,14 @@ export class HackerNewsIntegrationService extends IntegrationServiceBase { const settings = context.integration.settings as HackerNewsIntegrationSettings const keywords = Array.from(new Set([...settings.keywords, ...settings.urls])) - this.logger(context).info(`Fetching posts for keywords: ${keywords}`) + context.logger.info(`Fetching posts for keywords: ${keywords}`) const posts = await getPostsByKeywords( { keywords, after: context.onboarding ? 0 : moment().subtract(30, 'days').unix(), }, context.serviceContext, - this.logger(context), + context.logger, ) context.pipelineData = { @@ -71,10 +71,9 @@ export class HackerNewsIntegrationService extends IntegrationServiceBase { stream: IIntegrationStream, context: IStepContext, ): Promise { - const logger = this.logger(context) let newStreams: IIntegrationStream[] - const post: HackerNewsResponse = await getPost(stream.value, logger) + const post: HackerNewsResponse = await getPost(stream.value, context.logger) if (post.kids !== undefined) { newStreams = post.kids.map((a: number) => ({ diff --git a/backend/src/serverless/integrations/services/integrations/premium/linkedinIntegrationService.ts b/backend/src/serverless/integrations/services/integrations/premium/linkedinIntegrationService.ts index 523dbd07b5..01d6acde59 100644 --- a/backend/src/serverless/integrations/services/integrations/premium/linkedinIntegrationService.ts +++ b/backend/src/serverless/integrations/services/integrations/premium/linkedinIntegrationService.ts @@ -44,8 +44,7 @@ export class LinkedinIntegrationService extends IntegrationServiceBase { } async preprocess(context: IStepContext): Promise { - const log = this.logger(context) - log.info('Preprocessing!') + context.logger.info('Preprocessing!') const redis = await createRedisClient(true) const membersCache = new RedisCache('linkedin-members', redis) @@ -61,7 +60,7 @@ export class LinkedinIntegrationService extends IntegrationServiceBase { const pizzlyId = `${context.integration.tenantId}-${PlatformType.LINKEDIN}` if (organization.profilePictureUrl === undefined) { - const org = await getOrganization(pizzlyId, organization.id.toString(), log) + const org = await getOrganization(pizzlyId, organization.id.toString(), context.logger) context.integration.settings.organizations = [ ...context.integration.settings.organizations.filter((o) => o.id !== organization.id), { @@ -71,7 +70,11 @@ export class LinkedinIntegrationService extends IntegrationServiceBase { ] } - const posts = await getAllOrganizationPosts(pizzlyId, organization.organizationUrn, log) + const posts = await getAllOrganizationPosts( + pizzlyId, + organization.organizationUrn, + context.logger, + ) let cachedData = context.integration.settings.posts || [] if (cachedData.length === 0) { @@ -124,8 +127,7 @@ export class LinkedinIntegrationService extends IntegrationServiceBase { stream: IIntegrationStream, context: IStepContext, ): Promise { - const log = this.logger(context) - log.debug({ stream: stream.value, metadata: stream.metadata }, 'Processing stream!') + context.logger.debug({ stream: stream.value, metadata: stream.metadata }, 'Processing stream!') switch (stream.value) { case 'post_comments': @@ -146,12 +148,10 @@ export class LinkedinIntegrationService extends IntegrationServiceBase { stream: IIntegrationStream, context: IStepContext, ): Promise { - const log = this.logger(context) - const comments = await getAllCommentComments( context.pipelineData.pizzlyId, stream.metadata.urnId, - log, + context.logger, ) const activities: AddActivitiesSingle[] = [] @@ -215,8 +215,6 @@ export class LinkedinIntegrationService extends IntegrationServiceBase { stream: IIntegrationStream, context: IStepContext, ): Promise { - const log = this.logger(context) - let lastReactionTs: number | undefined const cachedPost = context.integration.settings.posts.find( (p) => p.id === stream.metadata.urnId, @@ -231,7 +229,7 @@ export class LinkedinIntegrationService extends IntegrationServiceBase { const reactions = await getAllPostReactions( context.pipelineData.pizzlyId, stream.metadata.urnId, - log, + context.logger, lastReactionTs, ) @@ -293,8 +291,6 @@ export class LinkedinIntegrationService extends IntegrationServiceBase { stream: IIntegrationStream, context: IStepContext, ): Promise { - const log = this.logger(context) - let lastCommentTs: number | undefined const cachedPost = context.integration.settings.posts.find( (p) => p.id === stream.metadata.urnId, @@ -316,7 +312,7 @@ export class LinkedinIntegrationService extends IntegrationServiceBase { const comments = await getAllPostComments( context.pipelineData.pizzlyId, stream.metadata.urnId, - log, + context.logger, lastCommentTs, ) @@ -389,8 +385,6 @@ export class LinkedinIntegrationService extends IntegrationServiceBase { } private async parseMember(memberUrn: string, context: IStepContext): Promise { - const log = this.logger(context) - const member: Member = { username: { [PlatformType.LINKEDIN]: '', @@ -416,7 +410,7 @@ export class LinkedinIntegrationService extends IntegrationServiceBase { const userString = await membersCache.getOrAdd( userId, async () => { - const user = await getMember(context.pipelineData.pizzlyId, userId, log) + const user = await getMember(context.pipelineData.pizzlyId, userId, context.logger) return JSON.stringify(user) }, 24 * 60 * 60, @@ -449,7 +443,11 @@ export class LinkedinIntegrationService extends IntegrationServiceBase { const organizationString = await membersCache.getOrAdd( userId, async () => { - const organization = await getOrganization(context.pipelineData.pizzlyId, userId, log) + const organization = await getOrganization( + context.pipelineData.pizzlyId, + userId, + context.logger, + ) return JSON.stringify(organization) }, 24 * 60 * 60, diff --git a/backend/src/serverless/integrations/services/integrations/redditIntegrationService.ts b/backend/src/serverless/integrations/services/integrations/redditIntegrationService.ts index 25fb1bb4a6..902883739c 100644 --- a/backend/src/serverless/integrations/services/integrations/redditIntegrationService.ts +++ b/backend/src/serverless/integrations/services/integrations/redditIntegrationService.ts @@ -81,16 +81,15 @@ export class RedditIntegrationService extends IntegrationServiceBase { stream: IIntegrationStream, context: IStepContext, ): Promise { - const logger: Logger = this.logger(context) let newStreams: IIntegrationStream[] switch (stream.value.split(':')[0]) { case 'subreddit': - return this.subRedditStream(stream, context, logger) + return this.subRedditStream(stream, context) case 'comments': - return this.commentsStream(stream, context, logger) + return this.commentsStream(stream, context) default: - return this.moreCommentsStream(stream, context, logger) + return this.moreCommentsStream(stream, context) } } @@ -100,18 +99,19 @@ export class RedditIntegrationService extends IntegrationServiceBase { * For each post, it will create a new stream to fetch its comments. * @param stream the full stream information * @param context context passed along worker messages - * @param logger a logger instance for structured logging * @returns the processed stream results */ async subRedditStream( stream: IIntegrationStream, context: IStepContext, - logger: Logger, ): Promise { const subreddit = stream.value.split(':')[1] const pizzlyId = context.pipelineData.pizzlyId const after = stream.metadata.after - const response: RedditPostsResponse = await getPosts({ subreddit, pizzlyId, after }, logger) + const response: RedditPostsResponse = await getPosts( + { subreddit, pizzlyId, after }, + context.logger, + ) const posts = response.data.children @@ -169,13 +169,11 @@ export class RedditIntegrationService extends IntegrationServiceBase { * It will create new streams for the tree expansions that the API returns * @param stream the full stream information * @param context context passed along worker messages - * @param logger a logger instance for structured logging * @returns the processed stream results */ async commentsStream( stream: IIntegrationStream, context: IStepContext, - logger: Logger, ): Promise { const subreddit = stream.metadata.channel const postId = stream.value.split(':')[1] @@ -183,7 +181,7 @@ export class RedditIntegrationService extends IntegrationServiceBase { const response: RedditCommentsResponse = await getComments( { subreddit, pizzlyId, postId }, - logger, + context.logger, ) const comments = response[1].data.children @@ -199,7 +197,7 @@ export class RedditIntegrationService extends IntegrationServiceBase { postId, stream, context, - logger, + context.logger, ) activities = activities.concat(commentOut.activities) newStreams = newStreams.concat(commentOut.newStreams) @@ -233,13 +231,11 @@ export class RedditIntegrationService extends IntegrationServiceBase { * Process a stream of type morecomments. It will expand the comments that are left to expand from the comment tree. * @param stream the full stream information * @param context context passed along worker messages - * @param logger a logger instance for structured logging * @returns the processed stream results */ async moreCommentsStream( stream: IIntegrationStream, context: IStepContext, - logger: Logger, ): Promise { const postId = stream.metadata.postId const sourceParentId = stream.metadata.sourceParentId @@ -248,7 +244,7 @@ export class RedditIntegrationService extends IntegrationServiceBase { const response: RedditMoreCommentsResponse = await getMoreComments( { postId, pizzlyId, children }, - logger, + context.logger, ) const comments = response.json.data.things @@ -264,7 +260,7 @@ export class RedditIntegrationService extends IntegrationServiceBase { sourceParentId, stream, context, - logger, + context.logger, ) activities = activities.concat(commentOut.activities) newStreams = newStreams.concat(commentOut.newStreams) diff --git a/backend/src/serverless/integrations/services/integrations/slackIntegrationService.ts b/backend/src/serverless/integrations/services/integrations/slackIntegrationService.ts index 5a875919dc..36896a4bc1 100644 --- a/backend/src/serverless/integrations/services/integrations/slackIntegrationService.ts +++ b/backend/src/serverless/integrations/services/integrations/slackIntegrationService.ts @@ -43,7 +43,7 @@ export class SlackIntegrationService extends IntegrationServiceBase { async preprocess(context: IStepContext): Promise { let channelsFromSlackAPI = await getChannels( { token: context.integration.token }, - this.logger(context), + context.logger, ) const channels = context.integration.settings.channels @@ -57,7 +57,7 @@ export class SlackIntegrationService extends IntegrationServiceBase { return c }) - const team = await getTeam({ token: context.integration.token }, this.logger(context)) + const team = await getTeam({ token: context.integration.token }, context.logger) const teamUrl = team.url const members = context.integration.settings.members ? context.integration.settings.members : {} @@ -105,7 +105,7 @@ export class SlackIntegrationService extends IntegrationServiceBase { page: stream.metadata.page, perPage: 200, }, - this.logger(context), + context.logger, ) const nextPageStream: IIntegrationStream = nextPage @@ -202,7 +202,7 @@ export class SlackIntegrationService extends IntegrationServiceBase { } const memberResponse = await getMember( { token: context.integration.token, userId }, - this.logger(context), + context.logger, ) const record = memberResponse.records const member = { @@ -237,7 +237,7 @@ export class SlackIntegrationService extends IntegrationServiceBase { context, } } catch (e) { - this.logger(context).error('Error getting member in Slack', { userId }) + context.logger.error('Error getting member in Slack', { userId }) throw e } } diff --git a/backend/src/serverless/integrations/services/integrations/twitterIntegrationService.ts b/backend/src/serverless/integrations/services/integrations/twitterIntegrationService.ts index 2664b8f80d..ea1d1b9b89 100644 --- a/backend/src/serverless/integrations/services/integrations/twitterIntegrationService.ts +++ b/backend/src/serverless/integrations/services/integrations/twitterIntegrationService.ts @@ -61,8 +61,6 @@ export class TwitterIntegrationService extends IntegrationServiceBase { stream: IIntegrationStream, context: IStepContext, ): Promise { - const log = this.logger(context) - const { fn, arg } = TwitterIntegrationService.getUsecase( stream.value, context.pipelineData.profileId, @@ -79,7 +77,7 @@ export class TwitterIntegrationService extends IntegrationServiceBase { perPage: 100, ...arg, }, - this.logger(context), + context.logger, ) const nextPageStream = nextPage @@ -88,7 +86,7 @@ export class TwitterIntegrationService extends IntegrationServiceBase { const sleep = limit <= 1 ? timeUntilReset : undefined if (records === undefined) { - log.error( + context.logger.error( { stream: stream.value, page: stream.metadata.page, diff --git a/backend/src/serverless/integrations/services/integrations/twitterReachIntegrationService.ts b/backend/src/serverless/integrations/services/integrations/twitterReachIntegrationService.ts index 2afeb7404d..2b54bb2cbc 100644 --- a/backend/src/serverless/integrations/services/integrations/twitterReachIntegrationService.ts +++ b/backend/src/serverless/integrations/services/integrations/twitterReachIntegrationService.ts @@ -72,7 +72,7 @@ export class TwitterReachIntegrationService extends IntegrationServiceBase { usernames: members, token: context.integration.token, }, - this.logger(context), + context.logger, ) const nextPageStream = nextPage diff --git a/backend/src/serverless/integrations/types/discordTypes.ts b/backend/src/serverless/integrations/types/discordTypes.ts index 90ecc2c853..622a49682e 100644 --- a/backend/src/serverless/integrations/types/discordTypes.ts +++ b/backend/src/serverless/integrations/types/discordTypes.ts @@ -21,91 +21,120 @@ export interface DiscordGetMembersInput { perPage: number | 100 } -export interface DiscordChannel { - parentId?: string - id: string - name: string - thread?: boolean - type?: number +export interface DiscordStreamProcessResult { + activities: AddActivitiesSingle[] + newStreams: IIntegrationStream[] } -export type DiscordChannels = DiscordChannel[] - -export interface DiscordChannelsOut { - channels: DiscordChannels - forumChannels: DiscordChannels +export interface DiscordParsedReponse { + records: any + nextPage: string + limit: number + timeUntilReset: number } -export interface DiscordAuthor { - id: string - username: string - avatar: string | null - bot?: boolean +export interface DiscordGetMessagesOutput extends DiscordParsedReponse { + records: DiscordApiMessage[] } -export interface DiscordMention { - id: string - username: string +export interface DiscordGetMembersOutput extends DiscordParsedReponse { + records: DiscordApiMember[] } -export interface DiscordMessage { +export interface DiscordApiChannel { id: string type: number - content: string - channel_id: string - author: DiscordAuthor - attachments?: any - reactions?: any - timestamp: string - mentions?: [DiscordMention] - message_reference: { - message_id: string - guild_id: string - channel_id: string - } - thread: { - id: string - } -} - -export type DiscordMessages = DiscordMessage[] - -export interface DiscordStreamProcessResult { - activities: AddActivitiesSingle[] - newStreams: IIntegrationStream[] + guild_id?: string + name?: string + topic?: string + nsfw?: boolean + last_message_id?: string + parent_id?: string + flags?: number } -export interface DiscordMember { - user: DiscordAuthor - joined_at: string +export interface DiscordApiChannelMention { id: string + guild_id: string + type: number + name: string } -export type DiscordMembers = DiscordMember[] +export interface DiscordApiMessageReference { + message_id?: string + channel_id?: string + guild_id?: string + fail_if_not_exists?: boolean +} -export interface DiscordParsedReponse { - records: any - nextPage: string - limit: number - timeUntilReset: number +export interface DiscordApiReaction { + count: number + me: boolean + emoji: any } -export interface DiscordGetMessagesOutput extends DiscordParsedReponse { - records: DiscordMessages | [] +export interface DiscordApiAttachment { + id: string + filename: string + description?: string + content_type?: string + size: number + url: string + proxy_url: string + height?: number + width?: number + ephemeral?: boolean } -export interface DiscordGetMembersOutput extends DiscordParsedReponse { - records: DiscordMembers | [] +export interface DiscordApiMessage { + id: string + channel_id: string + author?: DiscordApiUser + content: string + timestamp: string + edited_timestamp: string | null + mention_everyone: boolean + mentions: DiscordApiUser[] + mention_roles: string[] + mention_channels: DiscordApiChannelMention[] + pinned: boolean + type: number + message_reference?: DiscordApiMessageReference + flags?: number + referenced_message?: DiscordApiMessage + thread?: DiscordApiChannel + reactions?: DiscordApiReaction[] + attachments?: DiscordApiAttachment[] } -export type ProcessedChannel = { +export interface DiscordApiUser { id: string - name: string - thread?: boolean - new?: boolean + username: string + discriminator: string + avatar?: string + bot?: boolean + system?: boolean + banner?: string + accent_color?: number + locale?: string + verified?: boolean + email?: string + flags?: number + premium_type?: number + public_flags?: number } -export interface ProcessedChannels { - channels: Array - forumChannels: Array +export interface DiscordApiMember { + user?: DiscordApiUser + nick?: string + avatar?: string + roles: string[] + joined_at: string + premium_since?: string + deaf: boolean + mute: boolean + flags: number + pending?: boolean + permissions?: string + communication_disabled_until?: string } diff --git a/backend/src/serverless/integrations/usecases/discord/errorHandler.ts b/backend/src/serverless/integrations/usecases/discord/errorHandler.ts new file mode 100644 index 0000000000..fc07335e90 --- /dev/null +++ b/backend/src/serverless/integrations/usecases/discord/errorHandler.ts @@ -0,0 +1,33 @@ +import { AxiosError, AxiosRequestConfig } from 'axios' +import { Logger } from '../../../../utils/logging' +import { RateLimitError } from '../../../../types/integration/rateLimitError' + +export const handleDiscordError = ( + err: AxiosError, + config: AxiosRequestConfig, + input: any, + logger: Logger, +): any => { + let url = config.url + if (config.params) { + const queryParams: string[] = [] + for (const [key, value] of Object.entries(config.params)) { + queryParams.push(`${key}=${encodeURIComponent(value as any)}`) + } + + url = `${config.url}?${queryParams.join('&')}` + } + + if (err && err.response && err.response.status === 429) { + logger.warn('Discord API rate limit exceeded') + let rateLimitResetSeconds = 60 + + if (err.response.headers['x-ratelimit-reset-after']) { + rateLimitResetSeconds = parseInt(err.response.headers['x-ratelimit-reset-after'], 10) + } + + return new RateLimitError(rateLimitResetSeconds, url, err) + } + logger.error({ err, input }, `Error while calling Slack API URL: ${url}`) + return err +} diff --git a/backend/src/serverless/integrations/usecases/discord/getChannel.ts b/backend/src/serverless/integrations/usecases/discord/getChannel.ts new file mode 100644 index 0000000000..43e0e8eb3b --- /dev/null +++ b/backend/src/serverless/integrations/usecases/discord/getChannel.ts @@ -0,0 +1,26 @@ +import axios, { AxiosRequestConfig } from 'axios' +import { Logger } from '../../../../utils/logging' +import { handleDiscordError } from './errorHandler' +import { DiscordApiChannel } from '../../types/discordTypes' + +export const getChannel = async ( + channelId: string, + token: string, + logger: Logger, +): Promise => { + const config: AxiosRequestConfig = { + method: 'get', + url: `https://discord.com/api/v10/channels/${channelId}`, + headers: { + Authorization: token, + }, + } + + try { + const response = await axios(config) + return response.data + } catch (err) { + const newErr = handleDiscordError(err, config, { channelId }, logger) + throw newErr + } +} diff --git a/backend/src/serverless/integrations/usecases/discord/getChannels.ts b/backend/src/serverless/integrations/usecases/discord/getChannels.ts index 23db7a63a5..d0596751d8 100644 --- a/backend/src/serverless/integrations/usecases/discord/getChannels.ts +++ b/backend/src/serverless/integrations/usecases/discord/getChannels.ts @@ -1,8 +1,6 @@ import axios from 'axios' import { - DiscordChannel, - DiscordChannels, - DiscordChannelsOut, + DiscordApiChannel, DiscordGetChannelsInput, DiscordGetMessagesInput, } from '../../types/discordTypes' @@ -12,8 +10,8 @@ import { Logger } from '../../../../utils/logging' /** * Try if a channel is readable - * @param accessToken Discord bot token - * @param channel Channel ID + * @param input getMessages input parameters + * @param logger logger * @returns Limit if the channel is readable, false otherwise */ async function tryChannel(input: DiscordGetMessagesInput, logger: Logger): Promise { @@ -32,7 +30,7 @@ async function getChannels( input: DiscordGetChannelsInput, logger: Logger, tryChannels = true, -): Promise { +): Promise { try { const config = { method: 'get', @@ -43,18 +41,10 @@ async function getChannels( } const response = await axios(config) - const result: DiscordChannels = response.data - - const forumChannels = result - .filter((c) => c.type === 15) - .map((c) => ({ - name: c.name, - id: c.id, - thread: true, - })) + const result: any = response.data if (tryChannels) { - const out: DiscordChannels = [] + const out: any[] = [] for (const channel of result) { const limit = await tryChannel( { @@ -66,31 +56,16 @@ async function getChannels( logger, ) if (limit) { - const toOut: DiscordChannel = { - name: channel.name, - id: channel.id, - } - out.push(toOut) + out.push(channel) if (limit <= 1 && limit !== false) { await timeout(5 * 1000) } } } - return { - channels: out, - forumChannels, - } + return out } - const channelsOut = result.map((c) => ({ - name: c.name, - id: c.id, - })) - - return { - channels: channelsOut, - forumChannels, - } + return result } catch (err) { logger.error({ err, input }, 'Error while getting channels from Discord') throw err diff --git a/backend/src/serverless/integrations/usecases/discord/getMember.ts b/backend/src/serverless/integrations/usecases/discord/getMember.ts new file mode 100644 index 0000000000..7eca2b2855 --- /dev/null +++ b/backend/src/serverless/integrations/usecases/discord/getMember.ts @@ -0,0 +1,27 @@ +import axios, { AxiosRequestConfig } from 'axios' +import { DiscordApiMember } from '../../types/discordTypes' +import { Logger } from '../../../../utils/logging' +import { handleDiscordError } from './errorHandler' + +export const getMember = async ( + guildId: string, + userId: string, + token: string, + logger: Logger, +): Promise => { + const config: AxiosRequestConfig = { + method: 'get', + url: `https://discord.com/api/v10/guilds/${guildId}/members/${userId}`, + headers: { + Authorization: token, + }, + } + + try { + const response = await axios(config) + return response.data + } catch (err) { + const newErr = handleDiscordError(err, config, { guildId, userId }, logger) + throw newErr + } +} diff --git a/backend/src/serverless/integrations/usecases/discord/getMembers.ts b/backend/src/serverless/integrations/usecases/discord/getMembers.ts index d1d8ce1f35..5863083b29 100644 --- a/backend/src/serverless/integrations/usecases/discord/getMembers.ts +++ b/backend/src/serverless/integrations/usecases/discord/getMembers.ts @@ -1,8 +1,8 @@ import axios from 'axios' import { + DiscordApiMember, DiscordGetMembersInput, DiscordGetMembersOutput, - DiscordMembers, } from '../../types/discordTypes' import { Logger } from '../../../../utils/logging' @@ -24,10 +24,10 @@ async function getMembers( } const response = await axios(config) - const records: DiscordMembers = response.data + const records: DiscordApiMember[] = response.data const limit = parseInt(response.headers['x-ratelimit-remaining'], 10) const timeUntilReset = parseInt(response.headers['x-ratelimit-reset-after'], 10) - const nextPage = records.length > 0 ? (records[records.length - 1].id as string) : '' + const nextPage = records.length > 0 ? (records[records.length - 1].user.id as string) : '' return { records, nextPage, diff --git a/backend/src/serverless/integrations/usecases/discord/getMessage.ts b/backend/src/serverless/integrations/usecases/discord/getMessage.ts new file mode 100644 index 0000000000..2966ad4e87 --- /dev/null +++ b/backend/src/serverless/integrations/usecases/discord/getMessage.ts @@ -0,0 +1,26 @@ +import axios, { AxiosRequestConfig } from 'axios' +import { Logger } from '../../../../utils/logging' +import { handleDiscordError } from './errorHandler' + +export const getMessage = async ( + channelId: string, + messageId: string, + token: string, + logger: Logger, +): Promise => { + const config: AxiosRequestConfig = { + method: 'get', + url: `https://discord.com/api/v10/channels/${channelId}/messages/${messageId}`, + headers: { + Authorization: token, + }, + } + + try { + const response = await axios(config) + return response.data + } catch (err) { + const newErr = handleDiscordError(err, config, { channelId, messageId }, logger) + throw newErr + } +} diff --git a/backend/src/serverless/integrations/usecases/discord/getMessages.ts b/backend/src/serverless/integrations/usecases/discord/getMessages.ts index 446eaea9a1..f994ea45b8 100644 --- a/backend/src/serverless/integrations/usecases/discord/getMessages.ts +++ b/backend/src/serverless/integrations/usecases/discord/getMessages.ts @@ -1,6 +1,6 @@ import axios from 'axios' import { - DiscordMessages, + DiscordApiMessage, DiscordParsedReponse, DiscordGetMessagesInput, } from '../../types/discordTypes' @@ -25,7 +25,7 @@ async function getMessages( } const response = await axios(config) - const records: DiscordMessages = response.data + const records: DiscordApiMessage[] = response.data const limit = parseInt(response.headers['x-ratelimit-remaining'], 10) const timeUntilReset = parseInt(response.headers['x-ratelimit-reset-after'], 10) diff --git a/backend/src/serverless/integrations/usecases/discord/getThreads.ts b/backend/src/serverless/integrations/usecases/discord/getThreads.ts index fcd355bf4e..f0ca75bf32 100644 --- a/backend/src/serverless/integrations/usecases/discord/getThreads.ts +++ b/backend/src/serverless/integrations/usecases/discord/getThreads.ts @@ -1,11 +1,11 @@ import axios from 'axios' -import { DiscordChannels, DiscordGetChannelsInput } from '../../types/discordTypes' +import { DiscordApiChannel, DiscordGetChannelsInput } from '../../types/discordTypes' import { Logger } from '../../../../utils/logging' async function getThreads( input: DiscordGetChannelsInput, logger: Logger, -): Promise { +): Promise { try { const config = { method: 'get', @@ -16,14 +16,7 @@ async function getThreads( } const response = await axios(config) - const result = response.data.threads - - return result.map((c) => ({ - name: c.name, - id: c.id, - parentId: c.parent_id, - thread: true, - })) + return response.data.threads } catch (err) { logger.error({ err, input }, 'Error while getting threads from Discord') throw err diff --git a/backend/src/serverless/integrations/webhooks/__tests__/github.test.ts b/backend/src/serverless/integrations/webhooks/__tests__/github.test.ts index b4787184ba..16a9200889 100644 --- a/backend/src/serverless/integrations/webhooks/__tests__/github.test.ts +++ b/backend/src/serverless/integrations/webhooks/__tests__/github.test.ts @@ -1,38 +1,56 @@ import moment from 'moment' import IntegrationRepository from '../../../../database/repositories/integrationRepository' import SequelizeTestUtils from '../../../../database/utils/sequelizeTestUtils' -import Error404 from '../../../../errors/Error404' import { GitHubGrid } from '../../grid/githubGrid' -import GitHubWebhook from '../github' import TestEvents from './events' import { PlatformType } from '../../../../types/integrationEnums' import { GithubActivityType } from '../../../../types/activityTypes' import { MemberAttributeName } from '../../../../database/attributes/member/enums' import { IntegrationServiceBase } from '../../services/integrationServiceBase' +import { GithubIntegrationService } from '../../services/integrations/githubIntegrationService' +import { IStepContext } from '../../../../types/integration/stepResult' +import { getServiceLogger } from '../../../../utils/logging' const db = null const installId = '23585816' -async function init(event = '', payload = {}, integration = false) { +const log = getServiceLogger() + +async function fakeContext(integration = {}): Promise { + const options = await SequelizeTestUtils.getTestIRepositoryOptions(db) + + return { + onboarding: false, + integration, + repoContext: options, + serviceContext: options, + limitCount: 0, + startTimestamp: 0, + logger: log, + pipelineData: {}, + } +} + +async function init(integration = false) { const options = await SequelizeTestUtils.getTestIRepositoryOptions(db) - let tenantId + if (integration) { - tenantId = ( - await IntegrationRepository.create( - { - platform: PlatformType.GITHUB, - token: '', - integrationIdentifier: installId, - }, - options, - ) - ).tenantId - } else { - tenantId = '' + const integration = await IntegrationRepository.create( + { + platform: PlatformType.GITHUB, + token: '', + integrationIdentifier: installId, + }, + options, + ) + + return { + tenantId: options.currentTenant.id, + integration, + } } return { - gh: new GitHubWebhook(event, payload), - tenantId, + tenantId: options.currentTenant.id, } } @@ -53,7 +71,7 @@ describe('Github webhooks tests', () => { name: 'Joan Reyero', url: 'https://github.com/joanreyero', } - const parsedMember = await GitHubWebhook.parseMember(member, 'token') + const parsedMember = await GithubIntegrationService.parseMember(member, await fakeContext()) const expected = { username: { [PlatformType.GITHUB]: 'joanreyero', @@ -76,6 +94,7 @@ describe('Github webhooks tests', () => { }, }, email: '', + displayName: 'Joan Reyero', } expect(parsedMember).toStrictEqual(expected) }) @@ -87,7 +106,7 @@ describe('Github webhooks tests', () => { url: 'https://github.com/joanreyero', twitterUsername: 'reyero', } - const parsedMember = await GitHubWebhook.parseMember(member, 'token') + const parsedMember = await GithubIntegrationService.parseMember(member, await fakeContext()) const expected = { username: { [PlatformType.GITHUB]: 'joanreyero', @@ -112,6 +131,7 @@ describe('Github webhooks tests', () => { }, }, email: '', + displayName: 'Joan Reyero', } expect(parsedMember).toStrictEqual(expected) }) @@ -132,7 +152,7 @@ describe('Github webhooks tests', () => { totalCount: 10, }, } - const parsedMember = await GitHubWebhook.parseMember(member, 'token') + const parsedMember = await GithubIntegrationService.parseMember(member, await fakeContext()) const expected = { username: { [PlatformType.GITHUB]: 'joanreyero', @@ -160,43 +180,22 @@ describe('Github webhooks tests', () => { }, }, reach: { [PlatformType.GITHUB]: 10 }, - email: 'joan@crowd.dev', + email: '', + displayName: 'Joan Reyero', organizations: [{ name: 'crowd.dev' }], } expect(parsedMember).toStrictEqual(expected) }) }) - describe('Find integrations test', () => { - it('It should find integration with a correct install ID', async () => { - const payload = { - installation: { - id: installId, - }, - } - const { gh } = await init('', payload, true) - const integrations = await gh.findIntegration() - expect(integrations).toBeDefined() - }) - - it('It should not find integration with a wrong tenant ID', async () => { - const payload = { - installation: { - id: '42', - }, - } - const { gh } = await init('', payload, true) - await expect(() => gh.findIntegration()).rejects.toThrowError(new Error404()) - }) - }) - describe('Issues tests', () => { it('It should parse an issue open coming from the GitHub API', async () => { - const { tenantId, gh } = await init(TestEvents.issues.event, TestEvents.issues.opened, true) - const issue = await gh.issue( - GithubActivityType.ISSUE_OPENED, - GitHubGrid.issueOpened, - TestEvents.issues.opened.issue.created_at, + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + + const issue = await GithubIntegrationService.parseWebhookIssue( + TestEvents.issues.opened, + context, ) const expected = { member: { @@ -221,27 +220,17 @@ describe('Github webhooks tests', () => { isKeyAction: GitHubGrid.issueOpened.isKeyAction, } expect(issue).toStrictEqual(expected) - - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - expect(fromDb).toBeDefined() }) it('It should parse an issue edited coming from the GitHub API', async () => { - const { tenantId, gh } = await init(TestEvents.issues.event, TestEvents.issues.opened, true) - - const issueCreated = await gh.main() - - gh.payload = TestEvents.issues.edited - gh.event = TestEvents.issues.event + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) - const issue = await gh.issue( - GithubActivityType.ISSUE_OPENED, - GitHubGrid.issueOpened, - TestEvents.issues.edited.issue.created_at, + const issue = await GithubIntegrationService.parseWebhookIssue( + TestEvents.issues.edited, + context, ) + const expected = { member: { username: { @@ -265,23 +254,17 @@ describe('Github webhooks tests', () => { isKeyAction: GitHubGrid.issueOpened.isKeyAction, } expect(issue).toStrictEqual(expected) - - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - - expect(fromDb.id).toBe(issueCreated.id) - expect(fromDb).toBeDefined() }) it('It should parse an issue reopened coming from the GitHub API', async () => { - const { tenantId, gh } = await init(TestEvents.issues.event, TestEvents.issues.reopened, true) - const issue = await gh.issue( - GithubActivityType.ISSUE_OPENED, - GitHubGrid.issueOpened, - TestEvents.issues.reopened.issue.created_at, + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + + const issue = await GithubIntegrationService.parseWebhookIssue( + TestEvents.issues.reopened, + context, ) + const expected = { member: { username: { @@ -305,21 +288,17 @@ describe('Github webhooks tests', () => { isKeyAction: GitHubGrid.issueOpened.isKeyAction, } expect(issue).toStrictEqual(expected) - - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - expect(fromDb).toBeDefined() }) it('It should parse an issue closed coming from the GitHub API', async () => { - const { tenantId, gh } = await init(TestEvents.issues.event, TestEvents.issues.closed, true) - const issue = await gh.issue( - GithubActivityType.ISSUE_CLOSED, - GitHubGrid.issueClosed, - TestEvents.issues.closed.issue.closed_at, + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + + const issue = await GithubIntegrationService.parseWebhookIssue( + TestEvents.issues.closed, + context, ) + const expected = { member: { username: { @@ -343,16 +322,13 @@ describe('Github webhooks tests', () => { isKeyAction: GitHubGrid.issueClosed.isKeyAction, } expect(issue).toStrictEqual(expected) - - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - expect(fromDb).toBeDefined() }) - it('getActivityWithMember should throw an error for all other actions', async () => { - const { gh } = await init(TestEvents.issues.event, TestEvents.issues.closed, true) + it('processWebhook should not return any operations for unsupported actions', async () => { + const { integration } = await init(true) + const context = await fakeContext(integration) + + const service = new GithubIntegrationService() const actions = [ 'deleted', @@ -368,31 +344,33 @@ describe('Github webhooks tests', () => { 'milestoned', 'demilestoned', ] + for (const action of actions) { - gh.payload.action = action - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toBeNull() - - try { - await gh.main() - fail('Should have thrown an error') - } catch (err) { - expect(err.action).toBe( - `GitHub WebHook processing of event 'issues' of type 'string' with action '${action}', with a payload type of 'object'.`, - ) + const webhook = { + payload: { + signature: '', + event: 'issues', + data: { + action, + }, + }, } + + const result = await service.processWebhook(webhook, context) + expect(result.operations).toStrictEqual([]) } }) }) describe('Discussion tests', () => { it('It should parse a discussion created event coming from the GitHub API', async () => { - const { tenantId, gh } = await init( - TestEvents.discussion.event, + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + const discussion = await GithubIntegrationService.parseWebhookDiscussion( TestEvents.discussion.created, - true, + context, ) - const discussion = await gh.discussion() + const expected = { member: { username: { @@ -422,22 +400,18 @@ describe('Github webhooks tests', () => { score: GitHubGrid.discussionOpened.score, isKeyAction: GitHubGrid.discussionOpened.isKeyAction, } - expect(discussion).toStrictEqual(expected) - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - expect(fromDb).toBeDefined() + expect(discussion).toStrictEqual(expected) }) it('It should parse a discussion edited event coming from the GitHub API', async () => { - const { tenantId, gh } = await init( - TestEvents.discussion.event, + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + const discussion = await GithubIntegrationService.parseWebhookDiscussion( TestEvents.discussion.edited, - true, + context, ) - const discussion = await gh.discussion() + const expected = { member: { username: { @@ -468,23 +442,14 @@ describe('Github webhooks tests', () => { isKeyAction: GitHubGrid.discussionOpened.isKeyAction, } expect(discussion).toStrictEqual(expected) - - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - expect(fromDb).toBeDefined() }) it('It should parse a discussion answered event coming from the GitHub API', async () => { - const { tenantId, gh } = await init( - TestEvents.discussion.event, + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + const discussion = await GithubIntegrationService.parseWebhookDiscussion( TestEvents.discussion.answered, - true, - ) - const discussion = await gh.answer( - GithubActivityType.DISCUSSION_COMMENT, - TestEvents.discussion.answered.discussion.node_id.toString(), + context, ) const expected = { member: { @@ -508,27 +473,18 @@ describe('Github webhooks tests', () => { isKeyAction: GitHubGrid.discussionOpened.isKeyAction, } expect(discussion).toStrictEqual(expected) - - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - expect(fromDb).toBeDefined() }) }) describe('Pull request tests', () => { it('It should parse an open PR coming from the GitHub API', async () => { - const { tenantId, gh } = await init( - TestEvents.pullRequests.event, + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + const pr = await GithubIntegrationService.parseWebhookPullRequest( TestEvents.pullRequests.opened, - true, - ) - const pr = await gh.pullRequest( - GithubActivityType.PULL_REQUEST_OPENED, - GitHubGrid.pullRequestOpened, - TestEvents.pullRequests.opened.pull_request.created_at, + context, ) + const expected = { member: { username: { @@ -549,31 +505,16 @@ describe('Github webhooks tests', () => { isKeyAction: GitHubGrid.pullRequestOpened.isKeyAction, } expect(pr).toStrictEqual(expected) - - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - expect(fromDb).toBeDefined() }) it('It should parse an edited PR coming from the GitHub API', async () => { - const { tenantId, gh } = await init( - TestEvents.pullRequests.event, - TestEvents.pullRequests.opened, - true, + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + const pr = await GithubIntegrationService.parseWebhookPullRequest( + TestEvents.pullRequests.edited, + context, ) - const prCreated = await gh.main() - - gh.payload = TestEvents.pullRequests.edited - gh.event = TestEvents.pullRequests.event - - const pr = await gh.pullRequest( - GithubActivityType.PULL_REQUEST_OPENED, - GitHubGrid.pullRequestOpened, - TestEvents.pullRequests.edited.pull_request.created_at, - ) const expected = { member: { username: { @@ -593,28 +534,18 @@ describe('Github webhooks tests', () => { score: GitHubGrid.pullRequestOpened.score, isKeyAction: GitHubGrid.pullRequestOpened.isKeyAction, } - expect(pr).toStrictEqual(expected) - - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - expect(fromDb.id).toBe(prCreated.id) - expect(fromDb).toBeDefined() + expect(pr).toStrictEqual(expected) }) it('It should parse a reopened PR coming from the GitHub API', async () => { - const { tenantId, gh } = await init( - TestEvents.pullRequests.event, + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + const pr = await GithubIntegrationService.parseWebhookPullRequest( TestEvents.pullRequests.reopened, - true, - ) - const pr = await gh.pullRequest( - GithubActivityType.PULL_REQUEST_OPENED, - GitHubGrid.pullRequestOpened, - TestEvents.pullRequests.reopened.pull_request.created_at, + context, ) + const expected = { member: { username: { @@ -636,25 +567,16 @@ describe('Github webhooks tests', () => { isKeyAction: GitHubGrid.pullRequestOpened.isKeyAction, } expect(pr).toStrictEqual(expected) - - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - expect(fromDb).toBeDefined() }) it('It should parse a closed PR coming from the GitHub API', async () => { - const { tenantId, gh } = await init( - TestEvents.pullRequests.event, + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + const pr = await GithubIntegrationService.parseWebhookPullRequest( TestEvents.pullRequests.closed, - true, - ) - const pr = await gh.pullRequest( - GithubActivityType.PULL_REQUEST_CLOSED, - GitHubGrid.pullRequestClosed, - TestEvents.pullRequests.closed.pull_request.closed_at, + context, ) + const expected = { member: { username: { @@ -675,16 +597,13 @@ describe('Github webhooks tests', () => { isKeyAction: GitHubGrid.pullRequestClosed.isKeyAction, } expect(pr).toStrictEqual(expected) - - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - expect(fromDb).toBeDefined() }) - it('getActivityWithMember should throw an error for all other actions', async () => { - const { gh } = await init(TestEvents.pullRequests.event, TestEvents.pullRequests.closed, true) + it('processWebhook should not return any operations for unsupported actions', async () => { + const { integration } = await init(true) + const context = await fakeContext(integration) + + const service = new GithubIntegrationService() const actions = [ 'assigned', @@ -702,26 +621,27 @@ describe('Github webhooks tests', () => { 'unlocked', ] for (const action of actions) { - gh.payload.action = action - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toBeNull() - - try { - await gh.main() - fail('Should have thrown an error') - } catch (err) { - expect(err.action).toBe( - `GitHub WebHook processing of event 'pull_request' of type 'string' with action '${action}', with a payload type of 'object'.`, - ) + const webhook = { + payload: { + signature: '', + event: 'pull_request', + data: { + action, + }, + }, } + + const result = await service.processWebhook(webhook, context) + expect(result.operations).toStrictEqual([]) } }) }) describe('Star tests', () => { it('It should parse a star event coming from the GitHub API', async () => { - const { tenantId, gh } = await init(TestEvents.star.event, TestEvents.star.created, true) - const star = await gh.star(GithubActivityType.STAR) + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + const star = await GithubIntegrationService.parseWebhookStar(TestEvents.star.created, context) const expected = { member: { @@ -745,25 +665,13 @@ describe('Github webhooks tests', () => { isKeyAction: false, } expect(star).toStrictEqual(expected) - // Check timestamp - - const fromMain = await gh.getActivityWithMember() - expected.sourceId = IntegrationServiceBase.generateSourceIdHash( - 'joanreyero', - 'star', - moment(fromMain.timestamp).unix().toString(), - PlatformType.GITHUB, - ) - - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - expect(fromDb).toBeDefined() }) it('It should parse an unstar event coming from the GitHub API', async () => { - const { tenantId, gh } = await init(TestEvents.star.event, TestEvents.star.deleted, true) - const star = await gh.star(GithubActivityType.UNSTAR) + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + const star = await GithubIntegrationService.parseWebhookStar(TestEvents.star.deleted, context) + const starTimestamp = star.timestamp delete star.timestamp const expected = { @@ -789,27 +697,15 @@ describe('Github webhooks tests', () => { expect(star).toStrictEqual(expected) // Check timestamp expect(moment(starTimestamp).unix()).toBeCloseTo(moment().unix(), 3) - - const fromMain = await gh.getActivityWithMember() - expected.sourceId = IntegrationServiceBase.generateSourceIdHash( - 'joanreyero', - GithubActivityType.UNSTAR, - moment(fromMain.timestamp).unix().toString(), - PlatformType.GITHUB, - ) - - delete fromMain.timestamp - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - expect(fromDb).toBeDefined() }) }) describe('Fork tests', () => { it('It should parse a fork event coming from the GitHub API', async () => { - const { tenantId, gh } = await init(TestEvents.fork.event, TestEvents.fork.created, true) - const fork = await gh.fork() + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + const fork = await GithubIntegrationService.parseWebhookFork(TestEvents.fork.created, context) + const expected = { member: { username: { @@ -827,28 +723,23 @@ describe('Github webhooks tests', () => { isKeyAction: true, } expect(fork).toStrictEqual(expected) - - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - expect(fromDb).toBeDefined() }) }) describe('Comments tests', () => { it('It should parse an issue comment created event coming from the GitHub API', async () => { - const { tenantId, gh } = await init(TestEvents.issues.event, TestEvents.issues.opened, true) - const issue = await gh.main() + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + const issue = await GithubIntegrationService.parseWebhookIssue( + TestEvents.issues.opened, + context, + ) - gh.payload = TestEvents.comment.issue.created - gh.payload.issue.node_id = issue.sourceId - gh.event = TestEvents.comment.event + const payload = TestEvents.comment.issue.created + payload.issue.node_id = issue.sourceId + const event = TestEvents.comment.event - const comment = await gh.comment( - GithubActivityType.ISSUE_COMMENT, - gh.payload.issue.node_id.toString(), - ) + const comment = await GithubIntegrationService.parseWebhookComment(event, payload, context) const expected = { member: { @@ -869,34 +760,27 @@ describe('Github webhooks tests', () => { isKeyAction: GitHubGrid.comment.isKeyAction, } expect(comment).toStrictEqual(expected) - - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - expect(fromDb).toBeDefined() - expect(fromDb.sourceParentId).toBe(issue.sourceId) - expect(fromDb.parentId).toBe(issue.id) }) it('It should parse an issue comment edited event coming from the GitHub API', async () => { - const { tenantId, gh } = await init(TestEvents.issues.event, TestEvents.issues.opened, true) - const issue = await gh.main() + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + const issue = await GithubIntegrationService.parseWebhookIssue( + TestEvents.issues.opened, + context, + ) - gh.payload = TestEvents.comment.issue.created - gh.payload.issue.node_id = issue.sourceId - gh.event = TestEvents.comment.event + let payload = TestEvents.comment.issue.created + payload.issue.node_id = issue.sourceId + let event = TestEvents.comment.event - const commentCreated = await gh.main() + await GithubIntegrationService.parseWebhookComment(event, payload, context) - gh.payload = TestEvents.comment.issue.edited - gh.payload.issue.node_id = issue.sourceId - gh.event = TestEvents.comment.event + payload = TestEvents.comment.issue.edited + payload.issue.node_id = issue.sourceId + event = TestEvents.comment.event - const comment = await gh.comment( - GithubActivityType.ISSUE_COMMENT, - gh.payload.issue.node_id.toString(), - ) + const comment = await GithubIntegrationService.parseWebhookComment(event, payload, context) const expected = { member: { @@ -917,34 +801,21 @@ describe('Github webhooks tests', () => { isKeyAction: GitHubGrid.comment.isKeyAction, } expect(comment).toStrictEqual(expected) - - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - - expect(fromDb).toBeDefined() - expect(fromDb.id).toBe(commentCreated.id) - expect(fromDb.sourceParentId).toBe(issue.sourceId) - expect(fromDb.parentId).toBe(issue.id) }) it('It should parse a pull request comment created event coming from the GitHub API', async () => { - const { tenantId, gh } = await init( - TestEvents.pullRequests.event, + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + const pull = await GithubIntegrationService.parseWebhookPullRequest( TestEvents.pullRequests.opened, - true, + context, ) - const pull = await gh.main() - gh.payload = TestEvents.comment.pullRequest.created - gh.payload.issue.node_id = pull.sourceId - gh.event = TestEvents.comment.event + const payload = TestEvents.comment.pullRequest.created + payload.issue.node_id = pull.sourceId + const event = TestEvents.comment.event - const comment = await gh.comment( - GithubActivityType.PULL_REQUEST_COMMENT, - gh.payload.issue.node_id.toString(), - ) + const comment = await GithubIntegrationService.parseWebhookComment(event, payload, context) const expected = { member: { @@ -965,37 +836,26 @@ describe('Github webhooks tests', () => { isKeyAction: GitHubGrid.comment.isKeyAction, } expect(comment).toStrictEqual(expected) - - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - expect(fromDb).toBeDefined() - expect(fromDb.sourceParentId).toBe(pull.sourceId) - expect(fromDb.parentId).toBe(pull.id) }) it('It should parse a pull request comment edited event coming from the GitHub API', async () => { - const { tenantId, gh } = await init( - TestEvents.pullRequests.event, + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + const pull = await GithubIntegrationService.parseWebhookPullRequest( TestEvents.pullRequests.opened, - true, + context, ) - const pull = await gh.main() - gh.payload = TestEvents.comment.pullRequest.created - gh.payload.issue.node_id = pull.sourceId - gh.event = TestEvents.comment.event + let payload = TestEvents.comment.pullRequest.created + payload.issue.node_id = pull.sourceId + let event = TestEvents.comment.event - const commentCreated = await gh.main() + await GithubIntegrationService.parseWebhookComment(event, payload, context) - gh.payload = TestEvents.comment.pullRequest.edited - gh.payload.issue.node_id = pull.sourceId - gh.event = TestEvents.comment.event + payload = TestEvents.comment.pullRequest.edited + payload.issue.node_id = pull.sourceId + event = TestEvents.comment.event - const comment = await gh.comment( - GithubActivityType.PULL_REQUEST_COMMENT, - gh.payload.issue.node_id.toString(), - ) + const comment = await GithubIntegrationService.parseWebhookComment(event, payload, context) const expected = { member: { @@ -1016,53 +876,44 @@ describe('Github webhooks tests', () => { isKeyAction: GitHubGrid.comment.isKeyAction, } expect(comment).toStrictEqual(expected) - - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - - expect(fromDb).toBeDefined() - expect(fromDb.id).toBe(commentCreated.id) - expect(fromDb.sourceParentId).toBe(pull.sourceId) - expect(fromDb.parentId).toBe(pull.id) }) - it('getActivityWithMember should throw an error for all other actions', async () => { - const { gh } = await init(TestEvents.comment.event, TestEvents.comment.issue, true) + it('processWebhook should not return any operations for unsupported actions', async () => { + const { integration } = await init(true) + const context = await fakeContext(integration) + + const service = new GithubIntegrationService() const actions = ['deleted'] for (const action of actions) { - gh.payload.action = action - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toBeNull() - - try { - await gh.main() - fail('Should have thrown error') - } catch (err) { - expect(err.action).toBe( - `GitHub WebHook processing of event 'issue_comment' of type 'string' with action '${action}', with a payload type of 'object'.`, - ) + const webhook = { + payload: { + signature: '', + event: 'issue_comment', + data: { + action, + }, + }, } + + const result = await service.processWebhook(webhook, context) + expect(result.operations).toStrictEqual([]) } }) + it('It should parse a discussion comment created event coming from the GitHub API', async () => { - const { tenantId, gh } = await init( - TestEvents.discussion.event, + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + const discussion = await GithubIntegrationService.parseWebhookDiscussion( TestEvents.discussion.created, - true, + context, ) - const discussion = await gh.main() - gh.payload = TestEvents.discussionComment.created - gh.payload.discussion.node_id = discussion.sourceId - gh.event = TestEvents.discussionComment.event + const payload = TestEvents.discussionComment.created + payload.discussion.node_id = discussion.sourceId + const event = TestEvents.discussionComment.event - const comment = await gh.comment( - GithubActivityType.DISCUSSION_COMMENT, - gh.payload.discussion.node_id.toString(), - ) + const comment = await GithubIntegrationService.parseWebhookComment(event, payload, context) const expected = { member: { @@ -1083,38 +934,27 @@ describe('Github webhooks tests', () => { isKeyAction: GitHubGrid.comment.isKeyAction, } expect(comment).toStrictEqual(expected) - - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - expect(fromDb).toBeDefined() - expect(fromDb.sourceParentId).toBe(discussion.sourceId) - expect(fromDb.parentId).toBe(discussion.id) }) it('It should parse a discussion comment edited event coming from the GitHub API', async () => { - const { tenantId, gh } = await init( - TestEvents.discussion.event, + const { tenantId, integration } = await init(true) + const context = await fakeContext(integration) + const discussion = await GithubIntegrationService.parseWebhookDiscussion( TestEvents.discussion.created, - true, + context, ) - const discussion = await gh.main() - gh.payload = TestEvents.discussionComment.created - gh.payload.discussion.node_id = discussion.sourceId - gh.event = TestEvents.discussionComment.event + let payload = TestEvents.discussionComment.created + payload.discussion.node_id = discussion.sourceId + let event = TestEvents.discussionComment.event - const commentCreated = await gh.main() + await GithubIntegrationService.parseWebhookComment(event, payload, context) - gh.payload = TestEvents.discussionComment.edited - gh.payload.discussion.node_id = discussion.sourceId - gh.event = TestEvents.discussionComment.event + payload = TestEvents.discussionComment.edited + payload.discussion.node_id = discussion.sourceId + event = TestEvents.discussionComment.event - const comment = await gh.comment( - GithubActivityType.DISCUSSION_COMMENT, - gh.payload.discussion.node_id.toString(), - ) + const comment = await GithubIntegrationService.parseWebhookComment(event, payload, context) const expected = { member: { @@ -1135,27 +975,6 @@ describe('Github webhooks tests', () => { isKeyAction: GitHubGrid.comment.isKeyAction, } expect(comment).toStrictEqual(expected) - - const fromMain = await gh.getActivityWithMember() - expect(fromMain).toStrictEqual(expected) - - const fromDb = await gh.main() - - expect(fromDb).toBeDefined() - expect(fromDb.id).toBe(commentCreated.id) - expect(fromDb.sourceParentId).toBe(discussion.sourceId) - expect(fromDb.parentId).toBe(discussion.id) - }) - }) - - describe('Previously failing tests', () => { - it('It should parse events that failed before', async () => { - for (let i = 0; i < TestEvents.failed.length; i++) { - const { gh } = await init(TestEvents.failed[i].event, TestEvents.failed[i].payload, true) - const out = await gh.main() - expect(out.id).toBeDefined() - expect(out).toBeDefined() - } }) }) }) diff --git a/backend/src/serverless/integrations/webhooks/github.ts b/backend/src/serverless/integrations/webhooks/github.ts deleted file mode 100644 index a68bf70a12..0000000000 --- a/backend/src/serverless/integrations/webhooks/github.ts +++ /dev/null @@ -1,549 +0,0 @@ -import moment from 'moment' -import verifyGithubWebhook from 'verify-github-webhook' -import { IS_TEST_ENV, GITHUB_CONFIG } from '../../../config' -import IntegrationRepository from '../../../database/repositories/integrationRepository' -import getUserContext from '../../../database/utils/getUserContext' -import { GitHubGrid } from '../grid/githubGrid' -import ActivityService from '../../../services/activityService' -import { AddActivitiesSingle, Member } from '../types/messageTypes' -import getMember from '../usecases/github/graphql/members' -import { PlatformType } from '../../../types/integrationEnums' -import { GithubActivityType } from '../../../types/activityTypes' -import { gridEntry } from '../grid/grid' -import { MemberAttributeName } from '../../../database/attributes/member/enums' -import getOrganization from '../usecases/github/graphql/organizations' -import { IntegrationServiceBase } from '../services/integrationServiceBase' -import { createServiceChildLogger } from '../../../utils/logging' -import { NotSupportedError } from '../../../types/integration/notSupportedError' - -type EventOutput = Promise - -const log = createServiceChildLogger('GithubWebhook') - -export default class GitHubWebhook { - static platform = PlatformType.GITHUB - - integration: Object - - event: string - - payload: any - - constructor(event: string, payload: Object) { - this.event = event - this.payload = payload - } - - /** - * Find the integration a payload belongs to - * @param identifier Integration identifier - * @returns The integration the payload belongs to - */ - async findIntegration(): Promise { - const identifier: string = this.payload.installation.id.toString() - return IntegrationRepository.findByIdentifier(identifier, PlatformType.GITHUB) - } - - /** - * - * @param integration Integration found - * @returns - */ - static getTenantId(integration): string { - return integration.tenantId.toString() - } - - /** - * Parse an issue activity given the payload coming from the GitHub webhook. - * It will get the member that performed the activity. If it exists, - * it will create a GitHub activity. - * @param type The type of event: opened or closed - * @returns The issue activity or null - */ - async issue(type: GithubActivityType, scoreGrid: gridEntry, timestamp: string): EventOutput { - const integration = (await this.findIntegration()) as any - const issue = this.payload.issue - const member: Member = await GitHubWebhook.getParsedMember(issue.user.login, integration.token) - - if (member) { - return { - member, - type, - timestamp: moment(timestamp).utc().toDate(), - platform: PlatformType.GITHUB, - tenant: GitHubWebhook.getTenantId(integration), - sourceId: issue.node_id.toString(), - sourceParentId: null, - url: issue.html_url, - title: issue.title, - channel: this.payload.repository.html_url, - body: issue.body, - attributes: { - state: issue.state, - }, - score: scoreGrid.score, - isKeyAction: scoreGrid.isKeyAction, - } - } - return null - } - - /** - * Parse a pull activity given the payload coming from the GitHub webhook. - * It will get the member that performed the activity. If it exists, - * it will create a GitHub activity. - * @param type The type of event: opened or closed - * @returns The pull activity or null - */ - async pullRequest( - type: GithubActivityType, - scoreGrid: gridEntry, - timestamp: string, - ): EventOutput { - const integration = (await this.findIntegration()) as any - const pull = this.payload.pull_request - const member: Member = await GitHubWebhook.getParsedMember(pull.user.login, integration.token) - if (member) { - return { - member, - type, - timestamp: moment(timestamp).utc().toDate(), - platform: PlatformType.GITHUB, - tenant: GitHubWebhook.getTenantId(integration), - sourceId: pull.node_id.toString(), - sourceParentId: null, - url: pull.html_url, - title: pull.title, - channel: this.payload.repository.html_url, - body: pull.body, - score: scoreGrid.score, - isKeyAction: scoreGrid.isKeyAction, - } - } - return null - } - - /** - * Parse a discussion started activity into crowd activities using the payload coming from the GitHub webhook. - * @returns The discussion-started activity or null - */ - async discussion(): EventOutput { - const integration = (await this.findIntegration()) as any - const discussion = this.payload.discussion - const member: Member = await GitHubWebhook.getParsedMember( - discussion.user.login, - integration.token, - ) - if (member) { - return { - member, - type: GithubActivityType.DISCUSSION_STARTED, - timestamp: moment(discussion.created_at).utc().toDate(), - platform: PlatformType.GITHUB, - tenant: GitHubWebhook.getTenantId(integration), - sourceId: discussion.node_id.toString(), - sourceParentId: null, - url: discussion.html_url, - title: discussion.title, - channel: this.payload.repository.html_url, - body: discussion.body, - attributes: { - category: { - id: discussion.category.node_id, - isAnswerable: discussion.category.is_answerable, - name: discussion.category.name, - slug: discussion.category.slug, - emoji: discussion.category.emoji, - description: discussion.category.description, - }, - }, - score: GitHubGrid.discussionOpened.score, - isKeyAction: GitHubGrid.discussionOpened.isKeyAction, - } - } - return null - } - - /** - * Parse a star activity into crowd activities using the payload coming from the GitHub webhook. - * @param type The type of event: opened(star) or closed(unstar) - * @returns The star activity or null - */ - async star(type: string): EventOutput { - const integration = (await this.findIntegration()) as any - const member: Member = await GitHubWebhook.getParsedMember( - this.payload.sender.login, - integration.token, - ) - if (member) { - const starredAt = - type === GithubActivityType.STAR ? moment(this.payload.starred_at).utc() : moment().utc() - return { - member, - type, - timestamp: starredAt.toDate(), - platform: PlatformType.GITHUB, - tenant: GitHubWebhook.getTenantId(integration), - sourceId: IntegrationServiceBase.generateSourceIdHash( - this.payload.sender.login, - type, - starredAt.unix().toString(), - PlatformType.GITHUB, - ), - sourceParentId: null, - channel: this.payload.repository.html_url, - score: type === 'star' ? GitHubGrid.star.score : GitHubGrid.unStar.score, - isKeyAction: GitHubGrid.star.isKeyAction, - } - } - return null - } - - /** - * Parse a fork activity given the payload coming from the GitHub webhook. - * It will get the member that performed the activity. If it exists, - * it will create a GitHub activity. - * @param type The type of event: opened or closed - * @returns The fork activity or null - */ - async fork(): EventOutput { - const integration = (await this.findIntegration()) as any - const member: Member = await GitHubWebhook.getParsedMember( - this.payload.sender.login, - integration.token, - ) - if (member) { - return { - member, - type: GithubActivityType.FORK, - timestamp: moment(this.payload.forkee.created_at).utc().toDate(), - platform: PlatformType.GITHUB, - tenant: GitHubWebhook.getTenantId(integration), - sourceId: this.payload.forkee.node_id.toString(), - sourceParentId: null, - channel: this.payload.repository.html_url, - score: GitHubGrid.fork.score, - isKeyAction: GitHubGrid.fork.isKeyAction, - } - } - return null - } - - /** - * Parse a comment activity given the payload coming from the GitHub webhook. - * It will get the member that performed the activity. If it exists, - * it will create a GitHub activity. - * @param type The type of event: comments can be generated from various - * places: issue-comment, pull_request-comment, discussion-comment - * @param sourceParentId remoted parent id of the comment. It can be - * a discussion-started, issue-created, or pull_request-opened activity id. - * @returns The comment activity or null - */ - async comment(type: string, sourceParentId: string): EventOutput { - const integration = (await this.findIntegration()) as any - const member: Member = await GitHubWebhook.getParsedMember( - this.payload.sender.login, - integration.token, - ) - if (member) { - const comment = this.payload.comment - return { - member, - type, - timestamp: moment(comment.created_at).utc().toDate(), - platform: PlatformType.GITHUB, - tenant: GitHubWebhook.getTenantId(integration), - sourceId: comment.node_id.toString(), - sourceParentId, - url: comment.html_url, - body: comment.body, - channel: this.payload.repository.html_url, - score: GitHubGrid.comment.score, - isKeyAction: GitHubGrid.comment.isKeyAction, - } - } - return null - } - - /** - * Parse a discussion answered activity given the payload coming from the GitHub webhook. - * We will be updating score and attributes.isSelectedAnswer for the already - * existing discussion comment. - * @param type Any comment type activity can be marked as an answer: - * issue-comment, pull_request-comment, discussion-comment - * @param sourceParentId remoted parent id of the comment. It can be - * a discussion-started, issue-created, or pull_request-opened activity id. - * @returns The answer comment activity or null - */ - async answer(type: string, sourceParentId: string): EventOutput { - const integration = (await this.findIntegration()) as any - const member: Member = await GitHubWebhook.getParsedMember( - this.payload.sender.login, - integration.token, - ) - if (member) { - const answer = this.payload.answer - return { - member, - type, - timestamp: moment(answer.created_at).utc().toDate(), - platform: PlatformType.GITHUB, - tenant: GitHubWebhook.getTenantId(integration), - sourceId: answer.node_id.toString(), - sourceParentId, - attributes: { - isSelectedAnswer: true, - }, - channel: this.payload.repository.html_url, - body: answer.body, - url: answer.html_url, - score: GitHubGrid.selectedAnswer.score, - isKeyAction: GitHubGrid.selectedAnswer.isKeyAction, - } - } - return null - } - - /** - * Get and parse a member using the GitHub API - * @param login The username of the member - * @param token The GitHub token of the integration - * @returns A member object, or null - */ - static async getParsedMember(login: string, token: string): Promise { - if (IS_TEST_ENV) { - return { - username: { - [PlatformType.GITHUB]: 'testMember', - }, - } - } - const member = await getMember(login, token) - if (member) { - return GitHubWebhook.parseMember(member, token) - } - return member - } - - /** - * Parse a user object coming from the GitHub API into a Crowd.dev member. - * @param member User object coming from the GitHub API - * @returns The parsed member - */ - static async parseMember(member: any, token): Promise { - const parsedMember: Member = { - username: { [PlatformType.GITHUB]: member.login }, - attributes: { - [MemberAttributeName.IS_HIREABLE]: { - [PlatformType.GITHUB]: member.isHireable || false, - }, - [MemberAttributeName.URL]: { - [PlatformType.GITHUB]: member.url, - }, - [MemberAttributeName.AVATAR_URL]: { - [PlatformType.GITHUB]: member.avatarUrl || '', - }, - [MemberAttributeName.BIO]: { - [PlatformType.GITHUB]: member.bio || '', - }, - [MemberAttributeName.LOCATION]: { - [PlatformType.GITHUB]: member.location || '', - }, - }, - email: member.email || '', - ...(member.company && { organizations: [member.company.trim()] }), - } - - if (member.websiteUrl) { - parsedMember.attributes[MemberAttributeName.WEBSITE_URL] = { - [PlatformType.GITHUB]: member.websiteUrl, - } - } - - if (member.twitterUsername) { - parsedMember.attributes[MemberAttributeName.URL][ - PlatformType.TWITTER - ] = `https://twitter.com/${member.twitterUsername}` - parsedMember.username[PlatformType.TWITTER] = member.twitterUsername - } - - if (member.company) { - if (IS_TEST_ENV) { - parsedMember.organizations = [{ name: 'crowd.dev' }] - } else { - const company = member.company.replace('@', '').trim() - const fromAPI = await getOrganization(company, token) - if (fromAPI) { - parsedMember.organizations = [ - { - name: fromAPI.name, - description: fromAPI.description ?? null, - location: fromAPI.location ?? null, - logo: fromAPI.avatarUrl ?? null, - url: fromAPI.url ?? null, - github: fromAPI.url - ? { handle: fromAPI.url.replace('https://github.com/', '') } - : null, - twitter: fromAPI.twitterUsername ? { handle: fromAPI.twitterUsername } : null, - website: fromAPI.websiteUrl ?? null, - }, - ] - } else { - parsedMember.organizations = [{ name: company }] - } - } - } - - if (member.followers && member.followers.totalCount > 0) { - parsedMember.reach = { [PlatformType.GITHUB]: member.followers.totalCount } - } - - return parsedMember - } - - /** - * Parse an event coming from the GitHub API into an activity. - * If the event does not correspond to a supported event, it will return null. - * @returns An activity to add to the database, nor null - */ - async getActivityWithMember(): EventOutput { - switch (this.event) { - case 'issues': - switch (this.payload.action) { - case 'edited': - case 'opened': - case 'reopened': - return this.issue( - GithubActivityType.ISSUE_OPENED, - GitHubGrid.issueOpened, - this.payload.issue.created_at, - ) - case 'closed': - return this.issue( - GithubActivityType.ISSUE_CLOSED, - GitHubGrid.issueClosed, - this.payload.issue.closed_at, - ) - default: - return null - } - - case 'discussion': - switch (this.payload.action) { - case 'edited': - case 'created': - return this.discussion() - case 'answered': - return this.answer( - GithubActivityType.DISCUSSION_COMMENT, - this.payload.discussion.node_id.toString(), - ) - default: - return null - } - - case 'pull_request': - switch (this.payload.action) { - case 'edited': - case 'opened': - case 'reopened': - return this.pullRequest( - GithubActivityType.PULL_REQUEST_OPENED, - GitHubGrid.pullRequestOpened, - this.payload.pull_request.created_at, - ) - case 'closed': - return this.pullRequest( - GithubActivityType.PULL_REQUEST_CLOSED, - GitHubGrid.pullRequestClosed, - this.payload.pull_request.closed_at, - ) - default: - return null - } - - case 'star': - switch (this.payload.action) { - case 'created': - return this.star(GithubActivityType.STAR) - case 'deleted': - return this.star(GithubActivityType.UNSTAR) - default: - return null - } - - case 'fork': - return this.fork() - - case 'discussion_comment': - switch (this.payload.action) { - case 'created': - case 'edited': - return this.comment( - GithubActivityType.DISCUSSION_COMMENT, - this.payload.discussion.node_id.toString(), - ) - default: - return null - } - case 'issue_comment': - switch (this.payload.action) { - case 'created': - case 'edited': - if ('pull_request' in this.payload.issue) { - return this.comment( - GithubActivityType.PULL_REQUEST_COMMENT, - this.payload.issue.node_id.toString(), - ) - } - return this.comment( - GithubActivityType.ISSUE_COMMENT, - this.payload.issue.node_id.toString(), - ) - default: - return null - } - - default: - return null - } - } - - /** - * Verifies a request coming from GitHub webhooks - * @param signature header signature - * @param data payload - * @returns The SQS message sent || Verification Error - */ - static verify(signature: string, data: any): void { - const secret = GITHUB_CONFIG.webhookSecret - - let isVerified: boolean - try { - isVerified = verifyGithubWebhook(signature, JSON.stringify(data), secret) // Returns true if verification succeeds; otherwise, false. - } catch (err) { - throw new Error(`Webhook not verified\n${err}`) - } - - if (!isVerified) { - throw new Error('Webhook not verified') - } - - log.info('Webhook verified') - } - - async main(): Promise { - const activity = await this.getActivityWithMember() - - if (activity) { - const userContext = await getUserContext(activity.tenant) - return new ActivityService(userContext).createWithMember(activity) - } - - throw new NotSupportedError( - `GitHub WebHook processing of event '${this.event}' of type '${typeof this - .event}' with action '${this.payload.action}', with a payload type of '${typeof this - .payload}'.`, - ) - } -} diff --git a/backend/src/serverless/integrations/workers/githubWebhookWorker.ts b/backend/src/serverless/integrations/workers/githubWebhookWorker.ts deleted file mode 100644 index 90c8d42212..0000000000 --- a/backend/src/serverless/integrations/workers/githubWebhookWorker.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { createChildLogger, createServiceChildLogger, Logger } from '../../../utils/logging' -import { PlatformType } from '../../../types/integrationEnums' -import IntegrationRepository from '../../../database/repositories/integrationRepository' -import IncomingWebhookRepository from '../../../database/repositories/incomingWebhookRepository' -import { WebhookError, WebhookState, WebhookType } from '../../../types/webhooks' -import SequelizeRepository from '../../../database/repositories/sequelizeRepository' -import { sendNodeWorkerMessage } from '../../utils/nodeWorkerSQS' -import { NodeWorkerProcessWebhookMessage } from '../../../types/mq/nodeWorkerProcessWebhookMessage' -import GitHubWebhook from '../webhooks/github' -import { IRepositoryOptions } from '../../../database/repositories/IRepositoryOptions' - -const log = createServiceChildLogger('githubWebhookWorker') - -export default async function githubWebhookWorker(req) { - const signature = req.headers['x-hub-signature'] - const event = req.headers['x-github-event'] - const data = req.body - - const identifier = data.installation.id.toString() - const integration = (await IntegrationRepository.findByIdentifier( - identifier, - PlatformType.GITHUB, - )) as any - - if (integration) { - log.info({ integrationId: integration.id }, 'Incoming GitHub Webhook!') - const options = await SequelizeRepository.getDefaultIRepositoryOptions() - const repo = new IncomingWebhookRepository(options) - - const result = await repo.create({ - tenantId: integration.tenantId, - integrationId: integration.id, - type: WebhookType.GITHUB, - payload: { - signature, - event, - data, - }, - }) - - await sendNodeWorkerMessage( - integration.tenantId, - new NodeWorkerProcessWebhookMessage(integration.tenantId, result.id), - ) - - return { - status: 204, - } - } - - log.error({ identifier }, 'No integration found for incoming GitHub Webhook!') - return { - status: 404, - } -} - -export const processWebhook = async ( - msg: NodeWorkerProcessWebhookMessage, - messageLogger: Logger, -) => { - const options = (await SequelizeRepository.getDefaultIRepositoryOptions()) as IRepositoryOptions - const logger = createChildLogger('githubWebhookProcessor', messageLogger, { - webhookId: msg.webhookId, - }) - options.log = logger - - logger.info('Processing GitHub Webhook!') - - // load webhook to process from database - options.transaction = await SequelizeRepository.createTransaction(options) - const repo = new IncomingWebhookRepository(options) - const webhook = await repo.findById(msg.webhookId) - - if (webhook) { - if (webhook.state !== WebhookState.PENDING) { - logger.error({ state: webhook.state }, 'Webhook is not in pending state!') - return - } - - try { - await GitHubWebhook.verify(webhook.payload.signature, webhook.payload.data) - - const processor = new GitHubWebhook(webhook.payload.event, webhook.payload.data) - await processor.main() - await repo.markCompleted(webhook.id) - logger.info('Webhook processed successfully!') - } catch (err) { - if (err.action) { - logger.warn({ action: err.action }, 'Action not supported!') - } else { - logger.error(err, 'Error processing webhook!') - } - - await repo.markError( - webhook.id, - new WebhookError(webhook.id, 'Error processing webhook!', err), - ) - } finally { - await SequelizeRepository.commitTransaction(options.transaction) - } - } else { - logger.error({ webhookId: msg.webhookId }, 'Webhook not found!') - } -} diff --git a/backend/src/types/integration/stepResult.ts b/backend/src/types/integration/stepResult.ts index f05eca8283..7d8c247315 100644 --- a/backend/src/types/integration/stepResult.ts +++ b/backend/src/types/integration/stepResult.ts @@ -1,5 +1,6 @@ import { IRepositoryOptions } from '../../database/repositories/IRepositoryOptions' import { IServiceOptions } from '../../services/IServiceOptions' +import { Logger } from '../../utils/logging' export interface IIntegrationStream { value: string @@ -32,6 +33,13 @@ export interface IProcessStreamResults { sleep?: number } +export interface IProcessWebhookResults { + // result of stream processing are operations that have to be done after + operations: IStreamResultOperation[] + // seconds to pause between continuing with integration processing for the remaining streams + sleep?: number +} + export interface IStepContext { // when did integration processing start startTimestamp: number @@ -48,9 +56,15 @@ export interface IStepContext { // integration that we are currently processing integration?: any + // webhook that we are currently processing + webhook?: any + // repository options for integration services to use when creating new instances of repositories repoContext: IRepositoryOptions // service options for integration services to use when creating new instances of services serviceContext: IServiceOptions + + // logger associated with the integration + logger: Logger } diff --git a/backend/src/types/mq/nodeWorkerProcessWebhookMessage.ts b/backend/src/types/mq/nodeWorkerProcessWebhookMessage.ts index 2b6d265fb1..ddb824715b 100644 --- a/backend/src/types/mq/nodeWorkerProcessWebhookMessage.ts +++ b/backend/src/types/mq/nodeWorkerProcessWebhookMessage.ts @@ -2,7 +2,11 @@ import { NodeWorkerMessageType } from '../../serverless/types/workerTypes' import { NodeWorkerMessageBase } from './nodeWorkerMessageBase' export class NodeWorkerProcessWebhookMessage extends NodeWorkerMessageBase { - constructor(public readonly tenantId: string, public readonly webhookId: string) { + constructor( + public readonly tenantId: string, + public readonly webhookId: string, + public readonly force?: boolean, + ) { super(NodeWorkerMessageType.PROCESS_WEBHOOK) } } diff --git a/backend/src/types/webhooks.ts b/backend/src/types/webhooks.ts index dafa002db8..688bce0358 100644 --- a/backend/src/types/webhooks.ts +++ b/backend/src/types/webhooks.ts @@ -8,6 +8,19 @@ export enum WebhookState { export enum WebhookType { GITHUB = 'GITHUB', + DISCORD = 'DISCORD', +} + +export enum DiscordWebsocketEvent { + MEMBER_ADDED = 'member_added', + MEMBER_UPDATED = 'member_updated', + MESSAGE_CREATED = 'message_created', + MESSAGE_UPDATED = 'message_updated', +} + +export interface DiscordWebsocketPayload { + event: DiscordWebsocketEvent + data: any } export interface GithubWebhookPayload { diff --git a/frontend/src/integrations/discord/components/activity/discord-activity-message.vue b/frontend/src/integrations/discord/components/activity/discord-activity-message.vue index 7009e13332..5734204cd1 100644 --- a/frontend/src/integrations/discord/components/activity/discord-activity-message.vue +++ b/frontend/src/integrations/discord/components/activity/discord-activity-message.vue @@ -22,26 +22,36 @@ class="inline-block ml-1" > {{ - ['channel_joined', 'channel_left'].includes( + v-if=" + !short && + !channelOnly && + !['channel_joined', 'channel_left'].includes( activity.type ) - ? '' - : activity.attributes.forum - ? 'in forum channel' - : 'in channel' - }} - + diff --git a/frontend/src/modules/activity/components/activity-content.vue b/frontend/src/modules/activity/components/activity-content.vue index ba752a9833..913ad8faa7 100644 --- a/frontend/src/modules/activity/components/activity-content.vue +++ b/frontend/src/modules/activity/components/activity-content.vue @@ -1,10 +1,19 @@ diff --git a/frontend/src/shared/loading/page-loader.vue b/frontend/src/shared/loading/page-loader.vue new file mode 100644 index 0000000000..ad97a284ef --- /dev/null +++ b/frontend/src/shared/loading/page-loader.vue @@ -0,0 +1,14 @@ + + + + + diff --git a/frontend/src/shared/shared-module.js b/frontend/src/shared/shared-module.js index ec90ae0ff1..e811d22bce 100644 --- a/frontend/src/shared/shared-module.js +++ b/frontend/src/shared/shared-module.js @@ -47,6 +47,7 @@ import Drawer from '@/shared/drawer/drawer' import AppLoader from '@/shared/loading/loader' import AppPageWrapper from '@/shared/layout/page-wrapper' import Image from '@/shared/image/image' +import AppPageLoader from '@/shared/loading/page-loader' /** * All shared components are globally registered, so there's no need to import them from other components @@ -103,6 +104,7 @@ export default { 'app-drawer': Drawer, 'app-loader': AppLoader, 'app-page-wrapper': AppPageWrapper, - 'app-image': Image + 'app-image': Image, + 'app-page-loader': AppPageLoader } } diff --git a/frontend/src/unleash/index.js b/frontend/src/unleash/index.js new file mode 100644 index 0000000000..4dec38a19e --- /dev/null +++ b/frontend/src/unleash/index.js @@ -0,0 +1,50 @@ +import { UnleashClient } from 'unleash-proxy-client' +import config from '@/config' + +export const FEATURE_FLAGS = { + eagleEye: 'eagle-eye', + communityCenterPro: 'community-help-center-pro', + organizations: 'organizations', + automations: 'automations', + linkedin: 'linkedin' +} + +export class Unleash { + constructor() { + const unleashConfig = { + url: config.unleash.host + '/api/frontend', + clientKey: config.unleash.apiKey, + appName: 'test', + environment: 'production' + } + + this.flags = FEATURE_FLAGS + this.unleash = new UnleashClient(unleashConfig) + } + + init(context) { + this.unleash.start() + + this.updateContext(context) + + this.unleash.on('ready', () => { + console.log(this.unleash.getAllToggles()) + }) + } + + isFlagEnabled(flag) { + return this.unleash.isEnabled(flag) + } + + updateContext(context) { + this.unleash.updateContext(context) + } + + premiumFeatureCopy() { + if (config.isCommunityVersion) { + return 'Premium' + } else { + return 'Growth' + } + } +} diff --git a/frontend/src/utils/posthog.js b/frontend/src/utils/posthog.js deleted file mode 100644 index d0b72cdc6d..0000000000 --- a/frontend/src/utils/posthog.js +++ /dev/null @@ -1,26 +0,0 @@ -import posthog from 'posthog-js' -import config from '@/config' - -export const featureFlags = { - eagleEye: 'eagle-eye', - communityCenterPro: 'community-help-center-pro', - organizations: 'organizations', - automations: 'automations', - linkedin: 'linkedin' -} - -export const isFeatureEnabled = async (flag) => { - if (config.isCommunityVersion) { - return true - } - - return posthog.isFeatureEnabled(flag) -} - -export const premiumFeatureCopy = () => { - if (config.isCommunityVersion) { - return 'Premium' - } else { - return 'Growth' - } -} diff --git a/scripts/cli b/scripts/cli index b30a724f7d..d0d818fa39 100755 --- a/scripts/cli +++ b/scripts/cli @@ -369,7 +369,7 @@ function up_scaffold() { wait_for_db migrate_local create_s3_buckets - create_qdrant_collection + # create_qdrant_collection bash pizzly-integrations.sh init_unleash } From c94907fa00b84fdbefb209acfa6b7cd85fa4186d Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Fri, 17 Feb 2023 14:48:13 +0000 Subject: [PATCH 37/56] Fix unleash export instance --- frontend/scripts/docker-entrypoint.sh | 1 + frontend/src/config.js | 2 ++ frontend/src/main.js | 4 ++-- frontend/src/modules/auth/auth-current-tenant.js | 5 ++--- frontend/src/unleash/index.js | 4 +++- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/frontend/scripts/docker-entrypoint.sh b/frontend/scripts/docker-entrypoint.sh index 18fa2b0f9d..30ef2e684c 100755 --- a/frontend/scripts/docker-entrypoint.sh +++ b/frontend/scripts/docker-entrypoint.sh @@ -29,6 +29,7 @@ declare -a ENV_VARIABLES=( "VUE_APP_FORMBRICKS_FORM_ID" "VUE_APP_STRIPE_GROWTH_PLAN_PAYMENT_LINK" "VUE_APP_STRIPE_CUSTOMER_PORTAL_LINK" + "VUE_APP_UNLEASH_URL" ) for ENV_VAR in "${ENV_VARIABLES[@]}" diff --git a/frontend/src/config.js b/frontend/src/config.js index e0638486c7..19cc892dd0 100644 --- a/frontend/src/config.js +++ b/frontend/src/config.js @@ -17,6 +17,7 @@ const defaultConfig = { protocol: process.env.VUE_APP_FRONTEND_PROTOCOL }, backendUrl: process.env.VUE_APP_BACKEND_URL, + unleashUrl: process.env.VUE_APP_UNLEASH_URL, websocketsUrl: process.env.VUE_APP_WEBSOCKETS_URL, tenantMode, isPlanEnabled, @@ -61,6 +62,7 @@ const composedConfig = { protocol: 'CROWD_VUE_APP_FRONTEND_PROTOCOL' }, backendUrl: 'CROWD_VUE_APP_BACKEND_URL', + unleashUrl: 'CROWD_VUE_APP_UNLEASH_URL', websocketsUrl: 'CROWD_VUE_APP_WEBSOCKETS_URL', tenantMode, isPlanEnabled, diff --git a/frontend/src/main.js b/frontend/src/main.js index 0d8d8ba016..7ec5aa1a7f 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -5,7 +5,7 @@ import plugins from '@/plugins' import VueClickAway from 'vue3-click-away' import modules from '@/modules' import config from '@/config' -import { Unleash } from '@/unleash' +import { UnleashIntance } from '@/unleash' import { init as i18nInit, @@ -51,7 +51,7 @@ i18nInit() app.use(VueLazyLoad) // Provide unleash instance for all app - app.provide('unleash', new Unleash()) + app.provide('unleash', UnleashIntance) app.config.productionTip = process.env.NODE_ENV === 'production' diff --git a/frontend/src/modules/auth/auth-current-tenant.js b/frontend/src/modules/auth/auth-current-tenant.js index 75c09bffb3..b03f272be0 100644 --- a/frontend/src/modules/auth/auth-current-tenant.js +++ b/frontend/src/modules/auth/auth-current-tenant.js @@ -1,6 +1,6 @@ import { tenantSubdomain } from '@/modules/tenant/tenant-subdomain' import config from '@/config' -import { inject } from 'vue' +import { UnleashIntance } from '@/unleash' /** * Auth Current Tenant @@ -109,11 +109,10 @@ export default class AuthCurrentTenant { if (!tenant) { return this.clear() } - const unleash = inject('unleash') // Refresh feature flags each time tenant is set if (!config.isCommunityVersion) { - await unleash?.updateContext({ + await UnleashIntance?.updateContext({ automationCount: tenant.automationCount, csvExportCount: tenant.csvExportCount, memberEnrichmentCount: tenant.memberEnrichmentCount, diff --git a/frontend/src/unleash/index.js b/frontend/src/unleash/index.js index 4dec38a19e..56da6ca554 100644 --- a/frontend/src/unleash/index.js +++ b/frontend/src/unleash/index.js @@ -12,7 +12,7 @@ export const FEATURE_FLAGS = { export class Unleash { constructor() { const unleashConfig = { - url: config.unleash.host + '/api/frontend', + url: `${config.unleash.host}/api/frontend`, clientKey: config.unleash.apiKey, appName: 'test', environment: 'production' @@ -48,3 +48,5 @@ export class Unleash { } } } + +export const UnleashIntance = new Unleash() From b1138578c0eab124766e8d13b85bb245341c6bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Sat, 18 Feb 2023 10:38:48 +0100 Subject: [PATCH 38/56] bugfix - going with dedicated unleash url --- frontend/.env.dist.local | 2 ++ frontend/src/config.js | 6 ++---- frontend/src/main.js | 4 ++-- frontend/src/modules/auth/auth-current-tenant.js | 4 ++-- frontend/src/unleash/index.js | 9 +++++---- frontend/vue.config.js | 8 -------- 6 files changed, 13 insertions(+), 20 deletions(-) diff --git a/frontend/.env.dist.local b/frontend/.env.dist.local index 5abb347c91..6761208b66 100644 --- a/frontend/.env.dist.local +++ b/frontend/.env.dist.local @@ -11,3 +11,5 @@ VUE_APP_CONVERSATIONS_PUBLIC_URL=http://localhost:3000 VUE_APP_PIZZLY_URL=http://localhost:3003 VUE_APP_PIZZLY_PUBLISHABLE_KEY=424242 VUE_APP_ENV=local +VUE_APP_UNLEASH_API_KEY=*:production.26f05b69ce3162e7502076ccc0240a190963829c057bca92ee85c6c3 +VUE_APP_UNLEASH_URL=http://localhost:4242 \ No newline at end of file diff --git a/frontend/src/config.js b/frontend/src/config.js index 19cc892dd0..1d51a90e99 100644 --- a/frontend/src/config.js +++ b/frontend/src/config.js @@ -17,7 +17,6 @@ const defaultConfig = { protocol: process.env.VUE_APP_FRONTEND_PROTOCOL }, backendUrl: process.env.VUE_APP_BACKEND_URL, - unleashUrl: process.env.VUE_APP_UNLEASH_URL, websocketsUrl: process.env.VUE_APP_WEBSOCKETS_URL, tenantMode, isPlanEnabled, @@ -39,7 +38,7 @@ const defaultConfig = { typeformTitle: process.env.VUE_APP_TYPEFORM_TITLE, unleash: { apiKey: process.env.VUE_APP_UNLEASH_API_KEY, - host: process.env.VUE_APP_UNLEASH_HOST + url: process.env.VUE_APP_UNLEASH_URL }, formbricks: { url: process.env.VUE_APP_FORMBRICKS_URL, @@ -62,7 +61,6 @@ const composedConfig = { protocol: 'CROWD_VUE_APP_FRONTEND_PROTOCOL' }, backendUrl: 'CROWD_VUE_APP_BACKEND_URL', - unleashUrl: 'CROWD_VUE_APP_UNLEASH_URL', websocketsUrl: 'CROWD_VUE_APP_WEBSOCKETS_URL', tenantMode, isPlanEnabled, @@ -84,7 +82,7 @@ const composedConfig = { typeformTitle: 'CROWD_VUE_APP_TYPEFORM_TITLE', unleash: { apiKey: 'CROWD_VUE_APP_UNLEASH_API_KEY', - host: 'CROWD_VUE_APP_UNLEASH_HOST' + url: 'CROWD_VUE_APP_UNLEASH_URL' }, formbricks: { url: 'CROWD_VUE_APP_FORMBRICKS_URL', diff --git a/frontend/src/main.js b/frontend/src/main.js index 7ec5aa1a7f..34bfe670fe 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -5,7 +5,7 @@ import plugins from '@/plugins' import VueClickAway from 'vue3-click-away' import modules from '@/modules' import config from '@/config' -import { UnleashIntance } from '@/unleash' +import { UnleashInstance } from '@/unleash' import { init as i18nInit, @@ -51,7 +51,7 @@ i18nInit() app.use(VueLazyLoad) // Provide unleash instance for all app - app.provide('unleash', UnleashIntance) + app.provide('unleash', UnleashInstance) app.config.productionTip = process.env.NODE_ENV === 'production' diff --git a/frontend/src/modules/auth/auth-current-tenant.js b/frontend/src/modules/auth/auth-current-tenant.js index b03f272be0..6d6f518235 100644 --- a/frontend/src/modules/auth/auth-current-tenant.js +++ b/frontend/src/modules/auth/auth-current-tenant.js @@ -1,6 +1,6 @@ import { tenantSubdomain } from '@/modules/tenant/tenant-subdomain' import config from '@/config' -import { UnleashIntance } from '@/unleash' +import { UnleashInstance } from '@/unleash' /** * Auth Current Tenant @@ -112,7 +112,7 @@ export default class AuthCurrentTenant { // Refresh feature flags each time tenant is set if (!config.isCommunityVersion) { - await UnleashIntance?.updateContext({ + await UnleashInstance?.updateContext({ automationCount: tenant.automationCount, csvExportCount: tenant.csvExportCount, memberEnrichmentCount: tenant.memberEnrichmentCount, diff --git a/frontend/src/unleash/index.js b/frontend/src/unleash/index.js index 56da6ca554..3e9803d1e6 100644 --- a/frontend/src/unleash/index.js +++ b/frontend/src/unleash/index.js @@ -12,9 +12,9 @@ export const FEATURE_FLAGS = { export class Unleash { constructor() { const unleashConfig = { - url: `${config.unleash.host}/api/frontend`, + url: `${config.unleash.url}/api/frontend`, clientKey: config.unleash.apiKey, - appName: 'test', + appName: 'crowd-web-app', environment: 'production' } @@ -28,7 +28,8 @@ export class Unleash { this.updateContext(context) this.unleash.on('ready', () => { - console.log(this.unleash.getAllToggles()) + console.log('unleash ready') + console.log('toggles', this.unleash.getAllToggles()) }) } @@ -49,4 +50,4 @@ export class Unleash { } } -export const UnleashIntance = new Unleash() +export const UnleashInstance = new Unleash() diff --git a/frontend/vue.config.js b/frontend/vue.config.js index 9baf8fa022..ce9301cd11 100644 --- a/frontend/vue.config.js +++ b/frontend/vue.config.js @@ -24,14 +24,6 @@ module.exports = { pathRewrite: { '^/api': '' } - }, - '/unleash': { - target: - process.env.UNLEASH_URL || - 'http://localhost:4242', - pathRewrite: { - '^/unleash': '' - } } } }, From f0b08279225140465599c204d27f5fed1ad839de Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Fri, 17 Feb 2023 17:51:36 +0000 Subject: [PATCH 39/56] Refactor unleash naming --- frontend/src/app.vue | 17 ++-------- .../linkedin/components/linkedin-connect.vue | 7 ++-- frontend/src/main.js | 4 --- .../src/modules/auth/auth-current-tenant.js | 9 ++---- frontend/src/modules/auth/auth-socket.js | 14 ++------ .../modules/automation/automation-store.js | 32 +++---------------- .../automation/pages/automation-list-page.vue | 9 +++--- .../components/integration-list-item.vue | 6 ++-- .../layout/components/paywall-modal.vue | 13 +++----- .../src/modules/layout/pages/paywall-page.vue | 6 ++-- .../components/settings/_general.vue | 14 ++++---- .../pages/community-help-center-page.vue | 7 ++-- .../src/premium/eagle-eye/eagle-eye-routes.js | 23 ++++++------- .../pages/eagle-eye-onboard-page.vue | 4 +-- .../pages/eagle-eye-page-wrapper.vue | 13 ++++---- frontend/src/unleash/index.js | 30 ++++++++++++----- 16 files changed, 78 insertions(+), 130 deletions(-) diff --git a/frontend/src/app.vue b/frontend/src/app.vue index 29db07d8c5..a0f695ba8a 100644 --- a/frontend/src/app.vue +++ b/frontend/src/app.vue @@ -19,6 +19,7 @@ diff --git a/frontend/src/unleash/index.js b/frontend/src/unleash/index.js index 3e9803d1e6..bc79c7f603 100644 --- a/frontend/src/unleash/index.js +++ b/frontend/src/unleash/index.js @@ -9,7 +9,7 @@ export const FEATURE_FLAGS = { linkedin: 'linkedin' } -export class Unleash { +export class FeatureFlagService { constructor() { const unleashConfig = { url: `${config.unleash.url}/api/frontend`, @@ -22,14 +22,13 @@ export class Unleash { this.unleash = new UnleashClient(unleashConfig) } - init(context) { - this.unleash.start() + init(tenant) { + const context = this.getContextFromTenant(tenant) + this.unleash.start() this.updateContext(context) - this.unleash.on('ready', () => { - console.log('unleash ready') - console.log('toggles', this.unleash.getAllToggles()) + console.log('Unleash is ready') }) } @@ -37,10 +36,25 @@ export class Unleash { return this.unleash.isEnabled(flag) } - updateContext(context) { + updateContext(tenant) { + const context = this.getContextFromTenant(tenant) + this.unleash.updateContext(context) } + getContextFromTenant(tenant) { + return { + tenantId: tenant.id, + tenantName: tenant.name, + isTrialPlan: tenant.isTrialPlan, + email: tenant.email, + automationCount: tenant.automationCount, + csvExportCount: tenant.csvExportCount, + memberEnrichmentCount: tenant.memberEnrichmentCount, + plan: tenant.plan + } + } + premiumFeatureCopy() { if (config.isCommunityVersion) { return 'Premium' @@ -50,4 +64,4 @@ export class Unleash { } } -export const UnleashInstance = new Unleash() +export const FeatureFlag = new FeatureFlagService() From 6c8ca1a7b071c42461e4d9b2a4aa539ffd435228 Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Mon, 20 Feb 2023 16:18:27 +0000 Subject: [PATCH 40/56] Update member enrichment count validation to unleash --- frontend/src/modules/member/member-enrichment.js | 9 ++++++--- frontend/src/modules/member/store/actions.js | 15 ++------------- frontend/src/unleash/index.js | 4 +++- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/frontend/src/modules/member/member-enrichment.js b/frontend/src/modules/member/member-enrichment.js index 74afecf451..d5795355c8 100644 --- a/frontend/src/modules/member/member-enrichment.js +++ b/frontend/src/modules/member/member-enrichment.js @@ -5,6 +5,7 @@ import { formatNumber } from '@/utils/number' import { h } from 'vue' import Message from '@/shared/message/message' import pluralize from 'pluralize' +import { FeatureFlag, FEATURE_FLAGS } from '@/unleash' const growthEnrichmentMax = 1000 const essentialEnrichmentMax = 5 @@ -25,15 +26,17 @@ export const getEnrichmentMax = (plan) => { } /** - * @param {*} memberEnrichmentCount current member enrichment count * @param {*} planEnrichmentCountMax maximum plan enrichment count * @returns if enrichment has reached limit */ export const checkEnrichmentLimit = ( - memberEnrichmentCount, planEnrichmentCountMax ) => { - if (memberEnrichmentCount === planEnrichmentCountMax) { + const isFeatureEnabled = FeatureFlag.isFlagEnabled( + FEATURE_FLAGS.memberEnrichment + ) + + if (!isFeatureEnabled) { ConfirmDialog({ vertical: true, type: 'danger', diff --git a/frontend/src/modules/member/store/actions.js b/frontend/src/modules/member/store/actions.js index 90084f707d..0226d5e666 100644 --- a/frontend/src/modules/member/store/actions.js +++ b/frontend/src/modules/member/store/actions.js @@ -306,19 +306,13 @@ export default { const currentTenant = rootGetters['auth/currentTenant'] - const { memberEnrichmentCount } = currentTenant const planEnrichmentCountMax = getEnrichmentMax( currentTenant.plan ) // Check if it has reached enrichment maximum // If so, show dialog to upgrade plan - if ( - checkEnrichmentLimit( - memberEnrichmentCount, - planEnrichmentCountMax - ) - ) { + if (checkEnrichmentLimit(planEnrichmentCountMax)) { return } @@ -390,12 +384,7 @@ export default { // Check if it has reached enrichment maximum // If so, show dialog to upgrade plan - if ( - checkEnrichmentLimit( - memberEnrichmentCount, - planEnrichmentCountMax - ) - ) { + if (checkEnrichmentLimit(planEnrichmentCountMax)) { return } diff --git a/frontend/src/unleash/index.js b/frontend/src/unleash/index.js index bc79c7f603..59c94d49ec 100644 --- a/frontend/src/unleash/index.js +++ b/frontend/src/unleash/index.js @@ -6,7 +6,9 @@ export const FEATURE_FLAGS = { communityCenterPro: 'community-help-center-pro', organizations: 'organizations', automations: 'automations', - linkedin: 'linkedin' + linkedin: 'linkedin', + memberEnrichment: 'member-enrichment', + csvExport: 'csv-export' } export class FeatureFlagService { From b97c8e9eabfade267330659f4604ca6f0bcdb13b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Tue, 21 Feb 2023 09:42:08 +0100 Subject: [PATCH 41/56] proper service name --- backend/src/api/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/api/index.ts b/backend/src/api/index.ts index 96f3305747..10e9fc829b 100644 --- a/backend/src/api/index.ts +++ b/backend/src/api/index.ts @@ -80,7 +80,7 @@ setImmediate(async () => { if (UNLEASH_CONFIG.url) { const unleash = new Unleash({ url: `${UNLEASH_CONFIG.url}/api`, - appName: 'test', + appName: 'crowd-api', customHeaders: { Authorization: UNLEASH_CONFIG.backendApiKey, }, From 3388533d6b1e814e27c02300e241c30bc5c955b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Tue, 21 Feb 2023 09:43:11 +0100 Subject: [PATCH 42/56] removed test.ts --- backend/src/bin/test.ts | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 backend/src/bin/test.ts diff --git a/backend/src/bin/test.ts b/backend/src/bin/test.ts deleted file mode 100644 index f172c45142..0000000000 --- a/backend/src/bin/test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { startUnleash } from 'unleash-client' -import { getServiceLogger } from '../utils/logging' -import { UNLEASH_CONFIG } from '../config' - -const log = getServiceLogger() - -setImmediate(async () => { - const unleash = await startUnleash({ - url: `${UNLEASH_CONFIG.url}/api`, - appName: 'test', - customHeaders: { - Authorization: UNLEASH_CONFIG.backendApiKey, - }, - }) - - log.info('Unleash client is ready!') - const defs = unleash.getFeatureToggleDefinitions() - console.log(defs) -}) From ea21dd58b98160f53d97cb2f18d42a13a8e12530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Tue, 21 Feb 2023 10:06:22 +0100 Subject: [PATCH 43/56] fixed linting errors --- backend/src/api/index.ts | 2 +- frontend/src/premium/eagle-eye/eagle-eye-routes.js | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/backend/src/api/index.ts b/backend/src/api/index.ts index 10e9fc829b..8c12d4bb22 100644 --- a/backend/src/api/index.ts +++ b/backend/src/api/index.ts @@ -4,7 +4,7 @@ import cors from 'cors' import helmet from 'helmet' import bunyanMiddleware from 'bunyan-middleware' import * as http from 'http' -import { startUnleash, Unleash } from 'unleash-client' +import { Unleash } from 'unleash-client' import { UNLEASH_CONFIG } from '../config' import { authMiddleware } from '../middlewares/authMiddleware' import { tenantMiddleware } from '../middlewares/tenantMiddleware' diff --git a/frontend/src/premium/eagle-eye/eagle-eye-routes.js b/frontend/src/premium/eagle-eye/eagle-eye-routes.js index 33c3a07b48..9bb9e5fbbb 100644 --- a/frontend/src/premium/eagle-eye/eagle-eye-routes.js +++ b/frontend/src/premium/eagle-eye/eagle-eye-routes.js @@ -4,11 +4,6 @@ import Permissions from '@/security/permissions' import { store } from '@/store' import { FeatureFlag } from '@/unleash' -const EagleEyeOnboardPage = () => - import( - '@/premium/eagle-eye/pages/eagle-eye-onboard-page.vue' - ) - const EagleEyeOnboardPage = () => import( '@/premium/eagle-eye/pages/eagle-eye-onboard-page.vue' From 10a3d4c735c18380c3a2897b7abe3f04e8a85ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Tue, 21 Feb 2023 10:08:45 +0100 Subject: [PATCH 44/56] fixed frontend docker entrypoint script --- frontend/scripts/docker-entrypoint.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/scripts/docker-entrypoint.sh b/frontend/scripts/docker-entrypoint.sh index 9840e2df2d..b7f2b334aa 100755 --- a/frontend/scripts/docker-entrypoint.sh +++ b/frontend/scripts/docker-entrypoint.sh @@ -21,8 +21,6 @@ declare -a ENV_VARIABLES=( "VUE_APP_ENV" "VUE_APP_PIZZLY_URL" "VUE_APP_PIZZLY_PUBLISHABLE_KEY" - "VUE_APP_UNLEASH_API_KEY" - "VUE_APP_UNLEASH_HOST" "VUE_APP_TYPEFORM_ID" "VUE_APP_TYPEFORM_TITLE" "VUE_APP_FORMBRICKS_URL" @@ -31,6 +29,7 @@ declare -a ENV_VARIABLES=( "VUE_APP_STRIPE_GROWTH_PLAN_PAYMENT_LINK" "VUE_APP_STRIPE_CUSTOMER_PORTAL_LINK" "VUE_APP_UNLEASH_URL" + "VUE_APP_UNLEASH_API_KEY" ) for ENV_VAR in "${ENV_VARIABLES[@]}" From 6b7ba4a726908c3b563bd9eea99618f29fb35a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Tue, 21 Feb 2023 10:18:23 +0100 Subject: [PATCH 45/56] fixes --- scripts/cli | 17 ----------------- scripts/services/frontend.yaml | 2 -- 2 files changed, 19 deletions(-) diff --git a/scripts/cli b/scripts/cli index d0d818fa39..f9c0b1daad 100755 --- a/scripts/cli +++ b/scripts/cli @@ -347,18 +347,6 @@ function create_s3_buckets() { # done } -function create_qdrant_collection() { - say "Creating Qdrant collection!" - curl -X PUT 'http://localhost:6333/collections/crowddev' \ - -H 'Content-Type: application/json' \ - --data-raw '{ - "vectors": { - "size": 768, - "distance": "Cosine" - } - }' -} - function init_unleash() { (cd $CLI_HOME/../backend && source source-local.sh && npm i && npm run script:unleash-init) } @@ -369,7 +357,6 @@ function up_scaffold() { wait_for_db migrate_local create_s3_buckets - # create_qdrant_collection bash pizzly-integrations.sh init_unleash } @@ -597,10 +584,6 @@ do restore_db_backup $2 exit; ;; - test-unleash) - init_unleash - exit; - ;; *) error "Invalid command '$1'" && say "$SCRIPT_USAGE" exit 1; ;; diff --git a/scripts/services/frontend.yaml b/scripts/services/frontend.yaml index 49d6fec89c..b3ea23628d 100644 --- a/scripts/services/frontend.yaml +++ b/scripts/services/frontend.yaml @@ -14,7 +14,6 @@ services: environment: - DOCKER_BUILDKIT=1 - BACKEND_URL=http://api:8080 - - UNLEASH_URL=http://unleash:4242 ports: - '8081:8081' restart: always @@ -34,7 +33,6 @@ services: environment: - DOCKER_BUILDKIT=1 - BACKEND_URL=http://api:8080 - - UNLEASH_URL=http://unleash:4242 ports: - '8081:8081' networks: From 65e09246017b74faabb339c200cf5117ccdba4f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Tue, 21 Feb 2023 09:45:57 +0100 Subject: [PATCH 46/56] removed premium-api, premium-job-generator and premium-python-worker services and old eagle eye code --- .github/workflows/production-deploy.yaml | 108 - .../staging-deploy-premium-job-generator.yaml | 57 - ...staging-deploy-premium-python-backend.yaml | 74 - backend/.env.dist.composed | 4 - backend/.env.dist.local | 6 - .../config/custom-environment-variables.json | 4 +- backend/src/config/configTypes.ts | 2 - backend/src/config/index.ts | 1 - premium/eagle-eye/.dockerignore | 3 - premium/eagle-eye/.gitignore | 3 - premium/eagle-eye/.python-version | 1 - premium/eagle-eye/Dockerfile | 19 - premium/eagle-eye/Dockerfile.kube | 15 - .../crowd/eagle_eye/__init__.py | 5 - .../crowd/eagle_eye/apis/__init__.py | 8 - .../crowd/eagle_eye/apis/embed_api.py | 64 - .../crowd/eagle_eye/apis/vector_api.py | 299 - .../crowd-eagle-eye/crowd/eagle_eye/config.py | 33 - .../crowd/eagle_eye/infrastructure/logging.py | 32 - .../crowd/eagle_eye/infrastructure/sqs.py | 135 - .../crowd-eagle-eye/crowd/eagle_eye/models.py | 122 - .../crowd/eagle_eye/scheduled.py | 40 - .../crowd-eagle-eye/crowd/eagle_eye/search.py | 113 - .../crowd/eagle_eye/sources/__init__.py | 3 - .../crowd/eagle_eye/sources/devto.py | 158 - .../crowd/eagle_eye/sources/hacker_news.py | 68 - .../crowd/eagle_eye/sources/post_process.py | 130 - .../eagle_eye/sources/test/test_devto.py | 220 - .../sources/test/test_hacker_news.py | 115 - .../crowd-eagle-eye/crowd/eagle_eye/sync.py | 34 - .../crowd/eagle_eye/test/test_search.py | 106 - premium/eagle-eye/crowd-eagle-eye/setup.py | 19 - premium/eagle-eye/data.json | 1 - premium/eagle-eye/hacker_news.csv | 550 - premium/eagle-eye/hacker_news_processed.csv | 3289 ----- premium/eagle-eye/handler.py | 29 - premium/eagle-eye/local_events/devto.json | 3 - premium/eagle-eye/local_events/hn.json | 3 - premium/eagle-eye/local_events/search.json | 5 - premium/eagle-eye/package-lock.json | 11532 ---------------- premium/eagle-eye/package.json | 18 - premium/eagle-eye/requirements-serverless.txt | 1 - premium/eagle-eye/requirements.txt | 5 - premium/eagle-eye/server.py | 41 - premium/eagle-eye/serverless.yml | 77 - premium/eagle-eye/start-premium-api.sh | 4 - .../eagle-eye/start-premium-python-worker.sh | 4 - premium/eagle-eye/worker.py | 19 - premium/job-generator/.dockerignore | 3 - premium/job-generator/.eslintrc.js | 70 - premium/job-generator/.prettierignore | 2 - premium/job-generator/.prettierrc | 7 - premium/job-generator/Dockerfile | 9 - premium/job-generator/babel.config.json | 5 - .../config/custom-environment-variables.json | 15 - premium/job-generator/config/default.json | 3 - premium/job-generator/config/docker.json | 1 - premium/job-generator/config/production.json | 1 - premium/job-generator/config/staging.json | 1 - premium/job-generator/config/test.json | 1 - premium/job-generator/package-lock.json | 10527 -------------- premium/job-generator/package.json | 32 - premium/job-generator/src/aws.ts | 17 - premium/job-generator/src/config.ts | 23 - premium/job-generator/src/job-generator.ts | 25 - .../src/jobs/eagleEyeRefreshJob.ts | 30 - premium/job-generator/src/jobs/index.ts | 6 - premium/job-generator/src/logging.ts | 67 - .../src/premiumPythonWorkerSQS.ts | 29 - premium/job-generator/src/types.ts | 27 - premium/job-generator/tsconfig.json | 18 - scripts/builders/premium-job-generator.sh | 5 - scripts/builders/premium-python-backend.sh | 5 - scripts/cli | 18 +- scripts/scaffold.yaml | 8 - scripts/services/premium-api.yaml | 44 - scripts/services/premium-job-generator.yaml | 47 - scripts/services/premium-python-worker.yaml | 44 - start.sh | 50 - 79 files changed, 10 insertions(+), 28712 deletions(-) delete mode 100644 .github/workflows/staging-deploy-premium-job-generator.yaml delete mode 100644 .github/workflows/staging-deploy-premium-python-backend.yaml delete mode 100644 premium/eagle-eye/.dockerignore delete mode 100644 premium/eagle-eye/.gitignore delete mode 100644 premium/eagle-eye/.python-version delete mode 100644 premium/eagle-eye/Dockerfile delete mode 100644 premium/eagle-eye/Dockerfile.kube delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/__init__.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/apis/__init__.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/apis/embed_api.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/apis/vector_api.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/config.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/infrastructure/logging.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/infrastructure/sqs.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/models.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/scheduled.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/search.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/__init__.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/devto.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/hacker_news.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/post_process.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/test/test_devto.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/test/test_hacker_news.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sync.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/test/test_search.py delete mode 100644 premium/eagle-eye/crowd-eagle-eye/setup.py delete mode 100644 premium/eagle-eye/data.json delete mode 100644 premium/eagle-eye/hacker_news.csv delete mode 100644 premium/eagle-eye/hacker_news_processed.csv delete mode 100644 premium/eagle-eye/handler.py delete mode 100644 premium/eagle-eye/local_events/devto.json delete mode 100644 premium/eagle-eye/local_events/hn.json delete mode 100644 premium/eagle-eye/local_events/search.json delete mode 100644 premium/eagle-eye/package-lock.json delete mode 100644 premium/eagle-eye/package.json delete mode 100644 premium/eagle-eye/requirements-serverless.txt delete mode 100644 premium/eagle-eye/requirements.txt delete mode 100644 premium/eagle-eye/server.py delete mode 100644 premium/eagle-eye/serverless.yml delete mode 100755 premium/eagle-eye/start-premium-api.sh delete mode 100755 premium/eagle-eye/start-premium-python-worker.sh delete mode 100644 premium/eagle-eye/worker.py delete mode 100644 premium/job-generator/.dockerignore delete mode 100644 premium/job-generator/.eslintrc.js delete mode 100644 premium/job-generator/.prettierignore delete mode 100644 premium/job-generator/.prettierrc delete mode 100644 premium/job-generator/Dockerfile delete mode 100644 premium/job-generator/babel.config.json delete mode 100644 premium/job-generator/config/custom-environment-variables.json delete mode 100644 premium/job-generator/config/default.json delete mode 100644 premium/job-generator/config/docker.json delete mode 100644 premium/job-generator/config/production.json delete mode 100644 premium/job-generator/config/staging.json delete mode 100644 premium/job-generator/config/test.json delete mode 100644 premium/job-generator/package-lock.json delete mode 100644 premium/job-generator/package.json delete mode 100644 premium/job-generator/src/aws.ts delete mode 100644 premium/job-generator/src/config.ts delete mode 100644 premium/job-generator/src/job-generator.ts delete mode 100644 premium/job-generator/src/jobs/eagleEyeRefreshJob.ts delete mode 100644 premium/job-generator/src/jobs/index.ts delete mode 100644 premium/job-generator/src/logging.ts delete mode 100644 premium/job-generator/src/premiumPythonWorkerSQS.ts delete mode 100644 premium/job-generator/src/types.ts delete mode 100644 premium/job-generator/tsconfig.json delete mode 100644 scripts/builders/premium-job-generator.sh delete mode 100644 scripts/builders/premium-python-backend.sh delete mode 100644 scripts/services/premium-api.yaml delete mode 100644 scripts/services/premium-job-generator.yaml delete mode 100644 scripts/services/premium-python-worker.yaml delete mode 100755 start.sh diff --git a/.github/workflows/production-deploy.yaml b/.github/workflows/production-deploy.yaml index cfd805244d..95dae69638 100644 --- a/.github/workflows/production-deploy.yaml +++ b/.github/workflows/production-deploy.yaml @@ -27,18 +27,6 @@ on: description: Deploy frontend? required: true type: boolean - deploy_premium_api: - description: Deploy premium-api service? - required: true - type: boolean - deploy_premium_python_worker: - description: Deploy premium-python-worker service? - required: true - type: boolean - deploy_premium_job_generator: - description: Deploy premium-job-generator service? - required: true - type: boolean env: DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} @@ -114,48 +102,6 @@ jobs: id: image run: echo "IMAGE=${{ steps.image-builder.outputs.image }}" >> $GITHUB_OUTPUT - build-and-push-premium-job-generator: - runs-on: ubuntu-latest - if: ${{ inputs.deploy_premium_job_generator }} - outputs: - image: ${{ steps.image.outputs.IMAGE }} - defaults: - run: - shell: bash - steps: - - name: Check out repository code - uses: actions/checkout@v2 - - - uses: ./.github/actions/build-docker-image - id: image-builder - with: - image: premium-job-generator - - - name: Set docker image output - id: image - run: echo "IMAGE=${{ steps.image-builder.outputs.image }}" >> $GITHUB_OUTPUT - - build-and-push-premium-python-backend: - runs-on: ubuntu-latest - if: ${{ inputs.deploy_premium_api || inputs.deploy_premium_python_worker }} - outputs: - image: ${{ steps.image.outputs.IMAGE }} - defaults: - run: - shell: bash - steps: - - name: Check out repository code - uses: actions/checkout@v2 - - - uses: ./.github/actions/build-docker-image - id: image-builder - with: - image: premium-python-backend - - - name: Set docker image output - id: image - run: echo "IMAGE=${{ steps.image-builder.outputs.image }}" >> $GITHUB_OUTPUT - deploy-api: needs: build-and-push-backend runs-on: ubuntu-latest @@ -262,57 +208,3 @@ jobs: service: python-worker image: ${{ needs.build-and-push-python-worker.outputs.image }} cluster: ${{ env.CROWD_CLUSTER }} - - deploy-premium-job-generator: - needs: build-and-push-premium-job-generator - runs-on: ubuntu-latest - if: ${{ inputs.deploy_premium_job_generator }} - defaults: - run: - shell: bash - - steps: - - name: Check out repository code - uses: actions/checkout@v2 - - - uses: ./.github/actions/deploy-service - with: - service: premium-job-generator - image: ${{ needs.build-and-push-premium-job-generator.outputs.image }} - cluster: ${{ env.CROWD_CLUSTER }} - - deploy-premium-python-worker: - needs: build-and-push-premium-python-backend - runs-on: ubuntu-latest - if: ${{ inputs.deploy_premium_python_worker }} - defaults: - run: - shell: bash - - steps: - - name: Check out repository code - uses: actions/checkout@v2 - - - uses: ./.github/actions/deploy-service - with: - service: premium-python-worker - image: ${{ needs.build-and-push-premium-python-backend.outputs.image }} - cluster: ${{ env.CROWD_CLUSTER }} - - deploy-premium-api: - needs: build-and-push-premium-python-backend - runs-on: ubuntu-latest - if: ${{ inputs.deploy_premium_api }} - defaults: - run: - shell: bash - - steps: - - name: Check out repository code - uses: actions/checkout@v2 - - - uses: ./.github/actions/deploy-service - with: - service: premium-api - image: ${{ needs.build-and-push-premium-python-backend.outputs.image }} - cluster: ${{ env.CROWD_CLUSTER }} diff --git a/.github/workflows/staging-deploy-premium-job-generator.yaml b/.github/workflows/staging-deploy-premium-job-generator.yaml deleted file mode 100644 index e90ad416a5..0000000000 --- a/.github/workflows/staging-deploy-premium-job-generator.yaml +++ /dev/null @@ -1,57 +0,0 @@ -name: Staging Deploy Premium Job Generator service - -on: - push: - branches: - - 'staging/**' - paths: - - 'premium/job-generator/**' - -env: - DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} - DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} - CROWD_CLUSTER: ${{ secrets.STAGING_CLUSTER_NAME }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_REGION: ${{ secrets.AWS_REGION }} - SLACK_CHANNEL: deploys-staging - SLACK_WEBHOOK: ${{ secrets.STAGING_SLACK_CHANNEL_HOOK }} - -jobs: - build-and-push: - runs-on: ubuntu-latest - outputs: - image: ${{ steps.image.outputs.IMAGE }} - defaults: - run: - shell: bash - - steps: - - name: Check out repository code - uses: actions/checkout@v2 - - - uses: ./.github/actions/build-docker-image - id: image-builder - with: - image: premium-job-generator - - - name: Set docker image output - id: image - run: echo "IMAGE=${{ steps.image-builder.outputs.image }}" >> $GITHUB_OUTPUT - - deploy-premium-job-generator: - needs: build-and-push - runs-on: ubuntu-latest - defaults: - run: - shell: bash - - steps: - - name: Check out repository code - uses: actions/checkout@v2 - - - uses: ./.github/actions/deploy-service - with: - service: premium-job-generator - image: ${{ needs.build-and-push.outputs.image }} - cluster: ${{ env.CROWD_CLUSTER }} diff --git a/.github/workflows/staging-deploy-premium-python-backend.yaml b/.github/workflows/staging-deploy-premium-python-backend.yaml deleted file mode 100644 index 53d140873c..0000000000 --- a/.github/workflows/staging-deploy-premium-python-backend.yaml +++ /dev/null @@ -1,74 +0,0 @@ -name: Staging Deploy Premium Python Backend services - -on: - push: - branches: - - 'staging/**' - paths: - - 'premium/eagle-eye/**' - -env: - DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} - DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} - CROWD_CLUSTER: ${{ secrets.STAGING_CLUSTER_NAME }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_REGION: ${{ secrets.AWS_REGION }} - SLACK_CHANNEL: deploys-staging - SLACK_WEBHOOK: ${{ secrets.STAGING_SLACK_CHANNEL_HOOK }} - -jobs: - build-and-push: - runs-on: ubuntu-latest - outputs: - image: ${{ steps.image.outputs.IMAGE }} - defaults: - run: - shell: bash - - steps: - - name: Check out repository code - uses: actions/checkout@v2 - - - uses: ./.github/actions/build-docker-image - id: image-builder - with: - image: premium-python-backend - - - name: Set docker image output - id: image - run: echo "IMAGE=${{ steps.image-builder.outputs.image }}" >> $GITHUB_OUTPUT - - deploy-premium-python-worker: - needs: build-and-push - runs-on: ubuntu-latest - defaults: - run: - shell: bash - - steps: - - name: Check out repository code - uses: actions/checkout@v2 - - - uses: ./.github/actions/deploy-service - with: - service: premium-python-worker - image: ${{ needs.build-and-push.outputs.image }} - cluster: ${{ env.CROWD_CLUSTER }} - - deploy-premium-api: - needs: build-and-push - runs-on: ubuntu-latest - defaults: - run: - shell: bash - - steps: - - name: Check out repository code - uses: actions/checkout@v2 - - - uses: ./.github/actions/deploy-service - with: - service: premium-api - image: ${{ needs.build-and-push.outputs.image }} - cluster: ${{ env.CROWD_CLUSTER }} diff --git a/backend/.env.dist.composed b/backend/.env.dist.composed index 8221924b62..dae8b42ad6 100644 --- a/backend/.env.dist.composed +++ b/backend/.env.dist.composed @@ -1,13 +1,9 @@ -# Api settings -CROWD_PREMIUM_API_URL=http://premium-api:5000 - # SQS settings CROWD_SQS_HOST="sqs" CROWD_SQS_ENDPOINT=http://sqs:9324 CROWD_SQS_NODEJS_WORKER_QUEUE="http://sqs:9324/000000000000/nodejs-worker.fifo" CROWD_SQS_NODEJS_WORKER_DELAYABLE_QUEUE=http://sqs:9324/000000000000/nodejs-worker CROWD_SQS_PYTHON_WORKER_QUEUE="http://sqs:9324/000000000000/python-worker.fifo" -CROWD_SQS_PREMIUM_PYTHON_WORKER_QUEUE="http://sqs:9324/000000000000/premium-python-worker.fifo" # Redis settings CROWD_REDIS_HOST=redis diff --git a/backend/.env.dist.local b/backend/.env.dist.local index 6b1cffc435..9bfbbf1c08 100755 --- a/backend/.env.dist.local +++ b/backend/.env.dist.local @@ -9,7 +9,6 @@ CROWD_API_FRONTEND_URL=http://localhost:8081 CROWD_API_FRONTEND_URL_WITH_SUBDOMAINS= CROWD_API_JWT_SECRET=your-secret CROWD_API_JWT_EXPIRES_IN='100 years' -CROWD_PREMIUM_API_URL=http://localhost:5000 # SQS settings CROWD_SQS_HOST=localhost @@ -18,7 +17,6 @@ CROWD_SQS_ENDPOINT=http://localhost:9324 CROWD_SQS_NODEJS_WORKER_QUEUE=http://localhost:9324/000000000000/nodejs-worker.fifo CROWD_SQS_NODEJS_WORKER_DELAYABLE_QUEUE=http://localhost:9324/000000000000/nodejs-worker CROWD_SQS_PYTHON_WORKER_QUEUE=http://localhost:9324/000000000000/python-worker.fifo -CROWD_SQS_PREMIUM_PYTHON_WORKER_QUEUE=http://localhost:9324/000000000000/premium-python-worker.fifo CROWD_SQS_AWS_ACCOUNT_ID=000000000000 CROWD_SQS_AWS_ACCESS_KEY_ID=x CROWD_SQS_AWS_SECRET_ACCESS_KEY=x @@ -127,10 +125,6 @@ CROWD_PIZZLY_INTEGRATIONS=reddit,linkedin # Cohere settings CROWD_COHERE_API_KEY= -# Vector settings -CROWD_QDRANT_HOST=qdrant -CROWD_QDRANT_PORT=6333 - # Enrichment settings CROWD_ENRICHMENT_URL= CROWD_ENRICHMENT_API_KEY= diff --git a/backend/config/custom-environment-variables.json b/backend/config/custom-environment-variables.json index 09bff12be8..851c3ac5d2 100644 --- a/backend/config/custom-environment-variables.json +++ b/backend/config/custom-environment-variables.json @@ -5,8 +5,7 @@ "frontendUrl": "CROWD_API_FRONTEND_URL", "frontendUrlWithSubdomain": "CROWD_API_FRONTEND_URL_WITH_SUBDOMAINS", "jwtSecret": "CROWD_API_JWT_SECRET", - "jwtExpiresIn": "CROWD_API_JWT_EXPIRES_IN", - "premiumApiUrl": "CROWD_PREMIUM_API_URL" + "jwtExpiresIn": "CROWD_API_JWT_EXPIRES_IN" }, "redis": { "username": "CROWD_REDIS_USERNAME", @@ -20,7 +19,6 @@ "nodejsWorkerQueue": "CROWD_SQS_NODEJS_WORKER_QUEUE", "nodejsWorkerDelayableQueue": "CROWD_SQS_NODEJS_WORKER_DELAYABLE_QUEUE", "pythonWorkerQueue": "CROWD_SQS_PYTHON_WORKER_QUEUE", - "premiumPythonWorkerQueue": "CROWD_SQS_PREMIUM_PYTHON_WORKER_QUEUE", "aws": { "accountId": "CROWD_SQS_AWS_ACCOUNT_ID", "accessKeyId": "CROWD_SQS_AWS_ACCESS_KEY_ID", diff --git a/backend/src/config/configTypes.ts b/backend/src/config/configTypes.ts index 0e9561b784..c58e190ffa 100644 --- a/backend/src/config/configTypes.ts +++ b/backend/src/config/configTypes.ts @@ -30,7 +30,6 @@ export interface SQSConfiguration { nodejsWorkerQueue: string nodejsWorkerDelayableQueue: string pythonWorkerQueue: string - premiumPythonWorkerQueue: string aws: AwsCredentials } @@ -84,7 +83,6 @@ export interface ApiConfiguration { url: string frontendUrl: string frontendUrlWithSubdomain: string - premiumApiUrl: string edition: string jwtSecret: string jwtExpiresIn: string diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 8540ad7ebf..a617968247 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -124,7 +124,6 @@ export const API_CONFIG: ApiConfiguration = KUBE_MODE frontendUrlWithSubdomain: process.env.FRONTEND_URL_WITH_SUBDOMAIN, jwtSecret: process.env.AUTH_JWT_SECRET, jwtExpiresIn: process.env.AUTH_JWT_EXPIRES_IN, - premiumApiUrl: '', } export const PLANS_CONFIG: PlansConfiguration = KUBE_MODE ? config.get('plans') diff --git a/premium/eagle-eye/.dockerignore b/premium/eagle-eye/.dockerignore deleted file mode 100644 index 984fbdcd76..0000000000 --- a/premium/eagle-eye/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -.env -**/venv* -Dockerfile* \ No newline at end of file diff --git a/premium/eagle-eye/.gitignore b/premium/eagle-eye/.gitignore deleted file mode 100644 index a78fdba7ea..0000000000 --- a/premium/eagle-eye/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.env* -**/build -**/qdrant_storage \ No newline at end of file diff --git a/premium/eagle-eye/.python-version b/premium/eagle-eye/.python-version deleted file mode 100644 index c7413b842f..0000000000 --- a/premium/eagle-eye/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.8.14 diff --git a/premium/eagle-eye/Dockerfile b/premium/eagle-eye/Dockerfile deleted file mode 100644 index 3b5ec64138..0000000000 --- a/premium/eagle-eye/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ - -FROM public.ecr.aws/lambda/python:3.8 as builder - -RUN yum -y install gcc gcc-c++ - -WORKDIR /var/task - -COPY . . - -RUN pip3 install datadog-lambda && \ - pip3 install -r requirements.txt - -FROM public.ecr.aws/lambda/python:3.8 -COPY --from=public.ecr.aws/datadog/lambda-extension:latest /opt/extensions /opt/extensions -COPY --from=builder /var/task /var/task -COPY --from=builder /var/lang/lib/python3.8/site-packages /var/lang/lib/python3.8/site-packages - -# You can overwrite command in `serverless.yml` template -CMD ["datadog_lambda.handler.handler"] \ No newline at end of file diff --git a/premium/eagle-eye/Dockerfile.kube b/premium/eagle-eye/Dockerfile.kube deleted file mode 100644 index 19f37e0260..0000000000 --- a/premium/eagle-eye/Dockerfile.kube +++ /dev/null @@ -1,15 +0,0 @@ -FROM python:3.8-bullseye - -RUN apt install -y --no-install-recommends gcc - -WORKDIR /var/task - -COPY ./requirements.txt ./ -COPY ./crowd-eagle-eye/setup.py ./crowd-eagle-eye/ - -RUN python -m venv --copies ./venv && . ./venv/bin/activate && ./venv/bin/pip install -r requirements.txt - -COPY . . - -USER root -RUN mkdir /.cache && chmod -R 777 /.cache diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/__init__.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/__init__.py deleted file mode 100644 index 6400313a19..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from crowd.eagle_eye.config import KUBE_MODE - -if not KUBE_MODE: - import dotenv - dotenv.load_dotenv() diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/apis/__init__.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/apis/__init__.py deleted file mode 100644 index 9f6546845f..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/apis/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from crowd.eagle_eye.apis.embed_api import EmbedAPI # noqa -from crowd.eagle_eye.apis.vector_api import VectorAPI # noqa -from crowd.eagle_eye.config import KUBE_MODE - -if not KUBE_MODE: - import dotenv - found = dotenv.find_dotenv(".env") - dotenv.load_dotenv(found) diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/apis/embed_api.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/apis/embed_api.py deleted file mode 100644 index 731718bca5..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/apis/embed_api.py +++ /dev/null @@ -1,64 +0,0 @@ -from sentence_transformers import SentenceTransformer - - -class EmbedAPI: - """ - API for embedding vectors. - """ - - def __init__(self, truncate='LEFT'): - """ - Embed constructor. - - Args: - model (str, optional): Which model to use. Defaults to 'medium'. - truncate (str, optional): LEFT or RIGHT. If the text is too long, - give preference to left or right hand side. - Defaults to 'LEFT'. - """ - self.model = SentenceTransformer('multi-qa-mpnet-base-dot-v1') - self.truncate = truncate - - def embed_points(self, points): - """ - Embed a list of points. - - Args: - points ([Point]): List of Points. - - Returns: - [Point]: Same list of points, with the embed field filled in. - """ - texts = [point.combined for point in points] - embeds = self.embed_texts(texts) - for point, embed in zip(points, embeds): - point.embed = embed - return points - - def embed_texts(self, texts): - """ - Embed a list of texts - - Args: - texts ([str]): list of texts to embed. - - Returns: - [[[float]]]: list of vectors - """ - vectors = [] - for text in texts: - vectors.append(self.model.encode(text).tolist()) - - return vectors - - def embed_one(self, text): - """ - Embed one text. - - Args: - text (str): text to embed - - Returns: - [[float]]: embed vector - """ - return self.embed_texts([text, ])[0] diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/apis/vector_api.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/apis/vector_api.py deleted file mode 100644 index c4747536d3..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/apis/vector_api.py +++ /dev/null @@ -1,299 +0,0 @@ -from qdrant_client import QdrantClient -from qdrant_client.http import models -import datetime -import time -from crowd.eagle_eye.apis import EmbedAPI -import itertools -from crowd.eagle_eye.config import QDRANT_HOST, QDRANT_PORT, QDRANT_API_KEY, IS_DEV_ENV -from crowd.eagle_eye.infrastructure.logging import get_logger - -logger = get_logger(__name__) - - -class VectorAPI: - """ - Class to interact with the vector database. - """ - - def __init__(self, do_init=False, cloud=True): - """ - Initialize the VectorAPI. - - Args: - index_name (str, optional): Name of the DB index. Defaults to "crowddev". - """ - self.collection_name = "crowddev" - - if cloud: - - if IS_DEV_ENV: - self.client = QdrantClient(host=QDRANT_HOST, port=QDRANT_PORT) - - else: - self.client = QdrantClient( - host=QDRANT_HOST, - port=QDRANT_PORT, - prefer_grpc=True, - api_key=QDRANT_API_KEY, - ) - - else: - if IS_DEV_ENV: - self.client = QdrantClient(host='localhost', port=6333) - else: - self.client = QdrantClient(host='crowd-qdrant', port=6333) - - if do_init: - self.client.recreate_collection( - collection_name=self.collection_name, - vectors_config=models.VectorParams(size=768, distance=models.Distance.COSINE), - ) - for field_name in ['title', 'text', 'url']: - self.client.create_payload_index( - collection_name=self.collection_name, - field_name=field_name, - field_schema=models.TextIndexParams( - type="text", - tokenizer=models.TokenizerType.WORD, - min_token_len=2, - max_token_len=15, - lowercase=True, - ) - ) - - @staticmethod - def _chunks(iterable, batch_size=80): - """A helper function to break an iterable into chunks of size batch_size. - https://www.pinecone.io/docs/insert-data/#batching-upserts. - - Args: - iterable (iterable): The iterable to break into chunks. - batch_size (int, optional): The size of each chunk. Defaults to 80. - """ - it = iter(iterable) - chunk = list(itertools.islice(it, batch_size)) - while chunk: - yield chunk - chunk = list(itertools.islice(it, batch_size)) - - def upsert(self, points, processed=False): - """ - Upsert a list of points into the vector database. - - Args: - points ([Point]): points to upsert. - processed (Bool): whether the points have already been turned into Qdrant vectors - """ - - if (len(points) == 0): - return - - if not processed: - vectors = [ - models.PointStruct( - id=point.id, - payload=point.payload_as_dict(), - vector=point.embed, - ) for point in points - ] - else: - vectors = points - - for vectors_chunk in VectorAPI._chunks(vectors, batch_size=100): - try: - self.client.upsert( - collection_name=self.collection_name, - points=vectors_chunk - ) - except Exception as e: - logger.error("Error in upsert: %s", {'error': e, 'points': vectors_chunk}) - raise e - - return "OK" - - def count(self): - """ - Count the number of vectors in a collection. - """ - return self.client.count( - collection_name=self.collection_name, - exact=True, - ) - - @ staticmethod - def _get_timestamp(ndays, start=int(time.time())): - """ - Get the unix timestamp for a given number of days ago. - - Args: - ndays (int): number of days ago. - start (int, optional): start timestamp. Defaults to int(time.time()). - - Returns: - int: timestamp - """ - now = datetime.datetime.fromtimestamp(start) - return int((now - datetime.timedelta(days=ndays)).timestamp()) - - def find_existing_ids(self, ids): - """ - Given a list of ids, find which ones already exist in the vector database. - - Args: - ids ([str]): list of ids to find. - - Returns: - [str]: list of existing ids. - """ - try: - existing = self.client.retrieve( - collection_name=self.collection_name, - ids=ids, - ) - - return [point.id for point in existing] - except Exception as e: - logger.error("Error in find_existing_ids: %s", e) - raise e - - def delete(self, ids): - """ - Delete a list of ids from the vector database. - - Args: - ids ([str]): list of ids to delete. - - Returns: - str: success message. - """ - if type(ids) == str: - ids = [ids] - self.client.delete( - collection_name=self.collection_name, - points_selector=models.PointIdsList( - points=ids - ), - ) - - def make_filters(self, ndays, exclude, exact_keywords, platform=None): - """ - Make filters for search or scrolling - - Args: - ndays (int): number of days ago to search - exclude ([int]): List of IDs to exclude - exact_keywords ([str]): List of keywords to match exactly. It will match any. - - Returns: - models.Filter: Qdrant filter - """ - start = self._get_timestamp(ndays) - should = [] - - exclude = [int(e) for e in exclude] - - if exact_keywords: - for exact_keyword in exact_keywords: - for key in ['title', 'text', 'url']: - should.append( - models.FieldCondition( - key=key, - match=models.MatchText(text=exact_keyword.lower()), - ) - ) - must = [ - models.FieldCondition( - key="timestamp", - range=models.Range( - gte=start, - ), - ) - ] - if platform: - must.append( - models.FieldCondition( - key="platform", - match=models.MatchText(text=platform), - ) - ) - return models.Filter( - must=must, - should=should, - must_not=[ - models.HasIdCondition(has_id=exclude), - ] - ) - - def search(self, query, ndays, exclude, exact_keywords=False, embed_api=None): - """ - Perform a search on the vector database. - We can set number of days ago, and exclude certain ids. - - Args: - query (str): query to perform, for example a keyword - ndays (int): maximum number of days ago to search - exclude ([str]): list of ids to exclude from the search - embed_api (EmbedAPI, optional): Already initialised EmbedAPI. Defaults to None. - - Returns: - [dict]: list of results - """ - try: - if embed_api is None: - embed_api = EmbedAPI() - # Embed the query into a vector - vector = embed_api.embed_one(query) - - return self.client.search( - collection_name=self.collection_name, - query_vector=vector, - limit=20, - score_threshold=0.1, - query_filter=self.make_filters(ndays, exclude, exact_keywords), - with_payload=True, - ) - except Exception as e: - logger.error("Error in search: %s", { - 'error': e, - 'query': query, - 'ndays': ndays, - 'exclude': exclude, - 'exact_keywords': exact_keywords, - }) - raise e - - def keyword_match(self, ndays, exclude, exact_keywords, platform=None): - try: - ndays = min(ndays, 10000) - return self.client.scroll( - collection_name=self.collection_name, - scroll_filter=self.make_filters(ndays, exclude, exact_keywords, platform), - limit=100, - with_payload=True, - ) - except Exception as e: - logger.error("Error in keyword_match: %s", { - 'error': e, - 'ndays': ndays, - 'exclude': exclude, - 'exact_keywords': exact_keywords, - }) - raise e - - def scroll(self, page): - """ - Iterate through points with pagination. - - Args: - next_page (int): the page to fetch - - Returns: - tuple(list, int): (vectors, next page) - """ - return self.client.scroll( - collection_name=self.collection_name, - offset=page, - limit=100, - with_payload=True, - with_vectors=True, - ) diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/config.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/config.py deleted file mode 100644 index cb4b0614f0..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/config.py +++ /dev/null @@ -1,33 +0,0 @@ -import os - -KUBE_MODE = os.environ.get("KUBE_MODE") is not None - -IS_TEST_ENV = os.environ.get("SERVICE_ENV") == "test" -IS_DEV_ENV = os.environ.get("SERVICE_ENV") == "development" or \ - os.environ.get("SERVICE_ENV") == "docker" or \ - os.environ.get("SERVICE_ENV") is None -IS_PROD_ENV = os.environ.get("SERVICE_ENV") == "production" -IS_STAGING_ENV = os.environ.get("SERVICE_ENV") == "staging" - -SERVICE = os.environ.get("SERVICE") - -LOG_LEVEL = os.environ.get("LOG_LEVEL") or "INFO" -if LOG_LEVEL == "TRACE": - LOG_LEVEL = "DEBUG" -elif LOG_LEVEL == "FATAL": - LOG_LEVEL = "CRITICAL" -elif LOG_LEVEL == "WARN": - LOG_LEVEL = "WARNING" - -QDRANT_HOST = os.environ.get("CROWD_QDRANT_HOST") -QDRANT_PORT = os.environ.get("CROWD_QDRANT_PORT") -QDRANT_API_KEY = os.environ.get("CROWD_QDRANT_API_KEY") - -SQS_HOST = os.environ.get("CROWD_SQS_HOST") -SQS_PORT = os.environ.get("CROWD_SQS_PORT") -SQS_ENDPOINT_URL = f"http://{SQS_HOST}:{SQS_PORT}" if IS_DEV_ENV else None -SQS_ACCESS_KEY_ID = os.environ.get("CROWD_SQS_AWS_ACCESS_KEY_ID") -SQS_SECRET_ACCESS_KEY = os.environ.get("CROWD_SQS_AWS_SECRET_ACCESS_KEY") -SQS_REGION = os.environ.get("CROWD_SQS_AWS_REGION") - -PREMIUM_PYTHON_WORKER_QUEUE = os.environ.get("CROWD_SQS_PREMIUM_PYTHON_WORKER_QUEUE") diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/infrastructure/logging.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/infrastructure/logging.py deleted file mode 100644 index b77ad90a00..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/infrastructure/logging.py +++ /dev/null @@ -1,32 +0,0 @@ -import logging -from datetime import datetime - -from pythonjsonlogger import jsonlogger -from crowd.eagle_eye.config import SERVICE, LOG_LEVEL - - -class CustomJsonFormatter(jsonlogger.JsonFormatter): - def add_fields(self, log_record, record, message_dict): - super(CustomJsonFormatter, self).add_fields(log_record, record, message_dict) - log_record['name'] = SERVICE - if not log_record.get('timestamp'): - now = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ') - log_record['timestamp'] = now - if log_record.get('level'): - log_record['level'] = log_record['level'].upper() - else: - log_record['level'] = record.levelname - - -def get_logger(name): - logger = logging.getLogger(f"{SERVICE}/{name}") - logger.setLevel(LOG_LEVEL.upper()) - - if not logger.handlers: - logHandler = logging.StreamHandler() - formatter = CustomJsonFormatter('%(timestamp)s %(level)s %(name)s %(message)s') - logHandler.setFormatter(formatter) - logger.addHandler(logHandler) - logger.propagate = False - - return logger diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/infrastructure/sqs.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/infrastructure/sqs.py deleted file mode 100644 index 61967f9b96..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/infrastructure/sqs.py +++ /dev/null @@ -1,135 +0,0 @@ -import boto3 -import os -from uuid import uuid1 as uuid -import json - -from crowd.eagle_eye.config import KUBE_MODE, IS_DEV_ENV, SQS_ENDPOINT_URL, SQS_REGION, \ - SQS_SECRET_ACCESS_KEY, SQS_ACCESS_KEY_ID -from crowd.eagle_eye.infrastructure.logging import get_logger - -logger = get_logger(__name__) - - -def string_converter(o): - """ - Function that converts object to string - This will be used when converting to Json, to convert non serializable attributes - """ - return o.__str__() - - -class SQS: - """ - Class to handle SQS requests. Can send and recieve messages. - """ - - def __init__(self, sqs_url): - """ - Initialise class to handle SQS requests. - - Args: - sqs_url (str): SQS url. - """ - self.sqs_url = sqs_url - # Otherwise from the environment files. - - if KUBE_MODE: - if IS_DEV_ENV: - self.sqs = boto3.client("sqs", - endpoint_url=SQS_ENDPOINT_URL, - region_name=SQS_REGION, - aws_secret_access_key=SQS_SECRET_ACCESS_KEY, - aws_access_key_id=SQS_ACCESS_KEY_ID) - else: - self.sqs = boto3.client("sqs", - region_name=SQS_REGION, - aws_secret_access_key=SQS_SECRET_ACCESS_KEY, - aws_access_key_id=SQS_ACCESS_KEY_ID) - else: - if os.environ.get("NODE_ENV") == "development": - self.sqs = boto3.client( - "sqs", - region_name="eu-central-1", - aws_access_key_id=os.environ.get("AWS_ACCESS_KEY_ID_CROWD"), - aws_secret_access_key=os.environ.get("AWS_SECRET_ACCESS_KEY_CROWD"), - endpoint_url=f'{os.environ.get("LOCALSTACK_HOSTNAME")}:{os.environ.get("LOCALSTACK_PORT")}' - ) - else: - self.sqs = boto3.client( - "sqs", - region_name="eu-central-1", - aws_access_key_id=os.environ.get("AWS_ACCESS_KEY_ID_CROWD"), - aws_secret_access_key=os.environ.get("AWS_SECRET_ACCESS_KEY_CROWD"), - ) - - def send_message(self, body, id, deduplicationId, attributes=None): - """ - Sent a message to the queue - - Args: - body (dict): the body of the message. - id (str): id of the message group - attributes (dict, optional): attributes for the message. Defaults to {}. - - Returns: - [type]: [description] - """ - - if not attributes: - attributes = {} - - if type(body) is not str: - body = json.dumps(body, default=string_converter) - return self.sqs.send_message( - QueueUrl=self.sqs_url, - MessageAttributes=attributes, - MessageBody=body, - MessageGroupId=id, - MessageDeduplicationId=deduplicationId, - ) - - def receive_message(self, delete=True, wait_time_seconds=0, visibility_timeout=60): - """ - Receive a message from the queue. - - Args: - delete (bool, optional): delete after receiving. Defaults to True. - wait_time_seconds (int, optional): how long should the request wait for a queue message. - visibility_timeout (int, optional): how long should the message be invisible to other receivers - - Returns: - dict: The fetched message. If no messages, returns None. - """ - response = self.sqs.receive_message( - QueueUrl=self.sqs_url, - MaxNumberOfMessages=1, - MessageAttributeNames=["All"], - VisibilityTimeout=visibility_timeout, - WaitTimeSeconds=wait_time_seconds, - ) - - if "Messages" in response.keys(): - - message = response["Messages"][0] - receipt_handle = message["ReceiptHandle"] - - if delete: - # Delete received message from queue - self.sqs.delete_message(QueueUrl=self.sqs_url, ReceiptHandle=receipt_handle) - return message - - return None - - def delete_message(self, receipt_handle): - """ - Delete a message from the queue. - Args: - receipt_handle: (string, required): receipt handle from the SQS message - - Returns: None - """ - self.sqs.delete_message(QueueUrl=self.sqs_url, ReceiptHandle=receipt_handle) - - @staticmethod - def make_id(): - return str(uuid()) diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/models.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/models.py deleted file mode 100644 index 9e37537774..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/models.py +++ /dev/null @@ -1,122 +0,0 @@ -import hashlib -import json - - -class Payload: - """ - Class to represent a payload, which is the readable information in a post. - Attributes: - - platform: Platform (hacker_news, dev.to...) - - title: Title of the post - - username: Username of the poster - - timestamp: Timestamp of the post - - postAttributes: Attributes of the post - - url: URL of the post - - destination_url: - - text: Text of the post - - sourceId: ID of the post - - userAttributes: userAttributes of the user - """ - - def __init__(self, id, platform, title, username, timestamp, url='', - destination_url='', text='', userAttributes=None, postAttributes=None): - """ - Class constructor. - - Args: - id (str): ID of the post - platform (str): Platform (hacker_news, dev.to...) - title (str): Title of the post - username (str): Username of the poster - timestamp (int): Timestamp of the post (unix timestamp) - score (int): Score of the post - url (str: . Url of the post Defaults to '' - destination_url (str, optional): Destination URL of the post - text (str, optional): Text of the post Defaults to '' - """ - self.platform = platform - self.title = title - self.username = username - self.timestamp = timestamp - self.url = url - self.destination_url = destination_url - self.text = text - self.sourceId = f'{platform}:{id}' - self.vectorId = self.sourceId - self.userAttributes = userAttributes if userAttributes else {} - self.postAttributes = postAttributes if postAttributes else {} - - def to_dict(self): - """ - Convert the payload to a dictionary. - We need to convert the userAttributes and postAttributes to a string by using json.dumps. - - Returns: - dict: dictionary representation of the payload - """ - vs = vars(self) - # Vector DB does not accept JSON, so we need to convert the userAttributes and postAttributes to a string. - vs['postAttributes'] = json.dumps(vs['postAttributes']) - vs['userAttributes'] = json.dumps(vs['userAttributes']) - return vars(self) - - def __repr__(self): - return f'Payload: {self.username} in {self.platform}: {self.title} ({self.timestamp})' - - -class Vector: - """ - Class to represent a vector in the search engine. - Attributes: - - id: ID of the vector - - payload: Readable post information. See Payload class. - - combined: Title + text - - embed: Embedded vector - """ - - def __init__(self, id, payload, combined='', embed=''): - """ - Vector class constructor. - - Args: - id (str): ID of the post - payload (Payload or dict): Readable post information. See Payload class. - combined (str, optional): Title + Text. Defaults to ''. - embed (str, optional): Embedded vector. Defaults to ''. - """ - # Payload can be a dict or a Payload object - self.payload = Payload(id, **payload) if type(payload) == dict else payload - self.sourceId = self.payload.vectorId - self.id = Vector.make_id(id, payload.platform) - self.combined = combined - self.embed = embed - - @staticmethod - def make_id(id, platform): - """ - Construct a hashed id from the id of the post and the platform. - - Args: - id (str | int): id of the post - platform (str): platform - - Returns: - str: hashed ID - """ - return int(hashlib.sha256(f'{platform}-{id}'.encode('utf-8')).hexdigest(), 16) % 10**8 - - def payload_as_dict(self): - """ - Get the Payload as a dict. - - Returns: - dict: Payload as a dict. - """ - return self.payload.to_dict() - - def __repr__(self): - return f"""Vector({self.id}): - - payload: {self.payload} - - embedded: {self.embed != ''} - - combined: {self.combined != ''} - """ diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/scheduled.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/scheduled.py deleted file mode 100644 index 2e182c8074..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/scheduled.py +++ /dev/null @@ -1,40 +0,0 @@ -import requests -import json -import json -from crowd.eagle_eye.sources import hacker_news -from crowd.eagle_eye.sources import devto -from crowd.eagle_eye.sources import post_process -from crowd.eagle_eye.apis import EmbedAPI -from crowd.eagle_eye.apis.vector_api import VectorAPI -from crowd.eagle_eye.infrastructure.logging import get_logger - -logger = get_logger(__name__) - - -def scheduled_main(source, restart=False): - """ - Main function. - It will get the data from Hacker News, process the data that was not yet in the database, vectorise it, and save it to the database. - """ - vector_api = VectorAPI(do_init=restart) - embed_api = EmbedAPI() - - if source == 'hacker_news': - logger.info("Source is Hacker News") - data = hacker_news() - elif source == 'devto': - logger.info("Source is Dev.to") - data = devto() - - else: - raise ValueError(f'Unknown source: {source}') - - logger.info('Finding existing IDs...') - existing_ids = vector_api.find_existing_ids([point.id for point in data]) - data = post_process(data, existing_ids) - data = embed_api.embed_points(data) - return vector_api.upsert(data) - - -if __name__ == '__main__': - scheduled_main('hacker_news', restart=False) diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/search.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/search.py deleted file mode 100644 index f10fc64700..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/search.py +++ /dev/null @@ -1,113 +0,0 @@ -import json -from crowd.eagle_eye.apis.vector_api import VectorAPI -from crowd.eagle_eye.infrastructure.logging import get_logger - -logger = get_logger(__name__) - - -def remove_duplicates(iter): - """ - Remove duplicate posts from the list of returned posts. - If there are duplicates, we keep only the post with highest similarity score. - - Args: - iter (list): list of points - - Returns: - list: list of points without duplicates - """ - filter_dict = {} - for post in iter: - vid = post['vectorId'] - if vid in filter_dict and filter_dict[vid]['similarityScore'] < post['similarityScore']: - filter_dict[vid] = post - filter_dict[vid] = post - - return [filter_dict[key] for key in filter_dict] - - -def transform(query, exact_keywords, id, score, metadata): - """ - Transform a set of results for crowd.dev's Node.js API - - Args: - query (str): strings to test with - id (int): id of the post - score (float): similarity score - post (dict): post coming from the vector DB - - Returns: - dict: transformed dict for crowd.dev's API - """ - if query == '': - keywords = [] - else: - keywords = [query] - - return { - 'vectorId': id, - 'sourceId': metadata['sourceId'], - 'title': metadata['title'], - 'url': metadata['url'], - 'text': metadata.get('text', ''), - 'username': metadata['username'], - 'platform': metadata['platform'], - 'timestamp': metadata['timestamp'], - 'similarityScore': score, - 'userAttributes': json.loads(metadata.get('userAttributes', '{}')), - 'postAttributes': json.loads(metadata.get('postAttributes', '{}')), - 'keywords': keywords, - 'exactKeywords': exact_keywords, - } - - -def search_main(queries, ndays, exclude, exact_keywords): - """ - Perform a similarity search on the vector DB. - - Args: - queries ([str]): List of strings to search with - ndays (int): Maximum number of days to search in - exclude ([int]): IDs to exclude from the search - exact_keywords ([str]): Exact keywords to match - - Returns: - _type_: _description_ - """ - logger.info(f"Starting search for queries {queries}") - vector = VectorAPI() - out = [] - if queries == []: - queries = [''] - for query in queries: - results = vector.search(query, ndays, exclude, exact_keywords) - for returned_point in results: - out.append(transform(query, exact_keywords, returned_point.id, - returned_point.score, returned_point.payload)) - out = remove_duplicates(out) - return json.dumps(out) - - -def keyword_match_main(ndays, exclude, exact_keywords, platform): - """ - Perform a keyword match on the vector DB. - - Args: - ndays (int): Maximum number of days to search in - exclude ([int]): IDs to exclude from the search - exact_keywords ([str]): Exact keywords to match - """ - vector = VectorAPI() - results = vector.keyword_match(ndays, exclude, exact_keywords, platform) - out = [] - if type(results[0]) == list: - results = results[0] - for returned_point in results: - transformed = transform('', exact_keywords, returned_point.id, 1, returned_point.payload) - # Check exactly which keywords matched - for keyword in exact_keywords: - if keyword in transformed['title'] or keyword in transformed['text']: - transformed['keywords'].append(keyword) - out.append(transformed) - out = remove_duplicates(out) - return json.dumps(out) diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/__init__.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/__init__.py deleted file mode 100644 index ed80da56bb..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from crowd.eagle_eye.sources.hacker_news import hacker_news # noqa -from crowd.eagle_eye.sources.devto import devto # noqa -from crowd.eagle_eye.sources.post_process import post_process # noqa diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/devto.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/devto.py deleted file mode 100644 index db06865edc..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/devto.py +++ /dev/null @@ -1,158 +0,0 @@ -import json -import requests -from crowd.eagle_eye.models import Vector, Payload -from crowd.eagle_eye.infrastructure.logging import get_logger -import time -from dateutil import parser - -logger = get_logger(__name__) - - -def pre_process(data): - """ - Process dev.to data. - - Args: - data ([dict]): List of posts. - - Returns: - [Point]: List of points. - """ - return [ - Vector( - payload=Payload( - id=point['id'], - platform='devto', - title=point['title'], - destination_url='', - url=point['url'], - text=point['description'], - username=point['user']['username'], - timestamp=date_to_timestamp(point['published_timestamp']), - postAttributes={ - 'tags': point.get('tag_list', []), - }, - userAttributes={ - 'user': { - 'githubUsername': point['user'].get('github_username', ''), - 'twitterUsername': point['user'].get('twitter_username', ''), - 'location': point['user'].get('location', ''), - 'joinedAt': point['user'].get('joined_at', ''), - 'name': point['user'].get('name', ''), - 'summary': point['user'].get('summary', ''), - 'website': point['user'].get('website', ''), - }, - 'organization': ({ - 'name': point['organization']['name'], - 'username': point['organization']['username'], - 'githubUsername': point['organization'].get('github_username', ''), - 'twitterUsername': point['organization'].get('twitter_username', ''), - 'location': point['organization'].get('location', ''), - 'joinedAt': point['organization'].get('joined_at', ''), - 'techStack': point['organization'].get('tech_stack', ''), - 'summary': point['organization'].get('summary', ''), - 'tagLine': point['organization'].get('tag_line', ''), - } - if point.get('organization', False) else {}) - } - ), - id=point['id'], - combined='', - embed='' - ) for point in data if point.get('user', {}).get('username', False) - ] - - -def ts_3h_ago(): - """ - Find the timestamp 3 hours ago. - - Returns: - int: timestamp. - """ - return int(round(time.time())) - (3 * 60 * 60) - - -def date_to_timestamp(date): - """ - String date to unix timestamp. - - Args: - date (str): date. - - Returns: - int: unix timestamp - """ - to_dt = parser.parse(date) - return int(time.mktime(to_dt.timetuple())) - - -def devto(sleep=True): - """ - Get dev.to data. - - Args: - sleep (bool, optional): Whether to sleep. Defaults to False. - - Returns: - [dict]: list of posts. - """ - - # We start with a non-finished state, and at page 1. - isFinished = False - page = 1 - finish_ts = ts_3h_ago() - posts = [] - - while not isFinished: - # Get posts from DevTo - from_dev = json.loads(requests.get('https://dev.to/api/articles/latest', params={ - 'per_page': 100, - 'page': page - }).content) - - # If there are no posts, we are done - if len(from_dev) == 0: - isFinished = True - break - - # We enrich the posts: we can get extra organisation and user information - enriched = [] - for post in from_dev: - if sleep: - time.sleep(1) - - user_content = requests.get( - f'https://dev.to/api/users/{post["user"]["user_id"]}').content - try: - user = json.loads(user_content) - except: - user = False - if user: - post['user'] = user - if 'organization' in post: - - if sleep: - time.sleep(1) - - post['organization'] = json.loads(requests.get( - f'https://dev.to/api/organizations/{post["organization"]["username"]}').content) - - enriched.append(post) - - # Add the enriched posts to the list of posts - posts += enriched - if date_to_timestamp(from_dev[-1]['published_timestamp']) < finish_ts: - isFinished = True - - page += 1 - time.sleep(1) - - # Return the list of processed posts - return pre_process(posts) - - -if __name__ == '__main__': - from pprint import pprint as pp - devto() - # pp(devto()) diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/hacker_news.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/hacker_news.py deleted file mode 100644 index ec79276bf3..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/hacker_news.py +++ /dev/null @@ -1,68 +0,0 @@ -import json -import requests -from crowd.eagle_eye.models import Vector, Payload -from crowd.eagle_eye.infrastructure.logging import get_logger - -logger = get_logger(__name__) - - -def pre_process(data): - """ - Process Hacker News data. - - Args: - data ([dict]): List of posts. - - Returns: - [Point]: List of points. - """ - return [ - Vector( - payload=Payload( - id=point['id'], - platform='hacker_news', - title=point['title'], - destination_url=point.get('url', ''), - url=f'https://news.ycombinator.com/item?id={point["id"]}', - text=point.get('text', ''), - username=point['by'], - timestamp=point['time'], - postAttributes={ - 'commentsCount': point['descendants'] if 'descendants' in point else len(point.get('kids', [])), - 'score': point['score'] - } - ), - id=point['id'], - combined='', - embed='' - ) for point in data - ] - - -def hacker_news(): - """ - Get the data from Hacker News. - """ - # Get top 500 posts from Hacker News. Returns a list of IDs - logger.info("Fetching top IDs from Hacker News...") - top = json.loads(requests.get('https://hacker-news.firebaseio.com/v0/topstories.json').content) - - best = json.loads(requests.get('https://hacker-news.firebaseio.com/v0/beststories.json').content) - - posts = top + best - - logger.info("Done") - logger.info("Fetching data from Hacker News...") - # For each post, get the data - data = [ - json.loads(requests.get(f'https://hacker-news.firebaseio.com/v0/item/{story_id}.json').content) - for story_id in posts - ] - logger.info("Done") - - # Return the processed data - return pre_process(data) - - -if __name__ == '__main__': - hacker_news() diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/post_process.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/post_process.py deleted file mode 100644 index fa2a90e1f4..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/post_process.py +++ /dev/null @@ -1,130 +0,0 @@ -import requests -import signal -from bs4 import BeautifulSoup -from urllib.parse import urlparse -from reppy.robots import Robots -from crowd.eagle_eye.infrastructure.logging import get_logger - -logger = get_logger(__name__) - - -def filter_existing(data, ids): - """ - Filter existing points from the data to post-process. - - Args: - data (_type_): _description_ - ids (_type_): _description_ - - Returns: - _type_: _description_ - """ - filtered = [point for point in data if point.id not in ids] - logger.info(f"Filtered {len(data) - len(filtered)} points") - return filtered - - -def fill_text(url, request_timeout=4): - """ - Fill text for points that don't have any given a destination URL. - - Args: - url (str): destination URL. - request_timeout (int): maximum time to wait for a content request - - Returns: - str: string, or URL if we can't find any text. - """ - # We cannot parse PDFs - if 'pdf' in url: - return url - - def timeout_handler(num, stack): - """ - Raises an exception after a timeout. - """ - raise Exception("Alarm") - - # We set a timeout for the request. If we don't get a response within this time, we give up. - signal.signal(signal.SIGALRM, timeout_handler) - # The timeout is 4 seconds - signal.alarm(request_timeout) - - try: - # We check if we are allowed to parse the text from this URL. - host = urlparse(url).hostname - robots = Robots.fetch(f'https://{host}/robots.txt') - if robots.allowed(url, 'my-user-agent'): # If we can parse - - # Return the text from the URL - html = requests.get(url).text - soup = BeautifulSoup(html, features="html.parser") - allowlist = [ - 'p' - ] - text = ' '.join([t for t in soup.find_all(text=True) if t.parent.name in allowlist]) - return text - - return url - - except Exception as e: # noqa: E722 - return url - - finally: - # Restart the timeout signal - signal.alarm(0) - - -def html_link(url, max_link_chars=60): - """ - Generate an HTML link from a URL. - - Args: - url (str): url - max_link_chars (int): maximum characters to allow in an HTML link - - Returns: - str: HTML link - """ - str_url = f'{url[:60]}...' if len(url) > max_link_chars else url - return f'{str_url}' - - -def post_process(data, existing_ids, max_text_chars=2000): - """ - Post-process the data. This is run when we already have a list of Points from the source. - - Args: - data ([Point]): list of points - existing_ids ([str]): Ids already found in the vector DB. - max_text_chars (int): maximum characters in text - - Returns: - [Point]: Points with the combined attribute filled out. - """ - data = filter_existing(data, existing_ids) - - out = [] - logger.info("Finding missing texts...") - for point in data: - # If there is no text, we try to get it from the destination URL - if not point.payload.text and point.payload.destination_url: - # This is commented for now. Giving better results. - # text = fill_text(point.payload.destination_url) - text = point.payload.destination_url - - # We do not want that whole text in the text field. It is likely dirty and long. - # Instead we give an HTML link to the destination URL. - point.payload.text = html_link(point.payload.destination_url) - - else: - text = point.payload.text - # Cap to max_text_chars characters - point.payload.text = text[:max_text_chars] - - point.combined = point.payload.title + "\n " + text - - out.append(point) - - logger.info("Done") - return out diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/test/test_devto.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/test/test_devto.py deleted file mode 100644 index ded3b4f481..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/test/test_devto.py +++ /dev/null @@ -1,220 +0,0 @@ -from crowd.eagle_eye.sources.devto import pre_process - -without_organization = { - 'canonical_url': 'https://dev.to/sokhavuth/tv-channel-website-route-to-static-assets-4dd6', - 'collection_id': 19428, - 'comments_count': 0, - 'cover_image': 'https://res.cloudinary.com/practicaldev/image/fetch/s--5Tc-jq6j--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jfaqz6f869nib9wrqhjo.png', - 'created_at': '2022-08-22T08:49:53Z', - 'crossposted_at': None, - 'description': 'GitHub: https://github.com/Sokhavuth/TV-Channel Vercel: ' - 'https://khmerweb-tv-channel.vercel.app/ In...', - 'edited_at': '2022-08-22T08:52:13Z', - 'id': 1173162, - 'last_comment_at': '2022-08-22T08:51:46Z', - 'path': '/sokhavuth/tv-channel-website-route-to-static-assets-4dd6', - 'positive_reactions_count': 0, - 'public_reactions_count': 0, - 'published_at': '2022-08-22T09:23:47Z', - 'published_timestamp': '2022-08-22T09:23:47Z', - 'readable_publish_date': 'Aug 22', - 'reading_time_minutes': 1, - 'slug': 'tv-channel-website-route-to-static-assets-4dd6', - 'social_image': 'https://res.cloudinary.com/practicaldev/image/fetch/s--H8KF-D0D--/c_imagga_scale,f_auto,fl_progressive,h_500,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jfaqz6f869nib9wrqhjo.png', - 'tag_list': ['webdev', 'tutorial', 'python', 'bottle'], - 'tags': 'webdev, tutorial, python, bottle', - 'title': 'TV Channel Website: Static Assets', - 'type_of': 'article', - 'url': 'https://dev.to/sokhavuth/tv-channel-website-route-to-static-assets-4dd6', - 'user': { - 'github_username': 'Sokhavuth', - 'id': 574924, - 'joined_at': 'Feb 7, 2021', - 'location': '', - 'name': 'Khmer Web', - 'profile_image': 'https://res.cloudinary.com/practicaldev/image/fetch/s--AV2-UEv7--/c_fill,f_auto,fl_progressive,h_320,q_auto,w_320/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/574924/64f4717e-5c7d-4e0c-ba85-521c9e7e5dff.jpg', - 'summary': '', - 'twitter_username': None, - 'type_of': 'user', - 'username': 'sokhavuth', - 'website_url': 'https://khmerweb.vercel.app/' - } -} - -with_organization = { - 'canonical_url': 'https://dev.to/producthackers/do-not-reinvent-the-wheel-400g', - 'collection_id': None, - 'comments_count': 0, - 'cover_image': 'https://res.cloudinary.com/practicaldev/image/fetch/s--L688S7sq--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9n1ihqefdv236pubhrmc.jpg', - 'created_at': '2022-07-27T10:07:45Z', - 'crossposted_at': None, - 'description': 'As a dev we are responsible in delivering value over number ' - 'of lines of code, that is our focus. Do not develop a tool ' - 'from zero when there are tons of them out there that cover ' - 'your needs.', - 'edited_at': None, - 'id': 1152635, - 'last_comment_at': '2022-08-22T09:01:43Z', - 'organization': { - 'github_username': 'ProductHackers', - 'id': 3260, - 'joined_at': '2020-11-04T10:24:05Z', - 'location': 'Madrid, Spain', - 'name': 'Product Hackers', - 'profile_image': 'https://res.cloudinary.com/practicaldev/image/fetch/s--cdztWIwP--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://dev-to-uploads.s3.amazonaws.com/uploads/organization/profile_image/3260/2d5868ca-8732-4f03-8693-fe45fe70772e.jpg', - 'story': '', - 'summary': 'We make your business grow.', - 'tag_line': '', - 'tech_stack': 'HTML, CSS, JS, React, Svelte, Nodejs, AWS', - 'twitter_username': 'Product_Hackers', - 'type_of': 'organization', - 'url': 'https://producthackers.com/', - 'username': 'producthackers' - }, - 'path': '/producthackers/do-not-reinvent-the-wheel-400g', - 'positive_reactions_count': 3, - 'public_reactions_count': 3, - 'published_at': '2022-08-22T09:01:43Z', - 'published_timestamp': '2022-08-22T09:01:43Z', - 'readable_publish_date': 'Aug 22', - 'reading_time_minutes': 4, - 'slug': 'do-not-reinvent-the-wheel-400g', - 'social_image': 'https://res.cloudinary.com/practicaldev/image/fetch/s--kNXzZN0c--/c_imagga_scale,f_auto,fl_progressive,h_500,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9n1ihqefdv236pubhrmc.jpg', - 'tag_list': ['nocode', 'tools', 'gtm', 'aws'], - 'tags': 'nocode, tools, gtm, aws', - 'title': 'Do not reinvent the wheel', - 'type_of': 'article', - 'url': 'https://dev.to/producthackers/do-not-reinvent-the-wheel-400g', - 'user': { - 'github_username': 'avcconti', - 'id': 26911, - 'joined_at': 'Jul 21, 2017', - 'location': 'Toledo, Spain', - 'name': 'Conti', - 'profile_image': 'https://res.cloudinary.com/practicaldev/image/fetch/s--G2X9WGPr--/c_fill,f_auto,fl_progressive,h_320,q_auto,w_320/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/26911/d77c1deb-30d8-45ff-bb3f-a14ed63395ee.jpeg', - 'summary': 'Software engineer at https://producthackers.com/', - 'twitter_username': 'avc_conti', - 'type_of': 'user', - 'username': 'conti', - 'website_url': '' - } -} - - -def test_with_organization(): - processed = pre_process([with_organization])[0] - - payload = processed.payload - - # Test the payload class - assert payload.vectorId == 'devto:1152635' - assert payload.sourceId == 'devto:1152635' - assert payload.title == 'Do not reinvent the wheel' - assert payload.url == 'https://dev.to/producthackers/do-not-reinvent-the-wheel-400g' - assert payload.username == 'conti' - assert payload.timestamp == 1661155303 - assert payload.platform == 'devto' - assert payload.text == 'As a dev we are responsible in delivering value over number of lines of code, that is our focus. Do not develop a tool from zero when there are tons of them out there that cover your needs.' - assert payload.destination_url == '' - assert payload.postAttributes == {'tags': ['nocode', 'tools', 'gtm', 'aws'], } - assert payload.userAttributes == { - 'user': { - 'githubUsername': 'avcconti', - 'twitterUsername': 'avc_conti', - 'location': 'Toledo, Spain', - 'joinedAt': 'Jul 21, 2017', - 'name': 'Conti', - 'summary': 'Software engineer at https://producthackers.com/', - 'website': '' - }, - 'organization': { - 'name': 'Product Hackers', - 'username': 'producthackers', - 'githubUsername': 'ProductHackers', - 'twitterUsername': 'Product_Hackers', - 'location': 'Madrid, Spain', - 'joinedAt': '2020-11-04T10:24:05Z', - 'techStack': 'HTML, CSS, JS, React, Svelte, Nodejs, AWS', - 'summary': 'We make your business grow.', - 'tagLine': '' - } - } - - # Test payload_as_dict - assert processed.payload_as_dict() == { - 'destination_url': '', - 'platform': 'devto', - 'postAttributes': '{"tags": ["nocode", "tools", "gtm", "aws"]}', - 'sourceId': 'devto:1152635', - 'text': 'As a dev we are responsible in delivering value over number of lines ' - 'of code, that is our focus. Do not develop a tool from zero when ' - 'there are tons of them out there that cover your needs.', - 'timestamp': 1661155303, - 'title': 'Do not reinvent the wheel', - 'url': 'https://dev.to/producthackers/do-not-reinvent-the-wheel-400g', - 'userAttributes': '{"user": {"githubUsername": "avcconti", "twitterUsername": ' - '"avc_conti", "location": "Toledo, Spain", "joinedAt": "Jul ' - '21, 2017", "name": "Conti", "summary": "Software engineer ' - 'at https://producthackers.com/", "website": ""}, ' - '"organization": {"name": "Product Hackers", "username": ' - '"producthackers", "githubUsername": "ProductHackers", ' - '"twitterUsername": "Product_Hackers", "location": "Madrid, ' - 'Spain", "joinedAt": "2020-11-04T10:24:05Z", "techStack": ' - '"HTML, CSS, JS, React, Svelte, Nodejs, AWS", "summary": ' - '"We make your business grow.", "tagLine": ""}}', - 'username': 'conti', - 'vectorId': 'devto:1152635' - } - - -def test_without_organization(): - processed = pre_process([without_organization])[0] - payload = processed.payload - - # Test the payload class - assert payload.vectorId == 'devto:1173162' - assert payload.sourceId == 'devto:1173162' - assert payload.title == 'TV Channel Website: Static Assets' - assert payload.url == 'https://dev.to/sokhavuth/tv-channel-website-route-to-static-assets-4dd6' - assert payload.username == 'sokhavuth' - assert payload.timestamp == 1661156627 - assert payload.platform == 'devto' - assert payload.text == 'GitHub: https://github.com/Sokhavuth/TV-Channel Vercel: https://khmerweb-tv-channel.vercel.app/ In...' - assert payload.destination_url == '' - assert payload.postAttributes == {'tags': ['webdev', 'tutorial', 'python', 'bottle']} - assert payload.userAttributes == { - 'user': { - 'githubUsername': 'Sokhavuth', - 'twitterUsername': None, - 'location': '', - 'joinedAt': 'Feb 7, 2021', - 'name': 'Khmer Web', - 'summary': '', - 'website': '' - }, - 'organization': {} - } - - # Test payload_as_dict - assert processed.payload_as_dict() == { - 'destination_url': '', - 'platform': 'devto', - 'postAttributes': '{"tags": ["webdev", "tutorial", "python", "bottle"]}', - 'sourceId': 'devto:1173162', - 'text': 'GitHub: https://github.com/Sokhavuth/TV-Channel Vercel: ' - 'https://khmerweb-tv-channel.vercel.app/ In...', - 'timestamp': 1661156627, - 'title': 'TV Channel Website: Static Assets', - 'url': 'https://dev.to/sokhavuth/tv-channel-website-route-to-static-assets-4dd6', - 'userAttributes': '{"user": {"githubUsername": "Sokhavuth", ' - '"twitterUsername": null, "location": "", "joinedAt": "Feb ' - '7, 2021", "name": "Khmer Web", "summary": "", "website": ' - '""}, "organization": {}}', - 'username': 'sokhavuth', - 'vectorId': 'devto:1173162' - } - - -if __name__ == '__main__': - # test_with_organization() - test_without_organization() diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/test/test_hacker_news.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/test/test_hacker_news.py deleted file mode 100644 index 4d817aa9f2..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sources/test/test_hacker_news.py +++ /dev/null @@ -1,115 +0,0 @@ -from crowd.eagle_eye.sources.hacker_news import pre_process - -with_text = { - 'by': 'jarrenae', - 'id': 32514823, - 'kids': [32516216, 32515059, 32515131], - 'score': 23, - 'text': 'Hi HN, I work with a mixed group of developers', - 'time': 1660856413, - 'title': 'Show HN: Quick Rewire – I made web tool to rewire your brain', - 'type': 'story', - 'url': 'https://www.quickrewire.com/' -} - -without_text = { - 'by': 'pepys', - 'descendants': 59, - 'id': 32515067, - 'kids': [32517765, - 32518573, - 32519490, - 32518310, - 32517771, - 32518465, - 32518271, - 32517748, - 32518578, - 32518563, - 32518801, - 32516251, - 32518144, - 32518046, - 32516078], - 'score': 126, - 'time': 1660857735, - 'title': 'Dublin Whiskey Fire', - 'type': 'story', - 'url': 'https://en.wikipedia.org/wiki/Dublin_whiskey_fire' -} - - -def test_without_text(): - processed = pre_process([without_text])[0] - - payload = processed.payload - - # Test the payload class - assert payload.vectorId == 'hacker_news:32515067' - assert payload.sourceId == 'hacker_news:32515067' - assert payload.title == 'Dublin Whiskey Fire' - assert payload.url == 'https://news.ycombinator.com/item?id=32515067' - assert payload.username == 'pepys' - assert payload.timestamp == 1660857735 - assert payload.platform == 'hacker_news' - assert payload.text == '' - assert payload.destination_url == 'https://en.wikipedia.org/wiki/Dublin_whiskey_fire' - assert payload.postAttributes == { - 'commentsCount': 59, - 'score': 126 - } - - # Test payload_as_dict - assert processed.payload_as_dict() == { - 'destination_url': 'https://en.wikipedia.org/wiki/Dublin_whiskey_fire', - 'platform': 'hacker_news', - 'postAttributes': '{"commentsCount": 59, "score": 126}', - 'sourceId': 'hacker_news:32515067', - 'text': '', - 'timestamp': 1660857735, - 'title': 'Dublin Whiskey Fire', - 'url': 'https://news.ycombinator.com/item?id=32515067', - 'userAttributes': '{}', - 'username': 'pepys', - 'vectorId': 'hacker_news:32515067' - } - - -def test_with_text(): - processed = pre_process([with_text])[0] - payload = processed.payload - - # Test the payload class - assert payload.vectorId == 'hacker_news:32514823' - assert payload.sourceId == 'hacker_news:32514823' - assert payload.title == 'Show HN: Quick Rewire – I made web tool to rewire your brain' - assert payload.url == 'https://news.ycombinator.com/item?id=32514823' - assert payload.username == 'jarrenae' - assert payload.timestamp == 1660856413 - assert payload.platform == 'hacker_news' - assert payload.text == 'Hi HN, I work with a mixed group of developers' - assert payload.destination_url == 'https://www.quickrewire.com/' - assert payload.postAttributes == { - 'commentsCount': 3, - 'score': 23 - } - - # Test payload_as_dict - assert processed.payload_as_dict() == { - 'destination_url': 'https://www.quickrewire.com/', - 'platform': 'hacker_news', - 'postAttributes': '{"commentsCount": 3, "score": 23}', - 'sourceId': 'hacker_news:32514823', - 'text': 'Hi HN, I work with a mixed group of developers', - 'timestamp': 1660856413, - 'title': 'Show HN: Quick Rewire – I made web tool to rewire your brain', - 'url': 'https://news.ycombinator.com/item?id=32514823', - 'userAttributes': '{}', - 'username': 'jarrenae', - 'vectorId': 'hacker_news:32514823' - } - - -if __name__ == '__main__': - test_without_text() - test_with_text() diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sync.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sync.py deleted file mode 100644 index 2b33b81294..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/sync.py +++ /dev/null @@ -1,34 +0,0 @@ -from pprint import pprint as pp -from crowd.eagle_eye.apis.vector_api import VectorAPI -from qdrant_client.http import models - - -import dotenv -found = dotenv.find_dotenv(".env.sync") -dotenv.load_dotenv(found) - -vector_out = VectorAPI(do_init=False, cloud=False) -print("Vector out initialised. It has {} vectors".format(vector_out.count())) -vector_in = VectorAPI(do_init=True, cloud=True) -print("Vector in initialised") - - -number = vector_out.count() -offset = None - -while True: - vectors = vector_out.scroll(offset) - - vectors_to_add = [ - models.PointStruct( - id=vector.id, - payload=vector.payload, - vector=vector.vector, - ) for vector in vectors[0] - ] - vector_in.upsert(vectors_to_add, processed=True) - - offset = vectors[-1] - if not offset: - break - print(f"Synced {vector_in.count()} of {number} vectors") diff --git a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/test/test_search.py b/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/test/test_search.py deleted file mode 100644 index 9732afdec0..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/crowd/eagle_eye/test/test_search.py +++ /dev/null @@ -1,106 +0,0 @@ -from crowd.eagle_eye.search import remove_duplicates - -out = [ - { - 'keywords': ['community'], - 'platform': 'devto', - 'postAttributes': {'tags': ['python', 'golf']}, - 'similarityScore': 0.253364444, - 'sourceId': 'devto:1173887', - 'text': 'Golf Game Code Progress Today marks the day ' - 'where I post my first project. I am...', - 'timestamp': 1661225580.0, - 'title': 'Golf Game', - 'url': 'https://dev.to/calebkumo/golf-game-470l', - 'userAttributes': { - 'organization': {}, - 'user': { - 'githubUsername': 'calebkumo', - 'joinedAt': 'Jun 26, 2022', - 'location': None, - 'name': 'calebkumo', - 'summary': None, - 'twitterUsername': None, - 'website': '' - } - }, - 'username': 'calebkumo', - 'vectorId': 'devto:1173887' - }, - { - 'keywords': ['community'], - 'platform': 'devto', - 'postAttributes': {'tags': []}, - 'similarityScore': 0.252538919, - 'sourceId': 'devto:1172752', - 'text': 'It takes quite a lot of time to keep updated on what is happening ' - 'in the tech world. So I thought it...', - 'timestamp': 1661185702.0, - 'title': 'Interesting Things in Tech lately (2022 week 33)', - 'url': 'https://dev.to/amabdev/interesting-things-in-tech-lately-2022-week-33-210d', - 'userAttributes': { - 'organization': {}, - 'user': { - 'githubUsername': None, - 'joinedAt': 'Jun 24, 2022', - 'location': '', - 'name': 'AmabDev', - 'summary': 'I am a passionate software developer ' - 'attempting to learn in public.\n' - 'Feel free to reach out. I will be ' - 'grateful for every opportunity to ' - 'learn and improve.', - 'twitterUsername': 'AmabDev', - 'website': '' - } - }, - 'username': 'amabdev', - 'vectorId': 'devto:1172752' - }, - { - 'keywords': ['open source'], - 'platform': 'devto', - 'postAttributes': {'tags': []}, - 'similarityScore': 0.4, - 'sourceId': 'devto:1172752', - 'text': 'It takes quite a lot of time to keep updated on what is happening ' - 'in the tech world. So I thought it...', - 'timestamp': 1661185702.0, - 'title': 'Interesting Things in Tech lately (2022 week 33)', - 'url': 'https://dev.to/amabdev/interesting-things-in-tech-lately-2022-week-33-210d', - 'userAttributes': { - 'organization': {}, - 'user': { - 'githubUsername': None, - 'joinedAt': 'Jun 24, 2022', - 'location': '', - 'name': 'AmabDev', - 'summary': 'I am a passionate software developer ' - 'attempting to learn in public.\n' - 'Feel free to reach out. I will be ' - 'grateful for every opportunity to ' - 'learn and improve.', - 'twitterUsername': 'AmabDev', - 'website': '' - } - }, - 'username': 'amabdev', - 'vectorId': 'devto:1172752' - } -] - - -def test_deduplication_no_repeated_keywords(): - to_test = out[:2] - assert len(to_test) == 2 - assert len(remove_duplicates(to_test)) == 2 - - -def test_deduplication_repeated_keywords(): - to_test = out - assert len(to_test) == 3 - - no_dups = remove_duplicates(to_test) - assert len(no_dups) == 2 - assert no_dups[1]['keywords'] == ['open source'] - assert no_dups[1]['similarityScore'] == 0.4 diff --git a/premium/eagle-eye/crowd-eagle-eye/setup.py b/premium/eagle-eye/crowd-eagle-eye/setup.py deleted file mode 100644 index 303975eead..0000000000 --- a/premium/eagle-eye/crowd-eagle-eye/setup.py +++ /dev/null @@ -1,19 +0,0 @@ -import io -import os - -from setuptools import setup, find_namespace_packages - - -def read(rel_path): - here = os.path.abspath(os.path.dirname(__file__)) - with io.open(os.path.join(here, rel_path), "r") as fp: - return fp.read() - - -setup( - name="crowd-eagle-eye", - packages=find_namespace_packages(include=["crowd.*"]), - install_requires=["requests", "bs4", "qdrant-client", "cohere", - "reppy", "python-dotenv", "python-dateutil", "python-dotenv", "sentence-transformers"], - -) diff --git a/premium/eagle-eye/data.json b/premium/eagle-eye/data.json deleted file mode 100644 index 6c4facbd98..0000000000 --- a/premium/eagle-eye/data.json +++ /dev/null @@ -1 +0,0 @@ -[{"by": "a_bored_husky", "descendants": 17, "id": 32438375, "kids": [32438626, 32438882, 32439111, 32438945, 32439717, 32439524, 32439779, 32439257, 32439626, 32438846, 32438958], "score": 65, "time": 1660311159, "title": "Asdf Performance", "type": "story", "url": "http://stratus3d.com/blog/2022/08/11/asdf-performance/"}, {"by": "janandonly", "descendants": 25, "id": 32438923, "kids": [32439470, 32439661, 32439669, 32439338, 32439529, 32439714, 32439394], "score": 29, "time": 1660313459, "title": "BlackRock bitcoin private trust", "type": "story", "url": "https://www.blackrock.com/institutions/en-us/insights/bitcoin-private-trust"}, {"by": "kungfudoi", "descendants": 7, "id": 32437965, "kids": [32439185], "score": 33, "time": 1660309560, "title": "PyPI package 'secretslib' drops fileless Linux malware to mine Monero", "type": "story", "url": "https://blog.sonatype.com/pypi-package-secretslib-drops-fileless-linux-malware-to-mine-monero"}, {"by": "nus07", "descendants": 27, "id": 32439438, "kids": [32439789, 32439604, 32439843, 32439635, 32439739, 32439559, 32439681, 32439671, 32439791, 32439625, 32439514, 32439804, 32439806, 32439550, 32439552, 32439795, 32439533, 32439571, 32439585, 32439556, 32439663, 32439582, 32439746, 32439608], "score": 29, "text": "I never seem to get picked for the new projects that involve new tech stacks and migration efforts. At my current company I am still maintaining an old codebase and Oracle database where some peers are working on migration to AWS and snowflake. Even at previous jobs I was always staffed on the unimportant legacy projects despite expressing interest in newer exciting projects . I do try to self learn and get certifications but somehow never get chosen to work on new exciting projects .\nAm I a bad engineer or do I come across wrong to management ? My performance reviews go great. What can I do or change ?", "time": 1660315475, "title": "Ask HN: Why am I always stuck working on legacy software", "type": "story"}, {"by": "gmays", "descendants": 13, "id": 32438399, "kids": [32439788, 32439357, 32439583], "score": 24, "time": 1660311276, "title": "One more clue to the Moon\u2019s origin", "type": "story", "url": "https://ethz.ch/en/news-and-events/eth-news/news/2022/08/one-more-clue-to-the-moons-origin.html"}, {"by": "bane", "descendants": 5, "id": 32420029, "kids": [32438915, 32439256, 32439243], "score": 39, "time": 1660176375, "title": "MySQL Raytracer", "type": "story", "url": "https://www.pouet.net/prod.php?which=83222"}, {"by": "alopes", "descendants": 1, "id": 32438942, "kids": [32439430], "score": 59, "time": 1660313506, "title": "Starlink Successfully Hacked Using $25 Modchip", "type": "story", "url": "https://threatpost.com/starlink-hack/180389/"}, {"by": "fnubbly", "descendants": 0, "id": 32439382, "score": 7, "time": 1660315293, "title": "Constructive and obsessive criticism in science", "type": "story", "url": "https://onlinelibrary.wiley.com/doi/full/10.1111/eci.13839"}, {"by": "swyx", "descendants": 2, "id": 32439511, "kids": [32439694], "score": 17, "time": 1660315891, "title": "Supabase Series B", "type": "story", "url": "https://supabase.com/blog/supabase-series-b"}, {"by": "mjg235", "descendants": 2, "id": 32439255, "kids": [32439833, 32439822, 32439773], "score": 15, "time": 1660314694, "title": "Kubernetes Statefulsets Are Broken", "type": "story", "url": "https://www.plural.sh/blog/kubernetes-statefulsets-are-broken/"}] \ No newline at end of file diff --git a/premium/eagle-eye/hacker_news.csv b/premium/eagle-eye/hacker_news.csv deleted file mode 100644 index 0987663b42..0000000000 --- a/premium/eagle-eye/hacker_news.csv +++ /dev/null @@ -1,550 +0,0 @@ -username,id,score,time,title,url,text,platform,vectorId -gigel82,32422522,193,1660202383,Mindustry – Open-Source Game,https://mindustrygame.github.io/,,Hacker News,61326502 -0x41534446,32423813,32,1660214530,Fully Dockerized Linux kernel debugging environment,https://github.com/0xricksanchez/like-dbg,,Hacker News,93095468 -modinfo,32408163,207,1660110380,Freeciv – open-source Civilization clone,http://www.freeciv.org/,,Hacker News,47196654 -bumbledraven,32421350,206,1660189674,Retirement of Amazon MOBI eBook file format,https://www.microsoftpressstore.com/promotions/product-announcement-retirement-of-amazon-mobi-ebook-142421,,Hacker News,82561471 -dcminter,32423356,32,1660210169,No Silver Bullet (1986) [pdf],http://worrydream.com/refs/Brooks-NoSilverBullet.pdf,,Hacker News,36119910 -edouard-harris,32424368,1,1660219247,SharpestMinds (YC W18) Is Hiring a Software Developer,https://public.3.basecamp.com/p/gR8WJgPHPUq5r51MyWSVAX5T,,Hacker News,75941271 -jacquesm,32423178,41,1660208169,Using satellites to uncover large methane emissions from landfills,https://www.science.org/doi/10.1126/sciadv.abn9683,,Hacker News,25913747 -gmemstr,32423080,43,1660207279,Hetzner Price Adjustment,https://docs.hetzner.com/general/others/price-adjustment/,,Hacker News,10851603 -JoachimS,32424055,30,1660216775,IPFS and Their Gateways,https://daniel.haxx.se/blog/2022/08/10/ipfs-and-their-gateways/,,Hacker News,64252295 -alexzeitler,32409842,83,1660126977,How to present to executives (2021),https://lethain.com/present-to-executives/,,Hacker News,58010741 -frumpish,32415960,28,1660154100,Themes in academic literature: prejudice and social justice,https://www.nas.org/academic-questions/35/2/themes-in-academic-literature-prejudice-and-social-justice#.YvPaE05MI_Q.twitter,,Hacker News,81841 -timost,32421793,152,1660194394,Podman 4.2.0,https://github.com/containers/podman/releases/tag/v4.2.0,,Hacker News,87976703 -mathiasn,32422871,20,1660205387,Launch HN: AccessOwl (YC S22) – Automating SaaS Provisioning and Permissioning,,"Hey HN, we are Mathias and Philip, co-founders of AccessOwl (https://www.accessowl.io/). AccessOwl automates your employees' access to SaaS products. We give you a simple way to provision and deprovision any SaaS tool, as well as to configure permission levels. See a demo here: https://www.accessowl.io/productdemo.

Most of us use SaaS tools for work day-in and day-out. How do we get access to those tools? For the most part, through a colleague or IT admin who creates all accounts and sets permissions manually.

Here’s what it usually looks like for the unfortunate admin: (1) receive a request for a new tool via email, Slack, JIRA or face-to-face. Since you are busy with something else, you write a todo for later; (2) you log in to the tool and realize that the permission that was requested is way too high so you check in with the requestor’s manager; (3) you finally set up the account and document user, tool and permission in a Gsheet/Notion/Airtable.

This quickly becomes a 30m task for a simple access request! This is still the best practice for most people and it sadly also was for us. We were both founders before and experienced the same tedious process in different flavors at our own startups and other companies.

At some point we migrated to Okta and partially automated our provisioning and deprovisioning (permissioning, however, stayed painfully manual). Why only partially automated? Because Okta utilizes the SCIM API which was either not available in our tool stack or required an expensive upgrade to enterprise-subscription (thanks to the “sso tax”: https://news.ycombinator.com/item?id=31175300). And yet, we still missed simple things such as approval steps, a straightforward way to request access, and access reviews.

We talked to hundreds of organizations and saw the same manual processes and self-built scripts everywhere. The pain often starts at growing companies with around 50 employees. At this stage the CTO usually gets fed up with manually (de)provisioning and documenting it in a Gsheet. Another widespread cause of headache are IT security certifications (e.g. SOC2, ISO27001,...), requiring to know which employee has access to what tool, regular access reviews, and timely offboardings.

It seemed crazy that in a world where SaaS has become the norm, there was no great way to manage something as seemingly “trivial”, but also as critical, as user accounts. The core issues are, as always, missing integrations. Despite SCIM being the standard for over a decade, not all applications are utilizing it. Worse, many vendors lock it up in their enterprise plan.

This brought us to our core design principle: AccessOwl has to work with every tool, no matter what integrations are available. We generalize all the available ways of integrations in a single, simple interface. We take care of all the grunt work needed to coax each SaaS tool into doing the right thing. Whether it’s calling public APIs or resorting to Plaid-style automations as a last resort. Our first iteration was a simple workflow in Slack (Request -> Approve -> Manual provision). It covered all access documentation and solved back-and-forth communication between stakeholders. Since then, we have been adding more and more integrations to SaaS tools to directly (de)provision without the use of SCIM APIs. Taking a similar approach to provisioning as “Plaid” did in banking. We’re already covering 100+ tools and counting.

So what does a typical workflow look like?!

Step 1: Request an access, onboarding or offboarding. For this we piggy-back on whatever messaging tool is used in your org (we are starting with Slack, Teams will follow). It’s as simple as clicking a button to get your request started (no more manual JIRA tickets!) and always gets forwarded to the right stakeholders.

Step 2: Provisioning and permissioning. In the most basic workflow the tool owner receives the approved request with all the information to manually provision the account. If and when you arrive at the point where manual provisioning becomes a pain, you can let us automate it for you. The requestor will automatically get process updates and the access will be audit-ready logged in the background.

Prices start at $2.5 per employee per month and we charge a fixed premium for the automation of (de)provisioning based on the total number of employees.

We are excited for the opportunity to share AccessOwl with you! We would be more than excited to hear your thoughts and feedback and your own experiences with SaaS access management!",Hacker News,68093028 -beefman,32419873,173,1660174999,New study overturns 100-year-old understanding of color perception,https://discover.lanl.gov/news/0810-color-perception,,Hacker News,85749603 -iosystem,32423556,43,1660211897,General belief in a just world is associated with dishonest behavior (2017),https://www.frontiersin.org/articles/10.3389/fpsyg.2017.01770/full,,Hacker News,48281665 -robtherobber,32423870,30,1660215055,"Work, Work, Work – So a Few Can Be Rich",https://www.counterpunch.org/2022/08/09/work-work-work-so-a-few-can-be-rich/,,Hacker News,68020154 -pabs3,32422505,88,1660202187,"Give nothing, expect nothing: Gitlab latest punching bag for entitled users",https://dissociatedpress.net/2022/08/10/give-nothing-expect-nothing-gitlabs-the-latest-punching-bag-for-entitled-users/,,Hacker News,51081044 -doener,32395587,32,1660034928,The Cluetrain Manifesto (1999),https://www.cluetrain.com/,,Hacker News,86636626 -dmitryminkovsky,32417534,404,1660161290,The World Excel Championship is being broadcast on ESPN,https://www.ladbible.com/sport/world-excel-championship-that-is-getting-national-tv-coverage-20220809,,Hacker News,11788585 -luu,32408184,36,1660110578,The commissar for traffic presents the latest five-year plan (2014) [pdf],http://www.stat.columbia.edu/~gelman/research/published/ChanceEthics11.pdf,,Hacker News,25086124 -thunderbong,32396759,67,1660047140,A Story About ‘Magic' (1983),http://catb.org/jargon/html/magic-story.html,,Hacker News,8164930 -tmikaeld,32423291,4,1660209351,Open Cybersecurity Schema Framework,https://github.com/ocsf,,Hacker News,14060534 -ibobev,32411141,55,1660136278,Descriptors Are Hard,https://www.jlekstrand.net/jason/blog/2022/08/descriptors-are-hard/,,Hacker News,32452879 -sohkamyung,32423632,16,1660212674,Backyard hens’ eggs contain 40 times more lead on average than shop eggs,https://theconversation.com/backyard-hens-eggs-contain-40-times-more-lead-on-average-than-shop-eggs-research-finds-187442,,Hacker News,21319286 -koinedad,32422374,58,1660200905,How to learn hard things in tech,https://technicallychallenged.substack.com/p/how-to-learn-hard-things-in-tech,,Hacker News,89865816 -obert,32420082,37,1660176941,Robotic swimming in curved space via geometric phase,https://www.pnas.org/doi/full/10.1073/pnas.2200924119,,Hacker News,59082190 -merwanedr,32384870,51,1659963542,Terminal Latency (2017),https://danluu.com/term-latency/,,Hacker News,81684182 -neutralino1,32413070,104,1660143410,Launch HN: Sematic (YC S22) – Open-source framework to build ML pipelines faster,,"Hi HN – I’m Emmanuel, founder of Sematic (https://sematic.dev). Sematic is an open-source framework to prototype and productionize end-to-end Machine Learning (ML) and Data Science (DS) pipelines in days instead of weeks or months. The idea is to do for ML development what Rails and Heroku did for web development.

I started my career searching for Supersymmetry and the Higgs boson on the Large Hadron Collider at CERN, then moved to industry. I spent the last four years building ML infrastructure at Cruise. In both academia and industry, I witnessed researchers, data scientists, and ML engineers spending an absurd share of their time building makeshift tooling, stitching up infrastructure, and battling obscure systems, instead of focusing on their core area of expertise: extracting insights and predictions from data.

This was painfully apparent at Cruise where the ML Platform team needed to grow linearly with the number of users to support and models to ship to the car. What should have just taken a click (e.g. retraining a model when world conditions change – COVID parklets, road construction sites, deployment to new cities) often required weeks of painstaking work. Existing tools for prototyping and productionizing ML/DS models did not enable developers to become autonomous and tackle new projects instead of babysitting current ones.

For example, a widely adopted tool such as Kubeflow Pipelines requires users to learn an obscure Python API, package and deploy their code and dependencies by hand, and does not offer exhaustive tracking and visualization of artifacts beyond simple metadata.

In order to become autonomous, users needed a dead-simple way to iterate seamlessly between local and cloud environments (change code, validate locally, run at scale in the cloud, repeat) and visualize objects (metrics, plots, datasets, configs) in a UI. Strong guarantees around dependency packaging, traceability of artifact lineage, and reproducibility would have to be provided out-of-the-box.

Sematic lets ML/DS developers build and run pipelines of arbitrary complexity with nothing more than minimalistic Python APIs. Business logic, dynamic pipeline graphs, configurations, resource requirements, etc. — all with only Python. We are bringing the lovable aspects of Jupyter Notebooks (iterative development, visualizations) to the actual pipeline.

How it works: Sematic resolves dynamic nested graphs of pipeline steps (simple Python functions) and intercepts all inputs and outputs of each step to type-check, serialize, version, and track them. Individual steps are orchestrated as Kubernetes jobs according to required resources (e.g. GPU, high-memory), and all tracking and visualization information is surfaced in a modern UI. Build assets (user code, third-party dependencies, drivers, static libraries) are packaged and shipped to remote workers at runtime, which enables a fast and seamless iterative development experience.

Sematic lets you achieve results much faster by not wasting time on packaging dependencies, foraging for output artifacts to visualize, investigating obscure failures in black-box container jobs, bookkeeping configurations, writing complex YAML templates to run multiple experiments, etc.

It can run on a local machine or be deployed to leverage cloud resources (e.g. GPUs, high-memory instances, map/reduce clusters, etc.) with minimal external dependencies: Python, PostgreSQL, and Kubernetes.

Sematic is open-source and free to use locally or self-hosted in your own cloud. We will provide a SaaS offering to enable access to cloud resources without the hassle of maintaining a cloud deployment. -To get started, simply run `$ pip install sematic; sematic start`. Check us out at https://sematic.dev, star our Github repo, and join our Discord for updates, feature requests, and bug reports.

We would love to hear from everyone about your experience building reliable end-to-end ML training pipelines, and anything else you’d like to share in the comments!",Hacker News,42862101 -gamblor956,32417230,214,1660159737,FCC cancels Starlink’s and LTD's rural development grants,https://arstechnica.com/tech-policy/2022/08/fcc-rejects-starlinks-886-million-grant-says-spacex-proposal-too-risky/,,Hacker News,79382119 -samwillis,32418679,382,1660166827,Let websites framebust out of native apps,https://www.holovaty.com/writing/framebust-native-apps/,,Hacker News,29366290 -metadat,32420986,222,1660186280,Click the Paw,https://www.google.com/search?q=cat,,Hacker News,92481844 -hwhelan,32420081,27,1660176920,Join Data from PostgreSQL Declaratively in GraphQL Without Writing SQL,https://stepzen.com/blog/join-data-postgresql-declarative-graphql-without-sql,,Hacker News,76471375 -the_mitsuhiko,32415470,1147,1660151904,Instagram can track anything you do on any website in their in-app browser,https://krausefx.com/blog/ios-privacy-instagram-and-facebook-can-track-anything-you-do-on-any-website-in-their-in-app-browser,,Hacker News,44780406 -chmaynard,32410223,57,1660130865,Adding Auditing to Pip,https://lwn.net/SubscriberLink/904197/9f5cc13b3c352127/,,Hacker News,97924799 -eatonphil,32412905,328,1660142859,How SQLite Helps You Do ACID,https://fly.io/blog/sqlite-internals-rollback-journal/,,Hacker News,36158008 -ivanvas,32414215,272,1660147313,Review of /e/ – Android-based alternative for mobile phones,https://thenewleafjournal.com/review-of-e-an-android-alternative-for-mobile-phones/,,Hacker News,48713851 -elsewhen,32414870,195,1660149713,Dark Matter Doesn't Exist,https://iai.tv/articles/dark-matter-doesnt-exist-auid-2180,,Hacker News,34163437 -mpweiher,32384016,212,1659955022,Vector graphics on GPU,https://gasiulis.name/vector-graphics-on-gpu/,,Hacker News,32814922 -thunderbong,32395589,431,1660034943,The Story of Mel (1983),https://www.cs.utah.edu/~elb/folklore/mel.html,,Hacker News,64887478 -larve,32410355,223,1660131871,“Autistic people can’t acknowledge when they’re wrong”,https://the.scapegoat.dev/autistic-people-cant-acknowledge-when-they-are-wrong/,,Hacker News,17965619 -Tomte,32410283,178,1660131375,Stringbike: Benefits (2020),https://www.stringbike.com/stringbike_benefits.html,,Hacker News,84047227 -amelius,32419708,26,1660173702,Where does energy go during destructive interference?,https://van.physics.illinois.edu/qa/listing.php?id=21973,,Hacker News,94433052 -LukeEF,32412803,234,1660142525,The semantic web is dead – Long live the semantic web,https://github.com/GavinMendelGleason/blog/blob/main/entries/semantic_future.md,,Hacker News,20713613 -quaffapint,32412170,641,1660140363,"'Too many employees, but few work': Pichai, Zuckerberg sound the alarm",https://www.business-standard.com/article/international/too-many-employees-but-few-work-pichai-zuckerberg-sound-the-alarm-122080801425_1.html,,Hacker News,32522250 -pepys,32409386,47,1660121914,Why Nagasaki? (2013),http://blog.nuclearsecrecy.com/2013/08/09/why-nagasaki/,,Hacker News,54143852 -__Joker,32423100,12,1660207448,California Exported Its Worst Problem to Texas,https://www.theatlantic.com/ideas/archive/2022/08/housing-crisis-affordability-covid-everywhere-problem/671077/,,Hacker News,81033563 -tjwds,32423988,3,1660216118,Wikipedia’s Credibility Is Toast,https://wikipediocracy.com/2022/08/11/wikipedias-credibility-is-toast/,,Hacker News,66969920 -brudgers,32392070,97,1659998719,To speak meaningfully about art,https://medium.com/luminasticity/to-speak-meaningfully-about-art-329093dbce7f,,Hacker News,17843441 -carride,32411493,1073,1660137834,Man who built ISP instead of paying Comcast $50K expands to hundreds of homes,https://arstechnica.com/tech-policy/2022/08/man-who-built-isp-instead-of-paying-comcast-50k-expands-to-hundreds-of-homes/,,Hacker News,12377675 -samclemens,32410286,53,1660131403,An artist who hooked British rock royalty on her revolutionary crochet (2021),https://www.collectorsweekly.com/articles/the-swedish-artist-who-hooked-british-rock-royalty-on-crochet/,,Hacker News,54991992 -mitchbob,32416815,88,1660157769,The Case for Degrowth,https://www.lrb.co.uk/the-paper/v44/n16/geoff-mann/reversing-the-freight-train,,Hacker News,64900627 -WaitWaitWha,32399949,785,1660061782,An incident impacting 5M accounts and private information on Twitter,https://privacy.twitter.com/en/blog/2022/an-issue-affecting-some-anonymous-accounts,,Hacker News,50009193 -gregsadetsky,32416556,37,1660156583,Fucked Up Mockups,https://fockups.com/,,Hacker News,85727381 -rubenfiszel,32400849,203,1660065558,Launch HN: Windmill (YC S22) – Turn scripts into internal apps and workflows,,"Ruben here, software engineer, long-time lurker of Hacker News and founder of Windmill. Windmill is a fully open-source self-hostable platform and runtime to build complex workflows, internal apps and integrations using any scripts in Python or Typescript-deno. I am back after having been revealed a bit too soon on HN and miraculously getting into YC (https://news.ycombinator.com/item?id=31272793).

To build internal apps for ops, integrations between services that cannot talk to each other directly, or to run background jobs that run your business logic and analytics, the two main options today are no-code solutions and old-fashioned, roll-your-own scripting. Both have problems, and our goal with Windmill is to find a new sweet spot between the two. No-code solutions are productive if your problem matches the tool exactly - but it not, they are rigid, hard to extend and quickly become tech debt, annihilating their initial time advantage. Indeed, no-code is just code but made by an opinionated someone else and hidden as a blackbox with an UI.

The alternative is to do it the old-fashioned way, writing everything from scratch, both backend and frontend, perhaps deploying it on the latest flavor of serverless, and pray to never have to touch it again because that took way too much time and it has now became a burden that the ops and business team might poke you about regularly.

Furthermore, the landscape of SaaS is specialized tools for everything—alerting, data analytics, administration panels, support management, integration between services—when it feels like a few scripts would have been as good or even better and spared you the need of depending on one yet another tool. This could be even further facilitated if there was a way to import the right bunch of scripts from a fellow community of engineers, tweak it and deploy it like you can do in communities where automation can be shared as simple JSON files, for instance in the node-red or home assistant community.. That’s the idea of Windmill: to bring back the power of scripting in an easy way.

With Windmill, you write normal scripts, or reuse ones made by others, and we make them production-grade and composable. You shouldn’t have to worry about things like http requests or scheduling jobs. We abstract much of that away, making your scripts be both more focused and more composable. You end up doing things the right way but much quicker.

We reduce the complexity of workflows, integrations and internal apps by uniting them all under one banner. At the heart, they mostly have the same needs: workflows with a UI or a schedule. One tool that does it all out-of-the-box offers greater consistency and allows you to grow the complexity of your toolset at your own pace.

I have an academic background in compilers and industry experience in distributed systems. My compiler work made me wary of solving every problem with a domain-specific-language (DSL) or complex frameworks. We can just do more with the well-crafted existing languages like Python or Typescript. Rolling up your own DSL is nice in theory, you can make it very ergonomic and focused on the task at hand, but then you start adding features and either reinvent existing – albeit worse – programming language or decide to stop there. In the very large majority of cases, a well crafted library is vastly superior to any DSL. By being able to use any library of Python and Typescript, we stand on the shoulders of giants.

I have also observed that the best distributed systems are often the most simple as they are more predictable and have invariants that are easier to reason with and scale horizontally. This is why for Windmill, we rely solely on Postgres + our native workers + our http REST api layer. Later on, we plan to build adapters to host the workers on AWS lambda or Cloudflare workers, and the queue on Kafka if your needs are exceptionally high.

At the heart of what we have built is a queue implemented in Postgres and workers implemented in Rust that create a sandbox (using nsjail), fetch dependencies, and execute scripts. Every script can be triggered through its name with an HTTP POST by passing a JSON payload in which every field corresponds 1:1 to an argument of the script’s main parameters. Most primitive types in Python or Typescript have a natural corresponding type in JSON so the conversion is always what you would expect. We then execute the script inside a new sandbox and then store the results in the same Postgres DB at the end of the job execution.

The HTTP payload can be sent from your own frontend or you can use our automatically generated UI. Indeed, we do a simple, yet effective analysis of the parameters of your script, and from it, generate the jsonschema corresponding to your parameters. That schema is what enables us to convert any script into a no-code like module for flows, or a standalone internal app with its auto-generated UI. In the case of Python, we also look at the imports to deduce the Pypi dependencies without you having to declare them.

For flows, we defined an open spec for building them out of those scripts we call OpenFlow: https://docs.windmill.dev/docs/openflow. It is essentially a json format for describing a sequence of steps with for loops and soon branching. The most interesting bit here is that each input of each step can define its input as a javascript expression that refers to and transforms the output of any previous step. We make it fast by leveraging native v8 integration in Rust (thanks to the deno team) for executing those expressions. This makes this apparently linear sequence a flexible DAG in which one can express complex workflows.

Then on top of that we have an UI builder for flows that hides most of the complexity to give an experience that is similar to a low-code platform where every step is treated as a blackbox. The platform itself offers all the features that you would expect: a variable and object store for storing states, plain values and credentials; a cron scheduler, tight permissioning for the sensitive credentials, groups, a webeditor with smart assistant to edit the scripts directly in the platform etc. Finally, we made a hub (https://hub.windmill.dev) to share flows and scripts with everyone. The goal is to grow over time an exhaustive library of pre-made modules and flows to tweak from so that you can focus on what is actually custom to you.

Windmill is open-source and self-hostable. You can think of it as a superset of both Pipedream and Airplane.dev. Compared to Temporal, the scripts themselves are agnostic of the flow in which they are embedded, which has the benefit of making it easier to build a hub of reusable modules. We are the only ones as far as we know to convert script parameters to UI automatically. We see ourselves as complementary to UI builder solutions like Retool or Tooljet as we do not want to focus too much on the auto-generated UI and could be used solely as the backend part of the two aforementioned tools.

We are now a team of 3 senior engineers and the product is progressing faster than ever with a public roadmap: https://github.com/orgs/windmill-labs/projects/2

We make money from commercial licenses, support and team plans on the hosted solution.

You can self-host it or try it https://app.windmill.dev, the free tier is generous (and the paid one is not enforced yet). Our landing page is: https://windmill.dev. We would appreciate your feedback and ideas and look forward to all your comments!",Hacker News,86156210 -alberto_ol,32411769,83,1660138964,We thank Miss Mary Tsingou (2020),https://www.lanl.gov/discover/publications/national-security-science/2020-winter/mary-tsingou.shtml,,Hacker News,90592736 -walterbell,32411206,162,1660136581,Wet/Dry Vacuum Buying Guide (2019),http://wet-dry-vac.com/wet-dry-vacuum-guide.html,,Hacker News,32675334 -gumby,32409102,239,1660119133,The strength of the strong force,https://phys.org/news/2022-08-strength-strong.html,,Hacker News,76324546 -andriodsheep,32420205,10,1660178157,Superlattices Could Make Bulky Capacitors Obsolete,https://spectrum.ieee.org/antiferroelectric,,Hacker News,94128681 -Digit-Al,32410096,61,1660129569,What are you supposed to do with old clothes?,https://www.theatlantic.com/technology/archive/2022/08/what-to-do-with-old-clothing-donation-waste/671043/,,Hacker News,92353439 -radicalbyte,32410075,118,1660129335,The mechanics of a sophisticated phishing scam and how we stopped it,https://blog.cloudflare.com/2022-07-sms-phishing-attacks,,Hacker News,55404706 -fxtentacle,32409966,205,1660128341,Show HN: State-of-the-art German speech recognition in 284 lines of C++,https://github.com/DeutscheKI/tevr-asr-tool,,Hacker News,12590703 -todsacerdoti,32422082,113,1660197574,There aren't that many uses for blockchains,https://calpaterson.com/blockchain.html,,Hacker News,43789833 -thesecretceo,32419129,140,1660169952,Disney surpasses Netflix in global paid streaming subscribers,https://www.axios.com/2022/08/10/disney-surpasses-netflix-global-paid-subscribers,,Hacker News,34958068 -wishfish,32416424,494,1660156035,OnlyFans bribed Meta to put porn stars on terror watchlist: lawsuits,https://nypost.com/2022/08/09/onlyfans-bribed-meta-to-put-thousands-of-porn-stars-on-terror-watchlist-suits-claim/,,Hacker News,28202288 -pepys,32402373,134,1660071529,Archaeologists rebury ‘first-of-its-kind’ Roman villa,https://www.smithsonianmag.com/smart-news/archaeologists-rebury-first-of-its-kind-roman-villa-180980535/,,Hacker News,58684685 -zdw,32398353,244,1660054825,Hydroponics: Growing an appreciation for plants,https://www.bunniestudios.com/blog/?p=6481,,Hacker News,17670489 -unripe_syntax,32394994,60,1660028468,Justin Kan: Web3 games don’t need to lure players with profit,https://techcrunch.com/2022/08/08/twitch-founder-justin-kan-on-crypto-web3-video-games-business-model-profit-play-to-earn/,,Hacker News,53080967 -b_mc2,32417410,57,1660160628,SQLite-HTTP: A SQLite extension for making HTTP requests,https://observablehq.com/@asg017/introducing-sqlite-http,,Hacker News,61413884 -valgaze,32414698,91,1660149133,Nip2: A spreadsheet-like GUI for the libvips image processing library,https://github.com/libvips/nip2,,Hacker News,1343390 -whatisweb3,32423680,5,1660213220,Why US Tornado Cash Sanctions Are Concerning for Open Software,https://www.youtube.com/watch?v=XpTrCA3tEKM,,Hacker News,98265700 -pvsukale3,32408716,237,1660115986,Faster Ruby: Thoughts from the outside,https://www.mgaudet.ca/technical/2022/8/9/faster-ruby-thoughts-from-the-outside,,Hacker News,60354631 -apollinaire,32409928,11,1660127931,"Going, going... Goethe?",https://www.historytoday.com/archive/missing-pieces/going-goinggoethe,,Hacker News,29708119 -bryanrasmussen,32408393,206,1660112789,Essential Climbing Knots,https://www.climbing.com/skills/essential-climbing-knots-complete-guide/,,Hacker News,95115152 -JumpCrisscross,32419522,38,1660172468,Argentina on Two Steaks a Day,https://idlewords.com/2006/04/argentina_on_two_steaks_a_day.htm,,Hacker News,93157125 -swyx,32407873,192,1660105851,Reddit’s database has two tables (2012),https://kevin.burke.dev/kevin/reddits-database-has-two-tables/,,Hacker News,91301774 -notPlancha,32423274,4,1660209167,Senior developers create more senior developers,https://gomakethings.com/senior-developers-create-more-senior-developers/,,Hacker News,92543289 -cebert,32410492,31,1660132894,AMD Threadripper Pro 5995WX and 5975WX Review,https://www.tomshardware.com/news/amd-threadripper-pro-5995wx-5975wx-cpu-review,,Hacker News,49050085 -kuba_dmp,32412036,124,1660139920,How to market to developers on Twitter: Learnings from 4 months of Supabase feed,https://www.developermarkepear.com/blog/developer-marketing-on-social-media-twitter-supabase,,Hacker News,93268362 -voxadam,32421755,5,1660193971,"Ofrak: Unpack, Modify, and Repack Binaries",https://ofrak.com/,,Hacker News,65190380 -danielskogly,32401159,432,1660066902,"Astro 1.0 – a web framework for building fast, content-focused websites",https://astro.build/blog/astro-1/,,Hacker News,33163494 -digital55,32414684,68,1660149104,Mathematicians crack a simple but stubborn class of equations,https://www.quantamagazine.org/ancient-equations-offer-new-look-at-number-groups-20220810/,,Hacker News,60310261 -ScottStevenson,32378695,439,1659897949,Ask HN: What's the next big thing that few people are talking about?,,"Blockchain & AI don't count, because they're being talked about plenty!",Hacker News,93151771 -kirillrogovoy,32410293,33,1660131451,I quit my business to start an open-source dev tool,https://rogovoy.me/blog/i-quit-my-business-to-start-dev-tool,,Hacker News,83197030 -RickJWagner,32420423,6,1660180133,"Rare, original print of the US Constitution going to Arkansas",https://crystalbridges.org/calendar/we-the-people/,,Hacker News,25167519 -Freddie111,32423308,54,1660209577,CEO's LinkedIn Crying Selfie About Layoffs Met with Backlash,https://www.newsweek.com/ceos-linkedin-crying-selfie-about-layoffs-backlash-1732677,,Hacker News,60681018 -treyfitty,32411586,207,1660138265,"Ask HN: Exercises to think, then speak, more clearly?",,"I read a quote along the lines of "Next to height, the most unfair advantage someone can have is the ability to walk into a room without preparation and persuade the audience on just about any subject."

At face value, this sounds preposterous but there's merit to what the author is saying. Upon reflection, I've realized that this superpower is a lot harder than it seems and it requires:

- Ability to think clearly -- Ability to encode into brain what you want to say -- Deliver message

I'm finding it difficult to perform the first 2 steps. Has anyone found great resources and exercises to help with this?",Hacker News,48388443 -romeros,32419182,26,1660170262,Ask HN: Folks who were around the 2008 Recession,,How does the current recession feel like to you compared to 2008?

Do you feel this is the beginning of the recession or are we in the middle/end of it?,Hacker News,5132150 -lproven,32411153,84,1660136318,The many derivatives of CP/M,https://www.theregister.com/2022/08/04/the_many_derivatives_of_cpm/,,Hacker News,3596823 -rd07,32421092,12,1660187169,Ask HN: Google Maps alternatives that uses OSM and has a review feature,,"Several months ago, there is a similar question here https://news.ycombinator.com/item?id=29774603. But, what I am looking for is a Google Maps alternative that :

- is based on OSM

- has a review feature like Google Maps

- is not tied to a company

- is open source (optional)",Hacker News,57935331 -omn1,32398391,402,1660054961,"From novice to master, and back again (2013)",https://blog.djmnet.org/2013/01/14/from-novice-to-master-and-back-again/,,Hacker News,5361150 -zdw,32394195,205,1660019777,Area 5150: 8088 MPH gets a successor,https://scalibq.wordpress.com/2022/08/08/area-5150-8088-mph-gets-a-successor/,,Hacker News,71484372 -oscarwao,32409811,326,1660126720,Why aren't smart people happier?,https://experimentalhistory.substack.com/p/why-arent-smart-people-happier,,Hacker News,24319684 -pablohoffman,32409632,280,1660124770,Ask HN: What are the best tools for web scraping in 2022?,,"Last time this question was asked on HN was in 2017 (https://news.ycombinator.com/item?id=15694118), a lot has changed in the last 5 years in the world of web scraping (legal landscape, antibot unblockers, data type specific APIs, etc), so I thought it may be a good idea to refresh this question and see what are the most popular tools used by the HN community these days.",Hacker News,8662874 -obert,32420165,30,1660177771,Microsoft lays off team focused on winning back consumers,https://www.theverge.com/2022/8/10/23299499/microsoft-layoffs-modern-life-win-back-consumers-team,,Hacker News,39791105 -ZacnyLos,32416003,140,1660154243,Why does anything exist?,https://alwaysasking.com/why-does-anything-exist/,,Hacker News,54947068 -hrowtawaya,32417815,35,1660162622,Ask HN: How to build relationships in an internationally remote org?,,"I started a new job as a Software Engineering Manager at a remote startup ~6 months ago. My direct reports, peers, and manager are globally distributed and I am really struggling (perhaps failing) to develop strong relationships with anyone in the organization.

I've never had trouble establishing relationships in the past and have always had a few "allies" up and down the org by this point. Based on feedback in all-hands, etc. I don't think that my situation is unique in the org.

While this is disconcerting to me on its own, the part I struggle with the most is that I don't have anyone I feel comfortable talking to about the daily challenges that my team and I face.

I can lean on my extended network to a point, but what I would really like is a dedicator mentor that I could discuss specific problems with, above and beyond what I could reasonably ask of a friend. Has anyone had success establishing this type of relationship? If so, how? Alternatively, is anyone else facing this type of problem in a globally distributed company? How are you managing it?",Hacker News,56014192 -ksec,32414835,81,1660149590,Oscar winning PARASITE was edited with a 10 year old copy of Final Cut Pro 7,https://twitter.com/noamkroll/status/1556755415353925642,,Hacker News,88851153 -EntICOnc,32408577,131,1660114679,How to choose the right Python concurrency API,https://superfastpython.com/python-concurrency-choose-api/,,Hacker News,18388537 -Tomte,32409329,7,1660121182,"Creating the Catalog, Before and After FRBR (2017)",http://kcoyle.net/mexico.html,,Hacker News,69966266 -atan2,32407430,136,1660100314,A History of Lua (2001),https://www.lua.org/history.html,,Hacker News,21592566 -tmabraham,32414811,142,1660149521,Stable Diffusion launch announcement,https://stability.ai/blog/stable-diffusion-announcement,,Hacker News,42961255 -alphabetting,32410610,102,1660133538,"Google Fiber plans 5-state growth spurt, biggest since 2015",https://www.reuters.com/business/media-telecom/exclusive-google-fiber-plans-5-state-growth-spurt-biggest-since-2015-2022-08-10/,,Hacker News,88083821 -Hard_Space,32384653,850,1659961565,"To uncover a deepfake video call, ask the caller to turn sideways",https://metaphysic.ai/to-uncover-a-deepfake-video-call-ask-the-caller-to-turn-sideways/,,Hacker News,93214886 -dsmmcken,32390526,656,1659990080,I replaced all our blog thumbnails using DALL·E 2,https://deephaven.io/blog/2022/08/08/AI-generated-blog-thumbnails/,,Hacker News,1612742 -Phileosopher,32421659,39,1660192873,Ask HN: How do you keep marching?,,"I'm working on a huge hobby project, and it's getting discouraging because the results are taking longer than I expected.

When you have a vision, how do you work toward it for long spurts? Or is it more of a "micro-visions" approach? Not sure if I'm asking the right questions, so feel free to reframe them if I'm not being clear enough.",Hacker News,64940530 -memorable,32395518,367,1660034223,"Thank You, Firebug (2017)",https://getfirebug.com/,,Hacker News,62611921 -xgdgsc,32407451,122,1660100612,JNumPy: Writing high-performance C extensions for Python in minutes,https://github.com/Suzhou-Tongyuan/jnumpy,,Hacker News,58002347 -pantalaimon,32396638,184,1660046176,Nvidia publishes 73k lines of 3D header files for Fermi through Ampere GPUs,https://www.phoronix.com/news/NVIDIA-3D-Headers-Fermi-Ampere,,Hacker News,40981807 -fabiendevos,32388410,171,1659979549,Launch HN: Wolfia (YC S22) – A mobile app emulator you can share with a link,,"Hi HN! We’re Fabien and Naren, co-founders of Wolfia (https://www.wolfia.com). Wolfia lets you share a link to a mobile emulator running your app. Developers can get feedback instantly on a feature they just built by sharing a link to an interactive version of their app. We’re starting with Android but iOS is coming soon!

Mobile app development in 2022 is harder than it should be - you can't easily change a line of code, rebuild the app, and have someone on the other side of the world see the result in seconds. Instead of the rapid iterations that web app developers enjoy, mobile app developers are stuck with pushing builds every night and waiting a day for the team to see the new code. That's if they even have a nightly build setup. Most people also only have one phone, so they can never test the Android app if they have an iPhone and vice versa.

We've been developing mobile apps for over 10 years (at Facebook, Wealthfront, etc.). In that time, the tooling has dramatically improved, yet we still found ourselves having to go and install emulators on a PM's laptop and give them commands to copy and paste on the terminal because they didn't have an Android phone. Or we would have to procure test phones and wait for a build to be pushed. We’re building Wolfia to finally make this process seamless.

Wolfia lets developers send a link to an APK (an Android binary) that's running on an emulator accessible via the browser. You can then play with the app without the need for a physical device. This dramatically shortens the feedback loop and completely transforms the dev cycle: from days to hours or even minutes.

Product managers and designers can use it to check that a new feature is being built up to their specs. Developers can use it to check if the code is running correctly. Founders, user researchers and salespeople can use it for interactive demos of the product.

We host headless (without GUI) Android emulators with hardware acceleration running on AWS bare metal instances to get high performance. We use WebSockets to make a two-way connection between the browser and the emulator through ADB (Android Debug Bridge). The emulator's GUI is displayed on the browser via an H.264 video feed, and we relay the user's touch events back to the emulator. We use WSS to make this secure.

Try it for free at https://www.wolfia.com! (you can try a demo - we used Materialistic, an open source HN app - or sign up for free and upload your own app)

We would love to hear your thoughts, ideas and feedback!",Hacker News,70660988 -justinludwig,32402630,221,1660072395,Implementing a Zero Trust Architecture,https://www.nccoe.nist.gov/projects/implementing-zero-trust-architecture,,Hacker News,72954652 -bshanks,32406883,142,1660094745,Baby’s First Garbage Collector (2013),https://journal.stuffwithstuff.com/2013/12/08/babys-first-garbage-collector/,,Hacker News,61291286 -cancan,32418675,24,1660166790,How to design a beautiful map,https://felt.com/blog/how-to-design-a-beautiful-map,,Hacker News,19153008 -icyfox,32403746,160,1660076606,Falling for Kubernetes,https://freeman.vc/notes/falling-for-kubernetes,,Hacker News,58979128 -ericliuche,32410948,311,1660135294,U.S. annual inflation rate drops to 8.5%,https://www.bls.gov/news.release/archives/cpi_08102022.htm,,Hacker News,6409026 -nreece,32393634,367,1660012171,How fast is 12th Gen Intel Core?,https://frame.work/blog/how-fast-is-12th-gen-intel-core,,Hacker News,25749206 -obert,32397341,38,1660050785,Sea creatures pollinate marine plants and algae,https://www.nationalgeographic.co.uk/science-and-technology/2022/08/sea-creatures-pollinate-marine-plants-and-algae-surprising-scientists,,Hacker News,41241673 -giuliomagnifico,32395840,264,1660037818,Our brain is a prediction machine that is always active,https://www.mpi.nl/news/our-brain-prediction-machine-always-active,,Hacker News,5675375 -Fabricio20,32399238,757,1660058543,“It’s time for Apple to fix texting”,https://www.android.com/get-the-message/,,Hacker News,50360547 -notpushkin,32402542,52,1660072130,Video Stabilization with FFmpeg and VidStab,https://www.paulirish.com/2021/video-stabilization-with-ffmpeg-and-vidstab/,,Hacker News,35409141 -larsiusprime,32398963,170,1660057241,W4 Games formed to strengthen Godot ecosystem,https://w4games.com/2022/08/09/hello-world-w4-games/,,Hacker News,21036027 -Destiner,32402631,151,1660072404,Sol: Open-source Alfred/Raycast alternative for macOS,https://github.com/ospfranco/sol,,Hacker News,21243302 -blacksqr,32405713,98,1660085996,Tcled: Pure Tcl Console Text Editor (2019),https://github.com/slebetman/tcled,,Hacker News,14540726 -ltratt,32408546,74,1660114377,Making a Video of a Single Window,https://tratt.net/laurie/blog/2022/making_a_video_of_a_single_window.html,,Hacker News,1713189 -Marat_Tokyo,32412745,38,1660142351,RaspberryPi for measuring bio signals (open source),https://github.com/HackerBCI,,Hacker News,27475430 -wooosh,32401548,153,1660068456,Lz_xor,http://richg42.blogspot.com/2022/01/lzxor.html,,Hacker News,87289853 -zdw,32394176,70,1660019571,The Godfather of Complexity,http://blog.computationalcomplexity.org/2022/08/the-godfather-of-complexity.html,,Hacker News,35457941 -weinzierl,32419253,24,1660170709,"Cisco hacked by Yanluowang ransomware gang, 2.8GB allegedly stolen",https://www.bleepingcomputer.com/news/security/cisco-hacked-by-yanluowang-ransomware-gang-28gb-allegedly-stolen/,,Hacker News,29795935 -marc__1,32406563,148,1660091938,AppLovin bids $17.5B to acquire Unity,https://www.axios.com/2022/08/09/applovin-unity-video-game-consolidation,,Hacker News,32997639 -zwischenzug,32396892,217,1660047856,“Who Should Write the Terraform?”,https://zwischenzugs.com/2022/08/08/who-should-write-the-terraform/,,Hacker News,23522622 -mhb,32410602,271,1660133481,U.K.'s online censorship bill causes more harm than it attempts to prevent,https://reason.com/2022/08/10/u-k-s-online-censorship-bill-causes-far-more-harm-than-it-attempts-to-prevent/,,Hacker News,39653546 -taubek,32403206,39,1660074352,From working at Subway to one of the greatest mathematicians (2015),https://www.quantamagazine.org/yitang-zhang-and-the-mystery-of-numbers-20150402,,Hacker News,26316029 -sundaypancakes,32413789,26,1660145861,Why Developers Are Building So Many Side Projects,https://future.com/developers-side-projects/,,Hacker News,21399823 -sweetheart,32403471,275,1660075416,Fishing gear accounts for an alarming amount of plastic in oceans (2021),https://www.nature.org/en-us/newsroom/ca-ocean-plastic/,,Hacker News,32254694 -bojangleslover,32421971,3,1660196356,Ask HN: How to best present to semi tech/quant-savvy audience?,,"Recently I have found myself presenting to senior management at a bank. I have found these presentations go one of three ways.

1) Fairly well but without a deep audience understanding -2) Fairly well with the audience hyper-fixated on the wrong detail -3) Fairly well with the audience hyper-fixated on the right detail -4) Fairly poorly with a few pity questions asked at the end

Because I keep getting asked back I'm sure I am on to something. But I really want to take these to the next level and put myself in buckets 1, 2 and 3 while avoiding bucket 4. I know due to natural variation in outcomes that there will be some 4's even for the best presenters.

Obviously this is context-dependent but I want to hear from the community.",Hacker News,96010569 -rcarmo,32395256,73,1660031344,A quick and practical “MSI” hash table,https://nullprogram.com/blog/2022/08/08/,,Hacker News,46719901 -p5v,32398969,190,1660057280,The problem with Go’s default HTTP handlers,https://preslav.me/2022/08/09/i-dont-like-golang-default-http-handlers/,,Hacker News,44279569 -antipaul,32420641,17,1660182115,Meta's own chatbot says the company 'exploits people',https://www.bbc.com/news/technology-62497674,,Hacker News,16479611 -ivanvas,32402977,166,1660073563,Google Maps' moat is evaporating (2020),https://joemorrison.substack.com/p/google-maps-moat-is-evaporating,,Hacker News,91707970 -notabanker,32416402,19,1660155887,"Ask HN: For a startup website to show customer logos, do you need permission?",,Many startup websites list company logos on their website as a form of social proof. I'm wondering if these startups took the company's permission before displaying their logo.,Hacker News,73649724 -samclemens,32397547,24,1660051725,Who Built the First Electric Rock 'N' Roll Guitar? (2019),https://www.collectorsweekly.com/articles/who-really-built-the-first-electric-rock-n-roll-guitar/,,Hacker News,13523302 -soheil,32407114,68,1660097115,Gmail Dynamic Email (a.k.a. AMP for Email),https://support.google.com/a/answer/9709409?hl=en,,Hacker News,25456984 -bane,32420761,11,1660183290,The Car-Replacement Bicycle (The Bakfiets),https://www.youtube.com/watch?v=rQhzEnWCgHA,,Hacker News,9829728 -InTheArena,32417675,29,1660162033,Jeff Geerling Is Sick,https://www.youtube.com/watch?v=MXxPsWjMW1A,,Hacker News,8606267 -kristianpaul,32407361,109,1660099523,Mental Model Practices,https://mmpractices.com/,,Hacker News,79559267 -pseudolus,32406452,107,1660091068,Artificial synapses 10k times faster than real thing,https://spectrum.ieee.org/artificial-synapses,,Hacker News,64464016 -martialg,32399612,181,1660060460,Dusting “Attack” via Tornado Cash to Public Wallets,https://etherscan.io/txsInternal?a=0x12d66f87a04a9e220743712ce6d9bb1b5616b8fc&p=1,,Hacker News,89702362 -todsacerdoti,32401480,49,1660068205,Federation vs. Clustering: Self-determination vs. distributed computing?,https://sequentialread.com/federation-vs-clustering-self-hosting/,,Hacker News,60800329 -geox,32421137,6,1660187549,Scientists identify mechanism crucial for Covid virus replication,https://www.utsouthwestern.edu/newsroom/articles/year-2022/august-covid-19-virus-replication.html,,Hacker News,39231598 -fuegoio,32405510,93,1660084946,"Show HN: 1024, a 2048 Puzzle Game",https://1024-game.netlify.app/,,Hacker News,2946961 -azalemeth,32383820,416,1659952551,Open AirPlay 2 Receiver,https://github.com/openairplay/airplay2-receiver,,Hacker News,33625762 -astonfred,32415055,31,1660150403,Directory of canned responses. If you lack inspiration,https://cannedtxt.com/,,Hacker News,9000037 -bryanrasmussen,32421538,10,1660191505,Hollywood’s Visual Effects Crisis,https://defector.com/inside-hollywoods-visual-effects-crisis/,,Hacker News,73631725 -erulabs,32401691,133,1660069027,How and why to host a blog at home,https://kubesail.com/blog/2022-08-08-how-and-why,,Hacker News,90863659 -camjohnson26,32416766,37,1660157535,Ralph Nader urges regulators to recall Tesla’s ‘manslaughtering’ FSD vehicles,https://www.theverge.com/2022/8/10/23299973/ralph-nader-tesla-fsd-recall-nhtsa-autopilot-crash,,Hacker News,42220676 -whoami_nr,32403504,126,1660075562,Tornado cash takedown and its repercussions,https://rnikhil.com/2022/08/09/tornado-cash-block.html,,Hacker News,37116449 -panarky,32421372,7,1660189790,How the New York Times Uses Machine Learning to Make Its Paywall Smarter,https://open.nytimes.com/how-the-new-york-times-uses-machine-learning-to-make-its-paywall-smarter-e5771d5f46f8?gi=fe03f90b8e13,,Hacker News,28664705 -triska,32401468,116,1660068143,ÆPIC Leak: Architecturally leaking uninitialized data from the microarchitecture [pdf],https://aepicleak.com/aepicleak.pdf,,Hacker News,45980012 -Meph504,32415256,22,1660151095,Tell HN: Network solution added .online to all of our domains,,"We have a number of very old domains that have been with network solutions since the late 1990s. Today we get a renewal notice for olddomain.online

log into our account to find all of these, and being redirected to our domain.

After like an hour of trying to track down the various people in our org who could have possibly done this. Our accountant find an email sent to her, saying as we have been "upgraded" as part of network solutions "Brand Protection Program"

Anyone else with network solutions notice this on your domains?",Hacker News,57567524 -indygreg2,32386762,306,1659972891,Achieving an open-source implementation of Apple Code Signing and notarization,https://gregoryszorc.com/blog/2022/08/08/achieving-a-completely-open-source-implementation-of-apple-code-signing-and-notarization/,,Hacker News,39974621 -eke_uche,32409980,10,1660128470,Show HN: Genti Audio – Stories and podcasts in African languages,https://gentimedia.com/,"Hi all, -Eke here, co-founder of Genti Audio. Genti Audio is a mobile app for streaming and downloading Africa-focused audiobooks, stories, and podcasts in regional and local African languages.

In September 2021, my sister and I sat down to work on an audio show exploring Nigeria’s cultural and linguistic diversity. As we began to put the show together, we realized that our target audience- Nigerians and Africans in both urban and rural areas, were not heavily present on any of the major audio platforms for this type of content. Recognizing this, we decided to first fix this distribution gap, and so the idea for Genti was born.

From just an idea, we began pooling resources and soon started developing our beta app. And after months of hard work building, scouring for content, and raising funds from supportive friends and family, we are very excited to announce the launch of our mobile app. We will continue to improve the app and roll out more features over the next 4 months. Download the App now on Google Play or the Apple App Store and start listening!

At Genti, our mission is to amplify African stories and voices to entertain, educate, and enrich lives. In line with our mission, we’ll spend the next 3 - 6 months getting the best entertaining and educative African audio content out there and curating for our users. We also believe that for every African story told there are hundreds waiting to be told, and that’s why we’ve begun working on developing engaging original content available exclusively on our platform. Genti is committed to playing a vital role in developing and deepening audio storytelling on the continent.

To download the app, visit the Genti website, or download directly from Google Play and the Apple App store and start listening!

If you’ve got a podcast, audiobook, or story you’d like to upload on Genti, please send an email to ojiugo@gentimedia.com and we’ll be in touch. We’d also love to get feedback from you on your experience with the Genti App.",Hacker News,78080007 -fortran77,32421292,7,1660189141,The Hacking of Starlink Terminals Has Begun,https://www.wired.com/story/starlink-internet-dish-hack/,,Hacker News,69040967 -philips,32405321,24,1660083941,Hydroponics: Growing an Appreciation for Plants,https://www.bunniestudios.com/blog/?p=6481,,Hacker News,55416361 -efavdb,32381206,276,1659917551,Spaced repetition can allow for infinite recall,https://www.efavdb.com/memory%20recall,,Hacker News,9122326 -nkmnz,32410333,35,1660131757,Ask HN: List of titles and specifications for tech jobs?,,"As jobs get more and more differentiated, it's getting harder for the "uninitiated" to find the right wording that speaks to the right people. Is there a conclusive list of job titles and specifications one could rely on?

FWIW, I'm looking for someone to lead all engineering efforts wrt to "everything analytics": -- what to measure and where to measure (EDIT: meaning "which actions, e.g. clicks, constitute the start of a specific action? How can we determine that a user stopped for break? etc... more details below!) -- which tools to use -- how to integrate libraries/services -- where to store data -- how to access raw data -- how to process raw data -- how to access processed information

... at a 10-15 person (six developers) Startup.

EDIT: To answer the questions below and specify the role: we're in EdTech, so the data we want to gather is used to 1) give users an overview of and feedback about their activity, 2) create effective and evidence-based interventions, and 3) improve learning outcomes and engagement. More detailed objectives are determined by management and research roles, but they still need to be translated into code – almost like a restaurant owner can tell a chef to make a specific dish, but the chef still needs to know which pan to use.",Hacker News,48334007 -_Microft,32399368,101,1660059227,Noether's Theorem in a Nutshell (2020),https://math.ucr.edu/home/baez/noether.html,,Hacker News,44627177 -graderjs,32396641,132,1660046214,How do palm trees survive hurricanes? (2017),https://www.indefenseofplants.com/blog/2017/9/10/how-do-palms-survive-hurricanes,,Hacker News,54601366 -ss48,32415224,23,1660150991,Amazon Kindle Moving from MOBI to ePub File Format,https://goodereader.com/blog/kindle/everything-you-need-to-know-about-the-amazon-kindle-supporting-epub,,Hacker News,16018480 -HelenePhisher,32377063,547,1659884910,Fake IMDB credits,https://peabee.substack.com/p/16-the-case-of-fake-imdb-credits,,Hacker News,44399816 -LinuxBender,32414954,34,1660150006,Iran cheerfully admits using cryptocurrency to pay for imports,https://www.theregister.com/2022/08/10/iran_pays_for_imports_in_crypto/,,Hacker News,56023237 -fest,32394607,154,1660024283,The tooling ecosystem that adds joy to KiCad,https://media.ccc.de/v/mch2022-332-the-tooling-ecosystem-that-adds-joy-to-kicad,,Hacker News,90918577 -jader201,32417726,20,1660162251,More Than a Third of U.S. Teens Are on Social Media Almost Constantly,https://www.wsj.com/articles/more-than-a-third-of-u-s-teens-are-on-social-media-almost-constantly-survey-says-11660140000,,Hacker News,65572845 -ingve,32399663,108,1660060705,Implementing parts of the Swift compiler in Swift,https://forums.swift.org/t/implementing-parts-of-the-swift-compiler-in-swift/59524,,Hacker News,59880085 -jeremylevy,32399752,96,1660061004,"Show HN: Recode – Free, open-source, community-driven Codespaces alternative",https://github.com/recode-sh/cli,"Hey HN,

As most of you (I think?), I cannot learn something without having a project, on the side, to implement what I’ve just learned.

Recode is the project that I've used to learn Go. It lets you create a development environment in your cloud provider account easily.

You can think of it as a desktop version of Gitpod / Coder / GitHub Codespaces less polished and with less features but 100% free, 100% open-source and 100% community-driven.

At the time of writing, it only works with Visual Studio Code and AWS.

In order to let you configure your development environments easily, I’ve chosen to use Docker with some Dockerfiles:

   - One for your user configuration.
-   
-   - One for your project.
-
-The user configuration corresponds to the tools / settings that you use in all your projects like your timezone / locale, your preferred shell or your dotfiles.

The project configuration corresponds to the tools / settings that you use in a specific project like Go >= 1.18 and Node.js >= 14.

As you may have guessed, the project configuration inherits from the user one.

> Why Docker and not something like NixOS, for example?

I know that containers are not meant to be used as a VM like that, but, at the time of writing, Docker is still the most widely used tool among developers to configure their environment (even if it may certainly change in the future :-)).

> Given that my dev env will run in a container does it mean that it will be limited?

Mostly not.

Given the scope of this project (a private instance running in your own cloud provider account), Docker is mostly used for configuration purpose and not to "isolate" the VM from your environment.

As a result, your development environment container runs in privileged mode in the same network than the host.

----

I post this here, because, you know, even learning project could be useful to someone.

Still learning Go by the way, so I'm open to any suggestions to improve.",Hacker News,57599617 -Dezocine,32410307,29,1660131554,Francis Fukuyama: Paths to Depolarization,https://www.persuasion.community/p/fukuyama-paths-to-depolarization,,Hacker News,68034289 -carride,32397920,168,1660053208,Almost every Ferrari sold since 2005 is being recalled,https://arstechnica.com/cars/2022/08/almost-every-ferrari-sold-since-2005-is-being-recalled/,,Hacker News,86424351 -oumua_don17,32401510,74,1660068322,Will Intel's AXG division survive Pat Gelsinger’s axe?,https://www.jonpeddie.com/editorials/will-axg-survive-gelsingers-axe/,,Hacker News,90774210 -dthul,32384550,283,1659960639,MiniRust,https://www.ralfj.de/blog/2022/08/08/minirust.html,,Hacker News,98401403 -TecoAndJix,32397699,72,1660052382,2022 NSA Codebreaker Challenge,https://nsa-codebreaker.org/home,,Hacker News,85728863 -throwaddzuzxd,32398181,83,1660054118,Ask HN: How to make a native GUI with a modern language?,,"HN has strong opinions against Electron so here are my requirements:

- I want to make a native looking GUI

- Cross platform (macOS, Windows, Linux)

- With a sane language (no C, C++ or Objective C)

- Ideally with a data flow looking like unidirectional data flow / Elm architecture

What options do I have?",Hacker News,7512236 -lerno,32392161,216,1659999378,The case against a C alternative,https://c3.handmade.network/blog/p/8486-the_case_against_a_c_alternative,,Hacker News,69495560 -andsoitis,32390499,212,1659989885,The productivity tax you pay for context switching,https://async.twist.com/context-switching/,,Hacker News,91901694 -vishnuharidas,32416786,23,1660157631,"Sure it has memory leaks but who cares, it’s a freaking missile",https://twitter.com/Carnage4Life/status/1556374093938626560,,Hacker News,21386231 -beefman,32406422,59,1660090850,Cognitive training: A field in search of a phenomenon,https://journals.sagepub.com/doi/10.1177/17456916221091830,,Hacker News,32384680 -zw123456,32407766,74,1660104598,Unprecedented 100% of First 14 Patients with Cancer Respond to Dostarlimab,https://ascopost.com/news/june-2022/unprecedented-100-of-first-14-untreated-patients-with-rectal-cancer-respond-to-pd-1-blocker-dostarlimab-gxly/,,Hacker News,62533922 -mfiguiere,32417690,27,1660162079,Disney raises price on ad-free Disney+ 38% to $10.99,https://www.cnbc.com/2022/08/10/disney-raises-price-on-ad-free-disney-38percent-as-part-of-new-pricing-structure.html,,Hacker News,56304662 -dboreham,32419601,6,1660173068,Why is my Twitter account in a superposition state?,,Trying to use an account I created a long time ago. Logging in with the old password fails. Attempts to reset the password using my email produce "Sorry we could not find your account". Meanwhile an attempt to create a new account with my email produces "Email has already been taken".,Hacker News,14820527 -xena,32381550,343,1659921641,I 10x'd a TI-84 emulator's speed by replacing a switch-case,https://artemis.sh/2022/08/07/emulating-calculators-fast-in-js.html,,Hacker News,87122798 -bookofjoe,32381790,335,1659924441,A physical wiring diagram for the human immune system,https://www.nature.com/articles/s41586-022-05028-x,,Hacker News,44087928 -111111101101,32420494,7,1660180760,DOJ Is Preparing to Sue Google over Ad Market as Soon as September,https://www.bloomberg.com/news/articles/2022-08-09/doj-poised-to-sue-google-over-ad-market-as-soon-as-september,,Hacker News,46114258 -ingve,32417373,3,1660160438,Dos and Don'ts of Machine Learning in Computer Security [pdf],https://www.usenix.org/system/files/sec22summer_arp.pdf,,Hacker News,77447884 -reimertz,32386290,229,1659970960,IKEA Symfonisk Gen2 Amp Modification Guide – A Much Cheaper Sonos Amp,https://www.thetylergibson.com/ikea-symfonisk-gen2-amp-modification-guide-a-much-cheaper-sonos-amp/,,Hacker News,36910249 -senzilla,32417272,3,1660159930,Installing OpenBSD on Scaleway Elastic Metal,https://www.senzilla.io/blog/2022/08/10/installing-openbsd-scaleway-elastic-metal/,,Hacker News,95747271 -tintinnabula,32396569,18,1660045541,The Disappearing Modernists,https://theamericanscholar.org/the-disappearing-modernists/,,Hacker News,6871667 -rhaksw,32376136,61,1659877144,Self-Reliance (1841),https://archive.vcu.edu/english/engweb/transcendentalism/authors/emerson/essays/selfreliance.html,,Hacker News,61102651 -larve,32392217,39,1659999866,"Barbara Liskov, the Architect of Modern Algorithms",https://www.quantamagazine.org/barbara-liskov-is-the-architect-of-modern-algorithms-20191120/,,Hacker News,80270460 -Arathorn,32413075,7,1660143435,Are We OIDC Yet? Moving Matrix to OIDC,https://areweoidcyet.com/,,Hacker News,15183734 -whatrocks,32386328,65,1659971202,A Linux desktop for your wall,https://charlieharrington.com/run-linux-on-electric-objects-eo1-wall-computer/,,Hacker News,34565907 -ivank,32390600,47,1659990554,The Locus of Entertainment,https://blog.nateliason.com/p/the-locus-of-entertainment,,Hacker News,33407697 -levmiseri,32394902,128,1660027220,Show HN: Yare 2 – Programmable RTS game,https://www.yare.io,"Hi HN! About a year ago I showed my side project Yare here (https://news.ycombinator.com/item?id=27365961) and was overblown by the feedback and support. Since then a lot has changed and I'm excited to share the beta of 'Yare 2' (https://www.yare.io/).

The simple programming game has evolved into something a little more complex with the ability to not only control the units with code, but now practically anything is programmable. E.g. the players can build their own UI elements to play the game with (when you choose 'play with mouse and keyboard' on the homescreen, it showcases what is possible to create).

This is a passion project that I don't plan to anyhow excessively monetize and will be always free to play, but I'm worried that it's perhaps growing into a too chaotic/confusing game and losing its initial simplicity.",Hacker News,70128729 -kevmo314,32392599,162,1660003378,MantaRay: Open-Source Ray Tracer,https://github.com/ange-yaghi/manta-ray,,Hacker News,90915863 -kamaraju,32413220,74,1660143908,Celsius Network Files Chapter 11 Bankruptcy,https://dfr.vermont.gov/consumer-alert/celsius-network-files-chapter-11-bankruptcy,,Hacker News,33695157 -cameron_b,32410374,32,1660132040,Why the IRS Needs $80B,https://www.washingtonpost.com/opinions/interactive/2022/irs-pipeline-tax-return-delays/,,Hacker News,35456165 -some_random,32398923,205,1660057069,Saskatoon Freezing Deaths,https://en.wikipedia.org/wiki/Saskatoon_freezing_deaths,,Hacker News,73545304 -ivanvas,32383943,122,1659954160,Teardown of a quartz crystal oscillator and the tiny IC inside,https://www.righto.com/2021/02/teardown-of-quartz-crystal-oscillator.html,,Hacker News,28101375 -ducaale,32405848,12,1660086790,Assorted thoughts on Zig and Rust (2020),https://www.scattered-thoughts.net/writing/assorted-thoughts-on-zig-and-rust/,,Hacker News,54670815 -smartmic,32379066,381,1659900395,Mysterious holes on the seafloor,https://oceanexplorer.noaa.gov/news/oer-updates/2022/mysterious-holes-seafloor/mysterious-holes-seafloor.html,,Hacker News,291005 -Trouble_007,32418853,7,1660167978,FDA Monkeypox Response,https://www.fda.gov/emergency-preparedness-and-response/mcm-issues/fda-monkeypox-response,,Hacker News,15078092 -bookofjoe,32392937,165,1660006298,A biochemist’s view of life’s origin reframes cancer and aging,https://www.quantamagazine.org/a-biochemists-view-of-lifes-origin-reframes-cancer-and-aging-20220808/,,Hacker News,8458488 -thesecretceo,32421054,4,1660186787,Texting between iPhone and Android is broken': Google puts Apple on blast for,https://www.businessinsider.com/google-tells-apple-fix-texting-between-android-iphone-green-bubbles-2022-8,,Hacker News,1060368 -obert,32383835,132,1659952808,Uses for an old Android device,https://www.computerworld.com/article/2487680/20-great-uses-for-an-old-android-device.html,,Hacker News,30899087 -alschwalm,32405526,12,1660085035,Wikidata Query Service,https://query.wikidata.org/,,Hacker News,68119458 -strzalek,32380769,323,1659913159,Why does gRPC insist on trailers?,https://carlmastrangelo.com/blog/why-does-grpc-insist-on-trailers,,Hacker News,66427074 -sumul,32376154,405,1659877289,Show HN: Figure is a daily logic puzzle game,https://figure.game,"Hello, HN! Figure is a little side project I’ve been working on. Someone described it as Bejeweled meets Wordle.

I built the puzzle interface and website in Next.js and React, which was a first for me and overall a great learning experience. The daily puzzle data is queued up in a PostgreSQL table. Another table stores anonymous solve stats. Once a day, a cron job hits a serverless API that promotes the next puzzle as “live” and prompts Next.js to update the prebaked static site with the new data. The game state is managed with Redux and your stats are persisted to localStorage. Framer Motion for animations. Styling is mostly Tailwind CSS. I use Figma for design and Logic Pro to make the sounds.

I get a lot of questions about how the puzzles are generated. It’s not super sexy. I generate random grids of tiles and then run them through a brute force solver (sounds rough but the puzzles don’t feel anything). Every few days, I play through puzzles that look promising based on the solution space and pick some good ones to go into the queue. The rest are sent back to the void (again, painless).

I’ve spent a little bit of time tinkering with a procedural generator, but so far the random ones are better. The downsides of the random approach are (1) the curation effort required, and (2) the high variability in puzzle difficulty. I have a feeling there’s a whole body of math and CS knowledge where Figure is an example of something that I don’t know the name for (imposter syndrome intensifies).

As for the future of Figure, I feel strongly about keeping it free of ads, login walls, in-app purchases, or anything else that infringes on enjoyment or privacy. I’d also like to make sure Figure is accessible to everyone. English isn’t exactly required to play, but translations for the UI and website would be nice. I’ve tried to build Figure to be friendly to people who have color vision deficiency and people who rely on screen readers and keyboard navigation, but I have no idea if it’s actually any fun in these cases.

Here are some miscellaneous thoughts…

1. It’s been surprisingly satisfying to build a web game with a modern frontend stack. I’ve noticed a lot of grumbling on HN over the years from OG web developers who yearn for the days of semantic HTML, a sprinkling of CSS, and vanilla JS. I was in that boat too and have grumbled plenty about the breakneck pace of frontend evolution. One of my goals with this project was to pick some popular frameworks and give them an honest try. I’m now a believer, but there’s still no way I can keep up with all the progress.

2. I found Tailwind awkward at first, but after a while I realized I was using Figma a lot less and just designing in code with utility classes, which is great for focus and flow. Having lived through the Web 2.0 standards revolution, it was hard to let go of some deeply rooted opinions about semantic purity, but overall I’m sold.

3. I really love side projects. At most jobs, you’re pushed toward specialization. Side projects allow you to build out a generalist skillset, which makes you better at your core job function and better at collaborating with others. It’s also liberating to explore and pivot around without time pressure. Figure started out as a 3D fidget toy in Unity where you fling projectiles at floating objects…

4. I made this game on my trusty 2013 MacBook Pro, which has been almost completely sufficient (ahem Docker ಠ_ಠ). I’ll probably get an M2 Air soon, but I’m reluctant to say goodbye to the best computer I’ve ever owned.

5. I’m very grateful for the people who build and maintain open source projects. It’s also delightful how many paid services offer generous free tiers to let developers play around: Figma, GitHub, Vercel, Supabase, and Pipedream, just to name a few that I’m currently using actively. If you work on FOSS and/or these excellent platforms, thank you.

Anyway, hope you like it. Happy to answer any questions.",Hacker News,38391990 -seansh,32395831,29,1660037713,One Word Broke C,https://web.archive.org/web/20210307213745/https://news.quelsolaar.com/2020/03/16/how-one-word-broke-c/,,Hacker News,31729979 -elsewhen,32417460,17,1660160927,Domino's tried to sell pizza to Italians. It failed,https://www.cnn.com/2022/08/10/business-food/dominos-exits-italy/index.html,,Hacker News,48911747 -vanilla-almond,32416236,8,1660155250,Tell HN: YouTube prioritises health-related searches 'From health sources',,"I only recently noticed this. It may be country-specific. Try searching for a medical condition or health issue. The YouTube search results are labelled 'From health sources'.

I'm not sure what to think of this change. Is it right to remove or deprioritise popular videos from search results if those videos come from unqualified "Doctors". I presume this also applies to anyone discussing a health topic who is not a health professional.

On the other hand, I understand why YouTube has taken this approach. There is a lot of misleading health advice too - it's impossible to police it all. YouTube's approach is to populate search results from health professionals or "credible health sources".

It's a difficult problem to tackle. What do think of this change to YouTube search? Do you think health videos should be unfiltered in search results - no matter the content, or who it comes from?

-----

Some links from YouTube:

Authoritative health information: https://www.youtube.com/howyoutubeworks/product-features/health-information/

Introducing new ways to help you find answers to your health questions: -https://blog.youtube/news-and-events/introducing-new-ways-help-you-find-answers-your-health-questions/",Hacker News,50972458 -pvitz,32384147,103,1659956530,De-anonymizing programmers from binaries (2017),https://arxiv.org/abs/1512.08546,,Hacker News,45018561 -jgillich,32397510,144,1660051560,AppLovin offers to buy Unity Software in $17.5 bln deal,https://www.reuters.com/markets/deals/applovin-offers-buy-unity-software-2022-08-09/,,Hacker News,21274238 -feross,32386276,66,1659970915,Why we chose Clojure,https://blog.kaleidos.net/penpot-chose-clojure-as-its-language-and-here-is-why/,,Hacker News,83755549 -zegl,32395076,95,1660029381,$5.6B cloud company Fivetran acquired its way to survival,https://www.forbes.com/sites/kenrickcai/2022/08/08/the-56-billion-internet-plumbers/,,Hacker News,77207121 -MilnerRoute,32420409,6,1660180039,Inflation drops to zero in July due to falling gas prices,https://www.axios.com/2022/08/10/inflation-cpi-report-july,,Hacker News,8332731 -kmod,32415580,3,1660152388,“Do AIs think” == “Do submarines swim”,https://blog.kevmod.com/2022/08/10/do-ais-think-do-submarines-swim/,,Hacker News,67206548 -grumblingdev,32411741,18,1660138833,Why are systems languages always overly complex?,,"I do most of my programming in Node and TypeScript. It's nice and simple.

I always wonder why we don't just use this syntax to write low-level system code. The module system is nice; functions, objects, and arrays are nice to work with; and the syntax is simple and familiar.

A systems language essentially just adds access to pointers.

In most of these systems languages, the raw memory management is often abstracted away into libraries, and we are just writing basic logic in a new convoluted syntax that a single dev happened to like. Think Rust, Zig, etc.

It's quite clear that TypeScript is going to be around forever. Why don't we just use this syntax for a systems language, and add a few constraints to make it low-level.

Imagine the same syntax/tooling for embedded, kernel, system (browsers, interpreters), backend, and frontend.

I just don't know why there is not more interest in this.",Hacker News,93374987 -flywind,32411178,6,1660136426,The Nim team's efforts in mitigating the false postives on the Nim binaries,https://forum.nim-lang.org/t/9358,,Hacker News,73034292 -neverminder,32396685,230,1660046617,Ask HN: Why did smartphones become a single point of failure?,,"i can't log in to any of my banks without my phone. Most of the systems in my workplace also require phone app authentication. I can't do any of those things with just a PC or laptop. Smartphones being the smallest and portable are surely the most lost and stolen. If someone got a hold of my PC or laptop - they would be able to do some damage, but not even close to if they were able to access my phone. Everything everywhere nowadays requires some app.",Hacker News,58959572 -hlship,32415184,4,1660150857,The Big Acquisition: What Nubank's Cognitect Acquisition Means for Clojure,https://www.juxt.pro/blog/the-big-acquisition,,Hacker News,80373963 -pwillia7,32384646,231,1659961494,Run your own DALL-E-like image generator,https://reticulated.net/dailyai/running-your-own-ai-image-generator-with-latent-diffusion/,,Hacker News,14209353 -jmerrick,32401413,12,1660067882,"Show HN: MOS, an application to help you deploy mathematical optimization models",https://fuinn.github.io/mos-docs/,"We built MOS in response to the frictions we experienced in deploying optimization solutions.

Some of the key benefits provided are the following: -- Models can be easily uploaded to the application after adding simple annotations to the model code. -- Models can be accessed via various available interfaces, including a REST API, a web graphical user interface, and client libraries in popular programming languages such as Python and Julia. -- Models can be run with different inputs by workers running locally or distributed over the network. -- Intermediate and end results can be extracted, browsed, and analyzed.

This is all available without the need for (the typically required) custom ad-hoc code.",Hacker News,6764307 -mountainview,32410630,8,1660133689,"Show HN:JuiceFS 1.0, A POSIX, HDFS, and S3 compliant cloud file system",https://juicefs.com/blog/en/posts/juicefs-release-v1/,,Hacker News,52991502 -Fendy,32422387,6,1660201016,Ask HN: What are the alternatives of HN for hackers?,,Don't get me wrong. I think Hacker News are great and I often read good posts/news/works here.

I am wondering if there are alternatives/peers beyond my knowledge and are as hacker-friendly as HN. Thanks.,Hacker News,56290696 -alistairSH,32396061,125,1660040835,Spiders Seem to Have REM-Like Sleep and May Even Dream,https://www.scientificamerican.com/article/spiders-seem-to-have-rem-like-sleep-and-may-even-dream/,,Hacker News,47479435 -boeingUH60,32387345,139,1659975034,The AK-47,https://coolmilitarystuff.com/the-ak-47/,,Hacker News,29867545 -smartblondeva,32399266,266,1660058674,Don’t call it a comeback: Java is still champ,https://github.com/readme/featured/java-programming-language,,Hacker News,90045539 -themodelplumber,32417031,11,1660158840,34 Years Ago: 11 y.o. hacker Zero Cool causes 7 pt. drop in stock exchange,https://twitter.com/hakluke/status/1557242086423871488,,Hacker News,44348018 -cp9,32385102,208,1659965276,Using unwrap() in Rust is okay,https://blog.burntsushi.net/unwrap/,,Hacker News,28249810 -tuyenhx,32410576,11,1660133355,Ask HN: How do you collect payment as Startup from Stripe none support country?,,"I wanted to use Stripe to collect payment. But I'm a founder from Stripe's none support countries.

I see there is an option Stripe Atlas. I'm a little hesitate about this option. I totally understand the cost, set up fee and yearly fee. But is there any other hidden fee after this? Like taxes? ...

I did research and saw a few posts tell that, it costed them about 10k/year (When using Stripe + Stripe Atlas) with many hidden fees.

I asked a lot of people around me, they avoided answering this and I don't know why. I even contacted Stripe's support, and they redirected my to a lawyer site with no clear answer. I'm so frustrated.

I have a dumb question.

How do you collect payment if you're in my situation?

Paypal seems a better option for this.",Hacker News,44757877 -feross,32385470,114,1659967248,DevDash: A highly configurable terminal dashboard,https://thedevdash.com/,,Hacker News,62038789 -travisgriggs,32421377,6,1660189834,Turkey’s underground city of 20k people,https://www.bbc.com/travel/article/20220810-derinkuyu-turkeys-underground-city-of-20000-people,,Hacker News,23992756 -Tomte,32384320,82,1659958406,"Lively Linear Lisp – 'Look Ma, No Garbage!' (1992) [pdf]",https://dl.acm.org/doi/pdf/10.1145/142137.142162,,Hacker News,68618253 -pdrummond,32379927,253,1659906577,From throwaway side project to Switch in 2 years: my indie gamedev story,https://kellsgame.com/how-kells-came-to-be/,,Hacker News,46412643 -donohoe,32410162,32,1660130227,Will Europe Force a Facebook Blackout?,https://www.wired.com/story/facebook-eu-us-data-transfers/,,Hacker News,98369744 -melenaboija,32420642,7,1660182116,Miraculin,https://en.wikipedia.org/wiki/Miraculin,,Hacker News,3623271 -dougabug,32387746,43,1659976598,Solving and explaining university math problems with Deep Learning,https://www.pnas.org/doi/10.1073/pnas.2123433119,,Hacker News,41539629 -goncalo-r,32384662,53,1659961645,Show HN: Build for any cloud with the same code,https://github.com/multycloud/multy,"We have been working on Multy, an open-source[1] tool that enables developers to deploy and switch to any cloud - AWS, Azure and GCP for now.

We realized that, even when using Terraform, writing infrastructure code is very different for each cloud provider. This means changing clouds or deploying the same infrastructure in multiple clouds requires rewriting the same thing multiple times. And even though most core resources have the same functionality, developers need to learn a new provider and all its nuances when choosing a new cloud. This is why we built Multy.

Multy is currently available as a Terraform provider. You can write cloud-agnostic code and then just choose which cloud you want to deploy to. Multy will then call the cloud provider APIs on your behalf. For example, the following Terraform code deploys a virtual network in AWS and can be easily changed to deploy to Azure or GCP:

``` -resource "multy_virtual_network" "vn" {

  cloud      = "aws" // or azure, or gcp
-
-  name       = "multy_vn"
-  cidr_block = "10.0.0.0/16"
-  location   = "eu_west_1"
-} -```

Our goal is to expose any configuration that is common across all clouds, but there’s always specific features that are not available in all of them. For example, if you want a very specific AWS CPU for your Virtual Machine or use a region that is only available in GCP. To enable this, we implemented overrides [2] - a way to configure the underlying infrastructure for cloud-specific purposes. You can also mix other Terraform code that uses the cloud-specific providers with Multy. While this makes you somewhat locked in, having your 80% or 90% of your infrastructure cloud-agnostic is still very powerful.

You can see more complex examples in our documentation - https://docs.multy.dev/examples/.

We’re still in early days and looking for feedback from other developers on our approach. Let us know what you think!

[1] https://github.com/multycloud/multy

[2] https://docs.multy.dev/overrides",Hacker News,6626854 -behnamoh,32421269,4,1660188960,This Cute Feature Summarizes Why I Prefer Mac to Windows and Linux,https://medium.com/@parttimeben/this-cute-feature-summarizes-why-i-prefer-mac-to-windows-and-linux-f87d46f09299,,Hacker News,70789286 -Jimmc414,32393536,142,1660011201,Three people in critical condition from Google data center 'electrical incident',https://www.sfgate.com/news/article/google-electrical-incident-injures-3-17360321.php,,Hacker News,26964144 -segfaultbuserr,32399672,49,1660060730,The do-it-yourself cyclotron (2010),https://www.symmetrymagazine.org/article/august-2010/the-do-it-yourself-cyclotron,,Hacker News,69860065 -todsacerdoti,32413349,8,1660144483,The Security Pros and Cons of Using Email Aliases,https://krebsonsecurity.com/2022/08/the-security-pros-and-cons-of-using-email-aliases/,,Hacker News,60210447 -Tomte,32401075,57,1660066540,Unrepresentative big surveys significantly overestimated US vaccine uptake,https://www.nature.com/articles/s41586-021-04198-4,,Hacker News,25843652 -Tomte,32383099,62,1659943387,Blosxom: The Zen of Blogging,http://www.blosxom.com/,,Hacker News,166545 -shreythecray,32404957,17,1660082435,What is product-led growth?,https://www.productled.org/foundations/what-is-product-led-growth,,Hacker News,77981192 -Tomte,32402661,18,1660072501,Tarot for Hackers (2019),https://xeiaso.net/blog/tarot-for-hackers-2019-07-24,,Hacker News,1388144 -aseemk,32379245,227,1659901619,"Ignore the haters, and other lessons learned from creating JSON5",https://aseemk.substack.com/p/ignore-the-f-ing-haters-json5,,Hacker News,93544274 -Tannon,32412740,3,1660142334,Web game for guessing the movie from the ML-generated pixel art,https://pixelquizgame.com,,Hacker News,10264577 -benbreen,32394533,14,1660023558,Breaking the news of the fall of Richard II,https://blogs.bl.uk/digitisedmanuscripts/2022/08/breaking-news.html,,Hacker News,14606499 -kiyanwang,32378752,252,1659898363,Oncall Compensation for Software Engineers,https://blog.pragmaticengineer.com/oncall-compensation/,,Hacker News,7727216 -mitchbob,32386984,111,1659973665,The Reluctant Prophet of Effective Altruism,https://www.newyorker.com/magazine/2022/08/15/the-reluctant-prophet-of-effective-altruism,,Hacker News,80344235 -jart,32376322,238,1659879055,Using Landlock to Sandbox GNU Make,https://justine.lol/make/,,Hacker News,24970701 -brianrisk,32379430,244,1659903092,"In-browser retro-futuristic tank game, open source",https://synthblast.com,,Hacker News,68348594 -signa11,32383028,32,1659942247,From Roots to Polynomials,http://blog.pkh.me/p/31-from-roots-to-polynomials.html,,Hacker News,57116849 -jordanmoconnor,32393545,396,1660011272,Write a note to your spouse every day,https://jdnoc.com/note/,,Hacker News,36482859 -selimonder,32384074,51,1659955751,Diffsound: Discrete Diffusion Model for Text-to-Sound Generation,http://dongchaoyang.top/text-to-sound-synthesis-demo/,,Hacker News,66562652 -thunderbong,32409479,5,1660122940,Tao: The Power of the Graph,https://engineering.fb.com/2013/06/25/core-data/tao-the-power-of-the-graph/,,Hacker News,19674944 -lucasfcosta,32382365,173,1659932498,Why your daily stand-ups don't work and how to fix them,https://lucasfcosta.com/2022/08/07/how-to-improve-daily-standups.html,,Hacker News,12751235 -ETH_start,32395971,381,1660039651,GitHub deleted accounts of people who contributed to Tornado Cash repos,https://twitter.com/bantg/status/1556721709931175937,,Hacker News,55469302 -persiankat,32419699,4,1660173653,What are the best resources to learn SIMD and intrinsics?,,Mainly interested in applications of Machine Learning and Computer Vision algorithms?,Hacker News,13311841 -iamzamek,32409112,7,1660119214,Show HN: Layoffbase – the place where you can get a new tech job after layoff,https://layoffbase.com/,"I knew that layoffs in tech were coming. -When it started, I've created Layoffbase to collect people without a job and help them get a new one. Now, I try to manually connect them with companies.

What do you think about it? How can I improve this?",Hacker News,89673249 -franczesko,32420903,3,1660185198,How Airbnb is ruining local communities in north Wales,https://www.theguardian.com/technology/2022/aug/10/i-wanted-my-children-to-grow-up-here-how-airbnb-is-ruining-local-communities-in-north-wales,,Hacker News,14702523 -nsoonhui,32398010,38,1660053513,How the Physics of Nothing Underlies Everything,https://www.quantamagazine.org/how-the-physics-of-nothing-underlies-everything-20220809/,,Hacker News,71712570 -zdw,32382868,98,1659940138,USB knob box doubles as a Blackmagic Designs camera remote,https://bikerglen.com/blog/usb-knobs-that-double-as-a-blackmagic-remote/,,Hacker News,70345619 -amichail,32375868,85,1659874444,Replayability in game design,https://medium.com/super-jump/replayability-in-game-design-798fbb91a726,,Hacker News,36977321 -FillardMillmore,32412087,14,1660140080,Never mind outrunning a T. rex – you could probably outwalk it,https://www.livescience.com/t-rex-slow-walker-tail.html,,Hacker News,9983833 -pseudolus,32420843,3,1660184477,Most insane depiction of firenado I have seen in a while,https://twitter.com/ReedTimmerAccu/status/1557536321056358405,,Hacker News,63692799 -galogon,32415651,12,1660152704,What goes into efficiently powering the M1? Some pretty fancy technology,https://twitter.com/marcan42/status/1557233812954038272,,Hacker News,65999059 -samizdis,32407571,72,1660102009,Elon Musk sells $6.9B worth of Tesla stock,https://www.axios.com/2022/08/10/elon-musk-sells-nearly-7-billion-tesla-stock,,Hacker News,79602460 -pjmlp,32383686,184,1659950969,Post-Apocalyptic Programming,https://zserge.com/posts/post-apocalyptic-programming/,,Hacker News,74770049 -ahstilde,32384687,197,1659961809,Tricks to start working despite not feeling like it,https://www.deprocrastination.co/blog/3-tricks-to-start-working-despite-not-feeling-like-it,,Hacker News,26830465 -mocko,32403498,10,1660075533,Crypto and Digital Assets All-Party Parliamentary Group Inquiry,https://cryptouk.io/appg/,,Hacker News,53658387 -baobob,32399148,71,1660058175,"Wildfires are destroying California's forest carbon credit reserves, study says",https://www.reuters.com/world/us/wildfires-are-destroying-californias-forest-carbon-credit-reserves-study-2022-08-05/,,Hacker News,17947620 -mooreds,32403353,19,1660074854,GoNoGo: Determine the upgrade confidence of your K8s cluster addons,https://github.com/FairwindsOps/gonogo,,Hacker News,44628276 -evo_9,32380731,161,1659912906,The “bicameral mind” 30 years on (2007),https://pubmed.ncbi.nlm.nih.gov/17509238/,,Hacker News,77010125 -pepys,32396618,8,1660045965,Georeferencing maps from George III’s atlases and albums,https://blogs.bl.uk/magnificentmaps/2022/03/georeferencing-maps-from-george-iiis-atlases-and-albums.html,,Hacker News,90910010 -Austin_Conlon,32420788,6,1660183598,Personal racket stringers for top tennis players [video],https://www.youtube.com/watch?v=4sRSqSupzyM,,Hacker News,64281106 -alhasaniq,32403121,9,1660074042,Golang Application runtime inspection tool,https://github.com/coretrix/clockwork,,Hacker News,60908893 -awanderingmind,32401564,135,1660068520,"The state of South Africa, 28ish years post-apartheid",https://www.awanderingmind.blog/posts/2022-07-30-state-of-south-africa.html,,Hacker News,71811662 -spenvo,32399495,90,1660059933,Someone Is Trolling Celebs by Sending ETH from Tornado Cash,https://www.coindesk.com/policy/2022/08/09/someone-is-trolling-celebs-by-sending-eth-from-tornado-cash/,,Hacker News,9599567 -jpieper,32381448,165,1659920499,Debugging bare-metal STM32 from the seventh level of hell,https://jpieper.com/2022/08/05/debugging-bare-metal-stm32-from-the-seventh-level-of-hell/,,Hacker News,59364874 -cirrus-clouds,32417546,7,1660161379,Energy bills are soaring in Europe. What are countries doing?,https://www.euronews.com/next/2022/07/29/energy-bills-are-soaring-in-europe-what-are-countries-doing-to-help-you-pay-them,,Hacker News,59666786 -Tomte,32402664,10,1660072509,How Not To Run an A/B Test (2010),https://www.evanmiller.org/how-not-to-run-an-ab-test.html,,Hacker News,61247860 -angristan,32383448,97,1659947763,How we got customers to sign up to Monzo in the early years,https://tomblomfield.com/post/691384431502557184/monzo-growth,,Hacker News,45588859 -nus07,32418728,8,1660167129,"GM Makes $1,500 OnStar Subscription Mandatory on GMC, Buick, Cadillac Models",https://www.thedrive.com/news/gm-makes-1500-onstar-subscription-mandatory-on-gmc-buick-cadillac-models,,Hacker News,6905944 -jakobgreenfeld,32384613,556,1659961277,No More “Insight Porn”,https://jakobgreenfeld.com/insight-porn,,Hacker News,42119149 -hnburnsy,32401721,18,1660069111,Twitter paid $5000 bug bounty that resulted in 5.4mm leaked records,https://hackerone.com/reports/1439026,,Hacker News,68139814 -rbanffy,32384868,84,1659963534,Chip Backdoors: Assessing the Threat,https://semiengineering.com/chip-backdoors-assessing-the-threat/,,Hacker News,53743601 -owenwil,32404366,42,1660079439,"Coinbase earnings: $1.1B loss, lower-than-expected revenue",https://www.bloomberg.com/news/articles/2022-08-09/coinbase-falls-after-second-quarter-revenue-misses-estimates,,Hacker News,93360518 -davidclark22,32404857,126,1660082010,Former Twitter employee convicted of charges related to spying for Saudis,https://politpost.com/2022/08/09/former-twitter-employee-convicted-of-charges-related-to-spying-for-saudis/,,Hacker News,46521718 -a-user-you-like,32413860,22,1660146087,Ask HN: Amazon lying about shipping dates?,,"Lately Amazon told me that an item would arrive in 2 days when I placed the order. I just now received an email that the item I ordered had its shipping date adjusted. It was going to be a month from now, but now Amazon says they can get it to me in 4 days! How lucky am I?

Have others experienced the same, gaslighting from Amazon?",Hacker News,19314202 -rchaudhary,32419558,7,1660172750,New Wi-Fi Reflection Tech Could Send Signal Through Impenetrable Walls,https://www.newsweek.com/new-wifi-reflection-tech-could-send-signal-through-impenetrable-walls-1732088,,Hacker News,63915566 -TekMol,32408322,22,1660111969,Ask HN: Is there a description of the file layout HN uses to store data?,,"As far as I know, HN uses no DB and just writes all data to plain text files.

Does this still hold true?

Is there a description of the layout somewhere? I wonder if it is just one file per comment and the name is the id. And what the internal structure of those files is.

I think it would be a very interesting example of a successful Web2 style project that writes to files instead of using a DB.",Hacker News,69732588 -wepple,32385362,205,1659966669,Incident report: Employee and customer account compromise,https://www.twilio.com/blog/august-2022-social-engineering-attack,,Hacker News,70040094 -sprkv5,32418808,3,1660167680,Ask HN: What are the skills and/or software(s) required to become an emcee?,,"I was just looking at the recent MultiVersus tournament hosted by a certain YouTube streamer live now; and I was kinda fascinated by how they were hosting, presenting the rules, tracking the players and their respective voice chatrooms, technical issues, etc. I do know that they've got some folks helping out behind the scenes. I wanted to know what it takes to setup such an event, especially for the host.",Hacker News,96687335 -martialg,32390605,85,1659990570,Doomed to repeat history? Lessons from the crypto wars of the 1990s (2015) [pdf],https://static.newamerica.org/attachments/3407-doomed-to-repeat-history-lessons-from-the-crypto-wars-of-the-1990s/Crypto%20Wars_ReDo.7cb491837ac541709797bdf868d37f52.pdf,,Hacker News,74381287 -adrian_mrd,32415431,9,1660151756,You deserve the right to repair your stuff (Ted talk),https://www.ted.com/talks/gay_gordon_byrne_you_deserve_the_right_to_repair_your_stuff,,Hacker News,66531291 -yamrzou,32397432,58,1660051250,The End of Manual Transmission,https://www.theatlantic.com/technology/archive/2022/08/stick-shift-manual-transmission-cars/671078/,,Hacker News,46717281 -coolmike,32405833,56,1660086722,In the U.S. Nepotism Is Key to Economic Success,https://www.psychologytoday.com/us/blog/how-do-you-know/202208/in-the-us-nepotism-is-key-economic-success,,Hacker News,64330468 -ciccionamente,32403604,18,1660075987,Show HN: WeExpire – Notes readable only after your death,https://weexpire.org/,,Hacker News,82049671 -signa11,32376937,65,1659884030,How (and Why) Neil Gaiman Finally Adapted ‘The Sandman’ for TV,https://variety.com/2022/tv/features/the-sandman-premiere-preview-neil-gaiman-interview-1235328771/,,Hacker News,9004575 -nikolay,32382514,124,1659934968,"Trealla – A compact, efficient Prolog interpreter written in plain-old C",https://github.com/trealla-prolog/trealla,,Hacker News,65866082 -rbanffy,32384827,103,1659963189,Who owns Tesla’s data?,https://spectrum.ieee.org/tesla-autopilot-data-ownership,,Hacker News,98592711 -yamrzou,32386189,258,1659970580,U.S. Treasury sanctions virtual currency mixer Tornado Cash,https://home.treasury.gov/news/press-releases/jy0916,,Hacker News,36617463 -mikhael,32419871,13,1660174985,America's Most Popular Sriracha Maker Confirms 'Unprecedented Shortage',https://www.foodandwine.com/news/sriracha-shortage-huy-fong-foods-pepper-supply,,Hacker News,46668533 -occamschainsaw,32403403,8,1660075051,Fusion Turns Up the Heat (Ignition Achieved),https://physics.aps.org/articles/v15/67,,Hacker News,4958831 -ksec,32396651,274,1660046272,France experiencing worst drought on record,https://www.bbc.co.uk/newsround/62456540,,Hacker News,66850205 -thunderbong,32404358,44,1660079403,Iknowwhatyoudownload.com,https://iknowwhatyoudownload.com/en/peer/,,Hacker News,52823201 -torts,32383426,38,1659947404,The East African Federation experiment,https://www.karlsnotes.com/the-east-african-federation/,,Hacker News,52040131 -cosmojg,32374113,279,1659849800,Our Roadmap for Nix,https://www.tweag.io/blog/2022-08-04-tweag-and-nix-future/,,Hacker News,76011983 -_Microft,32400002,31,1660061979,New Tuberculosis vaccine candidate safe in HIV- and non-HIV-exposed newborns,https://www.mpg.de/19040549/0801-bich-tuberculosis-vaccine-candidate-vpm1002-safe-in-hiv-and-non-hiv-exposed-newborns-as-study-shows-17216463-x,,Hacker News,67945001 -maverickJ,32375667,137,1659871743,"To Become Wise, Do Less",https://leveragethoughts.substack.com/p/to-become-wise-do-less,,Hacker News,52295345 -olalonde,32392997,429,1660006791,Man arrested for promoting jury nullification wins federal case,https://reason.com/2022/08/05/he-was-arrested-for-promoting-jury-nullification-a-federal-court-says-that-was-illegal/,,Hacker News,67259793 -amin,32380079,254,1659907588,"Look at median, and not mean GDP per capita",https://medianism.org/,,Hacker News,95768672 -blinding-streak,32384765,19,1659962653,The radical scope of Tesla’s data hoard,https://spectrum.ieee.org/tesla-autopilot-data-scope,,Hacker News,23694759 -mkl,32390730,65,1659991223,Spaced Repetition for Mathematics (2021),https://cronokirby.com/posts/2021/02/spaced-repetition-for-mathematics/,,Hacker News,40437788 -samueldebrule,32415972,8,1660154163,Spotify starts selling live music tickets to fans directly,https://techcrunch.com/2022/08/10/spotify-starts-selling-live-music-tickets-to-fans-directly/,,Hacker News,13552193 -susam,32392611,17,1660003465,"Sun, Earth and Moon Position – 3D Simulator",https://en.tutiempo.net/astronomy/sun-earth-moon-3d.html,,Hacker News,89897336 -eatonphil,32412329,56,1660140914,Correcting the Record on Meta’s Involvement in Nebraska Case,https://about.fb.com/news/2022/08/meta-response-nebraska-abortion-case/,,Hacker News,72803046 -zdw,32382860,57,1659940054,Our BMCs are not great at keeping accurate time,https://utcc.utoronto.ca/~cks/space/blog/sysadmin/BMCsNotGreatAtKeepingTime,,Hacker News,62200869 -signa11,32382977,79,1659941509,Wisp: Whitespace to Lisp,https://www.draketo.de/software/wisp,,Hacker News,47237553 -imartin2k,32385026,90,1659964749,Bridge Loans,https://avc.com/2022/08/bridge-loans/,,Hacker News,46793161 -cheinyeanlim,32405062,10,1660082899,Scientists Revived Organs in Pigs an Hour After They Died,https://singularityhub.com/2022/08/09/how-scientists-revived-cells-in-pigs-organs-an-hour-after-they-died/,,Hacker News,44946569 -cunidev,32375128,217,1659864957,Homebrew Bluetooth Headphones,https://homebrewheadphones.com/3d-printed-bluetooth-headphones/,,Hacker News,26281610 -_shadi,32409415,11,1660122154,"Ask HN: Teams migrated from Nomad to Kubernetes,what pushed you to migrate?",,"we are trying to pick a self-hosted container orchestration engine to use, after evaluating the pros and cons of both we decided Nomad would be the better option for us.

I used both in the past, and for self-hosted solution I also prefer the simplicity of Nomad, but I realize that Kubernetes has much more functionality, so I'm wondering if there is something that we will realize that we are missing once we start using Nomad for production workloads.

So my question is targeted at people who used Nomad in production, and later found themselves migrating to Kubernetes, what is your story? and what functionality did you miss the most that pushed you to move to Kubernetes. -Blogs and articles are also welcome.",Hacker News,66650214 -kelsier1,32390083,96,1659987693,Automated Reasoning at Amazon: A Conversation,https://www.amazon.science/blog/automated-reasoning-at-federated-logic-conference-floc,,Hacker News,59484065 -woofyman,32418223,23,1660164500,Mark Cuban: Buying real estate in the metaverse is ‘the dumbest’ idea ever,https://www.cnbc.com/2022/08/10/mark-cuban-buying-real-estate-in-the-metaverse-is-dumbest-idea-ever.html,,Hacker News,81188783 -luu,32390495,5,1659989839,Dev Diary for Surfwords,https://novalis.org/blog/2022-08-03-dev-diary--surfwords.html,,Hacker News,71400637 -bonkerbits,32376256,28,1659878289,A Parachute Accident in 1992 jump-started the birth of Augmented Reality,https://spectrum.ieee.org/history-of-augmented-reality,,Hacker News,3680089 -rlawson,32397750,23,1660052589,Ask HN: Is ease in getting started the key for Python's success?,,"I am just an intermediate Python dev (but a senior Java dev with 20+ years). What I have come to realize is that Python is just as complicated as Java! However it is much much easier to get started with.

Java is aimed squarely at professional devs and requires a lot of tooling and support. -Python requires almost nothing (interpreter + editor + a basic understanding of lists/dicts and control flow) to get started.

But do a big project with a large team and you'll quickly discover the rough edges and debates - a few that have come up lately for me at work - typing or no typing, oop or functional? pytest or unittest? poetry vs pipenv vs ... ? Occasional runtime errors. Project layout and organization (makes me miss maven sometimes). -Don't get me wrong - I really enjoy working in Python but I believe it would be a niche language if it were not so approachable to the beginner.",Hacker News,78952162 -Kaibeezy,32375095,111,1659864244,Ten years with a Citroën C6 (2021),https://driventowrite.com/2021/01/04/citroen-c6-long-term-test/,,Hacker News,40265379 -turtlegrids,32392474,20,1660002229,The Forbidden ARM Server That Is Banned in the US,https://www.servethehome.com/the-forbidden-arm-server-that-is-banned-in-the-us/2/,,Hacker News,28549883 -metadat,32413242,10,1660144011,Most Trolls Have Subclinical Sadism,https://www.psychologytoday.com/us/blog/finding-new-home/202208/research-shows-most-trolls-have-subclinical-sadism,,Hacker News,3086732 -walterbell,32374227,77,1659851791,Wizard with a Time Machine,https://microship.com/wizard-with-a-time-machine/,,Hacker News,69781432 -memorable,32374207,278,1659851483,How to stop being “terminally online”,https://nights.bearblog.dev/how-to-stop-being-terminally-online/,,Hacker News,96308110 -anigbrowl,32418425,5,1660165389,Former Twitter employee convicted of spying for Saudi Arabia,https://www.wsj.com/articles/former-twitter-employee-convicted-of-spying-for-saudi-arabia-11660076924,,Hacker News,4253003 -kjhughes,32376414,168,1659879814,Hacker’s Delight (2012),https://books.google.com/books/about/Hacker_s_Delight.html?id=VicPJYM0I5QC,,Hacker News,81593227 -todsacerdoti,32376542,154,1659880999,The pervasive effects of C's malloc() and free() on C APIs,https://utcc.utoronto.ca/~cks/space/blog/programming/CAPIsEffectsOfMalloc,,Hacker News,34693458 -ingve,32386085,30,1659970198,The ‘fat service’ pattern for Go web applications,https://www.alexedwards.net/blog/the-fat-service-pattern,,Hacker News,7853054 -signa11,32374278,124,1659852489,Let's Talk SkipList,https://ketansingh.me/posts/lets-talk-skiplist/,,Hacker News,65459807 -sixhobbits,32385856,82,1659969140,Show HN: SaveSlack – create searchable knowledgebase from your Slack community,https://saveslack.com,,Hacker News,8617295 -feross,32388648,22,1659980678,The Ants and the Pheromones (2021),https://blog.acolyer.org/2021/02/08/the-ants-and-the-pheromones/,,Hacker News,51143230 -reimertz,32386323,164,1659971180,"Starting October 19, storage limit will be enforced on all Gitlab Free accounts",https://docs.gitlab.com/ee/user/usage_quotas.html#namespace-storage-limit-enforcement-schedule,,Hacker News,93861906 -nicbou,32379139,142,1659900864,Making Quieter Technology,https://nicolasbouliane.com/blog/silence,,Hacker News,41495939 -upzylon,32377646,137,1659889466,A generically typed pipe function in TypeScript,https://github.com/MathisBullinger/froebel,,Hacker News,18994240 -WebbWeaver,32418972,10,1660168838,All children under 10 in London to be offered polio vaccine after virus detected,https://metro.co.uk/2022/08/10/polio-all-children-under-10-in-london-to-be-offered-jab-17159536/,,Hacker News,31574040 -sottol,32407298,24,1660098926,Robert Shiller predicted the 2008 housing bubble. Here’s his 2022 call,https://fortune.com/2022/08/09/housing-bubble-2022-call-robert-shiller-housing-market/,,Hacker News,80928838 -aarondf,32398789,13,1660056582,Breaking Apart the maintainer Monolith (By Swyx),https://github.com/readme/guides/maintainer-monolith,,Hacker News,25843766 -andrewfromx,32387815,77,1659976943,A secret language of cells? New cell computations uncovered,https://actu.epfl.ch/news/a-secret-language-of-cells-new-cell-computations-u/,,Hacker News,67094315 -Kaibeezy,32375756,50,1659872915,The day the music died? Denmark Street’s new ‘digitally enabled streetscape’,https://www.theguardian.com/artanddesign/2022/aug/07/outernet-london-now-building-review-denmark-street-tottenham-court-road-redevelopment-soho,,Hacker News,64515825 -Hooke,32375970,94,1659875433,The ejector seats that fire through the floor,https://www.bbc.com/future/article/20220802-why-some-aircraft-had-downward-firing-ejector-seats,,Hacker News,22899210 -tim--,32383227,94,1659944865,Coqui TTS: a deep learning toolkit for Text-to-Speech,https://github.com/coqui-ai/TTS,,Hacker News,47043214 -harel,32378085,123,1659893427,Cellular recovery after prolonged warm ischaemia of the whole body,https://www.nature.com/articles/s41586-022-05016-1,,Hacker News,13885096 -zdw,32376464,135,1659880301,Commit comments no longer appear in the pull request timeline,https://github.blog/changelog/2022-08-04-commit-comments-no-longer-appear-in-the-pull-request-timeline/,,Hacker News,27200036 -sebastianconcpt,32414165,9,1660147083,"Intel iAPX 432, a CPU with hardware Garbage Collector support",https://en.wikipedia.org/wiki/Intel_iAPX_432,,Hacker News,57933459 -als0,32409955,11,1660128213,How I wish I could organize my thoughts,https://drewdevault.com/2022/08/10/Organizing-my-thoughts.html,,Hacker News,22099622 -bilsbie,32380772,106,1659913173,The mitochondrial NAD+ transporter SLC25A51 is a fasting-induced gene,https://www.metabolismjournal.com/article/S0026-0495(22)00153-6/fulltext,,Hacker News,91201291 -rntn,32376059,34,1659876307,New Pompeii finds highlight middle-class life in doomed city,https://phys.org/news/2022-08-pompeii-highlight-middle-class-life-doomed.html,,Hacker News,80525924 -beefman,32406435,19,1660090953,Chinese molten-salt reactor cleared for start up,https://world-nuclear-news.org/Articles/Chinese-molten-salt-reactor-cleared-for-start-up,,Hacker News,80351568 -trocado,32375955,170,1659875323,Learning algebra in my 60s,https://www.theguardian.com/books/2022/aug/07/could-learning-algebra-in-my-60s-make-me-smarter-alec-wilkinson-a-divine-language-extract,,Hacker News,8185399 -georgia_peach,32374317,135,1659853159,Ivy – An interpreter for an APL-like language,https://pkg.go.dev/robpike.io/ivy,,Hacker News,43375055 -benbreen,32374390,29,1659854247,"Kikkuli, 1345 BCE: Training the Chariot Horse",https://web.archive.org/web/20121102233704/http://imh.org/history-of-the-horse/legacy-of-the-horse/harnessing-the-horse/kikkuli-1345.html,,Hacker News,29773761 -thereare5lights,32401849,38,1660069621,'Forever chemicals' in rainwater exceed safe levels,https://www.bbc.com/news/science-environment-62391069,,Hacker News,488805 -rayascott,32375448,47,1659869058,The Apollo On-Board Computers,https://web.archive.org/web/20120827000829/http://history.nasa.gov/afj/compessay.htm,,Hacker News,66339584 -manchoz,32383265,81,1659945334,Learn Effective C++ for Embedded Code,https://luckyresistor.me/knowledge/learn-cpp/,,Hacker News,78521714 -silent1mezzo,32377129,47,1659885410,"So, you want to become an Engineering Manager?",https://mckerlie.com/posts/you-want-to-be-an-engineering-manager/,,Hacker News,90956115 -beatthatflight,32419528,6,1660172517,World Excel Championship,https://www.youtube.com/watch?v=x1RVNGDSdw4,,Hacker News,75537268 -mrich,32405631,6,1660085608,Webb telescope reveals unpredicted bounty of bright galaxies in early universe,https://www.science.org/content/article/webb-telescope-reveals-unpredicted-bounty-bright-galaxies-early-universe,,Hacker News,61753930 -dnetesn,32375842,36,1659874094,How we perceive nature through our sense of smell,https://worldsensorium.com/how-we-perceive-nature-through-our-sense-of-smell/,,Hacker News,42290637 -marron,32391081,168,1659993192,Some Epson printers are programmed to stop working after a certain amount of use,https://gizmodo.com/epson-printer-end-of-service-life-error-not-working-dea-1849384045,,Hacker News,12605051 -mikece,32417531,5,1660161269,Google Fiber announces expansion to five states in the U.S.,https://www.neowin.net/news/google-fiber-announces-expansion-to-five-states-in-the-us/,,Hacker News,68278214 -labrador,32392202,48,1659999789,A content model is not a design system (2021),https://alistapart.com/article/a-content-model-is-not-a-design-system/,,Hacker News,80373410 -mellosouls,32376943,140,1659884086,Earbirding – How to Visualize Sounds,http://earbirding.com/blog/specs,,Hacker News,25684109 -pseudolus,32375718,48,1659872386,Experiments indicate that bees have surprisingly rich inner worlds,https://www.washingtonpost.com/outlook/2022/07/29/bee-cognition-insect-intelligence-research/,,Hacker News,58277588 -abhiminator,32378309,124,1659895202,Ask HN: What are some of your favorite YouTube channels?,,"Wanted to post a 2022 version of this classic HN question. Figured a Sunday would be a good day for this post.

What are some of the YouTube channels that you enjoy, particularly as an engineer/entrepreneur?",Hacker News,42455682 -lsferreira42,32397162,33,1660049898,Ask HN: Better way to create Anki cards?,,"Hello HN, i've been trying to use spaced repetition to help with my studies but creating cards in anki is a pain, do you have a better way to create cards? ( or an anki alternative that makes this easier? )",Hacker News,64695277 -PaulHoule,32413023,7,1660143274,"Phishers who breached Twilio and fooled Cloudflare could easily get you, too",https://arstechnica.com/information-technology/2022/08/phishers-breach-twilio-and-target-cloudflare-using-workers-home-numbers/,,Hacker News,87643728 -marginalia_nu,32391424,54,1659994898,A history of storage media (2017),https://codewords.recurse.com/issues/seven/a-history-of-storage-media,,Hacker News,22214272 -fvrghl,32417264,8,1660159908,A Boy Bosses of Silicon Valley Are on Their Way Out,https://www.nytimes.com/2022/08/10/business/silicon-valley-boy-boss.html,,Hacker News,24546686 -mikece,32417263,5,1660159902,Scientists Reveal New Info on ‘Giant Jets’ of Lightning in the Atmosphere,https://petapixel.com/2022/08/10/scientists-reveal-new-info-on-giant-jets-of-lightning-in-the-atmosphere/,,Hacker News,96870369 -eastdakota,32399657,17,1660060691,The mechanics of a sophisticated phishing scam and how we stopped it,https://blog.cloudflare.com/2022-07-sms-phishing-attacks/,,Hacker News,61647512 -PikelEmi,32419192,3,1660170309,Perseid meteor shower: All you need to know in 2022,https://earthsky.org/astronomy-essentials/everything-you-need-to-know-perseid-meteor-shower/,,Hacker News,2330941 -wooosh,32377597,97,1659889063,Computing Adler32 Checksums at 41 GB/s,https://wooo.sh/articles/adler32.html,,Hacker News,452702 -gmays,32404170,6,1660078567,Why Now’s the Perfect Time to Retool Your Hiring Process and Get Creative,https://review.firstround.com/why-nows-the-perfect-time-to-retool-your-hiring-process-and-get-creative,,Hacker News,62719807 -ingve,32377735,517,1659890217,“Code” 2nd Edition Now Available,https://www.charlespetzold.com/blog/2022/08/Code-2nd-Edition-Now-Available.html,,Hacker News,69467723 -conanxin,32410391,9,1660132178,The Dramatic Failure of Buckminster Fuller’s “Car of the Future”,https://slate.com/technology/2022/08/the-dymaxion-car-the-true-history-of-buckminster-fullers-failed-automobile.html,,Hacker News,9223395 -JumpCrisscross,32418970,3,1660168828,United Airlines Puts Down Deposit on Flying Taxis,https://www.wsj.com/articles/united-airlines-puts-down-deposit-on-flying-taxis-11660132800,,Hacker News,72362303 -jbegley,32385530,139,1659967539,Axios Sells for $525M,https://www.nytimes.com/2022/08/08/business/media/axios-cox-enterprises.html,,Hacker News,43350613 -cloudyporpoise,32403739,13,1660076591,Ask HN: How are platforms like Buffer and Hootsuite allowed to exist?,,"Companies like Meta and LinkedIn have taken a harsh stance against programmatic access, and scraping of their platforms. How is it that these companies like Buffer and Hootsuite can exist when it seems that what they do is directly a violation of the terms of use. For instance if I were to create a program to schedule my social media posts for some point in the future, wouldn't I be at risk for Instagram disabling my account?",Hacker News,57485883 -darrenbuckner,32402844,5,1660073142,"Show HN: Create bespoke, always-on, virtual coworking rooms (called cafes)",https://workfrom.com/browse/j2lw5h,,Hacker News,93031875 -gmays,32406878,22,1660094676,TikTok bombards young men with misogynistic videos,https://www.theguardian.com/technology/2022/aug/06/revealed-how-tiktok-bombards-young-men-with-misogynistic-videos-andrew-tate,,Hacker News,79994438 -rbanffy,32402657,6,1660072482,"Prefetch Side Channels Undermine Isolation Between User, Kernel on AMD CPUs",https://semiengineering.com/prefetch-side-channels-undermine-the-isolation-between-user-and-kernel-space-on-amd-cpus/,,Hacker News,67340178 -two_almonds,32385170,53,1659965615,The rise of ‘ARPA-everything’ and what it means for science (2021),https://www.nature.com/articles/d41586-021-01878-z,,Hacker News,70852288 -marttt,32374428,33,1659854849,Plop Boot Managers,https://www.plop.at/en/bootmanagers.html,,Hacker News,36034996 -Analemma_,32400852,29,1660065575,"SGX, Intel’s supposedly impregnable data fortress, has been breached yet again",https://arstechnica.com/information-technology/2022/08/architectural-bug-in-some-intel-cpus-is-more-bad-news-for-sgx-users/,,Hacker News,24194531 -gilad,32406918,5,1660095028,Organize Python code like a pro,https://guicommits.com/organize-python-code-like-a-pro/,,Hacker News,52964749 -nassimsoftware,32405705,21,1660085976,Discord has forums now,https://old.reddit.com/r/discordapp/comments/u9y02m/overview_of_forum_channels_new_feature/,,Hacker News,11377419 -indus,32388453,174,1659979757,Fintech is making credit cards weirder,https://workweek.com/2022/08/05/fintech-is-making-credit-cards-weirder/,,Hacker News,88824482 -bouiboui,32391377,16,1659994681,"Show HN: Rewind 4, a Chrome extension for bookmark hoarders",https://chrome.google.com/webstore/detail/rewind/oghafdocdmlkkjipdmnikdcgekjpiapf,,Hacker News,29523076 -shcheklein,32418526,17,1660165894,SQLite is exploding on Hacker News,https://twitter.com/shcheklein/status/1557466590983032832,,Hacker News,3554477 -daxaxelrod,32392541,56,1660002835,Rejected.us,https://rejected.us/,,Hacker News,69488435 -goindeep,32405399,18,1660084353,Ford Raises Prices of F-150 Lightning Electric Truck by Thousands of Dollars,https://www.nytimes.com/2022/08/09/business/ford-f-150-lightning-electric-truck-price.html,,Hacker News,67754341 -gautamcgoel,32418299,6,1660164831,Silicon Valley's Push into Transportation Has Been a Miserable Failure,https://gizmodo.com/silicon-valleys-transportation-failures-tesla-waymo-bir-1849382788,,Hacker News,90566426 -Tomte,32415588,8,1660152422,"Microsoft open-sources over 1,500 of its cute 3D emoji designs for anyone to use",https://arstechnica.com/gadgets/2022/08/microsoft-open-sources-its-cute-3d-emoji-albeit-without-clippy/,,Hacker News,24701126 -thiago_fm,32375394,119,1659868469,Tutors / tips to change your English accent,,"Let's start with that my accent is clear enough and I don't have communication issues at work. I actually feel quite comfortable.

But I'd love to have a perfect west coast American accent when I speak english. Having learned a few other languages myself, it feels pretty good when you can surprise a native.

Anybody that went through that process of improving their accent with a tutor or on their own could share their learnings on it?",Hacker News,16637223 -dnetesn,32375839,25,1659874052,Brain Fills in the Blanks with Experience,https://nautil.us/how-your-brain-fills-in-the-blanks-with-experience-22692/,,Hacker News,59766544 -marcodiego,32418130,4,1660164094,Microsoft claims Sony pays for ‘blocking rights’ to keep games off Xbox GamePass,https://www.theverge.com/2022/8/10/23300133/microsoft-sony-xbox-game-pass-blocking-rights-accusation,,Hacker News,38937097 -arunbahl,32400428,4,1660063897,"U.S. Develops Faster, More Energy-Efficient Programmable Resistors for AI",https://opengovasia.com/u-s-develops-faster-more-energy-efficient-ai-hardware/,,Hacker News,54630087 -feross,32378869,215,1659898985,Class Action Targets Experian over Account Security,https://krebsonsecurity.com/2022/08/class-action-targets-experian-over-account-security/,,Hacker News,85041813 -VigneshBaskaran,32376170,95,1659877438,The Thousand Brains Theory of Intelligence (2019),https://numenta.com/blog/2019/01/16/the-thousand-brains-theory-of-intelligence/,,Hacker News,73346208 -gmemstr,32400200,5,1660062853,Windows registry file format specification,https://github.com/msuhanov/regf/blob/master/Windows%20registry%20file%20format%20specification.md,,Hacker News,87661558 -valzevul,32406258,3,1660089372,"Show HN: Tuesday Triage, weekly crème de la crème of the Internet",https://tuesdaytriage.com/,"For the past two years I curate a newsletter with ~10 posts I've enjoyed reading and ~10 things I didn't know before, as well as a tad of my ranting and a book or two.",Hacker News,33080528 -ollifi,32402185,25,1660070842,They Told Their Therapists Everything. Hackers Leaked It All (2021),https://www.wired.com/story/vastaamo-psychotherapy-patients-hack-data-breach/,,Hacker News,82902205 -leephillips,32417934,3,1660163214,Amazon begins large-scale rollout of palm print-based payments,https://arstechnica.com/gadgets/2022/08/amazon-begins-large-scale-rollout-of-palm-print-based-payments/,,Hacker News,61019072 -pfdietz,32380471,87,1659910605,The Last Naval Battle of World War 2 (2018),https://www.navygeneralboard.com/the-last-naval-battle-of-world-war-2/,,Hacker News,58172648 -mywacaday,32415065,5,1660150429,Nowhere on Earth where rainwater safe to drink – study,https://www.rte.ie/news/newslens/2022/0810/1314927-rainwater-study/,,Hacker News,16424868 -rguiscard,32407588,16,1660102153,"World is losing ‘magical’ tradition of human-animal mutualism, study warns",https://news.mongabay.com/2022/06/world-is-losing-magical-tradition-of-human-animal-mutualism-study-warns/,,Hacker News,14697987 -nabla9,32378744,25,1659898322,The Singular Value Decomposition,https://peterbloem.nl/blog/pca-4,,Hacker News,74125870 -triska,32376984,88,1659884370,Trealla Prolog embedded in Go using WASM,https://github.com/guregu/trealla-go,,Hacker News,28659871 -Vaslo,32386778,159,1659972938,Amazon’s Roomba deal is about mapping your home,https://www.bloomberg.com/news/articles/2022-08-05/amazon-s-irobot-deal-is-about-roomba-s-data-collection,,Hacker News,8886099 -barathr,32399347,19,1660059122,Show HN: PGPP (Pretty Good Phone Privacy) – a new type of mobile privacy service,https://play.google.com/store/apps/details?id=com.invisv.pgpp&hl=en_US&gl=US,"Hi, we're Barath and Paul. We co-founded INVISV to build Pretty Good Phone Privacy (PGPP) [https://invisv.com/pgpp], an app and service that provides mobile identifier privacy (IMSI) and Internet privacy (IP) so that neither we nor other providers learn your network identity. We've been thinking about how phones are tracking devices in disguise (at a few layers) and what we can do about it. But the problem is that mobile networks are hard to change, and existing companies are reluctant to change things.

A couple years ago we had the idea that we could decouple your identity from your SIM (IMSI), so the mobile operator wouldn't know who you are but still provides you service. We did research, figured it out, and published it last year at Usenix Security. Then we took it to every mobile operator we could to see if they'd do it, but mostly got shrugs, confusion, or hostility. (We still hold out hope they'll change their minds.) So we decided we had to build and deploy it ourselves. And the mobile network is just the first part -- we also provide decoupled IP privacy (Relay) in PGPP via a partnership with Fastly, for when you're on WiFi or mobile data.

The implementation is simple: for mobile privacy we decouple authentication from connectivity. Those are conflated today. We provide service using eSIMs (so you need an eSIM capable Android for this part). So we don't learn which eSIM your phone gets each time (your IMSI now changes periodically), we authenticate you with a cryptographic protocol (Chaum's blind signatures) that proves you should get a new eSIM but doesn't reveal your identity. Then you get mobile data service. This isn't something that exists today, despite the tracking/data collection that's happened both by third parties (SDRs / IMSI catchers) and operators themselves. It's like MAC randomization for mobile networks.

We figured users would like better IP privacy too, so we used IETF MASQUE and collaborated with Fastly to provide relay service in PGPP as well. Relay service works on almost any Android device. This uses TLS to tunnel your traffic (which itself will usually be TLS encrypted, for almost all Web traffic today) through two hops and then to the rest of the Internet. The first hop is us -- we hide your IP but learn nothing of your traffic or where it's headed. The second hop is Fastly, who then connects you to the IP of the server you're trying to reach, but all they see is an INVISV IP trying to connect to some other IP. The site you're connecting to terminates your TLS stream but just sees it coming from Fastly.

This is a beta and there are several things that aren't ideal. We don't have free plans because providing actual connectivity is pretty expensive. We know that data-only mobile service isn't for everyone (that's what our mobile plans provide -- no phone number). So we offer Relay service on its own for folks who want that. We also know eSIMs are not ideal either, so we'd like to generalize that down the road.

We're focused on privacy, not just on mobile, and we'd love your feedback on the service and ideas about this and where to go next.

Thanks!

Barath and Paul",Hacker News,25561788 -mikece,32417696,4,1660162107,Facebook's Message Encryption Was Built to Fail,https://www.wired.com/story/facebook-message-encryption-abortion/,,Hacker News,47290178 -bookofjoe,32379586,21,1659904129,"Travel selfies on social networks, narcissism andthe “attraction-shading effect”",https://www.sciencedirect.com/science/article/abs/pii/S1447677019302037,,Hacker News,19220771 -falafelite,32384769,140,1659962691,Ask HN: Have you ever inherited a code base you thought was well done?,,"I see and hear a lot of complaints around inheriting code bases that are less than stellar. If anyone has, I'd love to hear about cases where you inherited a "good" code base, whatever that may mean: awesome test coverage, good documentation, solid organization, consistent styling/formatting, abundant best practices, whatever!",Hacker News,16133754 -sylens,32401228,29,1660067171,Why macOS Ventura Share menu is bad,https://lapcatsoftware.com/articles/VenturaShare.html,,Hacker News,10912258 -mw888,32397806,15,1660052798,Ask HN: Do you worry about CPU backdoors like IME?,,"On the surface these seem like a egregious affront on personal computing freedom and privacy, yet I rarely hear the topic brought up when the subject is being discussed. Perhaps the most damning claim to them is are government agencies’ ability to purchase CPUs with the ‘feature’ turned off.

What are the implications of such hardware on user security? Is the threat real, overblown, or relatively unexplored?",Hacker News,26232389 -uptown,32411428,13,1660137557,New Google site begs Apple for mercy in messaging war,https://arstechnica.com/gadgets/2022/08/new-google-site-begs-apple-for-mercy-in-messaging-war/,,Hacker News,61594365 -lawgimenez,32392793,136,1660005050,"Software Architecture Is Overrated, Clear and Simple Design Is Underrated (2019)",https://blog.pragmaticengineer.com/software-architecture-is-overrated/,,Hacker News,95588404 -sebg,32384710,18,1659962065,Open Source Tools for Computational Biology,https://www.pillar.vc/playlist/article/open-source-tools-for-computational-biology/,,Hacker News,85283479 -raybb,32417431,5,1660160790,The fall (and rise?) of unions in the US,https://www.youtube.com/watch?v=KtxITylE73U,,Hacker News,64614879 -Tomte,32383953,10,1659954285,Crew: A Weeding Manual for Modern Libraries (2012) [pdf],https://www.tsl.texas.gov/sites/default/files/public/tslac/ld/ld/pubs/crew/crewmethod12.pdf,,Hacker News,86844756 -abrax3141,32378999,11,1659899897,Artificial Intelligence and Machine Learning in Software as a Medical Device,https://www.fda.gov/medical-devices/software-medical-device-samd/artificial-intelligence-and-machine-learning-software-medical-device,,Hacker News,99513126 -belltaco,32417286,5,1660159987,FSD was never engaged during Tesla self-driving crash test by smear campaign,https://electrek.co/2022/08/10/tesla-self-driving-smear-campaign-releases-test-fails-fsd-never-engaged/,,Hacker News,4742369 -thomassmith65,32411020,6,1660135736,Drinking Bird,https://en.wikipedia.org/wiki/Drinking_bird,,Hacker News,80157119 -indus,32399064,19,1660057768,India's rocket fails to put satellites in right orbit in debut launch,https://www.space.com/india-sslv-rocket-first-launch,,Hacker News,45484580 -raunometsa,32376672,148,1659881981,Micro-SaaS Alternatives to BigTech/VC,https://microfounder.com/alternatives,"Hi HN

I started this crowdsourced list to find small internet products made by solo developers (or tiny teams) that can be used as alternatives to BigTech/VC-funded startups.

E.g. you can use Tally (by two devs, $14K MRR) instead of Typeform ($190M funding, 600+ employees)

or Plausible (by two devs, $83K MRR) instead of Google Analytics.

I added a link to a form where you can send me suggestions to alternatives, happy to add to the site!

Thanks, -Rauno",Hacker News,15307242 -ripvanwinkle,32374345,106,1659853538,A Soviet test pilot ejected two seconds before the crash of his MiG-29 (2019),https://theaviationgeekclub.com/that-time-a-soviet-test-pilot-ejected-two-seconds-before-the-crash-of-his-mig-29/,,Hacker News,4888565 -krstce,32404526,5,1660080252,Show HN: Convert eCommerce product pages to JSON with a simple API Call,https://ecom2json.com,,Hacker News,96879332 -samizdis,32417081,3,1660159036,Porsche Taycan Turbo S Sets Fastest Production EV Nürburgring Lap Record,https://www.thedrive.com/news/porsche-taycan-turbo-s-fastest-production-ev-nurburgring-lap-record,,Hacker News,13539063 -pigtailgirl,32407440,10,1660100491,SoftBank Vision Fund posts a $21.6B quarterly loss,https://www.cnbc.com/2022/08/08/softbank-vision-fund-posts-a-21point6-billion-quarterly-loss-.html,,Hacker News,43636174 -chapulin,32381763,18,1659924036,The Military Has an Office Dedicated to Tracking World’s Biggest Blocks of Ice,https://www.sandboxx.us/blog/why-the-military-has-an-office-dedicated-to-tracking-the-worlds-biggest-blocks-of-ice/,,Hacker News,77953852 -porknubbins,32402075,10,1660070371,Ask HN: What Happened to Open Courseware?,,"I learned CS from online courses and have been trying to learn basic EE as well. to It seems to me that free online courses by places like MIT or similar institutions have been declining for the past 5 years at least.

It is too cynical to think that institutions recognized that STEM classes by great professors are a rare and valuable resource, and that by sharing them freely they undermined the value of attending one of these elite institutions? Cost alone cannot be the full explanation as existing resources that were excellent have been actively taken down.

I know that UC Berkley's videos were taken down for failing to conform to accessibility laws so that it kind of a special case, but it wouldn't have been impossible to get them subtitled if the motivation were there.

Of course many of these resources can still be found if you search hard enough, and individual Youtube creators have been getting better and better, but I would really be fascinated to hear why there was such an institutional flourish and decline?",Hacker News,20821969 -anonimouse1234,32377084,59,1659885049,Ask HN: Where should I move to meet interesting tech people?,,"Hey everybody,

So after about 8 years of various unsuccessful startup attempts I bit the bullet and got a job.

Classical 6 figures tech job in AI for bigtech. Fully remote chill work hours you know the deal.

I used to live for work pouring all my heart into an idea talking to customers iterating working day and night.

Now, I want to work to live travel and most importantly I want to meet as many interesting tech people as possible.

Now my question. Where should I go? Ideally, I want to be able to go back to Germany at least for 3 months a year the rest I am open for suggestions.

Should I move to a digital nomad place like Bali or Portugal? Or a tech hub like San Francisco or Austin?

Time zone wise Hong Kong would be ideal but I am mostly working on my own so it isn't a deal breaker.

Also wherever I am, should I go to conferences ? Meetups? Dm random people on Twitter and Hackernews? Otherwise, il just keep chatting up a bunch of people in co-working spaces.

I feel like nowadays there must be quite a few people in this situation. Would love to hear your thoughts.",Hacker News,93130168 -armchairguy,32383525,41,1659948831,Ask HN: What Is the Lisp “Enlightment”?,,"Every time I read about Lisp I hear about the _enlightment_ phase, -but what is it?

I checked Lisp and what stands out most for me is the syntax and -the powerful REPL but aside from that, why is it so praised -compared to modern languages? I don't see many projects -using it either aside from certain exceptions.

Apologies for my ignorance _in advance_",Hacker News,55429025 -boredemployee,32384742,33,1659962375,Tell HN: Recruiters misusing HN's “Who wants to be hired”,,"It's getting worse each time and I'm sure I'm not alone on this. Taking advantage on "Who wants to be hired" recruiters are sending completely random (web scrap?) positions in our inboxes which leads me to think: if you don't care about your recruitment process, imagine how fcked up is your whole business. I stopped to use linkedin because of the same bs. Any idea on how to solve it here?",Hacker News,75874841 -elvio,32403407,3,1660075083,Shopify Releases React Native Skia: High Performance 2D Graphics,https://shopify.github.io//react-native-skia/,,Hacker News,84090957 -stakkur,32390378,28,1659989169,Ask HN: Does anyone use FreeBSD or OpenBSD as a daily environment?,,"Over the years, I've used MacOS and Linux, sometimes switching between the two. I'm curious to know if any readers use one of these BSD distros as a daily driver/dev environment, especially on laptops.

NOTE: Not seeking to start an OS flame war or info dump of what BSD is.",Hacker News,12580966 -empressplay,32402942,6,1660073404,Logo and the Language Microworld,https://turtlespaces.org/2022/08/09/logo-and-the-language-microworld/,,Hacker News,55123368 -arispen,32374137,32,1659850285,Show HN: Dungeons and Business Cards,https://arispen.itch.io/dnbc,,Hacker News,37334202 -robin_reala,32384495,75,1659960162,Adtech giant Criteo faces $65M fine in France for GDPR consent breaches,https://techcrunch.com/2022/08/05/criteo-gdpr-breaches-cnil/,,Hacker News,13184118 -thatsamonad,32392190,25,1659999671,Ask HN: Is there any worthwhile management training out there?,,"Hi HN,

I recently made the move from technical lead to full-blown engineering manager about 6 months ago. I was aware at the time that I’d be using a different set of skills than what I was used to when I was doing technical work. That being said, I picked up some of my technical skills and knowledge by attending some quality trainings, online courses, etc, so I know those kinds of things are out there for technical topics.

Are there any good/quality training courses or learning paths for engineering managers out there that you would recommend? A lot of the things I’ve been exposed to so far are pretty “fluffy”, so I’m hoping to find some good resources that will aid me in building the skills I need to help my team succeed.",Hacker News,41539864 -michaelwm,32402540,4,1660072127,Lem: Common Lisp editor/IDE with high expansibility,https://github.com/lem-project/lem,,Hacker News,71918078 -n8ta,32380045,50,1659907354,Ask HN: Best free software to read text aloud,,"What is the best software to read arbitrary text aloud in a decently human sounding voice? I'd be happy with a CLI tool or a website I can just paste text into.

There are many articles I'd rather hear than read so I can rest my eyes. I've tried the builtin macOS say cmd, naturalreaders (dot) com and they both suck.",Hacker News,33314814 -plasticbugs,32407533,27,1660101564,Facebook turned over chat messages of mother and daughter charged over abortion,https://www.nbcnews.com/tech/tech-news/facebook-turned-chat-messages-mother-daughter-now-charged-abortion-rcna42185,,Hacker News,75513668 -mkosmul,32374737,17,1659858952,Growing Up as an Origamist,https://origami.kosmulski.org/blog/2022-08-07-growing-up-origamist,,Hacker News,91806193 -philk10,32401078,75,1660066557,"Tesla’s self-driving technology fails to detect children in the road, tests find",https://www.theguardian.com/technology/2022/aug/09/tesla-self-driving-technology-safety-children,,Hacker News,29929863 -dovhyi,32395937,7,1660039161,The unsaid truth about working from home,https://www.alexscamp.com/the-unsaid-truth-about-working-from-home/,,Hacker News,71558435 -susam,32374981,58,1659862444,Emacs Manual for ITS Users (1981),https://dspace.mit.edu/handle/1721.1/6329,,Hacker News,42278398 -mooreds,32411793,6,1660139060,"Cannabis Could Transform Moffat into Kush, a Mecca of Marijuana Tourism",https://www.westword.com/news/cannabis-tourism-colorado-kush-moffat-area-420-san-luis-valley-marijuana-14659973,,Hacker News,17756413 -martialg,32375737,36,1659872606,Harnessing public entrepreneurship,https://elgl.org/podcast-harnessing-public-entrepreneurship-with-mitchell-weiss/,,Hacker News,97267838 -firstSpeaker,32415604,5,1660152486,Lumina is working on a smart standing desk that has a built-in display,https://www.engadget.com/lumina-sit-stand-desk-oled-display-150033942.html,,Hacker News,23160602 -dbingham,32376133,68,1659877121,A Possible Fix for Scientific Publishing,https://blog.peer-review.io/we-might-have-a-way-to-fix-scientific-publishing,,Hacker News,80356460 -ecliptik,32400562,5,1660064380,Prelinger Archives – “ephemeral” films from the 20th century,https://archive.org/details/prelinger,,Hacker News,50539542 -sharno,32374009,76,1659848139,Intel expands Oregon Fab building; 18A Node now 2024,https://chipsandcheese.com/2022/04/12/intel-renames-oregon-fab-gordon-moore-park-adds-270k-sq-ft-18a-node-now-2024/,,Hacker News,98882264 -yamrzou,32400462,5,1660064030,Are our brains Bayesian? (2016),https://rss.onlinelibrary.wiley.com/doi/full/10.1111/j.1740-9713.2016.00935.x,,Hacker News,64686574 -rntn,32411174,4,1660136414,"iRobot’s Roomba will soon be owned by Amazon, which raises privacy questions",https://theconversation.com/irobots-roomba-will-soon-be-owned-by-amazon-which-raises-privacy-questions-188355,,Hacker News,10562342 -cyanbane,32402455,14,1660071839,Two player mode in Super Punch Out ( SNES ) discovered,https://www.nintendolife.com/news/2022/08/super-punch-out-hidden-two-player-mode-discovered-28-years-later,,Hacker News,33570542 -bratao,32384350,10,1659958741,AppBlock – App with more than 1M/downloads was blocked on Play Store,https://www.appblock.app/appblock-is-temporarily-unavailable-on-google-play,,Hacker News,12719040 -rbanffy,32410934,6,1660135232,"Western Digital 22TB WD Gold, Red Pro, and Purple HDDs Hit Retail",https://www.anandtech.com/show/17501/western-digital-22tb-wd-gold-red-pro-and-purple-hdds-hit-retail,,Hacker News,26110958 -tosh,32375662,86,1659871720,Syncthing Anywhere with Tailscale,https://init8.lol/synthing-anywhere-with-tailscale/,,Hacker News,2955779 -aristofun,32382656,36,1659937253,Ask HN: Best books to build up entrepreneurial mindset?,,"When you grow up in a working class family building a business does not come naturally.

You don’t see it everyday, you don’t feel it from the inside. You don’t form subconscious knowledge of how it is done.

Then great books and educational resources are to the rescue!

Could you please name your personal top 3 of such a resources that not just pump you with emotions (most films are out of the table) and not just throw microeconomic formulas and theories at you,

But the ones showing you the truthful picture of inside-outs of a small to large businesses, with specific details and meaningful cases to learn from?",Hacker News,63897330 -michaelponrajah,32399700,26,1660060815,Why Heroku-like pricing models are hard to build,https://www.getlago.com/blog/why-heroku-like-pricing-models-are-hard-to-build,,Hacker News,22406312 -jckahn,32381188,16,1659917421,"Farmhand, the open source farming and resource management game for the browser",https://www.farmhand.life/,,Hacker News,60274450 -pamoroso,32378852,16,1659898916,Running Open Genera 2.0 on Linux (2020),https://archives.loomcom.com/genera/genera-install.html,,Hacker News,43000335 -Vaslo,32392832,35,1660005395,Russia starts stripping jetliners for parts as sanctions bite,https://www.nasdaq.com/articles/exclusive-russia-starts-stripping-jetliners-for-parts-as-sanctions-bite,,Hacker News,76051272 -keven,32399223,5,1660058475,Charity receives FDA approval to administer first-in-human CRISPR therapeutic,https://www.cureraredisease.org/fda-approval,,Hacker News,66550609 -matrix,32388997,36,1659982443,"Tesla Falsely Advertises Autopilot, Full Self-Driving Tech: California DMV",https://www.thedrive.com/news/tesla-falsely-advertises-autopilot-full-self-driving-tech-california-dmv,,Hacker News,48973822 -0xmohit,32387126,42,1659974144,Big Tech Is Spending Lots of Money to Make Antitrust Reform Seem Scary,https://www.bloomberg.com/news/articles/2022-08-03/big-tech-political-ad-spend-passes-pharmaceutical-industry,,Hacker News,19411501 -r721,32414276,6,1660147519,U.S. charges Iranian national of plot to assassinate John Bolton,https://www.cnbc.com/2022/08/10/us-charges-iranian-of-plot-to-assassinate-john-bolton.html,,Hacker News,29396539 -AlexanderTheGr8,32407142,29,1660097318,Tesla destroys child dummy in stoppage test,https://old.reddit.com/r/Damnthatsinteresting/comments/wkdh7r/tesla_absolutely_trucks_child_dummy_in_stoppage/,,Hacker News,33494664 -l2g,32377826,17,1659891068,Show HN: Apprise v1.0.0 – A lightweight all-in-one notification solution,https://github.com/caronc/apprise,"I introduced Hacker News to Apprise back when it was just an experiment (and supported just 30 or so notification services at the time). Now supporting more then 85+ services and with a ton of built in features, I officially created it's first stable v1.0.0 release marking a major milestone for the project.

Apprise doesn't compete with other notification services out there; instead it just acts as a proxy (or master switchboard) to support handling messages to them. It's a means of decoupling notification support from the systems that want to provide them. The idea is to adopt Apprise into your environment, and then you no longer have to worry about adding/removing support for new services as the come along and deprecating the ones that go away.

The way it works is that every service out there maps to a `schema://credentials/?optional_configuration`. You just need to define the schemas you use, and then you can already use Apprise. Check out the list of the services available today here: https://github.com/caronc/apprise#supported-notifications

Apprise is 100% open source (MIT Licensed). It has an acompanied API I built for those who want to centralize their configuration (found here: https://github.com/caronc/apprise-api).

Some reasons you may also all find it useful:

  - It works perfectly with legacy servers (supporting even Python 2.7).  So this fits system admins using older systems such as CentOS 6+
-  - It has a complete API that developers, devops, and administrators alike can leverage allowing them to control the notifications in their environments.
-  - It supports configuration files allowing you to securely hide your credentials and map them to simple tags like `family`, `devops`, `marketing`, etc. There is no limit to the number of tag assignments. It supports a simple TEXT (https://github.com/caronc/apprise/wiki/config_text) based configuration, as well as a more advanced and configurable YAML (https://github.com/caronc/apprise/wiki/config_yaml) based one.
-  - It sends all notifications asynchronously optimizing setups where there are many end-points to deliver to.
-  - It supports inputs are of MARKDOWN, HTML, and TEXT and can easily convert between these depending on the endpoint. For example: HTML provided input would be converted to TEXT before passing it along as a text message. However the same HTML content provided would not be converted if the endpoint accepted it as such (such as Telegram, or Email). 
-  - It supports breaking large messages into smaller ones to fit the upstream service. Hence a text message (160 characters) or a Tweet (280 characters) would be constructed for you if the notification you sent was larger.
-  - It supports file attachments too. So feel free to pass along an image, PDF, etc if the destination supports it.
-  - It can easily allow you to write your own custom notifications and/or simply leverage Apprise as routing service to perform admin tasks for you.  See here for more details: https://github.com/caronc/apprise/wiki/decorator_notify
-  - It has 100% code based test coverage. :)
-
-I hope to continue to add more services (and break 100+ supported services someday). I also hope some of you find it useful for your own project solution!",Hacker News,81530685 -rrauenza,32414138,11,1660146981,The Hacking of Starlink Terminals Has Begun,https://www.wired.com/story/starlink-internet-dish-hack/,,Hacker News,29865097 -pcr910303,32407915,9,1660106512,Some Were Meant for C: The Endurance of an Unmanageable Language [pdf],https://skeeto.s3.amazonaws.com/share/onward17-essays2.pdf,,Hacker News,52452318 -marban,32414093,4,1660146837,"Hotbit suspends trading, deposit, withdrawal and funding",https://hotbit.zendesk.com/hc/en-us/articles/8074249353495,,Hacker News,8358719 -mithunmanohar79,32409452,4,1660122630,Ask HN: Do you use JSON Schema in production?,,Do you use JSON Schema in production ? How are you making use of it ?,Hacker News,38247031 -sean_con,32407550,4,1660101763,GUI Framework on Linux,,"Hi.

I read this page.

https://news.ycombinator.com/item?id=32398181

In general, I'd be interested in GUI applications on linux.

Right of the bat, I dont like Javascript.

I know the following about linux and GUI Programming.

1. C / C++ are sort of lingua franca and are capable of making calls in the linux OS to draw a pixel on the frame buffer.

2. I think,but dont know this : rust will get a native ui framework.

I know that Linux is going to include rust in its kernel code, at least partially from the next update.

3. I am familiar with things like wrapping a C/C++ package in other languages, such as wxwidget wrapper in D. There's also things like gambas that wraps QT or GTK

4. I know that Ruby has a native toolkit, there's scenic for elixir, there's livy for python, there's Lazarus, there's tcl/tk, there's flutter from go, and well, Java.

5. There are also things like V using a custom drawing, or Ring using Allegro/ Cairo/ SDL2.

But I really dont like Javascript or web view, I also dont like java,and I dont want to rely on google for Dart/Flutter.

But I would like to be able to program linux GUI apps, where i can have a canvas element, where i can seamlessly draw text, images, vector, 3D graphics (via Vulkan, or if Vulkan is not possible then openGL) etc .

I would also like to access the speakers and the printer.

I have already listed the UI toolkit that what I am familiar with. My question is : did I miss something?

I'd be open to all knowledge, even crazy niche language with a nice UI toolkit. I am doing it for my own use, and thus won't mind the lack of popularity so to say.

Of course, this is an open ended question and I can't ask this in stackoverflow- thus I decided to ask here. I appreciate all input.

Thank you.",Hacker News,65431235 -elsewhen,32404007,15,1660077705,DOJ Poised to Sue Google over Ad Market as Soon as September,https://www.bloomberg.com/news/articles/2022-08-09/doj-poised-to-sue-google-over-ad-market-as-soon-as-september,,Hacker News,8045548 -andsoitis,32413939,5,1660146340,Google’s 144 Tbps undersea cable lands in South Africa,https://mybroadband.co.za/news/telecoms/455823-googles-massive-144-tbps-undersea-cable-lands-in-south-africa.html,,Hacker News,75855439 -sebnun,32389588,164,1659985548,Technical Writing Courses from Google,https://developers.google.com/tech-writing,,Hacker News,16863357 -leohonexus,32388279,52,1659978863,How the US Postal Service reads terrible handwriting,https://www.youtube.com/watch?v=XxCha4Kez9c,,Hacker News,56577105 -yzdbgd,32390409,9,1659989315,Show HN: Realtime visualization of 3D spectrogram with THREEJS shaders,,I've been working with 2D spectrograms for a while now while working with Speech recognition.

It had always fascinated me how speech and words had such distinct features. Looking at spectrograms is essentially like hearing with your eyes.

Over the weekend i built a tool to visualize your own audio into a spectrogram in 3D. I used threeJS with shaders and vanilla JS/Html.

Play with it here : https://spectrogram-threejs.vercel.app/

I hope it brings you as much joy as it does for me.,Hacker News,20616534 -userbinator,32374322,9,1659853234,Adventures Inside the Atom (1948),https://archive.org/details/GeneralElectricCompanyAdventuresInsideTheAtom1948,,Hacker News,31282455 -haunter,32385873,21,1659969230,Nvidia Announces Preliminary Financial Results for Second Quarter Fiscal 2023,https://nvidianews.nvidia.com/news/nvidia-announces-preliminary-financial-resultsfor-second-quarter-fiscal-2023,,Hacker News,91172269 -GLaNIK,32377069,97,1659884962,DALL-E + GPT-3 = ♥,https://medium.com/@glan1k/dall-e-gpt-3-d1aaaff38639,,Hacker News,30507980 diff --git a/premium/eagle-eye/hacker_news_processed.csv b/premium/eagle-eye/hacker_news_processed.csv deleted file mode 100644 index 599af94160..0000000000 --- a/premium/eagle-eye/hacker_news_processed.csv +++ /dev/null @@ -1,3289 +0,0 @@ -username,id,score,time,title,url,text,platform,vectorId,combined,n_tokens -gigel82,32422522,193,1660202383,Mindustry – Open-Source Game,https://mindustrygame.github.io/," - A sandbox tower-defense game. -",Hacker News,61326502,"Title: Mindustry – Open-Source Game; Content: - A sandbox tower-defense game. -",25 -0x41534446,32423813,32,1660214530,Fully Dockerized Linux kernel debugging environment,https://github.com/0xricksanchez/like-dbg," - Fully dockerized Linux kernel debugging environment - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. This repository aims at automating the boring steps when trying to set up a Linux kernel debugging environment. -All steps from building the kernel to running the kernel and attaching the debugger are transparently done inside docker containers to keep system requirements minimal. -Currently there's a dedicated docker container for every step: Everything is configured in the -So",Hacker News,93095468,"Title: Fully Dockerized Linux kernel debugging environment; Content: - Fully dockerized Linux kernel debugging environment - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. This repository aims at automating the boring steps when trying to set up a Linux kernel debugging environment. -All steps from building the kernel to running the kernel and attaching the debugger are transparently done inside docker containers to keep system requirements minimal. -Currently there's a dedicated docker container for every step: Everything is configured in the -So",232 -modinfo,32408163,207,1660110380,Freeciv – open-source Civilization clone,http://www.freeciv.org/,"Stable Version 3.0.3 released on 5th Aug 2022 Join forum to meet the users of Freeciv New developers are welcome to contribute to the project © The Freeciv Project 1996- . - Freeciv is free and open source software. Freeciv is released under the , while the Freeciv-web client is released under the .",Hacker News,47196654,"Title: Freeciv – open-source Civilization clone; Content: Stable Version 3.0.3 released on 5th Aug 2022 Join forum to meet the users of Freeciv New developers are welcome to contribute to the project © The Freeciv Project 1996- . - Freeciv is free and open source software. Freeciv is released under the , while the Freeciv-web client is released under the .",104 -bumbledraven,32421350,206,1660189674,Retirement of Amazon MOBI eBook file format,https://www.microsoftpressstore.com/promotions/product-announcement-retirement-of-amazon-mobi-ebook-142421,"ANNOUNCEMENT MOBI eBook files are going away soon. The MOBI format will no longer be available for download as of August 18, 2022 for any past purchase of a multi-format eBook here on the Microsoft Press Store website. Amazon has announced the retirement of its proprietary MOBI file format for eBooks, and a transition to the EPUB format for use on Kindle devices and apps. As of August 2022, you will no longer be able to send the MOBI file format to Kindles or the Kindle app using the Send to Kindle service. The MOBI file format no longer supports the newest document features, while the EPUB format is updated and accepted by Kindle devices. The EPUB and PDF links will remain. Purchases of future multi-format eBook files on microsoftpressstore.com after August 18 will include the EPUB and ",Hacker News,82561471,"Title: Retirement of Amazon MOBI eBook file format; Content: ANNOUNCEMENT MOBI eBook files are going away soon. The MOBI format will no longer be available for download as of August 18, 2022 for any past purchase of a multi-format eBook here on the Microsoft Press Store website. Amazon has announced the retirement of its proprietary MOBI file format for eBooks, and a transition to the EPUB format for use on Kindle devices and apps. As of August 2022, you will no longer be able to send the MOBI file format to Kindles or the Kindle app using the Send to Kindle service. The MOBI file format no longer supports the newest document features, while the EPUB format is updated and accepted by Kindle devices. The EPUB and PDF links will remain. Purchases of future multi-format eBook files on microsoftpressstore.com after August 18 will include the EPUB and ",192 -edouard-harris,32424368,1,1660219247,SharpestMinds (YC W18) Is Hiring a Software Developer,https://public.3.basecamp.com/p/gR8WJgPHPUq5r51MyWSVAX5T,,Hacker News,75941271,Title: SharpestMinds (YC W18) Is Hiring a Software Developer; Content: ,21 -jacquesm,32423178,41,1660208169,Using satellites to uncover large methane emissions from landfills,https://www.science.org/doi/10.1126/sciadv.abn9683,Please enable Cookies and reload the page. This process is automatic. Your browser will redirect to your requested content shortly. Please allow up to 5 seconds… Redirecting…,Hacker News,25913747,Title: Using satellites to uncover large methane emissions from landfills; Content: Please enable Cookies and reload the page. This process is automatic. Your browser will redirect to your requested content shortly. Please allow up to 5 seconds… Redirecting…,50 -gmemstr,32423080,43,1660207279,Hetzner Price Adjustment,https://docs.hetzner.com/general/others/price-adjustment/,"Please activate JavaScript in your browser and refresh this page. This platform will only perform optimally once JavaScript is activated. Energy prices from suppliers have risen drastically since the end of last year. This phenomenon has been affecting people and industries across the globe. And since prices are not likely to drop or stabilize in the near future, we are forced to increase the prices of many of our products by approximately 10%. In addition, we also unfortunately need to implement a serious increase to the electricity/air conditioning rates for our colocation products. A large number of our products in all locations are affected. The electricity/air conditioning flat rates for our colocation products are also affected. The products that do not directly use electricity are n",Hacker News,10851603,"Title: Hetzner Price Adjustment; Content: Please activate JavaScript in your browser and refresh this page. This platform will only perform optimally once JavaScript is activated. Energy prices from suppliers have risen drastically since the end of last year. This phenomenon has been affecting people and industries across the globe. And since prices are not likely to drop or stabilize in the near future, we are forced to increase the prices of many of our products by approximately 10%. In addition, we also unfortunately need to implement a serious increase to the electricity/air conditioning rates for our colocation products. A large number of our products in all locations are affected. The electricity/air conditioning flat rates for our colocation products are also affected. The products that do not directly use electricity are n",154 -JoachimS,32424055,30,1660216775,IPFS and Their Gateways,https://daniel.haxx.se/blog/2022/08/10/ipfs-and-their-gateways/,"The (IPFS) is according to the Wikipedia description: “a protocol, hypermedia and file sharing peer-to-peer network for storing and sharing data in a distributed file system.”. It works a little like bittorrent and you typically access content on it using a very long hash in an URL. Like this: I guess partly because IPFS is a rather new protocol not widely supported by many clients yet, people came up with the concept of IPFS “gateways”. (Others might have called it a proxy, because that is what it really is.) This is an HTTP server that runs on a machine that also knows how to speak and access IPFS. By sending the right HTTP request to the gateway, that includes the IPFS hash you are interested in, the gateway can respond with the contents from the IPFS hash. This way, you just nee",Hacker News,64252295,"Title: IPFS and Their Gateways; Content: The (IPFS) is according to the Wikipedia description: “a protocol, hypermedia and file sharing peer-to-peer network for storing and sharing data in a distributed file system.”. It works a little like bittorrent and you typically access content on it using a very long hash in an URL. Like this: I guess partly because IPFS is a rather new protocol not widely supported by many clients yet, people came up with the concept of IPFS “gateways”. (Others might have called it a proxy, because that is what it really is.) This is an HTTP server that runs on a machine that also knows how to speak and access IPFS. By sending the right HTTP request to the gateway, that includes the IPFS hash you are interested in, the gateway can respond with the contents from the IPFS hash. This way, you just nee",202 -alexzeitler,32409842,83,1660126977,How to present to executives (2021),https://lethain.com/present-to-executives/,"Have you presented to company executives about a key engineering initiative, walking into the room excited and leaving defeated? Maybe you only made it to your second slide before unrelated questions derailed the discussion. Maybe you worked through your entire presentation only to have folks say, “Great job,” and leave without any useful debate. Afterward, you’re not quite sure what happened, but you know it didn’t go well. Early in your career, you probably won’t interact with company executives frequently. Sure, if it’s a small enough company, you might, but it isn’t the norm. As you get further into your career, though, increasingly, your impact will be constrained by your ability to influence executives effectively. While is a prerequisite to influencing executives, there are also s",Hacker News,58010741,"Title: How to present to executives (2021); Content: Have you presented to company executives about a key engineering initiative, walking into the room excited and leaving defeated? Maybe you only made it to your second slide before unrelated questions derailed the discussion. Maybe you worked through your entire presentation only to have folks say, “Great job,” and leave without any useful debate. Afterward, you’re not quite sure what happened, but you know it didn’t go well. Early in your career, you probably won’t interact with company executives frequently. Sure, if it’s a small enough company, you might, but it isn’t the norm. As you get further into your career, though, increasingly, your impact will be constrained by your ability to influence executives effectively. While is a prerequisite to influencing executives, there are also s",181 -frumpish,32415960,28,1660154100,Themes in academic literature: prejudice and social justice,https://www.nas.org/academic-questions/35/2/themes-in-academic-literature-prejudice-and-social-justice#.YvPaE05MI_Q.twitter,"holds a Ph.D. in Computer Science from the Autonomous University of Madrid and is a widely published author in that field. Prof. Rozado has been teaching at New Zealand’s Otago Polytechnic since 2015; His research interests are computational content analysis and accessibility software. Rozado last appeared in these pages with “Prejudice and Victimization Themes in New York Times Discourse: A Chronological Analysis,” in spring 2020. Previous scholarly literature has documented a marked increase of words denoting prejudice and social justice themes in news media content. This work investigates the prevalence dynamics of such terms in academic papers published in all fields of knowledge. We use the Semantic Scholar Open Research Corpus (SSORC) containing, as of 2020, over 175 million publi",Hacker News,81841,"Title: Themes in academic literature: prejudice and social justice; Content: holds a Ph.D. in Computer Science from the Autonomous University of Madrid and is a widely published author in that field. Prof. Rozado has been teaching at New Zealand’s Otago Polytechnic since 2015; His research interests are computational content analysis and accessibility software. Rozado last appeared in these pages with “Prejudice and Victimization Themes in New York Times Discourse: A Chronological Analysis,” in spring 2020. Previous scholarly literature has documented a marked increase of words denoting prejudice and social justice themes in news media content. This work investigates the prevalence dynamics of such terms in academic papers published in all fields of knowledge. We use the Semantic Scholar Open Research Corpus (SSORC) containing, as of 2020, over 175 million publi",178 -timost,32421793,152,1660194394,Podman 4.2.0,https://github.com/containers/podman/releases/tag/v4.2.0,,Hacker News,87976703,Title: Podman 4.2.0; Content: ,13 -beefman,32419873,173,1660174999,New study overturns 100-year-old understanding of color perception,https://discover.lanl.gov/news/0810-color-perception,"August 10, 2022 A new study corrects an important error in the 3D mathematical space developed by the Nobel Prize–winning physicist Erwin Schrödinger and others and used by scientists and industry for more than 100 years to describe how your eye distinguishes one color from another. The research has the potential to boost scientific data visualizations, improve TVs and recalibrate the textile and paint industries. “The assumed shape of color space requires a paradigm shift,” said Roxana Bujack, a computer scientist with a background in mathematics who creates scientific visualizations at Los Alamos National Laboratory. Bujack is lead author of the by a Los Alamos team in the Proceedings of the National Academy of Science on the mathematics of color perception. ""Our research show",Hacker News,85749603,"Title: New study overturns 100-year-old understanding of color perception; Content: August 10, 2022 A new study corrects an important error in the 3D mathematical space developed by the Nobel Prize–winning physicist Erwin Schrödinger and others and used by scientists and industry for more than 100 years to describe how your eye distinguishes one color from another. The research has the potential to boost scientific data visualizations, improve TVs and recalibrate the textile and paint industries. “The assumed shape of color space requires a paradigm shift,” said Roxana Bujack, a computer scientist with a background in mathematics who creates scientific visualizations at Los Alamos National Laboratory. Bujack is lead author of the by a Los Alamos team in the Proceedings of the National Academy of Science on the mathematics of color perception. ""Our research show",190 -iosystem,32423556,43,1660211897,General belief in a just world is associated with dishonest behavior (2017),https://www.frontiersin.org/articles/10.3389/fpsyg.2017.01770/full,"The editor and reviewer's affiliations are the latest provided on their Loop research profiles and may not reflect their situation at the time of review. According to the just-world theory, people need to – or rather want to – believe that they live in a just world where they will receive what they earn and consequently earn what they receive. In the present work, we examined the influence of people’s general and personal beliefs in a just world (BJW) on their (dis)honest behavior. Given that general BJW was found to be linked to antisocial tendencies, we expected stronger general BJW to be linked to more dishonesty. Given that personal BJW was found to be correlated with trust and justice striving, a negative link with dishonesty could be assumed. In one study ( = 501), we applied a comm",Hacker News,48281665,"Title: General belief in a just world is associated with dishonest behavior (2017); Content: The editor and reviewer's affiliations are the latest provided on their Loop research profiles and may not reflect their situation at the time of review. According to the just-world theory, people need to – or rather want to – believe that they live in a just world where they will receive what they earn and consequently earn what they receive. In the present work, we examined the influence of people’s general and personal beliefs in a just world (BJW) on their (dis)honest behavior. Given that general BJW was found to be linked to antisocial tendencies, we expected stronger general BJW to be linked to more dishonesty. Given that personal BJW was found to be correlated with trust and justice striving, a negative link with dishonesty could be assumed. In one study ( = 501), we applied a comm",188 -pabs3,32422505,88,1660202187,"Give nothing, expect nothing: Gitlab latest punching bag for entitled users",https://dissociatedpress.net/2022/08/10/give-nothing-expect-nothing-gitlabs-the-latest-punching-bag-for-entitled-users/,"What do Docker, GitLab, and Red Hat have in common? Aside from various levels of participation in open source, they’ve all been punching bags over the past few years for non-paying users angry that they’ve taken some freebies off the table. When Docker had the temerity to introduce limits for free users pulling containers from DockerHub, or requiring a , lots of people started complaining and/or looking for a free alternative. When CentOS moved from a direct clone of RHEL 8 to the CentOS Stream model, hordes of people raised virtual torches and pitchforks because they were no longer able to run a freebie RHEL clone. Many noted that this was because of the uncertainty and having to either pay up or move to another RHEL clone. Few seemed to note that it’s when people don’t pay for its f",Hacker News,51081044,"Title: Give nothing, expect nothing: Gitlab latest punching bag for entitled users; Content: What do Docker, GitLab, and Red Hat have in common? Aside from various levels of participation in open source, they’ve all been punching bags over the past few years for non-paying users angry that they’ve taken some freebies off the table. When Docker had the temerity to introduce limits for free users pulling containers from DockerHub, or requiring a , lots of people started complaining and/or looking for a free alternative. When CentOS moved from a direct clone of RHEL 8 to the CentOS Stream model, hordes of people raised virtual torches and pitchforks because they were no longer able to run a freebie RHEL clone. Many noted that this was because of the uncertainty and having to either pay up or move to another RHEL clone. Few seemed to note that it’s when people don’t pay for its f",200 -doener,32395587,32,1660034928,The Cluetrain Manifesto (1999),https://www.cluetrain.com/," - These markets are conversations. Their members communicate in - language that is natural, open, honest, direct, funny and - often shocking. Whether explaining or complaining, joking or - serious, the human voice is unmistakably genuine. It can't be - faked. - Most corporations, on the other hand, only know how to - talk in the soothing, humorless monotone of the mission - statement, marketing brochure, and - your-call-is-important-to-us busy signal. Same old tone, same - old lies. No wonder networked markets have no respect for - companies unable or unwilling to speak as they do. - But learning to speak in a human voice is not some trick, - nor will corporations convince us they are human with lip - service about ""listening to customers."" They will - only sound ",Hacker News,86636626,"Title: The Cluetrain Manifesto (1999); Content: - These markets are conversations. Their members communicate in - language that is natural, open, honest, direct, funny and - often shocking. Whether explaining or complaining, joking or - serious, the human voice is unmistakably genuine. It can't be - faked. - Most corporations, on the other hand, only know how to - talk in the soothing, humorless monotone of the mission - statement, marketing brochure, and - your-call-is-important-to-us busy signal. Same old tone, same - old lies. No wonder networked markets have no respect for - companies unable or unwilling to speak as they do. - But learning to speak in a human voice is not some trick, - nor will corporations convince us they are human with lip - service about ""listening to customers."" They will - only sound ",228 -dmitryminkovsky,32417534,404,1660161290,The World Excel Championship is being broadcast on ESPN,https://www.ladbible.com/sport/world-excel-championship-that-is-getting-national-tv-coverage-20220809,"To make sure you never miss out on your favourite , we're happy to send you some reminders Click ' ' then ' ' to enable notifications There are so many sports around the world at the moment and they all bring atmosphere, thrills, spills, heartache, determination and adrenaline (in some way, shape or form). But we're here to present to you one hell of an exciting new adventure: Excel Esports. That’s right, a whole sport dedicated to ‘VLOOKUP’, ‘COUNTIF’, and ‘SUMIF’. We’ve officially peaked as a society. The sport has been set up by the Financial Modeling World Cup, with their most recent event the ‘ALL-STAR BATTLE’ jam-packed with commentators and analysis. And if you thought your Microsoft Excel skills were among the best, well, we’ve got some news for you. These la",Hacker News,11788585,"Title: The World Excel Championship is being broadcast on ESPN; Content: To make sure you never miss out on your favourite , we're happy to send you some reminders Click ' ' then ' ' to enable notifications There are so many sports around the world at the moment and they all bring atmosphere, thrills, spills, heartache, determination and adrenaline (in some way, shape or form). But we're here to present to you one hell of an exciting new adventure: Excel Esports. That’s right, a whole sport dedicated to ‘VLOOKUP’, ‘COUNTIF’, and ‘SUMIF’. We’ve officially peaked as a society. The sport has been set up by the Financial Modeling World Cup, with their most recent event the ‘ALL-STAR BATTLE’ jam-packed with commentators and analysis. And if you thought your Microsoft Excel skills were among the best, well, we’ve got some news for you. These la",246 -tmikaeld,32423291,4,1660209351,Open Cybersecurity Schema Framework,https://github.com/ocsf,"The Open Cybersecurity Schema Framework is an open-source project, delivering an extensible framework for developing schemas, along with a vendor-agnostic core security schema. Vendors and other data producers can adopt and extend the schema for their specific domains. Data engineers can map differing schemas to help security teams simplify data ingestion and normalization, so that data scientists and analysts can work with a common language for threat detection and investigation. The goal is to provide an open standard, adopted in any environment, application, or solution, while complementing existing security standards and processes. The framework is made up of a set of data types, an attribute dictionary, and the taxonomy. It is not restricted to the cybersecurity domain nor to events,",Hacker News,14060534,"Title: Open Cybersecurity Schema Framework; Content: The Open Cybersecurity Schema Framework is an open-source project, delivering an extensible framework for developing schemas, along with a vendor-agnostic core security schema. Vendors and other data producers can adopt and extend the schema for their specific domains. Data engineers can map differing schemas to help security teams simplify data ingestion and normalization, so that data scientists and analysts can work with a common language for threat detection and investigation. The goal is to provide an open standard, adopted in any environment, application, or solution, while complementing existing security standards and processes. The framework is made up of a set of data types, an attribute dictionary, and the taxonomy. It is not restricted to the cybersecurity domain nor to events,",161 -ibobev,32411141,55,1660136278,Descriptors Are Hard,https://www.jlekstrand.net/jason/blog/2022/08/descriptors-are-hard/,"Over the weekend, I if people would be interested in a rant about descriptor sets. As of the writing of this post, it has 46 likes so I’ll count that as a yes. I kind-of hate descriptor sets… Well, not descriptor sets per se. More descriptor set layouts. The fundamental problem, I think, was that we too closely tied memory layout to the shader interface. The Vulkan model works ok if your objective is to implement GL on top of Vulkan. You want 32 textures, 16 images, 24 UBOs, etc. and everything in your engine fits into those limits. As long as they’re always separate bindings in the shader, it works fine. It also works fine if you attempt to implement HLSL SM6.6 bindless on top of it. Have one giant descriptor set with all resources ever in giant arrays and pass indices into the sh",Hacker News,32452879,"Title: Descriptors Are Hard; Content: Over the weekend, I if people would be interested in a rant about descriptor sets. As of the writing of this post, it has 46 likes so I’ll count that as a yes. I kind-of hate descriptor sets… Well, not descriptor sets per se. More descriptor set layouts. The fundamental problem, I think, was that we too closely tied memory layout to the shader interface. The Vulkan model works ok if your objective is to implement GL on top of Vulkan. You want 32 textures, 16 images, 24 UBOs, etc. and everything in your engine fits into those limits. As long as they’re always separate bindings in the shader, it works fine. It also works fine if you attempt to implement HLSL SM6.6 bindless on top of it. Have one giant descriptor set with all resources ever in giant arrays and pass indices into the sh",204 -sohkamyung,32423632,16,1660212674,Backyard hens’ eggs contain 40 times more lead on average than shop eggs,https://theconversation.com/backyard-hens-eggs-contain-40-times-more-lead-on-average-than-shop-eggs-research-finds-187442," - Chief Environmental Scientist, EPA Victoria; Honorary Professor, Macquarie University - - Professor, Research School of Earth Sciences, Australian National University - - Professor, School of Natural Sciences, Macquarie University - and provide funding as members of The Conversation AU. There’s nothing like the fresh eggs from your own hens, the Australians who keep backyard chooks will tell you. Unfortunately, it’s often not just freshness and flavour that set their eggs apart from those in the shops. Our found backyard hens’ eggs contain, on average, more than 40 times the lead levels of commercially produced eggs. Almost one in two hens in our Sydney study had significant lead levels in their blood. Similarly, about half the eggs analysed contained lead",Hacker News,21319286,"Title: Backyard hens’ eggs contain 40 times more lead on average than shop eggs; Content: - Chief Environmental Scientist, EPA Victoria; Honorary Professor, Macquarie University - - Professor, Research School of Earth Sciences, Australian National University - - Professor, School of Natural Sciences, Macquarie University - and provide funding as members of The Conversation AU. There’s nothing like the fresh eggs from your own hens, the Australians who keep backyard chooks will tell you. Unfortunately, it’s often not just freshness and flavour that set their eggs apart from those in the shops. Our found backyard hens’ eggs contain, on average, more than 40 times the lead levels of commercially produced eggs. Almost one in two hens in our Sydney study had significant lead levels in their blood. Similarly, about half the eggs analysed contained lead",215 -koinedad,32422374,58,1660200905,How to learn hard things in tech,https://technicallychallenged.substack.com/p/how-to-learn-hard-things-in-tech,"So when learning technologies, software, and new tools how do I push through to the end? Here are some steps that I’ve found that work pretty well for me: If you keep doing this enough times eventually you will have accomplished the task, you will have learned the hard thing. I bet you will know the technology a lot more than you did before you started. This is basically the approach I took to learn computer programming with no formal Computer Science classes or coding bootcamp, and this is still how I learn new technologies daily. A quick note about the order of the steps: I used to start with #3 because it’s usually easier and sometimes faster. But more recently I have been forcing myself to start with only the documentation (#1 and #2) and see how far I can get before I get stuck. It’s ",Hacker News,89865816,"Title: How to learn hard things in tech; Content: So when learning technologies, software, and new tools how do I push through to the end? Here are some steps that I’ve found that work pretty well for me: If you keep doing this enough times eventually you will have accomplished the task, you will have learned the hard thing. I bet you will know the technology a lot more than you did before you started. This is basically the approach I took to learn computer programming with no formal Computer Science classes or coding bootcamp, and this is still how I learn new technologies daily. A quick note about the order of the steps: I used to start with #3 because it’s usually easier and sometimes faster. But more recently I have been forcing myself to start with only the documentation (#1 and #2) and see how far I can get before I get stuck. It’s ",186 -obert,32420082,37,1660176941,Robotic swimming in curved space via geometric phase,https://www.pnas.org/doi/full/10.1073/pnas.2200924119,,Hacker News,59082190,Title: Robotic swimming in curved space via geometric phase; Content: ,15 -merwanedr,32384870,51,1659963542,Terminal Latency (2017),https://danluu.com/term-latency/,"There’s . If you don’t want to watch the three minute video, they basically created a device which could simulate arbitrary latencies down to a fraction of a millisecond. At 100ms (1/10th of a second), which is typical of consumer tablets, the experience is terrible. At 10ms (1/100th of a second), the latency is noticeable, but the experience is ok, and at < 1ms the experience is great, as good as pen and paper. If you want to see a mini version of this for yourself, you can try a random Android tablet with a stylus vs. the current generation iPad Pro with the Apple stylus. The Apple device has well above 10ms end-to-end latency, but the difference is still quite dramatic -- it’s enough that I’ll actually use the new iPad Pro to take notes or draw diagrams, whereas I find Android tablets ",Hacker News,81684182,"Title: Terminal Latency (2017); Content: There’s . If you don’t want to watch the three minute video, they basically created a device which could simulate arbitrary latencies down to a fraction of a millisecond. At 100ms (1/10th of a second), which is typical of consumer tablets, the experience is terrible. At 10ms (1/100th of a second), the latency is noticeable, but the experience is ok, and at < 1ms the experience is great, as good as pen and paper. If you want to see a mini version of this for yourself, you can try a random Android tablet with a stylus vs. the current generation iPad Pro with the Apple stylus. The Apple device has well above 10ms end-to-end latency, but the difference is still quite dramatic -- it’s enough that I’ll actually use the new iPad Pro to take notes or draw diagrams, whereas I find Android tablets ",203 -neutralino1,32413070,104,1660143410,Launch HN: Sematic (YC S22) – Open-source framework to build ML pipelines faster,,"Hi HN – I’m Emmanuel, founder of Sematic (https://sematic.dev). Sematic is an open-source framework to prototype and productionize end-to-end Machine Learning (ML) and Data Science (DS) pipelines in days instead of weeks or months. The idea is to do for ML development what Rails and Heroku did for web development.

I started my career searching for Supersymmetry and the Higgs boson on the Large Hadron Collider at CERN, then moved to industry. I spent the last four years building ML infrastructure at Cruise. In both academia and industry, I witnessed researchers, data scientists, and ML engineers spending an absurd share of their time building makeshift tooling, stitching up infrastructure, and battling obscure systems, instead of focusing on their core area of expertise: extracting insights and predictions from data.

This was painfully apparent at Cruise where the ML Platform team needed to grow linearly with the number of users to support and models to ship to the car. What should have just taken a click (e.g. retraining a model when world conditions change – COVID parklets, road construction sites, deployment to new cities) often required weeks of painstaking work. Existing tools for prototyping and productionizing ML/DS models did not enable developers to become autonomous and tackle new projects instead of babysitting current ones.

For example, a widely adopted tool such as Kubeflow Pipelines requires users to learn an obscure Python API, package and deploy their code and dependencies by hand, and does not offer exhaustive tracking and visualization of artifacts beyond simple metadata.

In order to become autonomous, users needed a dead-simple way to iterate seamlessly between local and cloud environments (change code, validate locally, run at scale in the cloud, repeat) and visualize objects (metrics, plots, datasets, configs) in a UI. Strong guarantees around dependency packaging, traceability of artifact lineage, and reproducibility would have to be provided out-of-the-box.

Sematic lets ML/DS developers build and run pipelines of arbitrary complexity with nothing more than minimalistic Python APIs. Business logic, dynamic pipeline graphs, configurations, resource requirements, etc. — all with only Python. We are bringing the lovable aspects of Jupyter Notebooks (iterative development, visualizations) to the actual pipeline.

How it works: Sematic resolves dynamic nested graphs of pipeline steps (simple Python functions) and intercepts all inputs and outputs of each step to type-check, serialize, version, and track them. Individual steps are orchestrated as Kubernetes jobs according to required resources (e.g. GPU, high-memory), and all tracking and visualization information is surfaced in a modern UI. Build assets (user code, third-party dependencies, drivers, static libraries) are packaged and shipped to remote workers at runtime, which enables a fast and seamless iterative development experience.

Sematic lets you achieve results much faster by not wasting time on packaging dependencies, foraging for output artifacts to visualize, investigating obscure failures in black-box container jobs, bookkeeping configurations, writing complex YAML templates to run multiple experiments, etc.

It can run on a local machine or be deployed to leverage cloud resources (e.g. GPUs, high-memory instances, map/reduce clusters, etc.) with minimal external dependencies: Python, PostgreSQL, and Kubernetes.

Sematic is open-source and free to use locally or self-hosted in your own cloud. We will provide a SaaS offering to enable access to cloud resources without the hassle of maintaining a cloud deployment. -To get started, simply run `$ pip install sematic; sematic start`. Check us out at https://sematic.dev, star our Github repo, and join our Discord for updates, feature requests, and bug reports.

We would love to hear from everyone about your experience building reliable end-to-end ML training pipelines, and anything else you’d like to share in the comments!",Hacker News,42862101,"Title: Launch HN: Sematic (YC S22) – Open-source framework to build ML pipelines faster; Content: Hi HN – I’m Emmanuel, founder of Sematic (https://sematic.dev). Sematic is an open-source framework to prototype and productionize end-to-end Machine Learning (ML) and Data Science (DS) pipelines in days instead of weeks or months. The idea is to do for ML development what Rails and Heroku did for web development.

I started my career searching for Supersymmetry and the Higgs boson on the Large Hadron Collider at CERN, then moved to industry. I spent the last four years building ML infrastructure at Cruise. In both academia and industry, I witnessed researchers, data scientists, and ML engineers spending an absurd share of their time building makeshift tooling, stitching up infrastructure, and battling obscure systems, instead of focusing on their core area of expertise: extracting insights and predictions from data.

This was painfully apparent at Cruise where the ML Platform team needed to grow linearly with the number of users to support and models to ship to the car. What should have just taken a click (e.g. retraining a model when world conditions change – COVID parklets, road construction sites, deployment to new cities) often required weeks of painstaking work. Existing tools for prototyping and productionizing ML/DS models did not enable developers to become autonomous and tackle new projects instead of babysitting current ones.

For example, a widely adopted tool such as Kubeflow Pipelines requires users to learn an obscure Python API, package and deploy their code and dependencies by hand, and does not offer exhaustive tracking and visualization of artifacts beyond simple metadata.

In order to become autonomous, users needed a dead-simple way to iterate seamlessly between local and cloud environments (change code, validate locally, run at scale in the cloud, repeat) and visualize objects (metrics, plots, datasets, configs) in a UI. Strong guarantees around dependency packaging, traceability of artifact lineage, and reproducibility would have to be provided out-of-the-box.

Sematic lets ML/DS developers build and run pipelines of arbitrary complexity with nothing more than minimalistic Python APIs. Business logic, dynamic pipeline graphs, configurations, resource requirements, etc. — all with only Python. We are bringing the lovable aspects of Jupyter Notebooks (iterative development, visualizations) to the actual pipeline.

How it works: Sematic resolves dynamic nested graphs of pipeline steps (simple Python functions) and intercepts all inputs and outputs of each step to type-check, serialize, version, and track them. Individual steps are orchestrated as Kubernetes jobs according to required resources (e.g. GPU, high-memory), and all tracking and visualization information is surfaced in a modern UI. Build assets (user code, third-party dependencies, drivers, static libraries) are packaged and shipped to remote workers at runtime, which enables a fast and seamless iterative development experience.

Sematic lets you achieve results much faster by not wasting time on packaging dependencies, foraging for output artifacts to visualize, investigating obscure failures in black-box container jobs, bookkeeping configurations, writing complex YAML templates to run multiple experiments, etc.

It can run on a local machine or be deployed to leverage cloud resources (e.g. GPUs, high-memory instances, map/reduce clusters, etc.) with minimal external dependencies: Python, PostgreSQL, and Kubernetes.

Sematic is open-source and free to use locally or self-hosted in your own cloud. We will provide a SaaS offering to enable access to cloud resources without the hassle of maintaining a cloud deployment. -To get started, simply run `$ pip install sematic; sematic start`. Check us out at https://sematic.dev, star our Github repo, and join our Discord for updates, feature requests, and bug reports.

We would love to hear from everyone about your experience building reliable end-to-end ML training pipelines, and anything else you’d like to share in the comments!",973 -gamblor956,32417230,214,1660159737,FCC cancels Starlink’s and LTD's rural development grants,https://arstechnica.com/tech-policy/2022/08/fcc-rejects-starlinks-886-million-grant-says-spacex-proposal-too-risky/,"Front page layout Site theme Sign up or login to join the discussions! - - - - The Federal Communications Commission (FCC) has rejected Starlink's application to receive $885.51 million in broadband funding, essentially canceling a grant awarded by the FCC during then-Chairman Ajit Pai's tenure. Starlink was the Rural Digital Opportunity Fund (RDOF) grant in December 2020. But the satellite provider still needed FCC approval of a long-form application to receive the money, which is intended for areas with little or no high-speed broadband access. We wrote about potential problems with the SpaceX grant , in which ISPs bid on grants organized by census blocks. Consumer advocacy group Free Press accused Pai of ""subsidiz[ing] broadband for the rich,"" pointing out that Starlink was awar",Hacker News,79382119,"Title: FCC cancels Starlink’s and LTD's rural development grants; Content: Front page layout Site theme Sign up or login to join the discussions! - - - - The Federal Communications Commission (FCC) has rejected Starlink's application to receive $885.51 million in broadband funding, essentially canceling a grant awarded by the FCC during then-Chairman Ajit Pai's tenure. Starlink was the Rural Digital Opportunity Fund (RDOF) grant in December 2020. But the satellite provider still needed FCC approval of a long-form application to receive the money, which is intended for areas with little or no high-speed broadband access. We wrote about potential problems with the SpaceX grant , in which ISPs bid on grants organized by census blocks. Consumer advocacy group Free Press accused Pai of ""subsidiz[ing] broadband for the rich,"" pointing out that Starlink was awar",196 -samwillis,32418679,382,1660166827,Let websites framebust out of native apps,https://www.holovaty.com/writing/framebust-native-apps/,"Written by on August 10, 2022 Back in 1996, the website TotalNews.com had a brilliantly evil idea. Why not make a that itself contained all the top American news websites, directly embedded within? After all, why should people go to the trouble of visiting the Washington Post or New York Times websites directly? On TotalNews.com, the websites would be available in one place, with easy navigation. Using a new technology called the , TotalNews embedded the top American news sites — content, design and everything! — in such a way that the news was always fresh. (Because, well, it was .) Naturally, TotalNews added advertising around the news as well. It was only fair for them to be compensated with ad revenue for providing this incredible convenience. Yeah, it was the early, wild west da",Hacker News,29366290,"Title: Let websites framebust out of native apps; Content: Written by on August 10, 2022 Back in 1996, the website TotalNews.com had a brilliantly evil idea. Why not make a that itself contained all the top American news websites, directly embedded within? After all, why should people go to the trouble of visiting the Washington Post or New York Times websites directly? On TotalNews.com, the websites would be available in one place, with easy navigation. Using a new technology called the , TotalNews embedded the top American news sites — content, design and everything! — in such a way that the news was always fresh. (Because, well, it was .) Naturally, TotalNews added advertising around the news as well. It was only fair for them to be compensated with ad revenue for providing this incredible convenience. Yeah, it was the early, wild west da",184 -hwhelan,32420081,27,1660176920,Join Data from PostgreSQL Declaratively in GraphQL Without Writing SQL,https://stepzen.com/blog/join-data-postgresql-declarative-graphql-without-sql,"SQL is the go-to way to interact with relational databases such as PostgreSQL. When creating an API, either REST or GraphQL, for your PostgreSQL database, you need to know SQL to get your data in and out. Often developers are helped by ORM (Object Relational Mapping) tools to communicate with the database, and these tools abstract some of the knowledge you need to have of SQL to build your API. Even though these tools help you get started, they don't help you create efficient SQL. You wouldn't be the first developer to write an inefficient query that overloads or times-out your database. At StepZen, we've built tools and services to create GraphQL APIs declaratively - including improving the way you connect and communicate with your databases. This takes away some of the pain of writing ef",Hacker News,76471375,"Title: Join Data from PostgreSQL Declaratively in GraphQL Without Writing SQL; Content: SQL is the go-to way to interact with relational databases such as PostgreSQL. When creating an API, either REST or GraphQL, for your PostgreSQL database, you need to know SQL to get your data in and out. Often developers are helped by ORM (Object Relational Mapping) tools to communicate with the database, and these tools abstract some of the knowledge you need to have of SQL to build your API. Even though these tools help you get started, they don't help you create efficient SQL. You wouldn't be the first developer to write an inefficient query that overloads or times-out your database. At StepZen, we've built tools and services to create GraphQL APIs declaratively - including improving the way you connect and communicate with your databases. This takes away some of the pain of writing ef",188 -the_mitsuhiko,32415470,1147,1660151904,Instagram can track anything you do on any website in their in-app browser,https://krausefx.com/blog/ios-privacy-instagram-and-facebook-can-track-anything-you-do-on-any-website-in-their-in-app-browser,"Founder of - Want to be the first to hear about more privacy and mobile related essays? - -   |   - - The iOS Instagram and Facebook app render all third party links and ads within their app using a custom in-app browser. This , with the host app being able to track every single interaction with external websites, from all form inputs like passwords and addresses, to every single tap. Instagram is purposely working around the App Tracking Transparency permission system, which was designed to prevent this exact type of data collection. After its introduction, announced: Apple’s simple iPhone alert is Facebook complained that Apple’s App Tracking Transparency favors companies like Google because App Tracking Transparency “carves out browsers from the tracking prompts Apple requir",Hacker News,44780406,"Title: Instagram can track anything you do on any website in their in-app browser; Content: Founder of - Want to be the first to hear about more privacy and mobile related essays? - -   |   - - The iOS Instagram and Facebook app render all third party links and ads within their app using a custom in-app browser. This , with the host app being able to track every single interaction with external websites, from all form inputs like passwords and addresses, to every single tap. Instagram is purposely working around the App Tracking Transparency permission system, which was designed to prevent this exact type of data collection. After its introduction, announced: Apple’s simple iPhone alert is Facebook complained that Apple’s App Tracking Transparency favors companies like Google because App Tracking Transparency “carves out browsers from the tracking prompts Apple requir",186 -chmaynard,32410223,57,1660130865,Adding Auditing to Pip,https://lwn.net/SubscriberLink/904197/9f5cc13b3c352127/," - -The following subscription-only content has been made available to you -by an LWN subscriber. Thousands of subscribers depend on LWN for the -best news from the Linux and free software communities. If you enjoy this -article, please consider . Thank you -for visiting LWN.net! - - - - -A tool to discover known security vulnerabilities in the Python packages installed on -a system or required by a project, called , was recently -discussed on the . The developers of pip-audit of adding the functionality directly into the , rather than -keeping it as a separately installable tool. While the functionality provided by -pip-audit was seen as a clear benefit to the ecosystem, moving it -inside the pip ""tent"" was not as overwhelmingly popular. It is not obvious -that auditing is part of the",Hacker News,97924799,"Title: Adding Auditing to Pip; Content: - -The following subscription-only content has been made available to you -by an LWN subscriber. Thousands of subscribers depend on LWN for the -best news from the Linux and free software communities. If you enjoy this -article, please consider . Thank you -for visiting LWN.net! - - - - -A tool to discover known security vulnerabilities in the Python packages installed on -a system or required by a project, called , was recently -discussed on the . The developers of pip-audit of adding the functionality directly into the , rather than -keeping it as a separately installable tool. While the functionality provided by -pip-audit was seen as a clear benefit to the ecosystem, moving it -inside the pip ""tent"" was not as overwhelmingly popular. It is not obvious -that auditing is part of the",206 -eatonphil,32412905,328,1660142859,How SQLite Helps You Do ACID,https://fly.io/blog/sqlite-internals-rollback-journal/,"When database vendors recite their long list of features, they never enumerate ""doesn't lose your data"" as one of those features. It's just assumed. That's what a database is supposed to do. However, in reality, the best database vendors . I've written before about . In order not to lose any of it when a transaction goes wrong, SQLite implements a journal. It has two different modes: the rollback journal & the write-ahead log. Today we're diving into the rollback journal: what it is, how it works, and when to use it. To understand why you need a database journal, let's look at what happens without one. , we talked about how SQLite is split up into 4KB chunks called ""pages"". Any time you make a change—even a 1 byte change—SQLite will write a full 4KB page. If you tried to overwrite a",Hacker News,36158008,"Title: How SQLite Helps You Do ACID; Content: When database vendors recite their long list of features, they never enumerate ""doesn't lose your data"" as one of those features. It's just assumed. That's what a database is supposed to do. However, in reality, the best database vendors . I've written before about . In order not to lose any of it when a transaction goes wrong, SQLite implements a journal. It has two different modes: the rollback journal & the write-ahead log. Today we're diving into the rollback journal: what it is, how it works, and when to use it. To understand why you need a database journal, let's look at what happens without one. , we talked about how SQLite is split up into 4KB chunks called ""pages"". Any time you make a change—even a 1 byte change—SQLite will write a full 4KB page. If you tried to overwrite a",209 -elsewhen,32414870,195,1660149713,Dark Matter Doesn't Exist,https://iai.tv/articles/dark-matter-doesnt-exist-auid-2180,"Astronomers and physicists today understand the observed Universe in terms of a model universe in which the normal matter we see around us in the form of atoms makes up only 5% of all the energy in it. About 20% is made up of exotic dark matter particles and about 75% is made up of even more exotic dark energy. This dark-matter-based model (for each gram of normal matter there are 25 grams of the exotic dark matter) is about 20 years old, but the strong belief in the scientific community that dark matter exists goes back 30 years. ___ There is a simple test that these scientists are ignoring and which has already been applied and it tells us that dark matter does not exist. ___ The many searches worldwide for evidence of dark matter particles, going on since at least 30 years, have come up",Hacker News,34163437,"Title: Dark Matter Doesn't Exist; Content: Astronomers and physicists today understand the observed Universe in terms of a model universe in which the normal matter we see around us in the form of atoms makes up only 5% of all the energy in it. About 20% is made up of exotic dark matter particles and about 75% is made up of even more exotic dark energy. This dark-matter-based model (for each gram of normal matter there are 25 grams of the exotic dark matter) is about 20 years old, but the strong belief in the scientific community that dark matter exists goes back 30 years. ___ There is a simple test that these scientists are ignoring and which has already been applied and it tells us that dark matter does not exist. ___ The many searches worldwide for evidence of dark matter particles, going on since at least 30 years, have come up",175 -mpweiher,32384016,212,1659955022,Vector graphics on GPU,https://gasiulis.name/vector-graphics-on-gpu/,"Despite vector graphics being used in every computer with a screen connected to it, rendering of vector shapes and text is still mostly a task for the CPU. This is wrong and needs to be changed. Here I describe a general approach to rasterization and how we can ask for help from GPU when rendering vector paths. First, let's overview a general principle of rasterization of vector shapes. Here is an image with a clockwise circle in it and I'll demonstrate a very rudimentary algorithm for drawing one row of pixels of that image. For simplicity reasons, anti-aliasing will not be included at this time. For each pixel in this row we only need to know if its center is inside of this shape or outside. Outside pixels are left untouched while inside pixels are filled with color of that shape. We sta",Hacker News,32814922,"Title: Vector graphics on GPU; Content: Despite vector graphics being used in every computer with a screen connected to it, rendering of vector shapes and text is still mostly a task for the CPU. This is wrong and needs to be changed. Here I describe a general approach to rasterization and how we can ask for help from GPU when rendering vector paths. First, let's overview a general principle of rasterization of vector shapes. Here is an image with a clockwise circle in it and I'll demonstrate a very rudimentary algorithm for drawing one row of pixels of that image. For simplicity reasons, anti-aliasing will not be included at this time. For each pixel in this row we only need to know if its center is inside of this shape or outside. Outside pixels are left untouched while inside pixels are filled with color of that shape. We sta",174 -thunderbong,32395589,431,1660034943,The Story of Mel (1983),https://www.cs.utah.edu/~elb/folklore/mel.html,"This was posted to USENET by its author, Ed Nather (utastro!nather), -on May 21, 1983. - A recent article devoted to the *macho* side of programming - made the bald and unvarnished statement: - This is one of hackerdom's great heroic epics, free verse or no. In -a few spare images it captures more about the esthetics and psychology -of hacking than all the scholarly volumes on the subject put together. - [1992 postscript --- the author writes: ""The original submission to -the net was not in free verse, nor any approximation to it --- it was -straight prose style, in non-justified paragraphs. In bouncing around -the net it apparently got modified into the `free verse' form now -popular. In other words, it got hacked on the net. That seems -appropriate, somehow.""] -",Hacker News,64887478,"Title: The Story of Mel (1983); Content: This was posted to USENET by its author, Ed Nather (utastro!nather), -on May 21, 1983. - A recent article devoted to the *macho* side of programming - made the bald and unvarnished statement: - This is one of hackerdom's great heroic epics, free verse or no. In -a few spare images it captures more about the esthetics and psychology -of hacking than all the scholarly volumes on the subject put together. - [1992 postscript --- the author writes: ""The original submission to -the net was not in free verse, nor any approximation to it --- it was -straight prose style, in non-justified paragraphs. In bouncing around -the net it apparently got modified into the `free verse' form now -popular. In other words, it got hacked on the net. That seems -appropriate, somehow.""] -",211 -larve,32410355,223,1660131871,“Autistic people can’t acknowledge when they’re wrong”,https://the.scapegoat.dev/autistic-people-cant-acknowledge-when-they-are-wrong/,"🏡 📝 - - I have heard this sentence many times in my life, always in the workplace. This puzzles me as I pride myself on seeking out things I am wrong about and learning things I don't know. I have read similar experiences by other autistic people, which has helped me restore my self-confidence and given me a framework to analyze these situations. I want to share my experiences and insight to help allistic people become more aware of autistic communication patterns. When these conflicts arise, here are some things that might be happening. I know my thinking can be alien at times, which requires me to establish a context for them to use to understand what I'm saying. This can take a few minutes. However, people can become impatient and cut me off or interject with a snap interpretation of",Hacker News,17965619,"Title: “Autistic people can’t acknowledge when they’re wrong”; Content: 🏡 📝 - - I have heard this sentence many times in my life, always in the workplace. This puzzles me as I pride myself on seeking out things I am wrong about and learning things I don't know. I have read similar experiences by other autistic people, which has helped me restore my self-confidence and given me a framework to analyze these situations. I want to share my experiences and insight to help allistic people become more aware of autistic communication patterns. When these conflicts arise, here are some things that might be happening. I know my thinking can be alien at times, which requires me to establish a context for them to use to understand what I'm saying. This can take a few minutes. However, people can become impatient and cut me off or interject with a snap interpretation of",192 -Tomte,32410283,178,1660131375,Stringbike: Benefits (2020),https://www.stringbike.com/stringbike_benefits.html," - Your stringbike is always clean and oil free: whether riding or transporting or during storage or maintenance. - - Say goodbye to the greasy chain, the dangerously sharp sprockets or delicate derailleurs. No more greasy palms, greasy wrists, cuts, scrapes or soiled clothes. - - Strings are transferring the leg power to the rear wheel on a silky, smooth way, while filtering all vibrancy. - The pedaling experience is improved by the symmetrically balanced drive system. - - - The graceful movement of Stringdrive turns the heads everywhere, every time. - - Totally silent biking. - - Unique experience: no chain drive noise, no free wheel rolling noise, the only noise is the sound of the tires. - - Enjoy the silent whoosh. - The Stringdr",Hacker News,84047227,"Title: Stringbike: Benefits (2020); Content: - Your stringbike is always clean and oil free: whether riding or transporting or during storage or maintenance. - - Say goodbye to the greasy chain, the dangerously sharp sprockets or delicate derailleurs. No more greasy palms, greasy wrists, cuts, scrapes or soiled clothes. - - Strings are transferring the leg power to the rear wheel on a silky, smooth way, while filtering all vibrancy. - The pedaling experience is improved by the symmetrically balanced drive system. - - - The graceful movement of Stringdrive turns the heads everywhere, every time. - - Totally silent biking. - - Unique experience: no chain drive noise, no free wheel rolling noise, the only noise is the sound of the tires. - - Enjoy the silent whoosh. - The Stringdr",260 -amelius,32419708,26,1660173702,Where does energy go during destructive interference?,https://van.physics.illinois.edu/qa/listing.php?id=21973,"Hi Vishwajeet, - -You are absolutely correct that whenever you have destructive interference, there must be some constructive interference somewhere else. This much is obvious from the law of conservation of energy: anytime energy disappears from one place, we know it can be found in some form somewhere else. - -However, exactly this happens is often not at all obvious in a specific case, for which you can prove this fact only by careful calculations. In a few cases, the calculations involved aren't terribly difficult, and just require some algebra. One of these cases is the two-slit experiment, if you look far away from the slits. (Close to the slits, the math is a bit trickier, and you get a pretty but complicated pattern like .) - -As you know, destructive and constructive interfere",Hacker News,94433052,"Title: Where does energy go during destructive interference?; Content: Hi Vishwajeet, - -You are absolutely correct that whenever you have destructive interference, there must be some constructive interference somewhere else. This much is obvious from the law of conservation of energy: anytime energy disappears from one place, we know it can be found in some form somewhere else. - -However, exactly this happens is often not at all obvious in a specific case, for which you can prove this fact only by careful calculations. In a few cases, the calculations involved aren't terribly difficult, and just require some algebra. One of these cases is the two-slit experiment, if you look far away from the slits. (Close to the slits, the math is a bit trickier, and you get a pretty but complicated pattern like .) - -As you know, destructive and constructive interfere",189 -LukeEF,32412803,234,1660142525,The semantic web is dead – Long live the semantic web,https://github.com/GavinMendelGleason/blog/blob/main/entries/semantic_future.md," is -rarely mentioned these days, so seldom that the declaration of its -death could be met by most of a younger generation of programmers with -a question: ""The Semantic Who?"" This change in status is significant, but in some ways the Semantic -Web was on life-support since inception, and it continued to survive -only with the medical intervention of academic departments who had no -need to produce useable software or solve serious industry needs. That's not to say that Semantic Web technologies served any -industry needs. They certainly did so, but their penetration was -limited. And this limited penetration was not only the result of -ignorance on the part of data architects or software engineers. It was -also the fault of deep problems with the ideas in the -Semantic Web itself. The Semantic We",Hacker News,20713613,"Title: The semantic web is dead – Long live the semantic web; Content: is -rarely mentioned these days, so seldom that the declaration of its -death could be met by most of a younger generation of programmers with -a question: ""The Semantic Who?"" This change in status is significant, but in some ways the Semantic -Web was on life-support since inception, and it continued to survive -only with the medical intervention of academic departments who had no -need to produce useable software or solve serious industry needs. That's not to say that Semantic Web technologies served any -industry needs. They certainly did so, but their penetration was -limited. And this limited penetration was not only the result of -ignorance on the part of data architects or software engineers. It was -also the fault of deep problems with the ideas in the -Semantic Web itself. The Semantic We",189 -quaffapint,32412170,641,1660140363,"'Too many employees, but few work': Pichai, Zuckerberg sound the alarm",https://www.business-standard.com/article/international/too-many-employees-but-few-work-pichai-zuckerberg-sound-the-alarm-122080801425_1.html," -  |  - - https://mybs.in/2axmrhj - With global recession fears looming, some of the biggest names in the technology world have some ominous words to spare: Big Tech has hired more people, but only some of them are doing the work. - Meta (earlier Facebook) Founder Mark Zuckerberg fired the first salvo. It was the weekly Q&A on June 30, and he had said that the economy was headed for the “worst downturns that we’ve seen in recent history”. - - Then he continued. - - “Realistically, there are probably a bunch of people at the company who shouldn’t be here,” Zuckerberg said on the call, according to a Reuters report. “And part of my hope by raising expectations and having more aggressive goals, and just kind of turning up the heat a little bit, is that I think some of you might just say",Hacker News,32522250,"Title: 'Too many employees, but few work': Pichai, Zuckerberg sound the alarm; Content: -  |  - - https://mybs.in/2axmrhj - With global recession fears looming, some of the biggest names in the technology world have some ominous words to spare: Big Tech has hired more people, but only some of them are doing the work. - Meta (earlier Facebook) Founder Mark Zuckerberg fired the first salvo. It was the weekly Q&A on June 30, and he had said that the economy was headed for the “worst downturns that we’ve seen in recent history”. - - Then he continued. - - “Realistically, there are probably a bunch of people at the company who shouldn’t be here,” Zuckerberg said on the call, according to a Reuters report. “And part of my hope by raising expectations and having more aggressive goals, and just kind of turning up the heat a little bit, is that I think some of you might just say",238 -pepys,32409386,47,1660121914,Why Nagasaki? (2013),http://blog.nuclearsecrecy.com/2013/08/09/why-nagasaki/,An appropriate representation of the requested resource could not be found on this server. This error was generated by Mod_Security.,Hacker News,54143852,Title: Why Nagasaki? (2013); Content: An appropriate representation of the requested resource could not be found on this server. This error was generated by Mod_Security.,35 -__Joker,32423100,12,1660207448,California Exported Its Worst Problem to Texas,https://www.theatlantic.com/ideas/archive/2022/08/housing-crisis-affordability-covid-everywhere-problem/671077/,"The pandemic was supposed to ease high housing prices in coastal superstar cities. Instead, it spread them nationwide. On an otherwise sleepy Saturday morning, cars were parked bumper to bumper along a suburban street. Couples formed a line around the block, nervously sipping coffee and double-checking paperwork. They were there to see a charming but decidedly modest house—early-’90s suburban, vinyl shutters, holly bushes—that had just come on the market. Twenty-four hours later, the home had sold for 20 percent above the asking price and $100,000 more than it had sold for in 2006 at the height of a so-called housing bubble. That’s a story we’re used to hearing about the frenzied housing markets of coastal suburbs such as Orange County and Long Island. But this house wasn’t far from wher",Hacker News,81033563,"Title: California Exported Its Worst Problem to Texas; Content: The pandemic was supposed to ease high housing prices in coastal superstar cities. Instead, it spread them nationwide. On an otherwise sleepy Saturday morning, cars were parked bumper to bumper along a suburban street. Couples formed a line around the block, nervously sipping coffee and double-checking paperwork. They were there to see a charming but decidedly modest house—early-’90s suburban, vinyl shutters, holly bushes—that had just come on the market. Twenty-four hours later, the home had sold for 20 percent above the asking price and $100,000 more than it had sold for in 2006 at the height of a so-called housing bubble. That’s a story we’re used to hearing about the frenzied housing markets of coastal suburbs such as Orange County and Long Island. But this house wasn’t far from wher",193 -tjwds,32423988,3,1660216118,Wikipedia’s Credibility Is Toast,https://wikipediocracy.com/2022/08/11/wikipedias-credibility-is-toast/,An appropriate representation of the requested resource could not be found on this server. This error was generated by Mod_Security.,Hacker News,66969920,Title: Wikipedia’s Credibility Is Toast; Content: An appropriate representation of the requested resource could not be found on this server. This error was generated by Mod_Security.,38 -brudgers,32392070,97,1659998719,To speak meaningfully about art,https://medium.com/luminasticity/to-speak-meaningfully-about-art-329093dbce7f,"luminasticity To be able to speak meaningfully about any art you must be able to order that art into at least four categories, these are If you cannot do this you will never have anything worthwhile to say about a work of art, at the most you will be able to tell people what you like, and that can be helpful to them because they will know what music to buy you, or if they have similar tastes to yours they will be able to buy books for themselves based on your recommendation. But in conversation you will be unable to speak with others who do not share your tastes, you will be unable to defend these tastes beyond asserting that you like what you like, and you will be unable to understand the weakness in what you like because what you like is good, and what you do not like is not good, and th",Hacker News,17843441,"Title: To speak meaningfully about art; Content: luminasticity To be able to speak meaningfully about any art you must be able to order that art into at least four categories, these are If you cannot do this you will never have anything worthwhile to say about a work of art, at the most you will be able to tell people what you like, and that can be helpful to them because they will know what music to buy you, or if they have similar tastes to yours they will be able to buy books for themselves based on your recommendation. But in conversation you will be unable to speak with others who do not share your tastes, you will be unable to defend these tastes beyond asserting that you like what you like, and you will be unable to understand the weakness in what you like because what you like is good, and what you do not like is not good, and th",179 -carride,32411493,1073,1660137834,Man who built ISP instead of paying Comcast $50K expands to hundreds of homes,https://arstechnica.com/tech-policy/2022/08/man-who-built-isp-instead-of-paying-comcast-50k-expands-to-hundreds-of-homes/,"Front page layout Site theme Sign up or login to join the discussions! - - - - Jared Mauch, the Michigan man who built a fiber-to-the-home Internet provider because he couldn't get good broadband service from AT&T or Comcast, is expanding with the help of $2.6 million in government money. When we , he was providing service to about 30 rural homes including his own with his ISP, Washtenaw Fiber Properties LLC. Mauch now has about 70 customers and will extend his network to nearly 600 more properties with money from the American Rescue Plan's , he told Ars in a phone interview in mid-July. The US government allocated Washtenaw County for a variety of infrastructure projects, and the county to broadband. The county conducted a broadband study before the pandemic to identify unserve",Hacker News,12377675,"Title: Man who built ISP instead of paying Comcast $50K expands to hundreds of homes; Content: Front page layout Site theme Sign up or login to join the discussions! - - - - Jared Mauch, the Michigan man who built a fiber-to-the-home Internet provider because he couldn't get good broadband service from AT&T or Comcast, is expanding with the help of $2.6 million in government money. When we , he was providing service to about 30 rural homes including his own with his ISP, Washtenaw Fiber Properties LLC. Mauch now has about 70 customers and will extend his network to nearly 600 more properties with money from the American Rescue Plan's , he told Ars in a phone interview in mid-July. The US government allocated Washtenaw County for a variety of infrastructure projects, and the county to broadband. The county conducted a broadband study before the pandemic to identify unserve",202 -samclemens,32410286,53,1660131403,An artist who hooked British rock royalty on her revolutionary crochet (2021),https://www.collectorsweekly.com/articles/the-swedish-artist-who-hooked-british-rock-royalty-on-crochet/," - — - - Eric Clapton, wearing a crocheted “100% Birgitta” jacket by Birgitta Bjerke, performs with John Lennon during “The Rolling Stones’ Rock and Roll Circus,” December 11, 1968. (Photo by Jeff Hochberg/Getty Images) On December 11, 1968, Eric Clapton stepped onto a low stage inside Intertel (V.T.R. Services) Studio north of London to play a few tunes with John Lennon and Keith Richards; the occasion was the taping of “The Rolling Stones Rock and Roll Circus” for the BBC. At the time, Clapton was the most revered electric guitarist in rock, even amid the incendiary ascendancy of Jimi Hendrix. A few weeks earlier, Clapton had performed his last two shows as a member of Cream at the prestigious Royal Albert Hall, and by the summer of 1969, he would team up with Steve Winwood of Traff",Hacker News,54991992,"Title: An artist who hooked British rock royalty on her revolutionary crochet (2021); Content: - — - - Eric Clapton, wearing a crocheted “100% Birgitta” jacket by Birgitta Bjerke, performs with John Lennon during “The Rolling Stones’ Rock and Roll Circus,” December 11, 1968. (Photo by Jeff Hochberg/Getty Images) On December 11, 1968, Eric Clapton stepped onto a low stage inside Intertel (V.T.R. Services) Studio north of London to play a few tunes with John Lennon and Keith Richards; the occasion was the taping of “The Rolling Stones Rock and Roll Circus” for the BBC. At the time, Clapton was the most revered electric guitarist in rock, even amid the incendiary ascendancy of Jimi Hendrix. A few weeks earlier, Clapton had performed his last two shows as a member of Cream at the prestigious Royal Albert Hall, and by the summer of 1969, he would team up with Steve Winwood of Traff",231 -mitchbob,32416815,88,1660157769,The Case for Degrowth,https://www.lrb.co.uk/the-paper/v44/n16/geoff-mann/reversing-the-freight-train,"London Review of Books In the latest issue: More search Options Browse by Subject ​ how to talk about modern economies without talking about growth: productivity, entrepreneurial ‘risk-taking’ and the profit-driven cycle of expansion and accumulation. Economic growth is understood to be a natural or automatic process, its absence taken as evidence that we must somehow have got in its way. The purpose of economic policymaking is, accordingly, presented as a matter of loosening the ‘fetters’ on growth, as if the economy were a wealth-generating beast, always raring to go, if only we’d let it. Given all this, it may come as a surprise to learn that the analysis of ‘economic growth’ in its contemporary sense is a relatively recent development. Some will say that Adam Smith was the first theori",Hacker News,64900627,"Title: The Case for Degrowth; Content: London Review of Books In the latest issue: More search Options Browse by Subject ​ how to talk about modern economies without talking about growth: productivity, entrepreneurial ‘risk-taking’ and the profit-driven cycle of expansion and accumulation. Economic growth is understood to be a natural or automatic process, its absence taken as evidence that we must somehow have got in its way. The purpose of economic policymaking is, accordingly, presented as a matter of loosening the ‘fetters’ on growth, as if the economy were a wealth-generating beast, always raring to go, if only we’d let it. Given all this, it may come as a surprise to learn that the analysis of ‘economic growth’ in its contemporary sense is a relatively recent development. Some will say that Adam Smith was the first theori",182 -gregsadetsky,32416556,37,1660156583,Fucked Up Mockups,https://fockups.com/," - F*cked up mockups All rights reserved",Hacker News,85727381,"Title: Fucked Up Mockups; Content: - F*cked up mockups All rights reserved",31 -alberto_ol,32411769,83,1660138964,We thank Miss Mary Tsingou (2020),https://www.lanl.gov/discover/publications/national-security-science/2020-winter/mary-tsingou.shtml,"Related Resources Resources - A half-century after being mentioned in the footnote of a seminal physics paper, one of the Laboratory’s first computer programmers gets the recognition she deserves. - , Los Alamos Scientific Laboratory published the paper “Studies of Nonlinear Problems,” which detailed the methods and results of a mathematical physics simulation run on the MANIAC, the Laboratory’s first electronic computer. The scientists who wrote the paper—Enrico Fermi, John Pasta, and Stanislaw Ulam—were quickly recognized for the remarkable simulation, which came to be called the Fermi-Pasta-Ulam (FPU) problem. In a footnote, the authors wrote, “We thank Miss Mary Tsingou for efficient coding of the problems and for running the computations on th",Hacker News,90592736,"Title: We thank Miss Mary Tsingou (2020); Content: Related Resources Resources - A half-century after being mentioned in the footnote of a seminal physics paper, one of the Laboratory’s first computer programmers gets the recognition she deserves. - , Los Alamos Scientific Laboratory published the paper “Studies of Nonlinear Problems,” which detailed the methods and results of a mathematical physics simulation run on the MANIAC, the Laboratory’s first electronic computer. The scientists who wrote the paper—Enrico Fermi, John Pasta, and Stanislaw Ulam—were quickly recognized for the remarkable simulation, which came to be called the Fermi-Pasta-Ulam (FPU) problem. In a footnote, the authors wrote, “We thank Miss Mary Tsingou for efficient coding of the problems and for running the computations on th",226 -gumby,32409102,239,1660119133,The strength of the strong force,https://phys.org/news/2022-08-strength-strong.html,"Your browser sent an invalid request. - We highly recommend setting a meaningful User-Agent header. -",Hacker News,76324546,"Title: The strength of the strong force; Content: Your browser sent an invalid request. - We highly recommend setting a meaningful User-Agent header. -",33 -andriodsheep,32420205,10,1660178157,Superlattices Could Make Bulky Capacitors Obsolete,https://spectrum.ieee.org/antiferroelectric,"IEEE websites place cookies on your device to give you the best user experience. By using our websites, you agree to the placement of these cookies. To learn more, read our Privacy Policy. Researchers hope artificial antiferroelectric capacitors could help miniaturize electronics further In artificial antiferroelectric structures, electric dipoles are normally arranged in ways that lead to zero electric polarization. One roadblock to shrinking present-day electronics is the relatively large size of their capacitors. Now scientists have developed new ""superlattices"" that might help build capacitors as small as one-hundredth the size of conventional ones. Whereas store energy in chemical form, store energy in an electric field. Batteries typically possess greater energy densities than ca",Hacker News,94128681,"Title: Superlattices Could Make Bulky Capacitors Obsolete; Content: IEEE websites place cookies on your device to give you the best user experience. By using our websites, you agree to the placement of these cookies. To learn more, read our Privacy Policy. Researchers hope artificial antiferroelectric capacitors could help miniaturize electronics further In artificial antiferroelectric structures, electric dipoles are normally arranged in ways that lead to zero electric polarization. One roadblock to shrinking present-day electronics is the relatively large size of their capacitors. Now scientists have developed new ""superlattices"" that might help build capacitors as small as one-hundredth the size of conventional ones. Whereas store energy in chemical form, store energy in an electric field. Batteries typically possess greater energy densities than ca",174 -Digit-Al,32410096,61,1660129569,What are you supposed to do with old clothes?,https://www.theatlantic.com/technology/archive/2022/08/what-to-do-with-old-clothing-donation-waste/671043/,"There are no good solutions to the problems of closet clean-out. In February, I ran out of hangers. The occasion was not exactly unforeseen—for at least a year, I had been rearranging the deck chairs on my personal-storage Titanic in an attempt to forestall the inevitable. I loaded two or three tank tops or summer dresses onto a single hanger. I carefully refolded everything in my dresser drawers to max out their capacity. I left the things I wore most frequently on a bedroom chair instead of wedging them into my closet. I didn’t buy anything new unless I absolutely needed it. Eventually, though, I did need some things, and I didn’t have anywhere to put them. Realizing you’ve exceeded the bounds of your closet is a low-grade domestic humiliation that’s become familiar to many Americans. On",Hacker News,92353439,"Title: What are you supposed to do with old clothes?; Content: There are no good solutions to the problems of closet clean-out. In February, I ran out of hangers. The occasion was not exactly unforeseen—for at least a year, I had been rearranging the deck chairs on my personal-storage Titanic in an attempt to forestall the inevitable. I loaded two or three tank tops or summer dresses onto a single hanger. I carefully refolded everything in my dresser drawers to max out their capacity. I left the things I wore most frequently on a bedroom chair instead of wedging them into my closet. I didn’t buy anything new unless I absolutely needed it. Eventually, though, I did need some things, and I didn’t have anywhere to put them. Realizing you’ve exceeded the bounds of your closet is a low-grade domestic humiliation that’s become familiar to many Americans. On",195 -radicalbyte,32410075,118,1660129335,The mechanics of a sophisticated phishing scam and how we stopped it,https://blog.cloudflare.com/2022-07-sms-phishing-attacks,"Please stand by, while we are checking your browser... Redirecting... Please enable Cookies and reload the page. Completing the CAPTCHA proves you are a human and gives you temporary access to the web property. If you are on a personal connection, like at home, you can run an anti-virus scan on your device to make sure it is not infected with malware. If you are at an office or shared network, you can ask the network administrator to run a scan across the network looking for misconfigured or infected devices. - - - - -",Hacker News,55404706,"Title: The mechanics of a sophisticated phishing scam and how we stopped it; Content: Please stand by, while we are checking your browser... Redirecting... Please enable Cookies and reload the page. Completing the CAPTCHA proves you are a human and gives you temporary access to the web property. If you are on a personal connection, like at home, you can run an anti-virus scan on your device to make sure it is not infected with malware. If you are at an office or shared network, you can ask the network administrator to run a scan across the network looking for misconfigured or infected devices. - - - - -",138 -fxtentacle,32409966,205,1660128341,Show HN: State-of-the-art German speech recognition in 284 lines of C++,https://github.com/DeutscheKI/tevr-asr-tool," - State-of-the-art (ranked #1 Aug 2022) German Speech Recognition in 284 lines of C++. This is a 100% private 100% offline 100% free CLI tool. - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. In August 2022, we ranked - -with a 3.64% word error rate. -Accordingly, the performance of this tool is considered to be -the best of what's currently possible -in German speech recognition: - -load the WAV file. - -execute the acoustic AI model. - -convert the predicted token logits into string ",Hacker News,12590703,"Title: Show HN: State-of-the-art German speech recognition in 284 lines of C++; Content: - State-of-the-art (ranked #1 Aug 2022) German Speech Recognition in 284 lines of C++. This is a 100% private 100% offline 100% free CLI tool. - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. In August 2022, we ranked - -with a 3.64% word error rate. -Accordingly, the performance of this tool is considered to be -the best of what's currently possible -in German speech recognition: - -load the WAV file. - -execute the acoustic AI model. - -convert the predicted token logits into string ",285 -todsacerdoti,32422082,113,1660197574,There aren't that many uses for blockchains,https://calpaterson.com/blockchain.html," - A criteria for judging when a - blockchain is applicable A common saying among those who are into their crypto is that ""the real - innovation isn't Bitcoin, but the "". Blockchains are - increasingly popular. At some point using a blockchain stopped being called - just 'blockchain technology' and started to be called . The implication being that - blockchains have such wide applicability that they will come to displace - the existing web as we know it now. But blockchains aren't a general purpose technology: they have very - limited and specific use-cases. And instead of decentralised currencies - being just the first use-case of many they might be one of only a few. Blockchains are best thought of as da",Hacker News,43789833,"Title: There aren't that many uses for blockchains; Content: - A criteria for judging when a - blockchain is applicable A common saying among those who are into their crypto is that ""the real - innovation isn't Bitcoin, but the "". Blockchains are - increasingly popular. At some point using a blockchain stopped being called - just 'blockchain technology' and started to be called . The implication being that - blockchains have such wide applicability that they will come to displace - the existing web as we know it now. But blockchains aren't a general purpose technology: they have very - limited and specific use-cases. And instead of decentralised currencies - being just the first use-case of many they might be one of only a few. Blockchains are best thought of as da",256 -thesecretceo,32419129,140,1660169952,Disney surpasses Netflix in global paid streaming subscribers,https://www.axios.com/2022/08/10/disney-surpasses-netflix-global-paid-subscribers,"Disney's stock spiked nearly 4% in after-hours trading Wednesday after the entertainment giant said it added 14.4 million Disney+ subscribers, blowing past Wall Street expectations. Disney now has more than 221 million total subscriptions across all of its subscription streaming offerings globally, , which reported 220.7 million global subscribers last quarter, after losing nearly 1 million subscribers compared to the previous quarter. The company also beat expectations for its revenues and profits, thanks to strong results in its theme parks division. Disney also announced a new pricing structure to support its new ad-supported tier, which is slated to debut in the U.S. on Dec. 8. : It's been a tumultuous year for streaming companies that are beginning to see slowed momentum coming",Hacker News,34958068,"Title: Disney surpasses Netflix in global paid streaming subscribers; Content: Disney's stock spiked nearly 4% in after-hours trading Wednesday after the entertainment giant said it added 14.4 million Disney+ subscribers, blowing past Wall Street expectations. Disney now has more than 221 million total subscriptions across all of its subscription streaming offerings globally, , which reported 220.7 million global subscribers last quarter, after losing nearly 1 million subscribers compared to the previous quarter. The company also beat expectations for its revenues and profits, thanks to strong results in its theme parks division. Disney also announced a new pricing structure to support its new ad-supported tier, which is slated to debut in the U.S. on Dec. 8. : It's been a tumultuous year for streaming companies that are beginning to see slowed momentum coming",168 -wishfish,32416424,494,1660156035,OnlyFans bribed Meta to put porn stars on terror watchlist: lawsuits,https://nypost.com/2022/08/09/onlyfans-bribed-meta-to-put-thousands-of-porn-stars-on-terror-watchlist-suits-claim/," - - - - - Thanks for contacting us. We've received your submission. OnlyFans squashed competitors in the online porn industry with the help of a bizarre scheme that bribed Meta employees to throw thousands of porn stars onto a terrorist watchlist, according to a group of explosive lawsuits.  Adult performers who sold X-rated photos and videos on rival sites saw their Instagram accounts falsely tagged as containing terrorist content — crippling their ability to promote their business and devastating their incomes, according to the suits. Sellers of smutty pictures were then “shadowbanned” across Instagram, Facebook, YouTube, Twitter and other sites, the suits allege. Targeted accounts also included businesses, celebrities, influencers and others who “have nothing to do with terrorism,”",Hacker News,28202288,"Title: OnlyFans bribed Meta to put porn stars on terror watchlist: lawsuits; Content: - - - - - Thanks for contacting us. We've received your submission. OnlyFans squashed competitors in the online porn industry with the help of a bizarre scheme that bribed Meta employees to throw thousands of porn stars onto a terrorist watchlist, according to a group of explosive lawsuits.  Adult performers who sold X-rated photos and videos on rival sites saw their Instagram accounts falsely tagged as containing terrorist content — crippling their ability to promote their business and devastating their incomes, according to the suits. Sellers of smutty pictures were then “shadowbanned” across Instagram, Facebook, YouTube, Twitter and other sites, the suits allege. Targeted accounts also included businesses, celebrities, influencers and others who “have nothing to do with terrorism,”",188 -pepys,32402373,134,1660071529,Archaeologists rebury ‘first-of-its-kind’ Roman villa,https://www.smithsonianmag.com/smart-news/archaeologists-rebury-first-of-its-kind-roman-villa-180980535/,"Sections The ruins were originally uncovered in Scarborough, England, last year - - - Molly Enking - - Ruins of a sprawling ancient Roman villa discovered in the United Kingdom have been reburied, just one year after their discovery was announced. , a government preservation organization, hopes the move will safeguard the “first-of-its-kind” archeological site for future generations, reports . The discovery last year delighted experts, who underscored its historical significance. “These archaeological remains are a fantastic find and are far more than we ever dreamed of discovering at this site,” said Keith Emerick, inspector of ancient monuments at Historic England, in a last year. “They are already giving us a better knowledge and understanding of ",Hacker News,58684685,"Title: Archaeologists rebury ‘first-of-its-kind’ Roman villa; Content: Sections The ruins were originally uncovered in Scarborough, England, last year - - - Molly Enking - - Ruins of a sprawling ancient Roman villa discovered in the United Kingdom have been reburied, just one year after their discovery was announced. , a government preservation organization, hopes the move will safeguard the “first-of-its-kind” archeological site for future generations, reports . The discovery last year delighted experts, who underscored its historical significance. “These archaeological remains are a fantastic find and are far more than we ever dreamed of discovering at this site,” said Keith Emerick, inspector of ancient monuments at Historic England, in a last year. “They are already giving us a better knowledge and understanding of ",220 -unripe_syntax,32394994,60,1660028468,Justin Kan: Web3 games don’t need to lure players with profit,https://techcrunch.com/2022/08/08/twitch-founder-justin-kan-on-crypto-web3-video-games-business-model-profit-play-to-earn/,,Hacker News,53080967,Title: Justin Kan: Web3 games don’t need to lure players with profit; Content: ,22 -b_mc2,32417410,57,1660160628,SQLite-HTTP: A SQLite extension for making HTTP requests,https://observablehq.com/@asg017/introducing-sqlite-http,,Hacker News,61413884,Title: SQLite-HTTP: A SQLite extension for making HTTP requests; Content: ,19 -valgaze,32414698,91,1660149133,Nip2: A spreadsheet-like GUI for the libvips image processing library,https://github.com/libvips/nip2," - A spreadsheet-like GUI for libvips. - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. nip2 is a GUI for the . It's a little like a spreadsheet: -you create a set of formula connecting your objects together, and on a change -nip2 recalculates. You can probably install nip2 via your package manager. For -Windows and OS X, you can download a binary from the . If you have to build from -source, see the section below. nip2 comes with a 50-page manual --- press F1 or Help / Contents in",Hacker News,1343390,"Title: Nip2: A spreadsheet-like GUI for the libvips image processing library; Content: - A spreadsheet-like GUI for libvips. - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. nip2 is a GUI for the . It's a little like a spreadsheet: -you create a set of formula connecting your objects together, and on a change -nip2 recalculates. You can probably install nip2 via your package manager. For -Windows and OS X, you can download a binary from the . If you have to build from -source, see the section below. nip2 comes with a 50-page manual --- press F1 or Help / Contents in",279 -whatisweb3,32423680,5,1660213220,Why US Tornado Cash Sanctions Are Concerning for Open Software,https://www.youtube.com/watch?v=XpTrCA3tEKM,,Hacker News,98265700,Title: Why US Tornado Cash Sanctions Are Concerning for Open Software; Content: ,18 -pvsukale3,32408716,237,1660115986,Faster Ruby: Thoughts from the outside,https://www.mgaudet.ca/technical/2022/8/9/faster-ruby-thoughts-from-the-outside,"Your Custom Text Here As someone who comes from a compiler background, when asked to make a language fast, I’m sympathetic to the reaction: “Just throw a compiler at it!”. However, working on SpiderMonkey, I’ve come to the conclusion that a fast language implementation has many moving parts, and a compiler is just one part of it. I’m going to get to Ruby, but before I get there, I want to take a tour briefly of some bits and pieces of SpiderMonkey that help make it a fast JavaScript engine; from that story, you may be able to intuit some of my suggestions for how Ruby ought to move forward! It’s taken me many years of working on SpiderMonkey to internalize some of the implications of various design choices, and how they drive good performance. For example, let’s discuss : In SpiderM",Hacker News,60354631,"Title: Faster Ruby: Thoughts from the outside; Content: Your Custom Text Here As someone who comes from a compiler background, when asked to make a language fast, I’m sympathetic to the reaction: “Just throw a compiler at it!”. However, working on SpiderMonkey, I’ve come to the conclusion that a fast language implementation has many moving parts, and a compiler is just one part of it. I’m going to get to Ruby, but before I get there, I want to take a tour briefly of some bits and pieces of SpiderMonkey that help make it a fast JavaScript engine; from that story, you may be able to intuit some of my suggestions for how Ruby ought to move forward! It’s taken me many years of working on SpiderMonkey to internalize some of the implications of various design choices, and how they drive good performance. For example, let’s discuss : In SpiderM",206 -apollinaire,32409928,11,1660127931,"Going, going... Goethe?",https://www.historytoday.com/archive/missing-pieces/going-goinggoethe,"The question of reconstruction was a thorny issue in postwar Germany, where celebrations of the ‘glorious’ past took on a different hue.  On the night of 22 March 1944 Frankfurt was hit by one of the largest air raids of the Second World War. Dodging German anti-aircraft defences, 816 British planes dropped more than 3,000 heavy explosive bombs and 1.2 million incendiary devices in less than an hour. The Old Town ( ) bore the brunt of it. Almost the entire quarter was destroyed. Churches were reduced to rubble and of 2,000 or so half-timbered buildings only one escaped unscathed.  Yet, of all the houses hit none so scarred the German consciousness as No. 23, Großer Hirschgraben. An elegant five-story building, it was an imposing, if otherwise unremarkable, structure – but for many Germans ",Hacker News,29708119,"Title: Going, going... Goethe?; Content: The question of reconstruction was a thorny issue in postwar Germany, where celebrations of the ‘glorious’ past took on a different hue.  On the night of 22 March 1944 Frankfurt was hit by one of the largest air raids of the Second World War. Dodging German anti-aircraft defences, 816 British planes dropped more than 3,000 heavy explosive bombs and 1.2 million incendiary devices in less than an hour. The Old Town ( ) bore the brunt of it. Almost the entire quarter was destroyed. Churches were reduced to rubble and of 2,000 or so half-timbered buildings only one escaped unscathed.  Yet, of all the houses hit none so scarred the German consciousness as No. 23, Großer Hirschgraben. An elegant five-story building, it was an imposing, if otherwise unremarkable, structure – but for many Germans ",196 -bryanrasmussen,32408393,206,1660112789,Essential Climbing Knots,https://www.climbing.com/skills/essential-climbing-knots-complete-guide/,"Get access to more than 30 brands, premium video, exclusive content, events, mapping, and more. Get access to more than 30 brands, premium video, exclusive content, events, mapping, and more. - Peace Out, Paywall - - Unlock world-class adventure journalism. - - Subscribe Now - - Create a personalized feed and bookmark your favorites. Already have an account? Create a personalized feed and bookmark your favorites. Already have an account? Using the Trace Eight to connect the rope to the climbing harness. - - Get full access to Outside Learn, our online education hub featuring in-depth fitness, nutrition, and adventure courses and more than 2,000 instructional videos when you sign up for Outside+ - . - ",Hacker News,95115152,"Title: Essential Climbing Knots; Content: Get access to more than 30 brands, premium video, exclusive content, events, mapping, and more. Get access to more than 30 brands, premium video, exclusive content, events, mapping, and more. - Peace Out, Paywall - - Unlock world-class adventure journalism. - - Subscribe Now - - Create a personalized feed and bookmark your favorites. Already have an account? Create a personalized feed and bookmark your favorites. Already have an account? Using the Trace Eight to connect the rope to the climbing harness. - - Get full access to Outside Learn, our online education hub featuring in-depth fitness, nutrition, and adventure courses and more than 2,000 instructional videos when you sign up for Outside+ - . - ",258 -JumpCrisscross,32419522,38,1660172468,Argentina on Two Steaks a Day,https://idlewords.com/2006/04/argentina_on_two_steaks_a_day.htm,"The classic beginner's mistake in Argentina is to neglect the first steak of the day. You will be tempted to just peck at it or even skip it altogether, rationalizing that you need to save yourself for the much larger steak later that night. But this is a false economy, like refusing to drink water in the early parts of a marathon. That first steak has to get you through the afternoon and half the night, until the restaurants begin to open at ten; the first steak is what primes your system to digest large quantities of animal protein, and it's the first steak that buffers the sudden sugar rush of your afternoon ice cream cone. The midnight second steak might be more the glamorous one, standing as it does a good three inches off the plate, but all it has to do is get you up and out o",Hacker News,93157125,"Title: Argentina on Two Steaks a Day; Content: The classic beginner's mistake in Argentina is to neglect the first steak of the day. You will be tempted to just peck at it or even skip it altogether, rationalizing that you need to save yourself for the much larger steak later that night. But this is a false economy, like refusing to drink water in the early parts of a marathon. That first steak has to get you through the afternoon and half the night, until the restaurants begin to open at ten; the first steak is what primes your system to digest large quantities of animal protein, and it's the first steak that buffers the sudden sugar rush of your afternoon ice cream cone. The midnight second steak might be more the glamorous one, standing as it does a good three inches off the plate, but all it has to do is get you up and out o",185 -notPlancha,32423274,4,1660209167,Senior developers create more senior developers,https://gomakethings.com/senior-developers-create-more-senior-developers/,"Last week, … Honestly, the only difference between a junior and senior developer is that you get better at identifying all the places where your code goes to shit. My friend Sarah Dayan (the brilliant dev behind ) . After climbing this ladder myself, having worked with many devs from intern to principal level, and contributed to the promotion process of multiple coworkers, I see many other areas that distinguish juniors from seniors. Spoiler alert: it’s a lot less technical than it seems. Her whole thread is worth a read. It’s really, good. The one part that stood out the most, though, was this… Seniors move teams forward by mentoring juniors. Instead of jumping onto the tasks they’ll be the best at, they’ll sponsor junior teammates through it. A senior’s top priority is to grow more ",Hacker News,92543289,"Title: Senior developers create more senior developers; Content: Last week, … Honestly, the only difference between a junior and senior developer is that you get better at identifying all the places where your code goes to shit. My friend Sarah Dayan (the brilliant dev behind ) . After climbing this ladder myself, having worked with many devs from intern to principal level, and contributed to the promotion process of multiple coworkers, I see many other areas that distinguish juniors from seniors. Spoiler alert: it’s a lot less technical than it seems. Her whole thread is worth a read. It’s really, good. The one part that stood out the most, though, was this… Seniors move teams forward by mentoring juniors. Instead of jumping onto the tasks they’ll be the best at, they’ll sponsor junior teammates through it. A senior’s top priority is to grow more ",192 -cebert,32410492,31,1660132894,AMD Threadripper Pro 5995WX and 5975WX Review,https://www.tomshardware.com/news/amd-threadripper-pro-5995wx-5975wx-cpu-review,"Tom's Hardware is supported by its audience. When you purchase through links on our site, we may earn an affiliate commission. . -By - -published - Threadripping with 64 Zen 3 cores. The new 64-core AMD Threadripper Pro 5995WX and 32-core Threadripper Pro 5975WX are finally available at retail, breaking free from the confines of pre-built OEM systems to contend for a spot on our list of . They have a tough act to follow: AMD's previous-gen Threadripper CPUs delivered a crushing blow to the entrenched Intel's HEDT workstation lineup, with the consumer models essentially market entirely while the Pro models relegated Intel to an . - -But there's a problem for enthusiasts — Intel abandoned the consumer-oriented high end desktop (HEDT) market after its crushing defeat , and now that AM",Hacker News,49050085,"Title: AMD Threadripper Pro 5995WX and 5975WX Review; Content: Tom's Hardware is supported by its audience. When you purchase through links on our site, we may earn an affiliate commission. . -By - -published - Threadripping with 64 Zen 3 cores. The new 64-core AMD Threadripper Pro 5995WX and 32-core Threadripper Pro 5975WX are finally available at retail, breaking free from the confines of pre-built OEM systems to contend for a spot on our list of . They have a tough act to follow: AMD's previous-gen Threadripper CPUs delivered a crushing blow to the entrenched Intel's HEDT workstation lineup, with the consumer models essentially market entirely while the Pro models relegated Intel to an . - -But there's a problem for enthusiasts — Intel abandoned the consumer-oriented high end desktop (HEDT) market after its crushing defeat , and now that AM",211 -kuba_dmp,32412036,124,1660139920,How to market to developers on Twitter: Learnings from 4 months of Supabase feed,https://www.developermarkepear.com/blog/developer-marketing-on-social-media-twitter-supabase,"Hey, I'm Kuba. Every month I share: - 10 dev marketing nuggets - 1 fact about pears Table of contents For months I couldn’t find a single account of a developer-focused company that did . And then I saw mention . Checked it out and they are crushing it. 28k+ followers and tweets getting 400+ likes and 100+ comments every week like it’s nothing. In 2 years. Nice. Just so you understand, most of the billion-dollar dev-focused companies are getting 10 likes and 2 retweets on Twitter. So the Supabase team is doing something really well. I wanted to know what it is. Took a weekend to go over the last 4 months (Jan-April 2022) of their Twitter feed to extract some learnings that you and I could use to get our company Twitter account some results. Here is what I learned: Ok, let’s div",Hacker News,93268362,"Title: How to market to developers on Twitter: Learnings from 4 months of Supabase feed; Content: Hey, I'm Kuba. Every month I share: - 10 dev marketing nuggets - 1 fact about pears Table of contents For months I couldn’t find a single account of a developer-focused company that did . And then I saw mention . Checked it out and they are crushing it. 28k+ followers and tweets getting 400+ likes and 100+ comments every week like it’s nothing. In 2 years. Nice. Just so you understand, most of the billion-dollar dev-focused companies are getting 10 likes and 2 retweets on Twitter. So the Supabase team is doing something really well. I wanted to know what it is. Took a weekend to go over the last 4 months (Jan-April 2022) of their Twitter feed to extract some learnings that you and I could use to get our company Twitter account some results. Here is what I learned: Ok, let’s div",231 -voxadam,32421755,5,1660193971,"Ofrak: Unpack, Modify, and Repack Binaries",https://ofrak.com/," - By continuing to use this site, you agree to the use of cookies. - . - ofrak - OFRAK is a binary analysis and modification platform that combines - the ability to unpack, analyze, modify, and repack binaries. - Explore in the GUI, then automate with the API. - OFRAK (Open Firmware Reverse Analysis Konsole) supports a wide - variety of binaries, including: userspace executables, embedded - filesystems, compressed and checksummed firmware, bootloaders, - RTOS/OS kernels, and everything in between. - - With OFRAK, you can automatically recognize and unpack an ELF - buried within an XZ-compressed CPIO filesystem inside of an ISO, - modi",Hacker News,65190380,"Title: Ofrak: Unpack, Modify, and Repack Binaries; Content: - By continuing to use this site, you agree to the use of cookies. - . - ofrak - OFRAK is a binary analysis and modification platform that combines - the ability to unpack, analyze, modify, and repack binaries. - Explore in the GUI, then automate with the API. - OFRAK (Open Firmware Reverse Analysis Konsole) supports a wide - variety of binaries, including: userspace executables, embedded - filesystems, compressed and checksummed firmware, bootloaders, - RTOS/OS kernels, and everything in between. - - With OFRAK, you can automatically recognize and unpack an ELF - buried within an XZ-compressed CPIO filesystem inside of an ISO, - modi",346 -danielskogly,32401159,432,1660066902,"Astro 1.0 – a web framework for building fast, content-focused websites",https://astro.build/blog/astro-1/," - - - - Over the last 16 months, has grown from an empty repo to over 13,000 stars on and 30,000 early users around the world. The Astro documentation has been translated into 6 different languages, and Astro has already been deployed at amazing companies such as , , , and . Astro v1.0 includes a few new features and improvements since our original beta announcement back in April, including: This v1.0 release symbolizes our commitment to API stability and production-readiness going forward. If you have been waiting to give Astro a try, now is a great time to start. You can also deploy an Astro v1.0 starter template to the web using the Netlify deploy button below. Don’t have an account? Don’t worry: Netlify is free to use for basic sites. If you need help migrating an existing As",Hacker News,33163494,"Title: Astro 1.0 – a web framework for building fast, content-focused websites; Content: - - - - Over the last 16 months, has grown from an empty repo to over 13,000 stars on and 30,000 early users around the world. The Astro documentation has been translated into 6 different languages, and Astro has already been deployed at amazing companies such as , , , and . Astro v1.0 includes a few new features and improvements since our original beta announcement back in April, including: This v1.0 release symbolizes our commitment to API stability and production-readiness going forward. If you have been waiting to give Astro a try, now is a great time to start. You can also deploy an Astro v1.0 starter template to the web using the Netlify deploy button below. Don’t have an account? Don’t worry: Netlify is free to use for basic sites. If you need help migrating an existing As",215 -digital55,32414684,68,1660149104,Mathematicians crack a simple but stubborn class of equations,https://www.quantamagazine.org/ancient-equations-offer-new-look-at-number-groups-20220810/,"How often are there integer solutions for equations of the form – = –1? Donghyun Lim for Quanta Magazine In the third century BCE, Archimedes a riddle about herding cattle that, he claimed, only a truly wise person could solve. His problem ultimately boiled down to an equation that involves the difference between two squared terms, which can be written as – = 1. Here, is an integer — a positive or negative counting number — and Archimedes was looking for solutions where both and are integers as well. This class of equations, called the Pell equations, has fascinated mathematicians over the millennia since. Some centuries after Archimedes, the Indian mathematician Brahmagupta, and later the mathematician Bhāskara II, provided algorithms to find integer solutions to these equ",Hacker News,60310261,"Title: Mathematicians crack a simple but stubborn class of equations; Content: How often are there integer solutions for equations of the form – = –1? Donghyun Lim for Quanta Magazine In the third century BCE, Archimedes a riddle about herding cattle that, he claimed, only a truly wise person could solve. His problem ultimately boiled down to an equation that involves the difference between two squared terms, which can be written as – = 1. Here, is an integer — a positive or negative counting number — and Archimedes was looking for solutions where both and are integers as well. This class of equations, called the Pell equations, has fascinated mathematicians over the millennia since. Some centuries after Archimedes, the Indian mathematician Brahmagupta, and later the mathematician Bhāskara II, provided algorithms to find integer solutions to these equ",194 -ScottStevenson,32378695,439,1659897949,Ask HN: What's the next big thing that few people are talking about?,,"Blockchain & AI don't count, because they're being talked about plenty!",Hacker News,93151771,"Title: Ask HN: What's the next big thing that few people are talking about?; Content: Blockchain & AI don't count, because they're being talked about plenty!",49 -RickJWagner,32420423,6,1660180133,"Rare, original print of the US Constitution going to Arkansas",https://crystalbridges.org/calendar/we-the-people/,"A world-class collection of American art, stunning architecture, and 120 acres of Ozark forest with five miles of trails. Admission to the museum is always free. Planning a visit to Crystal Bridges this spring? to learn what’s on and what to expect this season. Crystal Bridges will be closed on Thursday, November 25 for Thanksgiving. We have something for all types of learners. From educator resources to family activities to scholars, find what speaks to you and engage with us. Coming soon to a library near you, brings artmaking, music, storytelling, and more. Find opportunities to give and keep art accessible to all, become a member, or join our team. receive year-round perks, invitations to member-only events, travel opportunities, and more!",Hacker News,25167519,"Title: Rare, original print of the US Constitution going to Arkansas; Content: A world-class collection of American art, stunning architecture, and 120 acres of Ozark forest with five miles of trails. Admission to the museum is always free. Planning a visit to Crystal Bridges this spring? to learn what’s on and what to expect this season. Crystal Bridges will be closed on Thursday, November 25 for Thanksgiving. We have something for all types of learners. From educator resources to family activities to scholars, find what speaks to you and engage with us. Coming soon to a library near you, brings artmaking, music, storytelling, and more. Find opportunities to give and keep art accessible to all, become a member, or join our team. receive year-round perks, invitations to member-only events, travel opportunities, and more!",190 -treyfitty,32411586,207,1660138265,"Ask HN: Exercises to think, then speak, more clearly?",,"I read a quote along the lines of "Next to height, the most unfair advantage someone can have is the ability to walk into a room without preparation and persuade the audience on just about any subject."

At face value, this sounds preposterous but there's merit to what the author is saying. Upon reflection, I've realized that this superpower is a lot harder than it seems and it requires:

- Ability to think clearly -- Ability to encode into brain what you want to say -- Deliver message

I'm finding it difficult to perform the first 2 steps. Has anyone found great resources and exercises to help with this?",Hacker News,48388443,"Title: Ask HN: Exercises to think, then speak, more clearly?; Content: I read a quote along the lines of "Next to height, the most unfair advantage someone can have is the ability to walk into a room without preparation and persuade the audience on just about any subject."

At face value, this sounds preposterous but there's merit to what the author is saying. Upon reflection, I've realized that this superpower is a lot harder than it seems and it requires:

- Ability to think clearly -- Ability to encode into brain what you want to say -- Deliver message

I'm finding it difficult to perform the first 2 steps. Has anyone found great resources and exercises to help with this?",182 -romeros,32419182,26,1660170262,Ask HN: Folks who were around the 2008 Recession,,How does the current recession feel like to you compared to 2008?

Do you feel this is the beginning of the recession or are we in the middle/end of it?,Hacker News,5132150,Title: Ask HN: Folks who were around the 2008 Recession; Content: How does the current recession feel like to you compared to 2008?

Do you feel this is the beginning of the recession or are we in the middle/end of it?,59 -lproven,32411153,84,1660136318,The many derivatives of CP/M,https://www.theregister.com/2022/08/04/the_many_derivatives_of_cpm/,,Hacker News,3596823,Title: The many derivatives of CP/M; Content: ,13 -rd07,32421092,12,1660187169,Ask HN: Google Maps alternatives that uses OSM and has a review feature,,"Several months ago, there is a similar question here https://news.ycombinator.com/item?id=29774603. But, what I am looking for is a Google Maps alternative that :

- is based on OSM

- has a review feature like Google Maps

- is not tied to a company

- is open source (optional)",Hacker News,57935331,"Title: Ask HN: Google Maps alternatives that uses OSM and has a review feature; Content: Several months ago, there is a similar question here https://news.ycombinator.com/item?id=29774603. But, what I am looking for is a Google Maps alternative that :

- is based on OSM

- has a review feature like Google Maps

- is not tied to a company

- is open source (optional)",122 -omn1,32398391,402,1660054961,"From novice to master, and back again (2013)",https://blog.djmnet.org/2013/01/14/from-novice-to-master-and-back-again/,"In 1985, I was a freshman at St. Olaf College in Minnesota. The college had a VAX 11/780 running 4.2BSD and a PDP-11/70 running v7 with some Berkeley and local code hacked in. It was my first experience with multi-user systems other than dialing into an MS-DOS BBS or two. The college’s Academic Computing Center had printouts of the 4.2BSD manuals, plus some home-grown documentation, available for sale so students could learn how to use UNIX. One week I sat in the Science Center terminal room and started going through the alphabetical list of the commands available on the VAX, trying each one and reading its man page to learn what it did. Eventually I got to “su”. “Become the super-user”? What’s that? Does it involve wearing a cape? Sounds interesting, so I tried it. To my disappointment, i",Hacker News,5361150,"Title: From novice to master, and back again (2013); Content: In 1985, I was a freshman at St. Olaf College in Minnesota. The college had a VAX 11/780 running 4.2BSD and a PDP-11/70 running v7 with some Berkeley and local code hacked in. It was my first experience with multi-user systems other than dialing into an MS-DOS BBS or two. The college’s Academic Computing Center had printouts of the 4.2BSD manuals, plus some home-grown documentation, available for sale so students could learn how to use UNIX. One week I sat in the Science Center terminal room and started going through the alphabetical list of the commands available on the VAX, trying each one and reading its man page to learn what it did. Eventually I got to “su”. “Become the super-user”? What’s that? Does it involve wearing a cape? Sounds interesting, so I tried it. To my disappointment, i",216 -zdw,32394195,205,1660019777,Area 5150: 8088 MPH gets a successor,https://scalibq.wordpress.com/2022/08/08/area-5150-8088-mph-gets-a-successor/,"In case you have missed it, over the weekend, a new demo for IBM PC with CGA was released at Evoke, under the name . It placed first in the competition, which should not surprise anyone: I was wondering if I should comment on this demo, as I’m reasonably familiar with the man behind the curtain. I suppose the creators will write blogposts about the various parts, and give some insight into how it works, so I suggest you just wait for those. I am not one of the creators. I was also wondering if I should comment on that. Perhaps at a later time. I suppose what I can say about this is that during development of , we chose to make a demo that runs entirely on a composite monitor, as the ‘party trick’ was the 1024 colour mode, and it wouldn’t make sense to have to watch part of a demo on one ",Hacker News,71484372,"Title: Area 5150: 8088 MPH gets a successor; Content: In case you have missed it, over the weekend, a new demo for IBM PC with CGA was released at Evoke, under the name . It placed first in the competition, which should not surprise anyone: I was wondering if I should comment on this demo, as I’m reasonably familiar with the man behind the curtain. I suppose the creators will write blogposts about the various parts, and give some insight into how it works, so I suggest you just wait for those. I am not one of the creators. I was also wondering if I should comment on that. Perhaps at a later time. I suppose what I can say about this is that during development of , we chose to make a demo that runs entirely on a composite monitor, as the ‘party trick’ was the 1024 colour mode, and it wouldn’t make sense to have to watch part of a demo on one ",202 -oscarwao,32409811,326,1660126720,Why aren't smart people happier?,https://experimentalhistory.substack.com/p/why-arent-smart-people-happier,"Intelligence is a very general mental capability that, among other things, involves the ability to reason, plan, solve problems, think abstractly, comprehend complex ideas, learn quickly and learn from experience. It is not merely book learning, a narrow academic skill, or test-taking smarts. Rather, it reflects a broader and deeper capability for comprehending our surroundings-“catching on,” “making sense” of things, or “figuring out” what to do […] Intelligence, so defined, can be measured, and intelligence tests measure it well. Intelligence sounds pretty great. Who doesn’t want to “catch on” and “make sense”? Hell, “figuring out” what to do is pretty much all of life! Naturally, people with more of this mental horsepower must live happier lives. When they encounter a problem, they shou",Hacker News,24319684,"Title: Why aren't smart people happier?; Content: Intelligence is a very general mental capability that, among other things, involves the ability to reason, plan, solve problems, think abstractly, comprehend complex ideas, learn quickly and learn from experience. It is not merely book learning, a narrow academic skill, or test-taking smarts. Rather, it reflects a broader and deeper capability for comprehending our surroundings-“catching on,” “making sense” of things, or “figuring out” what to do […] Intelligence, so defined, can be measured, and intelligence tests measure it well. Intelligence sounds pretty great. Who doesn’t want to “catch on” and “make sense”? Hell, “figuring out” what to do is pretty much all of life! Naturally, people with more of this mental horsepower must live happier lives. When they encounter a problem, they shou",200 -pablohoffman,32409632,280,1660124770,Ask HN: What are the best tools for web scraping in 2022?,,"Last time this question was asked on HN was in 2017 (https://news.ycombinator.com/item?id=15694118), a lot has changed in the last 5 years in the world of web scraping (legal landscape, antibot unblockers, data type specific APIs, etc), so I thought it may be a good idea to refresh this question and see what are the most popular tools used by the HN community these days.",Hacker News,8662874,"Title: Ask HN: What are the best tools for web scraping in 2022?; Content: Last time this question was asked on HN was in 2017 (https://news.ycombinator.com/item?id=15694118), a lot has changed in the last 5 years in the world of web scraping (legal landscape, antibot unblockers, data type specific APIs, etc), so I thought it may be a good idea to refresh this question and see what are the most popular tools used by the HN community these days.",179 -obert,32420165,30,1660177771,Microsoft lays off team focused on winning back consumers,https://www.theverge.com/2022/8/10/23299499/microsoft-layoffs-modern-life-win-back-consumers-team,"We use cookies and other tracking technologies to improve your browsing experience on our site, show personalized content and targeted ads, analyze site traffic, and understand where our audiences come from. To learn more or opt-out, read our . Please also read our and , which became effective December 20, 2019. By choosing , you consent to our use of cookies and other tracking technologies. Filed under: Around 200 employees affected Microsoft is reportedly laying off its team focused on winning back consumers. In 2018 the software giant originally to win back the non-enterprise customers it let down, forming a Modern Life Experiences team to focus on professional consumers (prosumers). that Microsoft is laying off that team, and telling the roughly 200 affected employees to find ",Hacker News,39791105,"Title: Microsoft lays off team focused on winning back consumers; Content: We use cookies and other tracking technologies to improve your browsing experience on our site, show personalized content and targeted ads, analyze site traffic, and understand where our audiences come from. To learn more or opt-out, read our . Please also read our and , which became effective December 20, 2019. By choosing , you consent to our use of cookies and other tracking technologies. Filed under: Around 200 employees affected Microsoft is reportedly laying off its team focused on winning back consumers. In 2018 the software giant originally to win back the non-enterprise customers it let down, forming a Modern Life Experiences team to focus on professional consumers (prosumers). that Microsoft is laying off that team, and telling the roughly 200 affected employees to find ",173 -ZacnyLos,32416003,140,1660154243,Why does anything exist?,https://alwaysasking.com/why-does-anything-exist/,"Asking Big Questions Why does anything exist? Why is there something rather than nothing? Wouldn’t nothing have been so much easier? This question has awed and mystified people throughout time. The first question which we have a right to ask will be, “Why is there something rather than nothing?” Not the world is, is the mystical, but it is. No question is more sublime than why there is a Universe: why there is something rather than nothing. called this the “fundamental question of .” But it might as well be the fundamental question for any being — our existence poses a mystery that demands an answer. Every society in every time has wrestled with this dilemma. It’s our most enduring question. For we all seek to know: Lacking an answer, we are like a ship adrift. Our ignorance on th",Hacker News,54947068,"Title: Why does anything exist?; Content: Asking Big Questions Why does anything exist? Why is there something rather than nothing? Wouldn’t nothing have been so much easier? This question has awed and mystified people throughout time. The first question which we have a right to ask will be, “Why is there something rather than nothing?” Not the world is, is the mystical, but it is. No question is more sublime than why there is a Universe: why there is something rather than nothing. called this the “fundamental question of .” But it might as well be the fundamental question for any being — our existence poses a mystery that demands an answer. Every society in every time has wrestled with this dilemma. It’s our most enduring question. For we all seek to know: Lacking an answer, we are like a ship adrift. Our ignorance on th",197 -hrowtawaya,32417815,35,1660162622,Ask HN: How to build relationships in an internationally remote org?,,"I started a new job as a Software Engineering Manager at a remote startup ~6 months ago. My direct reports, peers, and manager are globally distributed and I am really struggling (perhaps failing) to develop strong relationships with anyone in the organization.

I've never had trouble establishing relationships in the past and have always had a few "allies" up and down the org by this point. Based on feedback in all-hands, etc. I don't think that my situation is unique in the org.

While this is disconcerting to me on its own, the part I struggle with the most is that I don't have anyone I feel comfortable talking to about the daily challenges that my team and I face.

I can lean on my extended network to a point, but what I would really like is a dedicator mentor that I could discuss specific problems with, above and beyond what I could reasonably ask of a friend. Has anyone had success establishing this type of relationship? If so, how? Alternatively, is anyone else facing this type of problem in a globally distributed company? How are you managing it?",Hacker News,56014192,"Title: Ask HN: How to build relationships in an internationally remote org?; Content: I started a new job as a Software Engineering Manager at a remote startup ~6 months ago. My direct reports, peers, and manager are globally distributed and I am really struggling (perhaps failing) to develop strong relationships with anyone in the organization.

I've never had trouble establishing relationships in the past and have always had a few "allies" up and down the org by this point. Based on feedback in all-hands, etc. I don't think that my situation is unique in the org.

While this is disconcerting to me on its own, the part I struggle with the most is that I don't have anyone I feel comfortable talking to about the daily challenges that my team and I face.

I can lean on my extended network to a point, but what I would really like is a dedicator mentor that I could discuss specific problems with, above and beyond what I could reasonably ask of a friend. Has anyone had success establishing this type of relationship? If so, how? Alternatively, is anyone else facing this type of problem in a globally distributed company? How are you managing it?",268 -ksec,32414835,81,1660149590,Oscar winning PARASITE was edited with a 10 year old copy of Final Cut Pro 7,https://twitter.com/noamkroll/status/1556755415353925642,"We’ve detected that JavaScript is disabled in this browser. Please enable JavaScript or switch to a supported browser to continue using twitter.com. You can see a list of supported browsers in our Help Center. - - - - - - © 2022 Twitter, Inc. - ",Hacker News,88851153,"Title: Oscar winning PARASITE was edited with a 10 year old copy of Final Cut Pro 7; Content: We’ve detected that JavaScript is disabled in this browser. Please enable JavaScript or switch to a supported browser to continue using twitter.com. You can see a list of supported browsers in our Help Center. - - - - - - © 2022 Twitter, Inc. - ",93 -Tomte,32409329,7,1660121182,"Creating the Catalog, Before and After FRBR (2017)",http://kcoyle.net/mexico.html,"by Karen Coyle Talk given at ; Universidad Nacional autonoma de Mexico; September 12, 2017 This work is licensed under a . - (Feel free to re-use, translate, transform, but please given credit to the source, this document.) There is a great deal of talk today about the future of the library catalog. -There is also ongoing work on developing a ""next generation"" library bibliographic data format, -possibly based on the model presented by the IFLA study group on the Functional Requirements for Bibliographic Records.  -There is a tendency, however, to treat the current state of data and catalogs as a starting point. -The historical context is, however, much richer. The history that we need to confront is long and complex. -In terms of technology, you can date library catalogs back to the tim",Hacker News,69966266,"Title: Creating the Catalog, Before and After FRBR (2017); Content: by Karen Coyle Talk given at ; Universidad Nacional autonoma de Mexico; September 12, 2017 This work is licensed under a . - (Feel free to re-use, translate, transform, but please given credit to the source, this document.) There is a great deal of talk today about the future of the library catalog. -There is also ongoing work on developing a ""next generation"" library bibliographic data format, -possibly based on the model presented by the IFLA study group on the Functional Requirements for Bibliographic Records.  -There is a tendency, however, to treat the current state of data and catalogs as a starting point. -The historical context is, however, much richer. The history that we need to confront is long and complex. -In terms of technology, you can date library catalogs back to the tim",201 -atan2,32407430,136,1660100314,A History of Lua (2001),https://www.lua.org/history.html," -by -Roberto Ierusalimschy, -Luiz Henrique de Figueiredo, -Waldemar Celes - - - - -There is an old joke that says that -""a camel is a horse designed by a committee"". -Among programming-language people, -this joke is almost as popular -as the legend about programming languages designed by committees. -This legend is supported by languages like Algol 68, PL/I, and Ada, -all designed by committees, -which did not fulfill the expectations of their sponsors. - -However, apart from committees, -there is an alternative theory for the -partial failure of those languages: -All of them were born to be big. -Each of them followed a top-down design process, -where the language was fully specified before any -programmer could try it, -even before any compiler was built. - -Most successful languages, on the other hand, -are ",Hacker News,21592566,"Title: A History of Lua (2001); Content: -by -Roberto Ierusalimschy, -Luiz Henrique de Figueiredo, -Waldemar Celes - - - - -There is an old joke that says that -""a camel is a horse designed by a committee"". -Among programming-language people, -this joke is almost as popular -as the legend about programming languages designed by committees. -This legend is supported by languages like Algol 68, PL/I, and Ada, -all designed by committees, -which did not fulfill the expectations of their sponsors. - -However, apart from committees, -there is an alternative theory for the -partial failure of those languages: -All of them were born to be big. -Each of them followed a top-down design process, -where the language was fully specified before any -programmer could try it, -even before any compiler was built. - -Most successful languages, on the other hand, -are ",215 -tmabraham,32414811,142,1660149521,Stable Diffusion launch announcement,https://stability.ai/blog/stable-diffusion-announcement,"User generated image from Stable Diffusion Beta Stability AI and our collaborators are proud to announce the first stage of release of Stable Diffusion to researchers via , the model weights are hosted by our friends at Hugging Face once you get access. and the . We are working together towards a public release soon.  This has been led by Patrick Esser from and Robin Rombach from the lab at Heidelberg University (now the ), combined with support from communities at , and our own generative AI team. Stable Diffusion is a text-to-image model that will empower billions of people to create stunning art within seconds. It is a breakthrough in speed and quality meaning that it can run on consumer GPUs. You can see some of the amazing output that has been created by this model without",Hacker News,42961255,"Title: Stable Diffusion launch announcement; Content: User generated image from Stable Diffusion Beta Stability AI and our collaborators are proud to announce the first stage of release of Stable Diffusion to researchers via , the model weights are hosted by our friends at Hugging Face once you get access. and the . We are working together towards a public release soon.  This has been led by Patrick Esser from and Robin Rombach from the lab at Heidelberg University (now the ), combined with support from communities at , and our own generative AI team. Stable Diffusion is a text-to-image model that will empower billions of people to create stunning art within seconds. It is a breakthrough in speed and quality meaning that it can run on consumer GPUs. You can see some of the amazing output that has been created by this model without",185 -alphabetting,32410610,102,1660133538,"Google Fiber plans 5-state growth spurt, biggest since 2015",https://www.reuters.com/business/media-telecom/exclusive-google-fiber-plans-5-state-growth-spurt-biggest-since-2015-2022-08-10/,"The roof of a Google fiber installation truck is pictured Salt Lake City, Utah, U.S., September 28, 2017. REUTERS/Mike Blake Aug 10 (Reuters) - Google Fiber plans to bring its high-speed internet service to multiple cities in Arizona, Colorado, Idaho, Nebraska and Nevada over the next several years in its first big expansion since it spun out as an independent Alphabet Inc unit in 2015. In his first media interview since becoming chief executive of Google Fiber in February 2018, Dinni Jain told Reuters on Wednesday that his team was finally prepared to ""add a little bit more build velocity"" after over four years of sharpening operations. The anticipated expansion to 22 metro areas across the United States from 17 today includes previously announced projects to launch in Mesa, Arizo",Hacker News,88083821,"Title: Google Fiber plans 5-state growth spurt, biggest since 2015; Content: The roof of a Google fiber installation truck is pictured Salt Lake City, Utah, U.S., September 28, 2017. REUTERS/Mike Blake Aug 10 (Reuters) - Google Fiber plans to bring its high-speed internet service to multiple cities in Arizona, Colorado, Idaho, Nebraska and Nevada over the next several years in its first big expansion since it spun out as an independent Alphabet Inc unit in 2015. In his first media interview since becoming chief executive of Google Fiber in February 2018, Dinni Jain told Reuters on Wednesday that his team was finally prepared to ""add a little bit more build velocity"" after over four years of sharpening operations. The anticipated expansion to 22 metro areas across the United States from 17 today includes previously announced projects to launch in Mesa, Arizo",183 -Hard_Space,32384653,850,1659961565,"To uncover a deepfake video call, ask the caller to turn sideways",https://metaphysic.ai/to-uncover-a-deepfake-video-call-ask-the-caller-to-turn-sideways/,"There is an interesting vulnerability in video deepfakes that, to date, has been generally overlooked by the security research community, perhaps because ‘live’, real-time deepfakes in video calls have not been a major cause for concern until very recently. For a number of reasons, which we’ll examine in this article, deepfakes are not usually very good at recreating profile views: The above examples are taken* from a session with tech exponent and commenter , who agreed to run some tests with us, using to change his appearance to that of a series of popular celebrities. DeepFaceLive is a live-streaming version of the popular software, and is capable of creating alternate video identities in real-time. From more or less face-on viewpoints, most of the celebrity recreations are quite e",Hacker News,93214886,"Title: To uncover a deepfake video call, ask the caller to turn sideways; Content: There is an interesting vulnerability in video deepfakes that, to date, has been generally overlooked by the security research community, perhaps because ‘live’, real-time deepfakes in video calls have not been a major cause for concern until very recently. For a number of reasons, which we’ll examine in this article, deepfakes are not usually very good at recreating profile views: The above examples are taken* from a session with tech exponent and commenter , who agreed to run some tests with us, using to change his appearance to that of a series of popular celebrities. DeepFaceLive is a live-streaming version of the popular software, and is capable of creating alternate video identities in real-time. From more or less face-on viewpoints, most of the celebrity recreations are quite e",192 -dsmmcken,32390526,656,1659990080,I replaced all our blog thumbnails using DALL·E 2,https://deephaven.io/blog/2022/08/08/AI-generated-blog-thumbnails/,"Blog posts with images get more engagement. Here’s the problem - we make a . How the heck are you supposed to pick images for technical topics like , , , , or using ? As a small team of mostly engineers, we don’t have the time or budget to commission custom artwork for every one of our blog posts. Our approach so far has been to spend 10 minutes scrolling through tangentially related but ultimately ill-fitting images from stock photo sites, download something not terrible, slap it in the front matter and hit publish. Can AI generated images from DALL-E make better blog thumbnails, do it cheaper, and generally just be more fun? Yes, quant fans, it can. I spent the weekend and $45 in OpenAi credits generating new thumbnails that better represent the content of all 100+ posts from",Hacker News,1612742,"Title: I replaced all our blog thumbnails using DALL·E 2; Content: Blog posts with images get more engagement. Here’s the problem - we make a . How the heck are you supposed to pick images for technical topics like , , , , or using ? As a small team of mostly engineers, we don’t have the time or budget to commission custom artwork for every one of our blog posts. Our approach so far has been to spend 10 minutes scrolling through tangentially related but ultimately ill-fitting images from stock photo sites, download something not terrible, slap it in the front matter and hit publish. Can AI generated images from DALL-E make better blog thumbnails, do it cheaper, and generally just be more fun? Yes, quant fans, it can. I spent the weekend and $45 in OpenAi credits generating new thumbnails that better represent the content of all 100+ posts from",203 -Phileosopher,32421659,39,1660192873,Ask HN: How do you keep marching?,,"I'm working on a huge hobby project, and it's getting discouraging because the results are taking longer than I expected.

When you have a vision, how do you work toward it for long spurts? Or is it more of a "micro-visions" approach? Not sure if I'm asking the right questions, so feel free to reframe them if I'm not being clear enough.",Hacker News,64940530,"Title: Ask HN: How do you keep marching?; Content: I'm working on a huge hobby project, and it's getting discouraging because the results are taking longer than I expected.

When you have a vision, how do you work toward it for long spurts? Or is it more of a "micro-visions" approach? Not sure if I'm asking the right questions, so feel free to reframe them if I'm not being clear enough.",123 -memorable,32395518,367,1660034223,"Thank You, Firebug (2017)",https://getfirebug.com/,"The story of Firefox and Firebug are synonymous with the rise of the web. - We fought the good fight and changed how developers inspect HTML and debug - JS in the browser. Firebug ushered the Web 2.0 era. Today, the work pioneered - by the Firebug community through the last 12 years lives on - in Firefox Developer Tools. Switch to the latest version of Firefox - and see the very latest devtools updates. - There are too many contributors to count but here are the names that come - to mind. Thank you for you work and passion for Firebug. It was not possible - without you. Try the new Firefox Quantum developer tools in Developer Edition or update - to the latest release version. Inside you will find the latest tools like - ",Hacker News,62611921,"Title: Thank You, Firebug (2017); Content: The story of Firefox and Firebug are synonymous with the rise of the web. - We fought the good fight and changed how developers inspect HTML and debug - JS in the browser. Firebug ushered the Web 2.0 era. Today, the work pioneered - by the Firebug community through the last 12 years lives on - in Firefox Developer Tools. Switch to the latest version of Firefox - and see the very latest devtools updates. - There are too many contributors to count but here are the names that come - to mind. Thank you for you work and passion for Firebug. It was not possible - without you. Try the new Firefox Quantum developer tools in Developer Edition or update - to the latest release version. Inside you will find the latest tools like - ",246 -xgdgsc,32407451,122,1660100612,JNumPy: Writing high-performance C extensions for Python in minutes,https://github.com/Suzhou-Tongyuan/jnumpy," - Writing Python C extensions in Julia within 5 minutes. - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. Requirements: You can install the Python package with the following command: . Note that JNumPy will install julia in for you, if there is no Julia installation available. create a Python package , write and export julia functions in the file create as follows: initialize and import the julia functions at : enjoy your Python extension package: This is the structure ",Hacker News,58002347,"Title: JNumPy: Writing high-performance C extensions for Python in minutes; Content: - Writing Python C extensions in Julia within 5 minutes. - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. Requirements: You can install the Python package with the following command: . Note that JNumPy will install julia in for you, if there is no Julia installation available. create a Python package , write and export julia functions in the file create as follows: initialize and import the julia functions at : enjoy your Python extension package: This is the structure ",255 -pantalaimon,32396638,184,1660046176,Nvidia publishes 73k lines of 3D header files for Fermi through Ampere GPUs,https://www.phoronix.com/news/NVIDIA-3D-Headers-Fermi-Ampere,"Michael Larabel is the principal author of Phoronix.com and founded the site in 2004 with a focus on enriching the Linux hardware experience. Michael has written more than 20,000 articles covering the state of Linux hardware support, Linux performance, graphics drivers, and other topics. Michael is also the lead developer of the Phoronix Test Suite, Phoromatic, and OpenBenchmarking.org automated benchmarking software. He can be followed via , , or contacted via . allows ad-free access to the site, multi-page articles on a single page, and other features while supporting this site's continued operations. The mission at Phoronix since 2004 has centered around enriching the Linux hardware experience. In addition to supporting our site through advertisements, you can help by . You can als",Hacker News,40981807,"Title: Nvidia publishes 73k lines of 3D header files for Fermi through Ampere GPUs; Content: Michael Larabel is the principal author of Phoronix.com and founded the site in 2004 with a focus on enriching the Linux hardware experience. Michael has written more than 20,000 articles covering the state of Linux hardware support, Linux performance, graphics drivers, and other topics. Michael is also the lead developer of the Phoronix Test Suite, Phoromatic, and OpenBenchmarking.org automated benchmarking software. He can be followed via , , or contacted via . allows ad-free access to the site, multi-page articles on a single page, and other features while supporting this site's continued operations. The mission at Phoronix since 2004 has centered around enriching the Linux hardware experience. In addition to supporting our site through advertisements, you can help by . You can als",195 -fabiendevos,32388410,171,1659979549,Launch HN: Wolfia (YC S22) – A mobile app emulator you can share with a link,,"Hi HN! We’re Fabien and Naren, co-founders of Wolfia (https://www.wolfia.com). Wolfia lets you share a link to a mobile emulator running your app. Developers can get feedback instantly on a feature they just built by sharing a link to an interactive version of their app. We’re starting with Android but iOS is coming soon!

Mobile app development in 2022 is harder than it should be - you can't easily change a line of code, rebuild the app, and have someone on the other side of the world see the result in seconds. Instead of the rapid iterations that web app developers enjoy, mobile app developers are stuck with pushing builds every night and waiting a day for the team to see the new code. That's if they even have a nightly build setup. Most people also only have one phone, so they can never test the Android app if they have an iPhone and vice versa.

We've been developing mobile apps for over 10 years (at Facebook, Wealthfront, etc.). In that time, the tooling has dramatically improved, yet we still found ourselves having to go and install emulators on a PM's laptop and give them commands to copy and paste on the terminal because they didn't have an Android phone. Or we would have to procure test phones and wait for a build to be pushed. We’re building Wolfia to finally make this process seamless.

Wolfia lets developers send a link to an APK (an Android binary) that's running on an emulator accessible via the browser. You can then play with the app without the need for a physical device. This dramatically shortens the feedback loop and completely transforms the dev cycle: from days to hours or even minutes.

Product managers and designers can use it to check that a new feature is being built up to their specs. Developers can use it to check if the code is running correctly. Founders, user researchers and salespeople can use it for interactive demos of the product.

We host headless (without GUI) Android emulators with hardware acceleration running on AWS bare metal instances to get high performance. We use WebSockets to make a two-way connection between the browser and the emulator through ADB (Android Debug Bridge). The emulator's GUI is displayed on the browser via an H.264 video feed, and we relay the user's touch events back to the emulator. We use WSS to make this secure.

Try it for free at https://www.wolfia.com! (you can try a demo - we used Materialistic, an open source HN app - or sign up for free and upload your own app)

We would love to hear your thoughts, ideas and feedback!",Hacker News,70660988,"Title: Launch HN: Wolfia (YC S22) – A mobile app emulator you can share with a link; Content: Hi HN! We’re Fabien and Naren, co-founders of Wolfia (https://www.wolfia.com). Wolfia lets you share a link to a mobile emulator running your app. Developers can get feedback instantly on a feature they just built by sharing a link to an interactive version of their app. We’re starting with Android but iOS is coming soon!

Mobile app development in 2022 is harder than it should be - you can't easily change a line of code, rebuild the app, and have someone on the other side of the world see the result in seconds. Instead of the rapid iterations that web app developers enjoy, mobile app developers are stuck with pushing builds every night and waiting a day for the team to see the new code. That's if they even have a nightly build setup. Most people also only have one phone, so they can never test the Android app if they have an iPhone and vice versa.

We've been developing mobile apps for over 10 years (at Facebook, Wealthfront, etc.). In that time, the tooling has dramatically improved, yet we still found ourselves having to go and install emulators on a PM's laptop and give them commands to copy and paste on the terminal because they didn't have an Android phone. Or we would have to procure test phones and wait for a build to be pushed. We’re building Wolfia to finally make this process seamless.

Wolfia lets developers send a link to an APK (an Android binary) that's running on an emulator accessible via the browser. You can then play with the app without the need for a physical device. This dramatically shortens the feedback loop and completely transforms the dev cycle: from days to hours or even minutes.

Product managers and designers can use it to check that a new feature is being built up to their specs. Developers can use it to check if the code is running correctly. Founders, user researchers and salespeople can use it for interactive demos of the product.

We host headless (without GUI) Android emulators with hardware acceleration running on AWS bare metal instances to get high performance. We use WebSockets to make a two-way connection between the browser and the emulator through ADB (Android Debug Bridge). The emulator's GUI is displayed on the browser via an H.264 video feed, and we relay the user's touch events back to the emulator. We use WSS to make this secure.

Try it for free at https://www.wolfia.com! (you can try a demo - we used Materialistic, an open source HN app - or sign up for free and upload your own app)

We would love to hear your thoughts, ideas and feedback!",727 -justinludwig,32402630,221,1660072395,Implementing a Zero Trust Architecture,https://www.nccoe.nist.gov/projects/implementing-zero-trust-architecture," - An official website of the United States government - - Here’s how you know - - - - A website belongs to an official government - organization in the United States. - - - - A ( - - ) or means you’ve safely connected to - the .gov website. Share sensitive information only on official, - secure websites. - Conventional network security has focused on perimeter defenses, but many organizations no longer have a clearly-defined perimeter. To protect a modern digital enterprise, organizations need a comprehensive strategy for secure “anytime, anywhere” access to their corporate resources (e.g., applications, legacy systems, data, and device",Hacker News,72954652,"Title: Implementing a Zero Trust Architecture; Content: - An official website of the United States government - - Here’s how you know - - - - A website belongs to an official government - organization in the United States. - - - - A ( - - ) or means you’ve safely connected to - the .gov website. Share sensitive information only on official, - secure websites. - Conventional network security has focused on perimeter defenses, but many organizations no longer have a clearly-defined perimeter. To protect a modern digital enterprise, organizations need a comprehensive strategy for secure “anytime, anywhere” access to their corporate resources (e.g., applications, legacy systems, data, and device",343 -bshanks,32406883,142,1660094745,Baby’s First Garbage Collector (2013),https://journal.stuffwithstuff.com/2013/12/08/babys-first-garbage-collector/,"When I get stressed out and have too much to do, I have this paradoxical -reaction where I escape from that by coming up with thing to do. -Usually it’s a tiny self-contained program that I can write and finish. The other morning, I was freaking myself out about and the and , and all of the sudden, I thought, “I should write a -garbage collector.” Yes, I realize how crazy that paragraph makes me seem. But my faulty wiring is -your free tutorial on a fundamental piece of programming language -implementation! In about a hundred lines of vanilla C, I managed to whip up a -basic collector that actually, you know, collects. Garbage collection is considered one of the more shark-infested waters of -programming, but in this post, I’ll give you a nice kiddie pool to paddle around -in. (There may ",Hacker News,61291286,"Title: Baby’s First Garbage Collector (2013); Content: When I get stressed out and have too much to do, I have this paradoxical -reaction where I escape from that by coming up with thing to do. -Usually it’s a tiny self-contained program that I can write and finish. The other morning, I was freaking myself out about and the and , and all of the sudden, I thought, “I should write a -garbage collector.” Yes, I realize how crazy that paragraph makes me seem. But my faulty wiring is -your free tutorial on a fundamental piece of programming language -implementation! In about a hundred lines of vanilla C, I managed to whip up a -basic collector that actually, you know, collects. Garbage collection is considered one of the more shark-infested waters of -programming, but in this post, I’ll give you a nice kiddie pool to paddle around -in. (There may ",216 -cancan,32418675,24,1660166790,How to design a beautiful map,https://felt.com/blog/how-to-design-a-beautiful-map,"At Felt we’re building a tool that empowers anyone to make a great map. As with any creative tool, applying a few key techniques to the design of your map can take it from a rough draft to a beautiful, professional design. We spend a lot of time thinking about how to make maps look great in Felt. Here is the guidance we've developed. ‍ As the design and cartography leads for Felt, we think a lot about how to make Felt useful and beautiful, with the goal of helping you make maps that are both useful and beautiful! By following the guidance below, your maps will look better in no time. First up, the contents of your map are the most make-or-break part of the craft. Who is your audience? What do they need to know? And how will they use it? Put yourself in the shoes of the viewer as much ",Hacker News,19153008,"Title: How to design a beautiful map; Content: At Felt we’re building a tool that empowers anyone to make a great map. As with any creative tool, applying a few key techniques to the design of your map can take it from a rough draft to a beautiful, professional design. We spend a lot of time thinking about how to make maps look great in Felt. Here is the guidance we've developed. ‍ As the design and cartography leads for Felt, we think a lot about how to make Felt useful and beautiful, with the goal of helping you make maps that are both useful and beautiful! By following the guidance below, your maps will look better in no time. First up, the contents of your map are the most make-or-break part of the craft. Who is your audience? What do they need to know? And how will they use it? Put yourself in the shoes of the viewer as much ",204 -icyfox,32403746,160,1660076606,Falling for Kubernetes,https://freeman.vc/notes/falling-for-kubernetes,"I've considered myself a strong kubernetes skeptic in the past. Bare metal is always my first choice both for projects and startups. That includes the that runs this blog. Calling it a stack might even be an exaggeration. It's a CI toolchain with an nginx configuration on the host. But it does its job, can handle surprising concurrent load, and is cheap to host. It costs just $10 a month and can likely go side by side with corporate blogging platforms that cost two orders of magnitude more to host. Premature optimization might be the root of all evil but so is premature scale. I'm convinced that companies over complicate their architecture prematurely, which leads to headaches for engineers and instability for users. A monorepo with a simple server should be the default place to start. R",Hacker News,58979128,"Title: Falling for Kubernetes; Content: I've considered myself a strong kubernetes skeptic in the past. Bare metal is always my first choice both for projects and startups. That includes the that runs this blog. Calling it a stack might even be an exaggeration. It's a CI toolchain with an nginx configuration on the host. But it does its job, can handle surprising concurrent load, and is cheap to host. It costs just $10 a month and can likely go side by side with corporate blogging platforms that cost two orders of magnitude more to host. Premature optimization might be the root of all evil but so is premature scale. I'm convinced that companies over complicate their architecture prematurely, which leads to headaches for engineers and instability for users. A monorepo with a simple server should be the default place to start. R",176 -ericliuche,32410948,311,1660135294,U.S. annual inflation rate drops to 8.5%,https://www.bls.gov/news.release/archives/cpi_08102022.htm,"An official website of the United States government - - - - - Federal government websites often end in .gov or .mil. Before sharing sensitive information, - make sure you're on a federal government site. - - - The - ensures that you are connecting to the official website and that any - information you provide is encrypted and transmitted securely. - All items Food Food at home Food away from home Energy Energy commodities Gasoline (all types) Fuel oil Energy services Electricity Utility (piped) gas service All items less food and energy Commodities less food and energy commodities New vehicles Used cars and trucks Apparel Medical care commodities Services less energy services Shelter Transportation services Medical care services - - Not seasonally adjusted. - All items Food Foo",Hacker News,6409026,"Title: U.S. annual inflation rate drops to 8.5%; Content: An official website of the United States government - - - - - Federal government websites often end in .gov or .mil. Before sharing sensitive information, - make sure you're on a federal government site. - - - The - ensures that you are connecting to the official website and that any - information you provide is encrypted and transmitted securely. - All items Food Food at home Food away from home Energy Energy commodities Gasoline (all types) Fuel oil Energy services Electricity Utility (piped) gas service All items less food and energy Commodities less food and energy commodities New vehicles Used cars and trucks Apparel Medical care commodities Services less energy services Shelter Transportation services Medical care services - - Not seasonally adjusted. - All items Food Foo",193 -nreece,32393634,367,1660012171,How fast is 12th Gen Intel Core?,https://frame.work/blog/how-fast-is-12th-gen-intel-core,"Sie haben noch kein Konto? Sie haben noch kein Konto? When we announced the new Framework Laptop with the latest 12th Gen Intel® Core™ processors, we provided a small peek at its performance: in Cinebench R23 multi-core — which measures overall CPU performance — 12th Gen posted results almost double those of 11th Gen! We’ve shared some in our last announcement, and will go into greater detail today by sharing benchmarking results that demonstrate how powerful the upgraded Framework Laptop is across a broad range of use cases. With both generations of the Framework Laptop available in the , there are currently a total of six different processors. For our first test, we chose Cinebench R23, a popular benchmarking tool based on Cinema 4D’s rendering technology, to check each processor’s si",Hacker News,25749206,"Title: How fast is 12th Gen Intel Core?; Content: Sie haben noch kein Konto? Sie haben noch kein Konto? When we announced the new Framework Laptop with the latest 12th Gen Intel® Core™ processors, we provided a small peek at its performance: in Cinebench R23 multi-core — which measures overall CPU performance — 12th Gen posted results almost double those of 11th Gen! We’ve shared some in our last announcement, and will go into greater detail today by sharing benchmarking results that demonstrate how powerful the upgraded Framework Laptop is across a broad range of use cases. With both generations of the Framework Laptop available in the , there are currently a total of six different processors. For our first test, we chose Cinebench R23, a popular benchmarking tool based on Cinema 4D’s rendering technology, to check each processor’s si",195 -obert,32397341,38,1660050785,Sea creatures pollinate marine plants and algae,https://www.nationalgeographic.co.uk/science-and-technology/2022/08/sea-creatures-pollinate-marine-plants-and-algae-surprising-scientists,"This colorised confocal microscopy image shows the body of an isopod covered in the germ cells of a red algae, Gracilaria gracilis. New research shows that these animals spread around the algae’s spermatia, effectively pollinating them. About a decade ago, Vivianne Solis-Weiss, a marine biologist at Universidad Nacional Autónoma de México who studies marine worms, talked to a colleague studying seagrasses, flowering plants that grow in the ocean. “‘Every time we gather the flowers, we see these small animals all over them,’” she recalls her colleague telling her. Both wondered why these little worms and tiny shrimp-like crustaceans would gather there. Could they be pollinating the plants—the marine equivalent of bees and butterflies? Solis-Weiss and her colleagues hypothesise",Hacker News,41241673,"Title: Sea creatures pollinate marine plants and algae; Content: This colorised confocal microscopy image shows the body of an isopod covered in the germ cells of a red algae, Gracilaria gracilis. New research shows that these animals spread around the algae’s spermatia, effectively pollinating them. About a decade ago, Vivianne Solis-Weiss, a marine biologist at Universidad Nacional Autónoma de México who studies marine worms, talked to a colleague studying seagrasses, flowering plants that grow in the ocean. “‘Every time we gather the flowers, we see these small animals all over them,’” she recalls her colleague telling her. Both wondered why these little worms and tiny shrimp-like crustaceans would gather there. Could they be pollinating the plants—the marine equivalent of bees and butterflies? Solis-Weiss and her colleagues hypothesise",221 -giuliomagnifico,32395840,264,1660037818,Our brain is a prediction machine that is always active,https://www.mpi.nl/news/our-brain-prediction-machine-always-active,"This is in line with a recent theory on how our brain works: it is a prediction machine, which continuously compares sensory information that we pick up (such as images, sounds and language) with internal predictions. ""This theoretical idea is extremely popular in neuroscience, but the existing evidence for it is often indirect and restricted to artificial situations,"" says lead author Micha Heilbron. ""I would really like to understand precisely how this works and test it in different situations."" Brain research into this phenomenon is usually done in an artificial setting, Heilbron reveals. To evoke predictions, participants are asked to stare at a single pattern of moving dots for half an hour, or listen to simple patterns in sounds like 'beep beep boop, beep beep boop, …. ""Studies of th",Hacker News,5675375,"Title: Our brain is a prediction machine that is always active; Content: This is in line with a recent theory on how our brain works: it is a prediction machine, which continuously compares sensory information that we pick up (such as images, sounds and language) with internal predictions. ""This theoretical idea is extremely popular in neuroscience, but the existing evidence for it is often indirect and restricted to artificial situations,"" says lead author Micha Heilbron. ""I would really like to understand precisely how this works and test it in different situations."" Brain research into this phenomenon is usually done in an artificial setting, Heilbron reveals. To evoke predictions, participants are asked to stare at a single pattern of moving dots for half an hour, or listen to simple patterns in sounds like 'beep beep boop, beep beep boop, …. ""Studies of th",178 -Fabricio20,32399238,757,1660058543,“It’s time for Apple to fix texting”,https://www.android.com/get-the-message/,"Google serves cookies to analyze traffic to this site. Information about your use of our site is shared with Google for that purpose. . It’s not about the color of the bubbles. It’s the blurry videos, broken group chats, missing read receipts and typing indicators, no texting over Wi-Fi, and more. These exist because Apple refuses to adopt modern texting standards when people with iPhones and Android phones text each other. Apple turns texts between iPhones and Android phones into SMS and MMS, out-of-date technologies from the 90s and 00s. But Apple can adopt RCS—the —for these threads instead. Solving the problem without changing your iPhone to iPhone conversations and making messaging better for everyone. It’s not about the color of the bubbles—iPhone users get a bad text",Hacker News,50360547,"Title: “It’s time for Apple to fix texting”; Content: Google serves cookies to analyze traffic to this site. Information about your use of our site is shared with Google for that purpose. . It’s not about the color of the bubbles. It’s the blurry videos, broken group chats, missing read receipts and typing indicators, no texting over Wi-Fi, and more. These exist because Apple refuses to adopt modern texting standards when people with iPhones and Android phones text each other. Apple turns texts between iPhones and Android phones into SMS and MMS, out-of-date technologies from the 90s and 00s. But Apple can adopt RCS—the —for these threads instead. Solving the problem without changing your iPhone to iPhone conversations and making messaging better for everyone. It’s not about the color of the bubbles—iPhone users get a bad text",211 -notpushkin,32402542,52,1660072130,Video Stabilization with FFmpeg and VidStab,https://www.paulirish.com/2021/video-stabilization-with-ffmpeg-and-vidstab/," - - Way back in Dec 2015, @maxogden wrote a nice on stabilizing your own video with ffmpeg. I return to it on occasion and have updated my gist comment to offer some updated commands. Since enough has changed regarding installation and use, I figure a new, spiffy, and working guide deserves a non-gist home. Presenting the 2021-era guide to pretty easy DIY video stabilization! On linux, you can . There are , like , , . The defaults are good, but you may want to experiment. There’s even a visual diagnostic mode. Assuming the source video is named … You now have a ! Use the or filter, depending on if you want them stacked vertically or side-by-side: - - - - - -Heyo, I'm -a , -and work on the team focused on Developer Tooling. - I live in sunny Palo Alto. - or Paul Irish doe",Hacker News,35409141,"Title: Video Stabilization with FFmpeg and VidStab; Content: - - Way back in Dec 2015, @maxogden wrote a nice on stabilizing your own video with ffmpeg. I return to it on occasion and have updated my gist comment to offer some updated commands. Since enough has changed regarding installation and use, I figure a new, spiffy, and working guide deserves a non-gist home. Presenting the 2021-era guide to pretty easy DIY video stabilization! On linux, you can . There are , like , , . The defaults are good, but you may want to experiment. There’s even a visual diagnostic mode. Assuming the source video is named … You now have a ! Use the or filter, depending on if you want them stacked vertically or side-by-side: - - - - - -Heyo, I'm -a , -and work on the team focused on Developer Tooling. - I live in sunny Palo Alto. - or Paul Irish doe",243 -larsiusprime,32398963,170,1660057241,W4 Games formed to strengthen Godot ecosystem,https://w4games.com/2022/08/09/hello-world-w4-games/,"Hello everyone! We are pleased to announce the formation of , a new company created by veterans Juan Linietsky, Rémi Verschelde and Fabio Alessandrelli, and veteran entrepreneur Nicola Farronato. W4 Games was formed to strengthen the Godot ecosystem by providing both enterprise and independent developers with a complementary suite of commercial products and services to successfully develop and publish video games to all existing platforms in the market. Further announcements about these products and services will be made over the coming weeks and months as they become available. As part of our development philosophy we want to give back to Godot wherever possible. Throughout the development of our products we will be open sourcing as much as we can, including additions to Godot that str",Hacker News,21036027,"Title: W4 Games formed to strengthen Godot ecosystem; Content: Hello everyone! We are pleased to announce the formation of , a new company created by veterans Juan Linietsky, Rémi Verschelde and Fabio Alessandrelli, and veteran entrepreneur Nicola Farronato. W4 Games was formed to strengthen the Godot ecosystem by providing both enterprise and independent developers with a complementary suite of commercial products and services to successfully develop and publish video games to all existing platforms in the market. Further announcements about these products and services will be made over the coming weeks and months as they become available. As part of our development philosophy we want to give back to Godot wherever possible. Throughout the development of our products we will be open sourcing as much as we can, including additions to Godot that str",165 -Destiner,32402631,151,1660072404,Sol: Open-source Alfred/Raycast alternative for macOS,https://github.com/ospfranco/sol," - MacOS launcher & command palette - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. Sol is a command palette, focused on simplicity and speed. It’s open source, free and 100% local. Get the latest version from the , once installed the app can auto-update itself. You can also install it via Brew MIT License - MacOS launcher & command palette - ",Hacker News,21243302,"Title: Sol: Open-source Alfred/Raycast alternative for macOS; Content: - MacOS launcher & command palette - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. Sol is a command palette, focused on simplicity and speed. It’s open source, free and 100% local. Get the latest version from the , once installed the app can auto-update itself. You can also install it via Brew MIT License - MacOS launcher & command palette - ",237 -blacksqr,32405713,98,1660085996,Tcled: Pure Tcl Console Text Editor (2019),https://github.com/slebetman/tcled," - Pure Tcl Console Text Editor - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. Simple text editor with syntax hilighting in a single file tcl script! This software is released under a simple 2-clause BSD license. This editor is based on Steve Redler's minimal console text editor -in Tcl ( ). I took Steve's code and modified it to do -syntax hilighting. Since then it's had enough features added to it that it is -now good enough for me to use as my primary code editor. Part of the r",Hacker News,14540726,"Title: Tcled: Pure Tcl Console Text Editor (2019); Content: - Pure Tcl Console Text Editor - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. Simple text editor with syntax hilighting in a single file tcl script! This software is released under a simple 2-clause BSD license. This editor is based on Steve Redler's minimal console text editor -in Tcl ( ). I took Steve's code and modified it to do -syntax hilighting. Since then it's had enough features added to it that it is -now good enough for me to use as my primary code editor. Part of the r",264 -ltratt,32408546,74,1660114377,Making a Video of a Single Window,https://tratt.net/laurie/blog/2022/making_a_video_of_a_single_window.html,"In this post I'm going to quickly go through what I did. I hope you get two -things from this. First, FFmpeg, hk, and xwininfo are great examples of tools -whose power can be magnified by combining them with other tools. -Second, I'm not presenting an end product as much as I am presenting example -recipes which you can alter and adjust to fit your circumstances. - - - - The first problem is automatically determining what portion of the screen I -want to capture. Fortunately, xwininfo does exactly what I want: when I run it, -the cursor changes to a ""+""; and, when I click on a window, it outputs information -to stdout about that window. Here's what happens when I click on the editor -window I'm typing this post into: - - - -What I need to extract are: - - - -Let's assume I've put xwininfo's output into . ",Hacker News,1713189,"Title: Making a Video of a Single Window; Content: In this post I'm going to quickly go through what I did. I hope you get two -things from this. First, FFmpeg, hk, and xwininfo are great examples of tools -whose power can be magnified by combining them with other tools. -Second, I'm not presenting an end product as much as I am presenting example -recipes which you can alter and adjust to fit your circumstances. - - - - The first problem is automatically determining what portion of the screen I -want to capture. Fortunately, xwininfo does exactly what I want: when I run it, -the cursor changes to a ""+""; and, when I click on a window, it outputs information -to stdout about that window. Here's what happens when I click on the editor -window I'm typing this post into: - - - -What I need to extract are: - - - -Let's assume I've put xwininfo's output into . ",212 -Marat_Tokyo,32412745,38,1660142351,RaspberryPi for measuring bio signals (open source),https://github.com/HackerBCI," - Open-Source board for converting RaspberryPI to Brain-computer interface - - - - - - Real-time EEG BCI signal processing by Python - - - - - - Open-Source board for converting RaspberryPI to Brain-computer interface - - Real-time EEG BCI signal processing by Python - Loading…",Hacker News,27475430,"Title: RaspberryPi for measuring bio signals (open source); Content: - Open-Source board for converting RaspberryPI to Brain-computer interface - - - - - - Real-time EEG BCI signal processing by Python - - - - - - Open-Source board for converting RaspberryPI to Brain-computer interface - - Real-time EEG BCI signal processing by Python - Loading…",154 -wooosh,32401548,153,1660068456,Lz_xor,http://richg42.blogspot.com/2022/01/lzxor.html," - - -",Hacker News,87289853,"Title: Lz_xor; Content: - - -",16 -zdw,32394176,70,1660019571,The Godfather of Complexity,http://blog.computationalcomplexity.org/2022/08/the-godfather-of-complexity.html,"May he rest in peace. He passed away on July 29th, not Aug 29th. Thank you. Thanks. Fixed the date. I was sad to read about Hartmanis passing away - there was much to admire about him; not only was he a legend in the field, but he was super inspiring to graduate students that he did not advise. In the 80s he was a central (founding) figure in Cornell CS and continued to inspire those of us who took a class with him, and were working in TCS, if not complexity theory. Very approachable, humble and friendly. The one time he was talking about isomorphism conjecture, I was totally confused, as I was thinking ""graph isomorphism""! I am pretty sure he thought GI would be in P (eventually) as well. He made research fun, and interesting, but more importantly he was a role model for many of us. I re",Hacker News,35457941,"Title: The Godfather of Complexity; Content: May he rest in peace. He passed away on July 29th, not Aug 29th. Thank you. Thanks. Fixed the date. I was sad to read about Hartmanis passing away - there was much to admire about him; not only was he a legend in the field, but he was super inspiring to graduate students that he did not advise. In the 80s he was a central (founding) figure in Cornell CS and continued to inspire those of us who took a class with him, and were working in TCS, if not complexity theory. Very approachable, humble and friendly. The one time he was talking about isomorphism conjecture, I was totally confused, as I was thinking ""graph isomorphism""! I am pretty sure he thought GI would be in P (eventually) as well. He made research fun, and interesting, but more importantly he was a role model for many of us. I re",202 -marc__1,32406563,148,1660091938,AppLovin bids $17.5B to acquire Unity,https://www.axios.com/2022/08/09/applovin-unity-video-game-consolidation,"AppLovin , the popular video game making software company, for $17.54 billion in an all-stock deal. This is the latest high-profile deal in the . While AppLovin is best known as a mobile ad tech company, it has expanded into video game publishing in recent years. AppLovin's bid doesn't include ironSource, a rival that Unity offered to buy for $4.4 billion last month. That is: Unity must now choose between the two companies. Unity is set to announce its quarterly earnings later today, and it's sure to get some questions about the offer.",Hacker News,32997639,"Title: AppLovin bids $17.5B to acquire Unity; Content: AppLovin , the popular video game making software company, for $17.54 billion in an all-stock deal. This is the latest high-profile deal in the . While AppLovin is best known as a mobile ad tech company, it has expanded into video game publishing in recent years. AppLovin's bid doesn't include ironSource, a rival that Unity offered to buy for $4.4 billion last month. That is: Unity must now choose between the two companies. Unity is set to announce its quarterly earnings later today, and it's sure to get some questions about the offer.",152 -zwischenzug,32396892,217,1660047856,“Who Should Write the Terraform?”,https://zwischenzugs.com/2022/08/08/who-should-write-the-terraform/,"Working in , ‘. I’m asked this in various forms, and at various levels, but the title’s question (‘Who should write the Terraform?) is a fairly typical one. Consultants are often asked simple questions that invite simple answers, but it’s our job to frustrate our clients, so . The reason it depends is that . Even if there is an ‘ideal’ answer, the world is not ideal, and the best thing for a client at that time might not be the best thing for the industry in general. So here I attempt to lay out the factors that help me answer that questions as honestly as possible. But before that, we need to lay out some background. Those old enough to remember when the word ‘middleware’ was everywhere will know that many industry terms are so vague or generic as to be meaningless. However, for ‘pla",Hacker News,23522622,"Title: “Who Should Write the Terraform?”; Content: Working in , ‘. I’m asked this in various forms, and at various levels, but the title’s question (‘Who should write the Terraform?) is a fairly typical one. Consultants are often asked simple questions that invite simple answers, but it’s our job to frustrate our clients, so . The reason it depends is that . Even if there is an ‘ideal’ answer, the world is not ideal, and the best thing for a client at that time might not be the best thing for the industry in general. So here I attempt to lay out the factors that help me answer that questions as honestly as possible. But before that, we need to lay out some background. Those old enough to remember when the word ‘middleware’ was everywhere will know that many industry terms are so vague or generic as to be meaningless. However, for ‘pla",211 -mhb,32410602,271,1660133481,U.K.'s online censorship bill causes more harm than it attempts to prevent,https://reason.com/2022/08/10/u-k-s-online-censorship-bill-causes-far-more-harm-than-it-attempts-to-prevent/,"You are now logged in. - - - - - - With the U.K.'s Conservative Party closing in on deciding left by Boris Johnson's tenure as prime minister, that country's governing apparatus will soon get back to the important business of intruding into people's lives. At the top of the to-do list is the long-coming which, as has become traditional for legislation, does nothing that its title suggests. In fact, those who offend the government with their online speech or efforts to protect privacy may soon be a lot safe. ""If the Online Safety Bill passes, the U.K. government will be able to directly silence user speech, and even imprison those who publish messages that it doesn't like,"" the Electronic Frontier Foundation's (EFF) Joe Mullin . ""The bill empowers the UK's Office of Communications (O",Hacker News,39653546,"Title: U.K.'s online censorship bill causes more harm than it attempts to prevent; Content: You are now logged in. - - - - - - With the U.K.'s Conservative Party closing in on deciding left by Boris Johnson's tenure as prime minister, that country's governing apparatus will soon get back to the important business of intruding into people's lives. At the top of the to-do list is the long-coming which, as has become traditional for legislation, does nothing that its title suggests. In fact, those who offend the government with their online speech or efforts to protect privacy may soon be a lot safe. ""If the Online Safety Bill passes, the U.K. government will be able to directly silence user speech, and even imprison those who publish messages that it doesn't like,"" the Electronic Frontier Foundation's (EFF) Joe Mullin . ""The bill empowers the UK's Office of Communications (O",205 -taubek,32403206,39,1660074352,From working at Subway to one of the greatest mathematicians (2015),https://www.quantamagazine.org/yitang-zhang-and-the-mystery-of-numbers-20150402,"As a boy in Shanghai, China, Yitang Zhang believed he would someday solve a great problem in mathematics. In 1964, at around the age of nine, he found a proof of the Pythagorean theorem, which describes the relationship between the lengths of the sides of any right triangle. He was 10 when he first learned about two famous number theory problems, and the . While he was not yet aware of the centuries-old , he was already taken with prime numbers, often described as indivisible “atoms” that make up all other natural numbers. But soon after, the anti-intellectual Cultural Revolution shuttered schools and sent him and his mother to the countryside to work in the fields. Because of his father’s troubles with the Communist Party, Zhang was also unable to attend high school. For 10 years, he ",Hacker News,26316029,"Title: From working at Subway to one of the greatest mathematicians (2015); Content: As a boy in Shanghai, China, Yitang Zhang believed he would someday solve a great problem in mathematics. In 1964, at around the age of nine, he found a proof of the Pythagorean theorem, which describes the relationship between the lengths of the sides of any right triangle. He was 10 when he first learned about two famous number theory problems, and the . While he was not yet aware of the centuries-old , he was already taken with prime numbers, often described as indivisible “atoms” that make up all other natural numbers. But soon after, the anti-intellectual Cultural Revolution shuttered schools and sent him and his mother to the countryside to work in the fields. Because of his father’s troubles with the Communist Party, Zhang was also unable to attend high school. For 10 years, he ",195 -sweetheart,32403471,275,1660075416,Fishing gear accounts for an alarming amount of plastic in oceans (2021),https://www.nature.org/en-us/newsroom/ca-ocean-plastic/," - We personalize nature.org for you - - This website uses cookies to enhance your experience and analyze performance and traffic on our website. - - To manage or opt-out of receiving cookies, please visit our - - - - New study by TNC and the UC Santa Barbara is first ever comprehensive estimate of ocean plastic pollution from industrial fishing activity - - - - - - - - - - - September 16, 2021 - - | Santa Barbara, CA - - - - Juvenio Guerra - - M",Hacker News,32254694,"Title: Fishing gear accounts for an alarming amount of plastic in oceans (2021); Content: - We personalize nature.org for you - - This website uses cookies to enhance your experience and analyze performance and traffic on our website. - - To manage or opt-out of receiving cookies, please visit our - - - - New study by TNC and the UC Santa Barbara is first ever comprehensive estimate of ocean plastic pollution from industrial fishing activity - - - - - - - - - - - September 16, 2021 - - | Santa Barbara, CA - - - - Juvenio Guerra - - M",501 -bojangleslover,32421971,3,1660196356,Ask HN: How to best present to semi tech/quant-savvy audience?,,"Recently I have found myself presenting to senior management at a bank. I have found these presentations go one of three ways.

1) Fairly well but without a deep audience understanding -2) Fairly well with the audience hyper-fixated on the wrong detail -3) Fairly well with the audience hyper-fixated on the right detail -4) Fairly poorly with a few pity questions asked at the end

Because I keep getting asked back I'm sure I am on to something. But I really want to take these to the next level and put myself in buckets 1, 2 and 3 while avoiding bucket 4. I know due to natural variation in outcomes that there will be some 4's even for the best presenters.

Obviously this is context-dependent but I want to hear from the community.",Hacker News,96010569,"Title: Ask HN: How to best present to semi tech/quant-savvy audience?; Content: Recently I have found myself presenting to senior management at a bank. I have found these presentations go one of three ways.

1) Fairly well but without a deep audience understanding -2) Fairly well with the audience hyper-fixated on the wrong detail -3) Fairly well with the audience hyper-fixated on the right detail -4) Fairly poorly with a few pity questions asked at the end

Because I keep getting asked back I'm sure I am on to something. But I really want to take these to the next level and put myself in buckets 1, 2 and 3 while avoiding bucket 4. I know due to natural variation in outcomes that there will be some 4's even for the best presenters.

Obviously this is context-dependent but I want to hear from the community.",202 -rcarmo,32395256,73,1660031344,A quick and practical “MSI” hash table,https://nullprogram.com/blog/2022/08/08/,"I , so I’m accustomed to building whatever I need -on the fly, such as heaps, linked lists, and especially hash tables. Few -programs use more than a small subset of a data structure’s features, -making their implementation smaller, simpler, and more efficient than the -general case, which must handle every edge case. A typical hash table -tutorial will describe a relatively lengthy program, but in practice, -bespoke hash tables are . Over the years -I’ve worked out some basic principles for hash table construction that aid -in quick and efficient implementation. This article covers the technique -and philosophy behind what I’ve come to call the “mask-step-index” (MSI) -hash table, which is my standard approach. MSI hash tables are nothing novel, just a , hash table layered generically atop an ",Hacker News,46719901,"Title: A quick and practical “MSI” hash table; Content: I , so I’m accustomed to building whatever I need -on the fly, such as heaps, linked lists, and especially hash tables. Few -programs use more than a small subset of a data structure’s features, -making their implementation smaller, simpler, and more efficient than the -general case, which must handle every edge case. A typical hash table -tutorial will describe a relatively lengthy program, but in practice, -bespoke hash tables are . Over the years -I’ve worked out some basic principles for hash table construction that aid -in quick and efficient implementation. This article covers the technique -and philosophy behind what I’ve come to call the “mask-step-index” (MSI) -hash table, which is my standard approach. MSI hash tables are nothing novel, just a , hash table layered generically atop an ",207 -p5v,32398969,190,1660057280,The problem with Go’s default HTTP handlers,https://preslav.me/2022/08/09/i-dont-like-golang-default-http-handlers/,"All Go programmers learn early on what the shape of the standard HTTP handler function looks like: It is simple and easy to remember. At the same time, it is low-level enough not to limit or obscure the developer in any possible way—typical Go. Let’s build a slightly more complex example where the flow has to go through a couple of potentially error-prone operations before returning to the client. And here comes the big problem in my view. You aren’t actually returning anything. Regardless of the outcome, you simply write it to the response writer. This can lead to unnoticeable and difficult to trace bugs like in the example above: While we acknowledged the error, we didn’t return it immediately after it. By definition, we aren’t forced to, so the compiler wouldn’t complain either. It migh",Hacker News,44279569,"Title: The problem with Go’s default HTTP handlers; Content: All Go programmers learn early on what the shape of the standard HTTP handler function looks like: It is simple and easy to remember. At the same time, it is low-level enough not to limit or obscure the developer in any possible way—typical Go. Let’s build a slightly more complex example where the flow has to go through a couple of potentially error-prone operations before returning to the client. And here comes the big problem in my view. You aren’t actually returning anything. Regardless of the outcome, you simply write it to the response writer. This can lead to unnoticeable and difficult to trace bugs like in the example above: While we acknowledged the error, we didn’t return it immediately after it. By definition, we aren’t forced to, so the compiler wouldn’t complain either. It migh",191 -antipaul,32420641,17,1660182115,Meta's own chatbot says the company 'exploits people',https://www.bbc.com/news/technology-62497674,"Meta says the chatbot uses artificial intelligence and can chat on ""nearly any topic"". Asked what the chatbot thought of the company's CEO and founder, it replied ""our country is divided and he didn't help that at all"". Meta said the chatbot was a prototype and might produce rude or offensive answers. ""Everyone who uses Blender Bot is required to acknowledge they understand it's for research and entertainment purposes only, that it can make untrue or offensive statements, and that they agree to not intentionally trigger the bot to make offensive statements,"" said a Meta spokesperson. The chatbot, called , was released to the public on Friday. The programme ""learns"" from large amounts of publicly available language data. When asked about Mark Zuckerberg, the chatbot told the BBC: ""He d",Hacker News,16479611,"Title: Meta's own chatbot says the company 'exploits people'; Content: Meta says the chatbot uses artificial intelligence and can chat on ""nearly any topic"". Asked what the chatbot thought of the company's CEO and founder, it replied ""our country is divided and he didn't help that at all"". Meta said the chatbot was a prototype and might produce rude or offensive answers. ""Everyone who uses Blender Bot is required to acknowledge they understand it's for research and entertainment purposes only, that it can make untrue or offensive statements, and that they agree to not intentionally trigger the bot to make offensive statements,"" said a Meta spokesperson. The chatbot, called , was released to the public on Friday. The programme ""learns"" from large amounts of publicly available language data. When asked about Mark Zuckerberg, the chatbot told the BBC: ""He d",183 -ivanvas,32402977,166,1660073563,Google Maps' moat is evaporating (2020),https://joemorrison.substack.com/p/google-maps-moat-is-evaporating,"If you work at the intersection of maps and software, at some point in your life you’ve probably heard yourself muttering some version of the following analogy to a stubbornly confused family member: You know Google Maps? What I do is, like, build little pieces of Google Maps over and over for people who need them but can’t just use Google Maps because they’re not allowed to for some reason, or another. People have half-heartedly compared their profession to Google Maps at family gatherings for well over a decade, because since inception, Google has consistently created the best consumer-facing maps in the world. And I’m not just talking about coverage—they are top of the class in turn-by-turn navigation, geocoding, satellite imagery layers, street level imagery, place data, and on, and on",Hacker News,91707970,"Title: Google Maps' moat is evaporating (2020); Content: If you work at the intersection of maps and software, at some point in your life you’ve probably heard yourself muttering some version of the following analogy to a stubbornly confused family member: You know Google Maps? What I do is, like, build little pieces of Google Maps over and over for people who need them but can’t just use Google Maps because they’re not allowed to for some reason, or another. People have half-heartedly compared their profession to Google Maps at family gatherings for well over a decade, because since inception, Google has consistently created the best consumer-facing maps in the world. And I’m not just talking about coverage—they are top of the class in turn-by-turn navigation, geocoding, satellite imagery layers, street level imagery, place data, and on, and on",188 -notabanker,32416402,19,1660155887,"Ask HN: For a startup website to show customer logos, do you need permission?",,Many startup websites list company logos on their website as a form of social proof. I'm wondering if these startups took the company's permission before displaying their logo.,Hacker News,73649724,"Title: Ask HN: For a startup website to show customer logos, do you need permission?; Content: Many startup websites list company logos on their website as a form of social proof. I'm wondering if these startups took the company's permission before displaying their logo.",65 -samclemens,32397547,24,1660051725,Who Built the First Electric Rock 'N' Roll Guitar? (2019),https://www.collectorsweekly.com/articles/who-really-built-the-first-electric-rock-n-roll-guitar/," - — - - George Fullerton (left) testing a Stratocaster in the Fender factory, sometime in the mid-to-late 1950s. Photo courtesy of Richard Smith. Many places deserve to be called the birthplace of rock ’n’ roll. Memphis often gets the nod because that’s where Sam Phillips of Sun Records recorded Elvis Presley belting out an impromptu, uptempo cover of “That’s All Right” in 1954. Cleveland makes the list since it’s the place where, in 1951, a local disc jockey named Alan Freed coined the genre’s name. Chicago’s claim precedes Cleveland’s by several years; in 1948, McKinley Morganfield, aka Muddy Waters, took the tiny stage of a neighborhood tavern called Club Zanzibar, pulled up a chair, and played his hollow-body electric guitar so loud, the sounds emanating from his small amplifier ",Hacker News,13523302,"Title: Who Built the First Electric Rock 'N' Roll Guitar? (2019); Content: - — - - George Fullerton (left) testing a Stratocaster in the Fender factory, sometime in the mid-to-late 1950s. Photo courtesy of Richard Smith. Many places deserve to be called the birthplace of rock ’n’ roll. Memphis often gets the nod because that’s where Sam Phillips of Sun Records recorded Elvis Presley belting out an impromptu, uptempo cover of “That’s All Right” in 1954. Cleveland makes the list since it’s the place where, in 1951, a local disc jockey named Alan Freed coined the genre’s name. Chicago’s claim precedes Cleveland’s by several years; in 1948, McKinley Morganfield, aka Muddy Waters, took the tiny stage of a neighborhood tavern called Club Zanzibar, pulled up a chair, and played his hollow-body electric guitar so loud, the sounds emanating from his small amplifier ",227 -soheil,32407114,68,1660097115,Gmail Dynamic Email (a.k.a. AMP for Email),https://support.google.com/a/answer/9709409?hl=en,"  . Gmail supports , messages with interactive content. Dynamic email is sometimes called for email. You can interact with dynamic email like you would a website. For example, you can reply to an event invitation, or respond to comments in a Google Doc, without leaving Gmail. This article describes how dynamic email works with compliance rules, including: Because of the dynamic nature of AMP messages, the content displayed in Gmail messages can change as time passes. For example, a comment notification email from a Google Doc can have different contents each time the recipient opens the email. Every time someone replies to a comment, the reply is added to the notification email. Read about the . Dynamic email messages have both static and dynamic content. Compliance rules are applied t",Hacker News,25456984,"Title: Gmail Dynamic Email (a.k.a. AMP for Email); Content:   . Gmail supports , messages with interactive content. Dynamic email is sometimes called for email. You can interact with dynamic email like you would a website. For example, you can reply to an event invitation, or respond to comments in a Google Doc, without leaving Gmail. This article describes how dynamic email works with compliance rules, including: Because of the dynamic nature of AMP messages, the content displayed in Gmail messages can change as time passes. For example, a comment notification email from a Google Doc can have different contents each time the recipient opens the email. Every time someone replies to a comment, the reply is added to the notification email. Read about the . Dynamic email messages have both static and dynamic content. Compliance rules are applied t",171 -bane,32420761,11,1660183290,The Car-Replacement Bicycle (The Bakfiets),https://www.youtube.com/watch?v=rQhzEnWCgHA,,Hacker News,9829728,Title: The Car-Replacement Bicycle (The Bakfiets); Content: ,17 -InTheArena,32417675,29,1660162033,Jeff Geerling Is Sick,https://www.youtube.com/watch?v=MXxPsWjMW1A,,Hacker News,8606267,Title: Jeff Geerling Is Sick; Content: ,12 -kristianpaul,32407361,109,1660099523,Mental Model Practices,https://mmpractices.com/,,Hacker News,79559267,Title: Mental Model Practices; Content: ,9 -pseudolus,32406452,107,1660091068,Artificial synapses 10k times faster than real thing,https://spectrum.ieee.org/artificial-synapses,"IEEE websites place cookies on your device to give you the best user experience. By using our websites, you agree to the placement of these cookies. To learn more, read our Privacy Policy. New protonic programmable resistors may help speed learning in deep neural networks New artificial versions of the neurons and synapses in the human brain may be as small as one-thousandth the size of neurons and at least 10,000 times as fast as biological synapses, a study now finds. These new devices may help improve the speed at which the increasingly common and powerful artificial-intelligence systems known as deep neural networks learn, researchers say. In artificial , electrical components dubbed “neurons” are fed data and cooperate to solve a problem, such as recognizing images. The neural net re",Hacker News,64464016,"Title: Artificial synapses 10k times faster than real thing; Content: IEEE websites place cookies on your device to give you the best user experience. By using our websites, you agree to the placement of these cookies. To learn more, read our Privacy Policy. New protonic programmable resistors may help speed learning in deep neural networks New artificial versions of the neurons and synapses in the human brain may be as small as one-thousandth the size of neurons and at least 10,000 times as fast as biological synapses, a study now finds. These new devices may help improve the speed at which the increasingly common and powerful artificial-intelligence systems known as deep neural networks learn, researchers say. In artificial , electrical components dubbed “neurons” are fed data and cooperate to solve a problem, such as recognizing images. The neural net re",177 -todsacerdoti,32401480,49,1660068205,Federation vs. Clustering: Self-determination vs. distributed computing?,https://sequentialread.com/federation-vs-clustering-self-hosting/,"In my , I wrote a about how I'm changing direction away from my . I also wrote little bit about where I want to go with my software projects in the future. In this post, I'm going to expand further on that. In fact, I'm writing this now so that I can help myself organize my thoughts and clarify my own ideas. Last time I said that I wanted to produce a piece of software in which two server admins' servers can ""federate"" with each-other. Another 3rd friend who doesn't run thier own server can have an account on these two servers. If the server on which the account was originally registered gets powered off or lost in a fire, the friend can still log in and use their account like normal on the one remaining server. However, I think when I said ""federates"", it may have been a bit of a misn",Hacker News,60800329,"Title: Federation vs. Clustering: Self-determination vs. distributed computing?; Content: In my , I wrote a about how I'm changing direction away from my . I also wrote little bit about where I want to go with my software projects in the future. In this post, I'm going to expand further on that. In fact, I'm writing this now so that I can help myself organize my thoughts and clarify my own ideas. Last time I said that I wanted to produce a piece of software in which two server admins' servers can ""federate"" with each-other. Another 3rd friend who doesn't run thier own server can have an account on these two servers. If the server on which the account was originally registered gets powered off or lost in a fire, the friend can still log in and use their account like normal on the one remaining server. However, I think when I said ""federates"", it may have been a bit of a misn",206 -geox,32421137,6,1660187549,Scientists identify mechanism crucial for Covid virus replication,https://www.utsouthwestern.edu/newsroom/articles/year-2022/august-covid-19-virus-replication.html,"Newsroom -   - Findings could lead to new strategies to treat COVID-19 infections DALLAS – Aug. 10, 2022 – A team led by UT Southwestern researchers has identified how SARS-CoV-2, the virus that causes COVID-19, builds a structure called the RNA cap that’s critical for successful viral replication. The finding, published in , could lead to new strategies to attack COVID-19, which has sickened nearly 600 million and killed more than 6 million worldwide thus far. “We’re very excited to exploit and make drugs against this protein domain to inhibit RNA cap formation, which, if successful, could offer a whole new approach to treat COVID-19,” said study leader , Associate Professor of Molecular Biology, the Michael L. Rosenberg Scholar in Medical Research at UTSW, and a Howard Hug",Hacker News,39231598,"Title: Scientists identify mechanism crucial for Covid virus replication; Content: Newsroom -   - Findings could lead to new strategies to treat COVID-19 infections DALLAS – Aug. 10, 2022 – A team led by UT Southwestern researchers has identified how SARS-CoV-2, the virus that causes COVID-19, builds a structure called the RNA cap that’s critical for successful viral replication. The finding, published in , could lead to new strategies to attack COVID-19, which has sickened nearly 600 million and killed more than 6 million worldwide thus far. “We’re very excited to exploit and make drugs against this protein domain to inhibit RNA cap formation, which, if successful, could offer a whole new approach to treat COVID-19,” said study leader , Associate Professor of Molecular Biology, the Michael L. Rosenberg Scholar in Medical Research at UTSW, and a Howard Hug",213 -fuegoio,32405510,93,1660084946,"Show HN: 1024, a 2048 Puzzle Game",https://1024-game.netlify.app/,,Hacker News,2946961,"Title: Show HN: 1024, a 2048 Puzzle Game; Content: ",16 -azalemeth,32383820,416,1659952551,Open AirPlay 2 Receiver,https://github.com/openairplay/airplay2-receiver," - AirPlay 2 Receiver - Python implementation - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. Somewhat comprehensive python implementation of AP2 receiver using features. For now it implements: For now it does not implement: It may never implement: Next steps: Since multithreading is now enabled, this allows multiple concurrent connections. There are no safeguards -built to prevent you playing multiple streams. Python multiprocessing makes this ""DJ"" mode a -possibility but makes",Hacker News,33625762,"Title: Open AirPlay 2 Receiver; Content: - AirPlay 2 Receiver - Python implementation - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. Somewhat comprehensive python implementation of AP2 receiver using features. For now it implements: For now it does not implement: It may never implement: Next steps: Since multithreading is now enabled, this allows multiple concurrent connections. There are no safeguards -built to prevent you playing multiple streams. Python multiprocessing makes this ""DJ"" mode a -possibility but makes",239 -astonfred,32415055,31,1660150403,Directory of canned responses. If you lack inspiration,https://cannedtxt.com/,,Hacker News,9000037,Title: Directory of canned responses. If you lack inspiration; Content: ,15 -bryanrasmussen,32421538,10,1660191505,Hollywood’s Visual Effects Crisis,https://defector.com/inside-hollywoods-visual-effects-crisis/,"A head of hair is a wild, unreliable thing. It never stays the same length. It never stays in the same place, unless you have Doctor Strange amounts of pomade on you. Look in the mirror right now and you’ll inevitably find not one, but many stray hairs poking out this way and that. It’s unavoidable but also quite natural for hair to behave this way.  It is also a massive problem if you happen to be making a film or a television show. When you shoot an actor in one location but have to digitally relocate them to another, which happens quite frequently, you have to bring along every last follicular imperfection with them. According to a compositor who worked on the first movie, this is not an easy task. Far from it. “The heli-carrier sequence was shot on a runway in New Mexico. Scarlett Joh",Hacker News,73631725,"Title: Hollywood’s Visual Effects Crisis; Content: A head of hair is a wild, unreliable thing. It never stays the same length. It never stays in the same place, unless you have Doctor Strange amounts of pomade on you. Look in the mirror right now and you’ll inevitably find not one, but many stray hairs poking out this way and that. It’s unavoidable but also quite natural for hair to behave this way.  It is also a massive problem if you happen to be making a film or a television show. When you shoot an actor in one location but have to digitally relocate them to another, which happens quite frequently, you have to bring along every last follicular imperfection with them. According to a compositor who worked on the first movie, this is not an easy task. Far from it. “The heli-carrier sequence was shot on a runway in New Mexico. Scarlett Joh",194 -erulabs,32401691,133,1660069027,How and why to host a blog at home,https://kubesail.com/blog/2022-08-08-how-and-why,,Hacker News,90863659,Title: How and why to host a blog at home; Content: ,15 -camjohnson26,32416766,37,1660157535,Ralph Nader urges regulators to recall Tesla’s ‘manslaughtering’ FSD vehicles,https://www.theverge.com/2022/8/10/23299973/ralph-nader-tesla-fsd-recall-nhtsa-autopilot-crash,"We use cookies and other tracking technologies to improve your browsing experience on our site, show personalized content and targeted ads, analyze site traffic, and understand where our audiences come from. To learn more or opt-out, read our . Please also read our and , which became effective December 20, 2019. By choosing , you consent to our use of cookies and other tracking technologies. Filed under: Nader called FSD ‘one of the most dangerous and irresponsible actions by a car company in decades’ Ralph Nader, a former presidential candidate and nationally recognized consumer protection advocate, called on federal regulators to recall Tesla’s “Full Self-Driving” (FSD) driver-assist feature, calling its deployment “one of the most dangerous and irresponsible actions by a car compan",Hacker News,42220676,"Title: Ralph Nader urges regulators to recall Tesla’s ‘manslaughtering’ FSD vehicles; Content: We use cookies and other tracking technologies to improve your browsing experience on our site, show personalized content and targeted ads, analyze site traffic, and understand where our audiences come from. To learn more or opt-out, read our . Please also read our and , which became effective December 20, 2019. By choosing , you consent to our use of cookies and other tracking technologies. Filed under: Nader called FSD ‘one of the most dangerous and irresponsible actions by a car company in decades’ Ralph Nader, a former presidential candidate and nationally recognized consumer protection advocate, called on federal regulators to recall Tesla’s “Full Self-Driving” (FSD) driver-assist feature, calling its deployment “one of the most dangerous and irresponsible actions by a car compan",194 -whoami_nr,32403504,126,1660075562,Tornado cash takedown and its repercussions,https://rnikhil.com/2022/08/09/tornado-cash-block.html,"” If you have nothing to hide, you have nothing to fear” This is a common saying parroted by folks (made popular in the US after 9/11) for justifying many types of surveillance. It is also sometimes mistakenly used to justify the current blanket surveillance we all are a victim of. With the development in technology and rapid increase of surveillance budgets, law enforcement has gotten a lot easier as well. Recently, Tornado cash, a used to obfuscate the origin and destination of your money has been by the US Treasury. The implications prevent anybody from transacting with them which means, all the money held in their smart contract is effectively tainted. Funnily enough, they blacklisted only the contract address on the Ethereum but not the contract on Arbitrum or BSC. While it is n",Hacker News,37116449,"Title: Tornado cash takedown and its repercussions; Content: ” If you have nothing to hide, you have nothing to fear” This is a common saying parroted by folks (made popular in the US after 9/11) for justifying many types of surveillance. It is also sometimes mistakenly used to justify the current blanket surveillance we all are a victim of. With the development in technology and rapid increase of surveillance budgets, law enforcement has gotten a lot easier as well. Recently, Tornado cash, a used to obfuscate the origin and destination of your money has been by the US Treasury. The implications prevent anybody from transacting with them which means, all the money held in their smart contract is effectively tainted. Funnily enough, they blacklisted only the contract address on the Ethereum but not the contract on Arbitrum or BSC. While it is n",180 -panarky,32421372,7,1660189790,How the New York Times Uses Machine Learning to Make Its Paywall Smarter,https://open.nytimes.com/how-the-new-york-times-uses-machine-learning-to-make-its-paywall-smarter-e5771d5f46f8?gi=fe03f90b8e13,"NYT Open Save The New York Times launched its paywall in March 2011, beginning its journey as a subscription-first news and lifestyle service. Since its inception, this “metered” access service has been designed so that nonsubscribers can read a fixed number of articles every month before encountering a paywall; this article limit is widely referred to as the “meter limit.” This strategy has proven successful in generating subscriptions while at the same time allowing for initial exploratory access to new readers. In fact, in February 2022, when The Times acquired The Athletic Media Company, The Times achieved its goal of 10 million subscriptions and set a of 15 million subscribers by the end of 2027. This success has been possible in part due to continuous improvements in the paywall st",Hacker News,28664705,"Title: How the New York Times Uses Machine Learning to Make Its Paywall Smarter; Content: NYT Open Save The New York Times launched its paywall in March 2011, beginning its journey as a subscription-first news and lifestyle service. Since its inception, this “metered” access service has been designed so that nonsubscribers can read a fixed number of articles every month before encountering a paywall; this article limit is widely referred to as the “meter limit.” This strategy has proven successful in generating subscriptions while at the same time allowing for initial exploratory access to new readers. In fact, in February 2022, when The Times acquired The Athletic Media Company, The Times achieved its goal of 10 million subscriptions and set a of 15 million subscribers by the end of 2027. This success has been possible in part due to continuous improvements in the paywall st",181 -Meph504,32415256,22,1660151095,Tell HN: Network solution added .online to all of our domains,,"We have a number of very old domains that have been with network solutions since the late 1990s. Today we get a renewal notice for olddomain.online

log into our account to find all of these, and being redirected to our domain.

After like an hour of trying to track down the various people in our org who could have possibly done this. Our accountant find an email sent to her, saying as we have been "upgraded" as part of network solutions "Brand Protection Program"

Anyone else with network solutions notice this on your domains?",Hacker News,57567524,"Title: Tell HN: Network solution added .online to all of our domains; Content: We have a number of very old domains that have been with network solutions since the late 1990s. Today we get a renewal notice for olddomain.online

log into our account to find all of these, and being redirected to our domain.

After like an hour of trying to track down the various people in our org who could have possibly done this. Our accountant find an email sent to her, saying as we have been "upgraded" as part of network solutions "Brand Protection Program"

Anyone else with network solutions notice this on your domains?",150 -indygreg2,32386762,306,1659972891,Achieving an open-source implementation of Apple Code Signing and notarization,https://gregoryszorc.com/blog/2022/08/08/achieving-a-completely-open-source-implementation-of-apple-code-signing-and-notarization/,"As I've previously blogged in - -(2021-04-14) and - -(2022-04-25), I've been hacking on an open source implementation of Apple code -signing and notarization using the Rust programming language. This takes the form -of the crate / library and its CLI executable. -( / - / - ). As of that most recent post in April, I was pretty happy with the relative -stability of the implementation: we were able to sign, notarize, and staple -Mach-O binaries, directory bundles ( , bundles, etc), XAR -archives / flat packages / installers, and DMG disk images. Except for -the , -if Apple's official and tools support it, so do we. - This opens up new avenues for -Apple platform access. A major limitation in previous versions of the crate was our -reliance on Apple's -tool for notarization. Transporter is",Hacker News,39974621,"Title: Achieving an open-source implementation of Apple Code Signing and notarization; Content: As I've previously blogged in - -(2021-04-14) and - -(2022-04-25), I've been hacking on an open source implementation of Apple code -signing and notarization using the Rust programming language. This takes the form -of the crate / library and its CLI executable. -( / - / - ). As of that most recent post in April, I was pretty happy with the relative -stability of the implementation: we were able to sign, notarize, and staple -Mach-O binaries, directory bundles ( , bundles, etc), XAR -archives / flat packages / installers, and DMG disk images. Except for -the , -if Apple's official and tools support it, so do we. - This opens up new avenues for -Apple platform access. A major limitation in previous versions of the crate was our -reliance on Apple's -tool for notarization. Transporter is",243 -eke_uche,32409980,10,1660128470,Show HN: Genti Audio – Stories and podcasts in African languages,https://gentimedia.com/,"Hi all, -Eke here, co-founder of Genti Audio. Genti Audio is a mobile app for streaming and downloading Africa-focused audiobooks, stories, and podcasts in regional and local African languages.

In September 2021, my sister and I sat down to work on an audio show exploring Nigeria’s cultural and linguistic diversity. As we began to put the show together, we realized that our target audience- Nigerians and Africans in both urban and rural areas, were not heavily present on any of the major audio platforms for this type of content. Recognizing this, we decided to first fix this distribution gap, and so the idea for Genti was born.

From just an idea, we began pooling resources and soon started developing our beta app. And after months of hard work building, scouring for content, and raising funds from supportive friends and family, we are very excited to announce the launch of our mobile app. We will continue to improve the app and roll out more features over the next 4 months. Download the App now on Google Play or the Apple App Store and start listening!

At Genti, our mission is to amplify African stories and voices to entertain, educate, and enrich lives. In line with our mission, we’ll spend the next 3 - 6 months getting the best entertaining and educative African audio content out there and curating for our users. We also believe that for every African story told there are hundreds waiting to be told, and that’s why we’ve begun working on developing engaging original content available exclusively on our platform. Genti is committed to playing a vital role in developing and deepening audio storytelling on the continent.

To download the app, visit the Genti website, or download directly from Google Play and the Apple App store and start listening!

If you’ve got a podcast, audiobook, or story you’d like to upload on Genti, please send an email to ojiugo@gentimedia.com and we’ll be in touch. We’d also love to get feedback from you on your experience with the Genti App.",Hacker News,78080007,"Title: Show HN: Genti Audio – Stories and podcasts in African languages; Content: Hi all, -Eke here, co-founder of Genti Audio. Genti Audio is a mobile app for streaming and downloading Africa-focused audiobooks, stories, and podcasts in regional and local African languages.

In September 2021, my sister and I sat down to work on an audio show exploring Nigeria’s cultural and linguistic diversity. As we began to put the show together, we realized that our target audience- Nigerians and Africans in both urban and rural areas, were not heavily present on any of the major audio platforms for this type of content. Recognizing this, we decided to first fix this distribution gap, and so the idea for Genti was born.

From just an idea, we began pooling resources and soon started developing our beta app. And after months of hard work building, scouring for content, and raising funds from supportive friends and family, we are very excited to announce the launch of our mobile app. We will continue to improve the app and roll out more features over the next 4 months. Download the App now on Google Play or the Apple App Store and start listening!

At Genti, our mission is to amplify African stories and voices to entertain, educate, and enrich lives. In line with our mission, we’ll spend the next 3 - 6 months getting the best entertaining and educative African audio content out there and curating for our users. We also believe that for every African story told there are hundreds waiting to be told, and that’s why we’ve begun working on developing engaging original content available exclusively on our platform. Genti is committed to playing a vital role in developing and deepening audio storytelling on the continent.

To download the app, visit the Genti website, or download directly from Google Play and the Apple App store and start listening!

If you’ve got a podcast, audiobook, or story you’d like to upload on Genti, please send an email to ojiugo@gentimedia.com and we’ll be in touch. We’d also love to get feedback from you on your experience with the Genti App.",468 -fortran77,32421292,7,1660189141,The Hacking of Starlink Terminals Has Begun,https://www.wired.com/story/starlink-internet-dish-hack/,"To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . Musk’s has more than 3,000 small satellites into orbit. This satellite network beams internet connections to hard-to-reach locations on Earth and has been a . Thousands more satellites are planned for launch as the . Now, like any emerging technology, those satellite components are being hacked. Today, Lennert Wouters, a security researcher at the Belgian university KU Leuven, will reveal one of the first security breakdowns of Starlink’s user terminals, the satellite dishes (dubbed Dishy McFlatface) that are positioned on people’s homes and buildings. At the in Las Vegas, Wouters wil",Hacker News,69040967,"Title: The Hacking of Starlink Terminals Has Begun; Content: To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . Musk’s has more than 3,000 small satellites into orbit. This satellite network beams internet connections to hard-to-reach locations on Earth and has been a . Thousands more satellites are planned for launch as the . Now, like any emerging technology, those satellite components are being hacked. Today, Lennert Wouters, a security researcher at the Belgian university KU Leuven, will reveal one of the first security breakdowns of Starlink’s user terminals, the satellite dishes (dubbed Dishy McFlatface) that are positioned on people’s homes and buildings. At the in Las Vegas, Wouters wil",211 -efavdb,32381206,276,1659917551,Spaced repetition can allow for infinite recall,https://www.efavdb.com/memory%20recall," - - My friend Andrew is an advocate of the “spaced repetition” technique for -memorization of a great many facts [1]. The ideas behind this are two-fold: When one first “learns” a new fact, it needs to be reviewed frequently in - order to not forget it. However, with each additional review, the fact can -be retained longer before a refresher is needed to maintain it in recall. Because of this, one can maintain a large, growing body of facts in recall - through daily review: Each day, one need only review for ten minutes or so, -covering a small number of facts. The facts included should be sampled from the -full library in a way that prefers newer entries, but that also sprinkles in -older facts often enough so that none are ever forgotten. Apps have been -written to intelligently take care ",Hacker News,9122326,"Title: Spaced repetition can allow for infinite recall; Content: - - My friend Andrew is an advocate of the “spaced repetition” technique for -memorization of a great many facts [1]. The ideas behind this are two-fold: When one first “learns” a new fact, it needs to be reviewed frequently in - order to not forget it. However, with each additional review, the fact can -be retained longer before a refresher is needed to maintain it in recall. Because of this, one can maintain a large, growing body of facts in recall - through daily review: Each day, one need only review for ten minutes or so, -covering a small number of facts. The facts included should be sampled from the -full library in a way that prefers newer entries, but that also sprinkles in -older facts often enough so that none are ever forgotten. Apps have been -written to intelligently take care ",208 -nkmnz,32410333,35,1660131757,Ask HN: List of titles and specifications for tech jobs?,,"As jobs get more and more differentiated, it's getting harder for the "uninitiated" to find the right wording that speaks to the right people. Is there a conclusive list of job titles and specifications one could rely on?

FWIW, I'm looking for someone to lead all engineering efforts wrt to "everything analytics": -- what to measure and where to measure (EDIT: meaning "which actions, e.g. clicks, constitute the start of a specific action? How can we determine that a user stopped for break? etc... more details below!) -- which tools to use -- how to integrate libraries/services -- where to store data -- how to access raw data -- how to process raw data -- how to access processed information

... at a 10-15 person (six developers) Startup.

EDIT: To answer the questions below and specify the role: we're in EdTech, so the data we want to gather is used to 1) give users an overview of and feedback about their activity, 2) create effective and evidence-based interventions, and 3) improve learning outcomes and engagement. More detailed objectives are determined by management and research roles, but they still need to be translated into code – almost like a restaurant owner can tell a chef to make a specific dish, but the chef still needs to know which pan to use.",Hacker News,48334007,"Title: Ask HN: List of titles and specifications for tech jobs?; Content: As jobs get more and more differentiated, it's getting harder for the "uninitiated" to find the right wording that speaks to the right people. Is there a conclusive list of job titles and specifications one could rely on?

FWIW, I'm looking for someone to lead all engineering efforts wrt to "everything analytics": -- what to measure and where to measure (EDIT: meaning "which actions, e.g. clicks, constitute the start of a specific action? How can we determine that a user stopped for break? etc... more details below!) -- which tools to use -- how to integrate libraries/services -- where to store data -- how to access raw data -- how to process raw data -- how to access processed information

... at a 10-15 person (six developers) Startup.

EDIT: To answer the questions below and specify the role: we're in EdTech, so the data we want to gather is used to 1) give users an overview of and feedback about their activity, 2) create effective and evidence-based interventions, and 3) improve learning outcomes and engagement. More detailed objectives are determined by management and research roles, but they still need to be translated into code – almost like a restaurant owner can tell a chef to make a specific dish, but the chef still needs to know which pan to use.",340 -_Microft,32399368,101,1660059227,Noether's Theorem in a Nutshell (2020),https://math.ucr.edu/home/baez/noether.html," -Noether's theorem is an amazing result which lets physicists get -conserved quantities from symmetries of the laws of nature. Time -translation symmetry gives conservation of energy; space translation -symmetry gives conservation of momentum; rotation symmetry gives -conservation of angular momentum, and so on. - - -This result, proved in 1915 by shortly after she first arrived in Göttingen, was praised -by Einstein as a piece of ""penetrating mathematical -thinking"". It's now a standard workhorse in theoretical physics. - - -These days, students often first meet this theorem in a course on -quantum field theory. That can make it seem more complicated than it -really is. It works for classical field theory, not just quantum field -theory. And it also works for the classical mechanics of a point -",Hacker News,44627177,"Title: Noether's Theorem in a Nutshell (2020); Content: -Noether's theorem is an amazing result which lets physicists get -conserved quantities from symmetries of the laws of nature. Time -translation symmetry gives conservation of energy; space translation -symmetry gives conservation of momentum; rotation symmetry gives -conservation of angular momentum, and so on. - - -This result, proved in 1915 by shortly after she first arrived in Göttingen, was praised -by Einstein as a piece of ""penetrating mathematical -thinking"". It's now a standard workhorse in theoretical physics. - - -These days, students often first meet this theorem in a course on -quantum field theory. That can make it seem more complicated than it -really is. It works for classical field theory, not just quantum field -theory. And it also works for the classical mechanics of a point -",198 -graderjs,32396641,132,1660046214,How do palm trees survive hurricanes? (2017),https://www.indefenseofplants.com/blog/2017/9/10/how-do-palms-survive-hurricanes,"U.S. Navy photo by Jim Brooks public domain The destructive force of typhoons and hurricanes are no joking matter. Human structures are torn to shreds and flooded in the blink of an eye. It is devastating to say the least. With all of this destruction, one must wonder how native flora and fauna have coped with such forces over millions of years. The true survivors of these sorts of storms are the palms. What would completely shred an oak seems to ruffle a palm tree. What is it about palms that allows them to survive these storms intact?  To better understand palm adaptations, one must first consider their place on the evolutionary tree. Palms are monocots and they have more in common with grasses than they do trees like oaks or pines. Their wood evolved independently of other tree species.",Hacker News,54601366,"Title: How do palm trees survive hurricanes? (2017); Content: U.S. Navy photo by Jim Brooks public domain The destructive force of typhoons and hurricanes are no joking matter. Human structures are torn to shreds and flooded in the blink of an eye. It is devastating to say the least. With all of this destruction, one must wonder how native flora and fauna have coped with such forces over millions of years. The true survivors of these sorts of storms are the palms. What would completely shred an oak seems to ruffle a palm tree. What is it about palms that allows them to survive these storms intact?  To better understand palm adaptations, one must first consider their place on the evolutionary tree. Palms are monocots and they have more in common with grasses than they do trees like oaks or pines. Their wood evolved independently of other tree species.",181 -ss48,32415224,23,1660150991,Amazon Kindle Moving from MOBI to ePub File Format,https://goodereader.com/blog/kindle/everything-you-need-to-know-about-the-amazon-kindle-supporting-epub,"Good e-Reader By Amazon is going to be later this year. Customers will be able to use Send to Kindle to upload EPUB books directly to their e-reader. Amazon is working on the system integration right now and should be rolled out globally in August. You will be able to send EPUB books using your Send to Kindle email address. The company will also be adding EPUB support to the free Kindle app for iOS and Android devices and the Send to Kindle desktop app for PC and Mac. The Amazon Kindle will only be able to accept DRM-Free EPUB files, so they can’t handle books that have purchased from other ebook retailers. When you upload a DRM-Free EPUB book using the Send to Kindle feature, Amazon will not be natively supporting this file format. Instead, they will be converting the EPUB book to K",Hacker News,16018480,"Title: Amazon Kindle Moving from MOBI to ePub File Format; Content: Good e-Reader By Amazon is going to be later this year. Customers will be able to use Send to Kindle to upload EPUB books directly to their e-reader. Amazon is working on the system integration right now and should be rolled out globally in August. You will be able to send EPUB books using your Send to Kindle email address. The company will also be adding EPUB support to the free Kindle app for iOS and Android devices and the Send to Kindle desktop app for PC and Mac. The Amazon Kindle will only be able to accept DRM-Free EPUB files, so they can’t handle books that have purchased from other ebook retailers. When you upload a DRM-Free EPUB book using the Send to Kindle feature, Amazon will not be natively supporting this file format. Instead, they will be converting the EPUB book to K",201 -HelenePhisher,32377063,547,1659884910,Fake IMDB credits,https://peabee.substack.com/p/16-the-case-of-fake-imdb-credits,"I was casually browsing IMDb when I landed on the page for an upcoming Ranbir Kapoor starrer movie “Animal”. I saw the cast details and I found a face and a name I didn’t recognize. Finding out about this guy led me to a whole new world of how so many young Indian men from small towns are gaming the system to manufacture their own fake online clout. So who is this guy? I had not heard of him before and he is named in the “Top cast” category for this movie, alongside Ranbir Kapoor. I checked his IMDb page and this is what his bio and filmography look like. According to this, he has acting credits in some big-budget productions. I am beginning to suspect that this could be a case of IMDb vandalism. IMDb allows anyone to add and edit pages. They don’t allow you to see the edit history of a",Hacker News,44399816,"Title: Fake IMDB credits; Content: I was casually browsing IMDb when I landed on the page for an upcoming Ranbir Kapoor starrer movie “Animal”. I saw the cast details and I found a face and a name I didn’t recognize. Finding out about this guy led me to a whole new world of how so many young Indian men from small towns are gaming the system to manufacture their own fake online clout. So who is this guy? I had not heard of him before and he is named in the “Top cast” category for this movie, alongside Ranbir Kapoor. I checked his IMDb page and this is what his bio and filmography look like. According to this, he has acting credits in some big-budget productions. I am beginning to suspect that this could be a case of IMDb vandalism. IMDb allows anyone to add and edit pages. They don’t allow you to see the edit history of a",205 -LinuxBender,32414954,34,1660150006,Iran cheerfully admits using cryptocurrency to pay for imports,https://www.theregister.com/2022/08/10/iran_pays_for_imports_in_crypto/,,Hacker News,56023237,Title: Iran cheerfully admits using cryptocurrency to pay for imports; Content: ,16 -fest,32394607,154,1660024283,The tooling ecosystem that adds joy to KiCad,https://media.ccc.de/v/mch2022-332-the-tooling-ecosystem-that-adds-joy-to-kicad," - - and - - - A number of people have built wonderful and useful tools to make the life of KiCad users easier. cpresser and Kliment are here to give you a tour of a number of the most useful addons, and show you what they're good for and how they can improve your life. - We will go through a number of tools that people have built into the KiCad ecosystem - you may have used some of them, but a surprising number of KiCad users aren't aware they exist. We're here to fix that. We'll show you how to make your boards have fancy labels, how to get an interactive assembly guide for your designs, how to easily pack a bunch of boards in a production panel, how to automatically generate footprints, how to make your PCBs fit the real world, how to not repeat your effort when making lots of the same c",Hacker News,90918577,"Title: The tooling ecosystem that adds joy to KiCad; Content: - - and - - - A number of people have built wonderful and useful tools to make the life of KiCad users easier. cpresser and Kliment are here to give you a tour of a number of the most useful addons, and show you what they're good for and how they can improve your life. - We will go through a number of tools that people have built into the KiCad ecosystem - you may have used some of them, but a surprising number of KiCad users aren't aware they exist. We're here to fix that. We'll show you how to make your boards have fancy labels, how to get an interactive assembly guide for your designs, how to easily pack a bunch of boards in a production panel, how to automatically generate footprints, how to make your PCBs fit the real world, how to not repeat your effort when making lots of the same c",206 -ingve,32399663,108,1660060705,Implementing parts of the Swift compiler in Swift,https://forums.swift.org/t/implementing-parts-of-the-swift-compiler-in-swift/59524,"Hi all, In the past few years, some components of the Swift compiler have started being implemented in Swift, including: All of these components are for one reason or another. The new Swift Driver is optional because we are still maintaining the existing , which can be used for building a compiler with a host that doesn’t support Swift. Regular expression literals and the new SIL optimization passes are optional because we can build a compiler without them, then use that compiler to build a new compiler with them. All of this means that it is still possible to build a (mostly) working Swift compiler on a host where there is no existing Swift compiler, using the host C++ compiler. I propose that we start requiring an existing Swift compiler to build the Swift compiler. This opens the doo",Hacker News,59880085,"Title: Implementing parts of the Swift compiler in Swift; Content: Hi all, In the past few years, some components of the Swift compiler have started being implemented in Swift, including: All of these components are for one reason or another. The new Swift Driver is optional because we are still maintaining the existing , which can be used for building a compiler with a host that doesn’t support Swift. Regular expression literals and the new SIL optimization passes are optional because we can build a compiler without them, then use that compiler to build a new compiler with them. All of this means that it is still possible to build a (mostly) working Swift compiler on a host where there is no existing Swift compiler, using the host C++ compiler. I propose that we start requiring an existing Swift compiler to build the Swift compiler. This opens the doo",175 -jeremylevy,32399752,96,1660061004,"Show HN: Recode – Free, open-source, community-driven Codespaces alternative",https://github.com/recode-sh/cli,"Hey HN,

As most of you (I think?), I cannot learn something without having a project, on the side, to implement what I’ve just learned.

Recode is the project that I've used to learn Go. It lets you create a development environment in your cloud provider account easily.

You can think of it as a desktop version of Gitpod / Coder / GitHub Codespaces less polished and with less features but 100% free, 100% open-source and 100% community-driven.

At the time of writing, it only works with Visual Studio Code and AWS.

In order to let you configure your development environments easily, I’ve chosen to use Docker with some Dockerfiles:

   - One for your user configuration.
-   
-   - One for your project.
-
-The user configuration corresponds to the tools / settings that you use in all your projects like your timezone / locale, your preferred shell or your dotfiles.

The project configuration corresponds to the tools / settings that you use in a specific project like Go >= 1.18 and Node.js >= 14.

As you may have guessed, the project configuration inherits from the user one.

> Why Docker and not something like NixOS, for example?

I know that containers are not meant to be used as a VM like that, but, at the time of writing, Docker is still the most widely used tool among developers to configure their environment (even if it may certainly change in the future :-)).

> Given that my dev env will run in a container does it mean that it will be limited?

Mostly not.

Given the scope of this project (a private instance running in your own cloud provider account), Docker is mostly used for configuration purpose and not to "isolate" the VM from your environment.

As a result, your development environment container runs in privileged mode in the same network than the host.

----

I post this here, because, you know, even learning project could be useful to someone.

Still learning Go by the way, so I'm open to any suggestions to improve.",Hacker News,57599617,"Title: Show HN: Recode – Free, open-source, community-driven Codespaces alternative; Content: Hey HN,

As most of you (I think?), I cannot learn something without having a project, on the side, to implement what I’ve just learned.

Recode is the project that I've used to learn Go. It lets you create a development environment in your cloud provider account easily.

You can think of it as a desktop version of Gitpod / Coder / GitHub Codespaces less polished and with less features but 100% free, 100% open-source and 100% community-driven.

At the time of writing, it only works with Visual Studio Code and AWS.

In order to let you configure your development environments easily, I’ve chosen to use Docker with some Dockerfiles:

   - One for your user configuration.
-   
-   - One for your project.
-
-The user configuration corresponds to the tools / settings that you use in all your projects like your timezone / locale, your preferred shell or your dotfiles.

The project configuration corresponds to the tools / settings that you use in a specific project like Go >= 1.18 and Node.js >= 14.

As you may have guessed, the project configuration inherits from the user one.

> Why Docker and not something like NixOS, for example?

I know that containers are not meant to be used as a VM like that, but, at the time of writing, Docker is still the most widely used tool among developers to configure their environment (even if it may certainly change in the future :-)).

> Given that my dev env will run in a container does it mean that it will be limited?

Mostly not.

Given the scope of this project (a private instance running in your own cloud provider account), Docker is mostly used for configuration purpose and not to "isolate" the VM from your environment.

As a result, your development environment container runs in privileged mode in the same network than the host.

----

I post this here, because, you know, even learning project could be useful to someone.

Still learning Go by the way, so I'm open to any suggestions to improve.",551 -Dezocine,32410307,29,1660131554,Francis Fukuyama: Paths to Depolarization,https://www.persuasion.community/p/fukuyama-paths-to-depolarization,"Polarization—the sharp division of American society between red and blue—is the single greatest weakness of the United States as a country today. We face many challenges at present, over inflation, racial and gender inequality, crime, drug use, climate change, immigration, and the like, and all of these issues become harder if not impossible to solve if Americans fundamentally do not trust one another and seek to block any solution offered by the other side. This weakness is well understood by enemies like Russia’s Vladimir Putin, who has done everything he can to widen those divisions and has acted geopolitically at a moment when he thought the U.S. was too weak and self-preoccupied to respond effectively. Many people have recognized the centrality of polarization and offered solutions fo",Hacker News,68034289,"Title: Francis Fukuyama: Paths to Depolarization; Content: Polarization—the sharp division of American society between red and blue—is the single greatest weakness of the United States as a country today. We face many challenges at present, over inflation, racial and gender inequality, crime, drug use, climate change, immigration, and the like, and all of these issues become harder if not impossible to solve if Americans fundamentally do not trust one another and seek to block any solution offered by the other side. This weakness is well understood by enemies like Russia’s Vladimir Putin, who has done everything he can to widen those divisions and has acted geopolitically at a moment when he thought the U.S. was too weak and self-preoccupied to respond effectively. Many people have recognized the centrality of polarization and offered solutions fo",172 -carride,32397920,168,1660053208,Almost every Ferrari sold since 2005 is being recalled,https://arstechnica.com/cars/2022/08/almost-every-ferrari-sold-since-2005-is-being-recalled/,"Front page layout Site theme Sign up or login to join the discussions! - - - - Spare a thought for Ferrari. Not its F1 team, repeatedly snatching defeat from the jaws of victory as rival Red Bull romps away with the championships, but the road car division, which is in the process of recalling nearly every car it has sold since 2005. The problem is the cap of the brake fluid reservoir. It's designed to vent pressure if necessary, but evidently that design isn't so hot. Venting can fail to happen, causing a vacuum to build up, resulting in a possible leak of brake fluid. And if you don't have any brake fluid in your brake lines, you aren't going to be able to slow down or stop (without hitting something large and solid). The fix is therefore pretty simple—a new brake fluid reservoir ca",Hacker News,86424351,"Title: Almost every Ferrari sold since 2005 is being recalled; Content: Front page layout Site theme Sign up or login to join the discussions! - - - - Spare a thought for Ferrari. Not its F1 team, repeatedly snatching defeat from the jaws of victory as rival Red Bull romps away with the championships, but the road car division, which is in the process of recalling nearly every car it has sold since 2005. The problem is the cap of the brake fluid reservoir. It's designed to vent pressure if necessary, but evidently that design isn't so hot. Venting can fail to happen, causing a vacuum to build up, resulting in a possible leak of brake fluid. And if you don't have any brake fluid in your brake lines, you aren't going to be able to slow down or stop (without hitting something large and solid). The fix is therefore pretty simple—a new brake fluid reservoir ca",194 -oumua_don17,32401510,74,1660068322,Will Intel's AXG division survive Pat Gelsinger’s axe?,https://www.jonpeddie.com/editorials/will-axg-survive-gelsingers-axe/,"Thank you for signing up with us. Start purchasing reports to add to your new account today! Thank you for signing up with us. Start purchasing reports to add to your new account today! START TYPING KEYWORDS TO SEARCH OUR WEBSITE   Intel’s financial report revealed two hard-to-ignore situations. In a quarter where the company reported a loss combined with dropping margins and sales, Pat Gelsinger also jettisoned several non-essential business units that contributed to the drain. Of the groups Gelsinger got rid of was Optane (started in 2017, never made a profit), sold McAfee (bought in 2010, never made a profit), and shut down the drone group (started in 2015, never made a profit). Last year, Intel sold off its NAND business to Hynix, giving up its only Chinese fab, and sold off its money-",Hacker News,90774210,"Title: Will Intel's AXG division survive Pat Gelsinger’s axe?; Content: Thank you for signing up with us. Start purchasing reports to add to your new account today! Thank you for signing up with us. Start purchasing reports to add to your new account today! START TYPING KEYWORDS TO SEARCH OUR WEBSITE   Intel’s financial report revealed two hard-to-ignore situations. In a quarter where the company reported a loss combined with dropping margins and sales, Pat Gelsinger also jettisoned several non-essential business units that contributed to the drain. Of the groups Gelsinger got rid of was Optane (started in 2017, never made a profit), sold McAfee (bought in 2010, never made a profit), and shut down the drone group (started in 2015, never made a profit). Last year, Intel sold off its NAND business to Hynix, giving up its only Chinese fab, and sold off its money-",206 -dthul,32384550,283,1659960639,MiniRust,https://www.ralfj.de/blog/2022/08/08/minirust.html,"I have been thinking about the semantics of Rust – as in, the intended behavior of Rust programs when executed, in particular those containing unsafe code – a lot. -Probably too much. -But all of these thoughts are just in my head, which is not very useful when someone else wants to try and figure out how some tricky bit of unsafe Rust code behaves. -As part of the project, we often get questions asking whether a piece of code is fine or whether it has Undefined Behavior. -But clearly, that doesn’t scale: there are just too many questions to be asked, and figuring out the semantics by interacting with an oracle with many-day latency is rather frustrating. -We have , which is a much quicker oracle, but it’s also not always right and even then, it can just answer questions of the for",Hacker News,98401403,"Title: MiniRust; Content: I have been thinking about the semantics of Rust – as in, the intended behavior of Rust programs when executed, in particular those containing unsafe code – a lot. -Probably too much. -But all of these thoughts are just in my head, which is not very useful when someone else wants to try and figure out how some tricky bit of unsafe Rust code behaves. -As part of the project, we often get questions asking whether a piece of code is fine or whether it has Undefined Behavior. -But clearly, that doesn’t scale: there are just too many questions to be asked, and figuring out the semantics by interacting with an oracle with many-day latency is rather frustrating. -We have , which is a much quicker oracle, but it’s also not always right and even then, it can just answer questions of the for",202 -TecoAndJix,32397699,72,1660052382,2022 NSA Codebreaker Challenge,https://nsa-codebreaker.org/home," - New positions are posted all - the time, so check the website from time to time to see if anything - piques your interest. Lots of new hires enter - , where they spend the first few years doing six to nine month - rotational tours across NSA. - - Apply at . - NSA Codebreaker Challenge 2022: The 2022 Codebreaker Challenge will launch at 12:00 PM Eastern Time on Monday, August 8th! now and get ready. Looking for help? If you're interested in career opportunities, check out our . The Codebreaker Challenge was developed by the National Security Agency. Check us out at .",Hacker News,85728863,"Title: 2022 NSA Codebreaker Challenge; Content: - New positions are posted all - the time, so check the website from time to time to see if anything - piques your interest. Lots of new hires enter - , where they spend the first few years doing six to nine month - rotational tours across NSA. - - Apply at . - NSA Codebreaker Challenge 2022: The 2022 Codebreaker Challenge will launch at 12:00 PM Eastern Time on Monday, August 8th! now and get ready. Looking for help? If you're interested in career opportunities, check out our . The Codebreaker Challenge was developed by the National Security Agency. Check us out at .",165 -throwaddzuzxd,32398181,83,1660054118,Ask HN: How to make a native GUI with a modern language?,,"HN has strong opinions against Electron so here are my requirements:

- I want to make a native looking GUI

- Cross platform (macOS, Windows, Linux)

- With a sane language (no C, C++ or Objective C)

- Ideally with a data flow looking like unidirectional data flow / Elm architecture

What options do I have?",Hacker News,7512236,"Title: Ask HN: How to make a native GUI with a modern language?; Content: HN has strong opinions against Electron so here are my requirements:

- I want to make a native looking GUI

- Cross platform (macOS, Windows, Linux)

- With a sane language (no C, C++ or Objective C)

- Ideally with a data flow looking like unidirectional data flow / Elm architecture

What options do I have?",112 -lerno,32392161,216,1659999378,The case against a C alternative,https://c3.handmade.network/blog/p/8486-the_case_against_a_c_alternative,"Like several others I am writing an alternative to the C language (if you read this blog before then this shouldn't be news!). My language (C3) is fairly recent, there are others: Zig, Odin, Jai and older languages like eC. Looking at C++ alternatives there are languages like D, Rust, Nim, Crystal, Beef, Carbon and others. But is it possible to replace C? Let's consider some arguments against. The C language is not just the language itself but all the developer tools developed for the language. Do you want to do static analysis on your source code? - There are a lot of people working on that for C. Tools for detecting memory leaks, data races and other bugs? There's a lot of those, even if your language has better tooling out of the box. If you want to target some obscure platform, then li",Hacker News,69495560,"Title: The case against a C alternative; Content: Like several others I am writing an alternative to the C language (if you read this blog before then this shouldn't be news!). My language (C3) is fairly recent, there are others: Zig, Odin, Jai and older languages like eC. Looking at C++ alternatives there are languages like D, Rust, Nim, Crystal, Beef, Carbon and others. But is it possible to replace C? Let's consider some arguments against. The C language is not just the language itself but all the developer tools developed for the language. Do you want to do static analysis on your source code? - There are a lot of people working on that for C. Tools for detecting memory leaks, data races and other bugs? There's a lot of those, even if your language has better tooling out of the box. If you want to target some obscure platform, then li",189 -andsoitis,32390499,212,1659989885,The productivity tax you pay for context switching,https://async.twist.com/context-switching/,"You probably won’t finish this article. In fact, I may have already lost you to another tab in your browser. Or an email from your boss. Or a ping from a coworker. Or any number of other digital distractions that have come to define modern life. More and more, our work days feel like a Herculean struggle between emails, messages, and news alerts on the one side, and our beleaguered attention on the other. With the added pressures that come with , the average work day can feel like an endless spinning of wheels. There’s a name for that all-too-familiar experience of toggling between screens, apps, and tasks in response to interruptions: . And there’s a reason — well many reasons — it’s so difficult to get things done when context switching is your daily reality. This guide delves into the",Hacker News,91901694,"Title: The productivity tax you pay for context switching; Content: You probably won’t finish this article. In fact, I may have already lost you to another tab in your browser. Or an email from your boss. Or a ping from a coworker. Or any number of other digital distractions that have come to define modern life. More and more, our work days feel like a Herculean struggle between emails, messages, and news alerts on the one side, and our beleaguered attention on the other. With the added pressures that come with , the average work day can feel like an endless spinning of wheels. There’s a name for that all-too-familiar experience of toggling between screens, apps, and tasks in response to interruptions: . And there’s a reason — well many reasons — it’s so difficult to get things done when context switching is your daily reality. This guide delves into the",198 -vishnuharidas,32416786,23,1660157631,"Sure it has memory leaks but who cares, it’s a freaking missile",https://twitter.com/Carnage4Life/status/1556374093938626560,"We’ve detected that JavaScript is disabled in this browser. Please enable JavaScript or switch to a supported browser to continue using twitter.com. You can see a list of supported browsers in our Help Center. - - - - - - © 2022 Twitter, Inc. - ",Hacker News,21386231,"Title: Sure it has memory leaks but who cares, it’s a freaking missile; Content: We’ve detected that JavaScript is disabled in this browser. Please enable JavaScript or switch to a supported browser to continue using twitter.com. You can see a list of supported browsers in our Help Center. - - - - - - © 2022 Twitter, Inc. - ",91 -zw123456,32407766,74,1660104598,Unprecedented 100% of First 14 Patients with Cancer Respond to Dostarlimab,https://ascopost.com/news/june-2022/unprecedented-100-of-first-14-untreated-patients-with-rectal-cancer-respond-to-pd-1-blocker-dostarlimab-gxly/," - - - - Posted: 6/6/2022 12:36:00 PM - - Last Updated: - - COPYRIGHT CLEARANCE CENTER BUTTON - - COPYRIGHT CLEARANCE CENTER BUTTON - - Rarely, if ever, has one abstract presented at the ASCO Annual Meeting warranted its own session—but that happened with a small but mighty study from Memorial Sloan Kettering. In a study of patients with locally advanced mismatch repair–deficient (dMMR) rectal cancer, 6 months of treatment with the anti–PD-1 agent dostarlimab-gxly alone led to clinical complete responses in 100% of the study’s first 14 patients. So far, dostarlimab has spared every one of these patients of the need for chemotherapy, radiation, or surgery. The compelling results were presented at the 2022 ASCO Annual Meeting by , Head of the Colorectal Cancer Section",Hacker News,62533922,"Title: Unprecedented 100% of First 14 Patients with Cancer Respond to Dostarlimab; Content: - - - - Posted: 6/6/2022 12:36:00 PM - - Last Updated: - - COPYRIGHT CLEARANCE CENTER BUTTON - - COPYRIGHT CLEARANCE CENTER BUTTON - - Rarely, if ever, has one abstract presented at the ASCO Annual Meeting warranted its own session—but that happened with a small but mighty study from Memorial Sloan Kettering. In a study of patients with locally advanced mismatch repair–deficient (dMMR) rectal cancer, 6 months of treatment with the anti–PD-1 agent dostarlimab-gxly alone led to clinical complete responses in 100% of the study’s first 14 patients. So far, dostarlimab has spared every one of these patients of the need for chemotherapy, radiation, or surgery. The compelling results were presented at the 2022 ASCO Annual Meeting by , Head of the Colorectal Cancer Section",256 -mfiguiere,32417690,27,1660162079,Disney raises price on ad-free Disney+ 38% to $10.99,https://www.cnbc.com/2022/08/10/disney-raises-price-on-ad-free-disney-38percent-as-part-of-new-pricing-structure.html," unveiled a new pricing structure that incorporates an advertising-supported Disney+ as part of an effort to make its streaming business profitable. Starting Dec. 8 in the U.S., Disney+ with commercials will be $7.99 per month — currently the price of Disney+ without ads. The price of ad-free Disney+ will rise 38% to $10.99 — a $3 per month increase. The price of Hulu without ads will rise by $2 per month, from $12.99 to $14.99, effective Oct. 10. Hulu with ads will go up by $1 per month, rising from $6.99 to $7.99. Disney with ads would go up 43% to $9.99 per month. The price increases reflect the growing operating loss for Disney's streaming services. Disney+, Hulu and ESPN+ combined to lose $1.1 billion in the fiscal third quarter, $300 million more than the average analyst estimate, ",Hacker News,56304662,"Title: Disney raises price on ad-free Disney+ 38% to $10.99; Content: unveiled a new pricing structure that incorporates an advertising-supported Disney+ as part of an effort to make its streaming business profitable. Starting Dec. 8 in the U.S., Disney+ with commercials will be $7.99 per month — currently the price of Disney+ without ads. The price of ad-free Disney+ will rise 38% to $10.99 — a $3 per month increase. The price of Hulu without ads will rise by $2 per month, from $12.99 to $14.99, effective Oct. 10. Hulu with ads will go up by $1 per month, rising from $6.99 to $7.99. Disney with ads would go up 43% to $9.99 per month. The price increases reflect the growing operating loss for Disney's streaming services. Disney+, Hulu and ESPN+ combined to lose $1.1 billion in the fiscal third quarter, $300 million more than the average analyst estimate, ",221 -dboreham,32419601,6,1660173068,Why is my Twitter account in a superposition state?,,Trying to use an account I created a long time ago. Logging in with the old password fails. Attempts to reset the password using my email produce "Sorry we could not find your account". Meanwhile an attempt to create a new account with my email produces "Email has already been taken".,Hacker News,14820527,Title: Why is my Twitter account in a superposition state?; Content: Trying to use an account I created a long time ago. Logging in with the old password fails. Attempts to reset the password using my email produce "Sorry we could not find your account". Meanwhile an attempt to create a new account with my email produces "Email has already been taken".,89 -xena,32381550,343,1659921641,I 10x'd a TI-84 emulator's speed by replacing a switch-case,https://artemis.sh/2022/08/07/emulating-calculators-fast-in-js.html,"There’s a javascript emulator for the TI83+, TI84+, and TI84+CSE calculators called jsTIfied, which was written by Christopher Mitchell, founder of the calculator fan site . There’s not a whole lot of reasons to use it over something else if you’ve got a native option available, but if you don’t it’s pretty great. I got interested because it was the first emulator to support the TI84+CSE when that calculator was released in the early 2010s. The CSE was exciting because it retrofitted a 320x240 color display onto the hardware platform of the 84+SE, so all the other hardware and OS access was the same except for graphics. I wanted to be one of the first game developers for the CSE, but developing for the calculator without an emulator and debugger is pretty painful, so I tried out",Hacker News,87122798,"Title: I 10x'd a TI-84 emulator's speed by replacing a switch-case; Content: There’s a javascript emulator for the TI83+, TI84+, and TI84+CSE calculators called jsTIfied, which was written by Christopher Mitchell, founder of the calculator fan site . There’s not a whole lot of reasons to use it over something else if you’ve got a native option available, but if you don’t it’s pretty great. I got interested because it was the first emulator to support the TI84+CSE when that calculator was released in the early 2010s. The CSE was exciting because it retrofitted a 320x240 color display onto the hardware platform of the 84+SE, so all the other hardware and OS access was the same except for graphics. I wanted to be one of the first game developers for the CSE, but developing for the calculator without an emulator and debugger is pretty painful, so I tried out",223 -bookofjoe,32381790,335,1659924441,A physical wiring diagram for the human immune system,https://www.nature.com/articles/s41586-022-05028-x,"Thank you for visiting nature.com. You are using a browser version with limited support for CSS. To obtain - the best experience, we recommend you use a more up to date browser (or turn off compatibility mode in - Internet Explorer). In the meantime, to ensure continued support, we are displaying the site without styles - and JavaScript. Advertisement - - - ( ) - 33k 630 The human immune system is composed of a distributed network of cells circulating throughout the body, which must dynamically form physical associations and communicate using interactions between their cell-surface proteomes . Despite their therapeutic potential , our map of these surface interactions remains incomplete . Here, using a high-throughput surface receptor ",Hacker News,44087928,"Title: A physical wiring diagram for the human immune system; Content: Thank you for visiting nature.com. You are using a browser version with limited support for CSS. To obtain - the best experience, we recommend you use a more up to date browser (or turn off compatibility mode in - Internet Explorer). In the meantime, to ensure continued support, we are displaying the site without styles - and JavaScript. Advertisement - - - ( ) - 33k 630 The human immune system is composed of a distributed network of cells circulating throughout the body, which must dynamically form physical associations and communicate using interactions between their cell-surface proteomes . Despite their therapeutic potential , our map of these surface interactions remains incomplete . Here, using a high-throughput surface receptor ",213 -111111101101,32420494,7,1660180760,DOJ Is Preparing to Sue Google over Ad Market as Soon as September,https://www.bloomberg.com/news/articles/2022-08-09/doj-poised-to-sue-google-over-ad-market-as-soon-as-september,"To continue, please click the box below to let us know you're not a robot. Please make sure your browser supports JavaScript and cookies and that you are not blocking them from loading. For more information you can review our and . For inquiries related to this message please and provide the reference ID below.",Hacker News,46114258,"Title: DOJ Is Preparing to Sue Google over Ad Market as Soon as September; Content: To continue, please click the box below to let us know you're not a robot. Please make sure your browser supports JavaScript and cookies and that you are not blocking them from loading. For more information you can review our and . For inquiries related to this message please and provide the reference ID below.",84 -reimertz,32386290,229,1659970960,IKEA Symfonisk Gen2 Amp Modification Guide – A Much Cheaper Sonos Amp,https://www.thetylergibson.com/ikea-symfonisk-gen2-amp-modification-guide-a-much-cheaper-sonos-amp/,"We're back with a new one - Sonos and Ikea have updated the Symfonisk for Gen2.  On the outside, not much has changed.  Same shell, same buttons, same speakers. If you haven't seen the first article on why this thing is so cool, please .  So what's in the Gen2? There are some really noteworthy changes though: Enough of the speeds and feeds, you're here to mod.  Fortunately this time around is actually a little easier (if you have steady hands) than the Gen1. Following , taking your time along the way.  The last amp mod I did I timed at .  So not a ton of time to invest. If you're a DIYer already, there's also not much to spend.  At an absolute minimum you need some , a and a for each output location.  So for a two speaker setup, minimum cost is $320.  Thats 75% less expens",Hacker News,36910249,"Title: IKEA Symfonisk Gen2 Amp Modification Guide – A Much Cheaper Sonos Amp; Content: We're back with a new one - Sonos and Ikea have updated the Symfonisk for Gen2.  On the outside, not much has changed.  Same shell, same buttons, same speakers. If you haven't seen the first article on why this thing is so cool, please .  So what's in the Gen2? There are some really noteworthy changes though: Enough of the speeds and feeds, you're here to mod.  Fortunately this time around is actually a little easier (if you have steady hands) than the Gen1. Following , taking your time along the way.  The last amp mod I did I timed at .  So not a ton of time to invest. If you're a DIYer already, there's also not much to spend.  At an absolute minimum you need some , a and a for each output location.  So for a two speaker setup, minimum cost is $320.  Thats 75% less expens",251 -senzilla,32417272,3,1660159930,Installing OpenBSD on Scaleway Elastic Metal,https://www.senzilla.io/blog/2022/08/10/installing-openbsd-scaleway-elastic-metal/,"This post is a longer version of what I initially posted on . I like Scaleway because they (1) host in Europe and (2) provide a good mix of services from elastic metal to cloud instances and serverless functions. Let’s get into it… is a fancy name for what’s often called “bare metal” servers. Scaleway does provide some “elastic” features around these servers, such as elastic IP numbers. What I think is great with this offering is that you get pretty much full access to the . Having access to the remote console is what makes installing OpenBSD possible. Because compared to the cloud, bare metal is more… metal! 🤘 But also, while “cloud” does provide many operational benefits, the feature premium is often high. If all you need is a simple Unix server, then you’ll get m",Hacker News,95747271,"Title: Installing OpenBSD on Scaleway Elastic Metal; Content: This post is a longer version of what I initially posted on . I like Scaleway because they (1) host in Europe and (2) provide a good mix of services from elastic metal to cloud instances and serverless functions. Let’s get into it… is a fancy name for what’s often called “bare metal” servers. Scaleway does provide some “elastic” features around these servers, such as elastic IP numbers. What I think is great with this offering is that you get pretty much full access to the . Having access to the remote console is what makes installing OpenBSD possible. Because compared to the cloud, bare metal is more… metal! 🤘 But also, while “cloud” does provide many operational benefits, the feature premium is often high. If all you need is a simple Unix server, then you’ll get m",235 -rhaksw,32376136,61,1659877144,Self-Reliance (1841),https://archive.vcu.edu/english/engweb/transcendentalism/authors/emerson/essays/selfreliance.html,"We collect limited information about web visitors and use cookies on our website to provide you with the most optimal experience. These cookies help us provide you with personalized content and improve our website. To learn more about our web site privacy practices, please review . By clicking on ""I agree"", you agree to this use. Consenting to VCU's privacy policy requires the use of Javascript. Please enable Javascript functionality in your browser so you do not see this message again. “As a young student, that recognition helped me realize that I had what it was going to take to pursue art as a career. I was able to focus on my art and academic work without the stress of worrying how I was going to afford tuition.” Inaugural recipient of the Mallory Callan Memorial Scholarship",Hacker News,61102651,"Title: Self-Reliance (1841); Content: We collect limited information about web visitors and use cookies on our website to provide you with the most optimal experience. These cookies help us provide you with personalized content and improve our website. To learn more about our web site privacy practices, please review . By clicking on ""I agree"", you agree to this use. Consenting to VCU's privacy policy requires the use of Javascript. Please enable Javascript functionality in your browser so you do not see this message again. “As a young student, that recognition helped me realize that I had what it was going to take to pursue art as a career. I was able to focus on my art and academic work without the stress of worrying how I was going to afford tuition.” Inaugural recipient of the Mallory Callan Memorial Scholarship",172 -larve,32392217,39,1659999866,"Barbara Liskov, the Architect of Modern Algorithms",https://www.quantamagazine.org/barbara-liskov-is-the-architect-of-modern-algorithms-20191120/,"Barbara Liskov invented the architecture that underlies modern programs. “Designing something just powerful enough is an art.” for Quanta Magazine Good code has both substance and style. It provides all necessary information, without extraneous details. It bypasses inefficiencies and bugs. It is accurate, succinct and eloquent enough to be read and understood by humans. But by the late 1960s, advances in computing power had outpaced the abilities of programmers. Many computer scientists created programs without thought for design. They wrote long, incoherent algorithms riddled with “goto” statements — instructions for the machine to leap to a new part of the program if a certain condition is satisfied. Early coders relied on these statements to fix unforeseen consequences of their code, b",Hacker News,80270460,"Title: Barbara Liskov, the Architect of Modern Algorithms; Content: Barbara Liskov invented the architecture that underlies modern programs. “Designing something just powerful enough is an art.” for Quanta Magazine Good code has both substance and style. It provides all necessary information, without extraneous details. It bypasses inefficiencies and bugs. It is accurate, succinct and eloquent enough to be read and understood by humans. But by the late 1960s, advances in computing power had outpaced the abilities of programmers. Many computer scientists created programs without thought for design. They wrote long, incoherent algorithms riddled with “goto” statements — instructions for the machine to leap to a new part of the program if a certain condition is satisfied. Early coders relied on these statements to fix unforeseen consequences of their code, b",176 -Arathorn,32413075,7,1660143435,Are We OIDC Yet? Moving Matrix to OIDC,https://areweoidcyet.com/," • • • This site is being used to track the progress of migrating to (OIDC) for authentication. You can join the discussion at . We have also set up the which contains Homeservers, OIDC Providers and Clients for you to try out. There are also some videos below showing some of the use cases in action. For detailed background on the rationale to this project please see . Good question. There are a number of moving parts to this project which are outlined below. Jump to: Related MSCs: Outstanding key decision points: n.b. this is currently all in a rather than in mainline. proposes four types of Matrix client: These are the requirements for a client to be OIDC-aware from : That will depend on the homeserver administrator. In the case of the matrix.org homeserver we will. We",Hacker News,15183734,"Title: Are We OIDC Yet? Moving Matrix to OIDC; Content: • • • This site is being used to track the progress of migrating to (OIDC) for authentication. You can join the discussion at . We have also set up the which contains Homeservers, OIDC Providers and Clients for you to try out. There are also some videos below showing some of the use cases in action. For detailed background on the rationale to this project please see . Good question. There are a number of moving parts to this project which are outlined below. Jump to: Related MSCs: Outstanding key decision points: n.b. this is currently all in a rather than in mainline. proposes four types of Matrix client: These are the requirements for a client to be OIDC-aware from : That will depend on the homeserver administrator. In the case of the matrix.org homeserver we will. We",214 -whatrocks,32386328,65,1659971202,A Linux desktop for your wall,https://charlieharrington.com/run-linux-on-electric-objects-eo1-wall-computer/,"What was too early for NFTs, too vertical to be a Samsung Frame TV competitor, kickstarted to life by gifs, and acquired to death by Giphy? That's right, hobbitses, it's ! Electric Objects was a computer company building a . That's one of the coolest sentences ever, except for the part. Founder and CEO (a fellow Morgan Stanley escapee) wrote a great series of posts in 2018 that are worth a read for anyone interested in hardware startups. But, even better, just re-watch and experience the pure joy of the creative act of bringing a computer to life. Electric Objects was gobbled up by Giphy, which in turn was slurped and gorbled into Facebook, and the Electric Objects iOS app is sadly no more. Which, for a computer that was explicly designed to not have a keyboard or mouse, poses a ",Hacker News,34565907,"Title: A Linux desktop for your wall; Content: What was too early for NFTs, too vertical to be a Samsung Frame TV competitor, kickstarted to life by gifs, and acquired to death by Giphy? That's right, hobbitses, it's ! Electric Objects was a computer company building a . That's one of the coolest sentences ever, except for the part. Founder and CEO (a fellow Morgan Stanley escapee) wrote a great series of posts in 2018 that are worth a read for anyone interested in hardware startups. But, even better, just re-watch and experience the pure joy of the creative act of bringing a computer to life. Electric Objects was gobbled up by Giphy, which in turn was slurped and gorbled into Facebook, and the Electric Objects iOS app is sadly no more. Which, for a computer that was explicly designed to not have a keyboard or mouse, poses a ",203 -ivank,32390600,47,1659990554,The Locus of Entertainment,https://blog.nateliason.com/p/the-locus-of-entertainment,"Do you ever get bored anymore? I suspect the answer is no. How could you? The moment your mind has an opportunity to wander it is pulled back into Screenworld, seeking a new escape from the terror of our own thoughts.  This is often referenced as a bad thing. Another example of how technology has ruined us. Back in MY day, we threw rocks at each other when we were bored! What better times.  I’m not sure screens have changed our relationship with boredom though. I don’t believe people used to be more introspective, more pensive, or more bored. It’s easy to think that, reading the books of old, but those were all written by nerdy introspective types. Most people were still distracted entertainment-seekers, but they distracted themselves in different ways.  The image above of people reading t",Hacker News,33407697,"Title: The Locus of Entertainment; Content: Do you ever get bored anymore? I suspect the answer is no. How could you? The moment your mind has an opportunity to wander it is pulled back into Screenworld, seeking a new escape from the terror of our own thoughts.  This is often referenced as a bad thing. Another example of how technology has ruined us. Back in MY day, we threw rocks at each other when we were bored! What better times.  I’m not sure screens have changed our relationship with boredom though. I don’t believe people used to be more introspective, more pensive, or more bored. It’s easy to think that, reading the books of old, but those were all written by nerdy introspective types. Most people were still distracted entertainment-seekers, but they distracted themselves in different ways.  The image above of people reading t",186 -levmiseri,32394902,128,1660027220,Show HN: Yare 2 – Programmable RTS game,https://www.yare.io,"Hi HN! About a year ago I showed my side project Yare here (https://news.ycombinator.com/item?id=27365961) and was overblown by the feedback and support. Since then a lot has changed and I'm excited to share the beta of 'Yare 2' (https://www.yare.io/).

The simple programming game has evolved into something a little more complex with the ability to not only control the units with code, but now practically anything is programmable. E.g. the players can build their own UI elements to play the game with (when you choose 'play with mouse and keyboard' on the homescreen, it showcases what is possible to create).

This is a passion project that I don't plan to anyhow excessively monetize and will be always free to play, but I'm worried that it's perhaps growing into a too chaotic/confusing game and losing its initial simplicity.",Hacker News,70128729,"Title: Show HN: Yare 2 – Programmable RTS game; Content: Hi HN! About a year ago I showed my side project Yare here (https://news.ycombinator.com/item?id=27365961) and was overblown by the feedback and support. Since then a lot has changed and I'm excited to share the beta of 'Yare 2' (https://www.yare.io/).

The simple programming game has evolved into something a little more complex with the ability to not only control the units with code, but now practically anything is programmable. E.g. the players can build their own UI elements to play the game with (when you choose 'play with mouse and keyboard' on the homescreen, it showcases what is possible to create).

This is a passion project that I don't plan to anyhow excessively monetize and will be always free to play, but I'm worried that it's perhaps growing into a too chaotic/confusing game and losing its initial simplicity.",384 -kevmo314,32392599,162,1660003378,MantaRay: Open-Source Ray Tracer,https://github.com/ange-yaghi/manta-ray," - An open source physically based renderer. - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. is an advanced open-source renderer. It uses modern rendering techniques to generate photorealistic images of complex scenes. This ray-tracer is also featured in the following YouTube videos on my channel : To get started, consider reading this tutorial: . Tutorials are continually added here: This project was recently migrated to CMake and the setup instructions have changed. They w",Hacker News,90915863,"Title: MantaRay: Open-Source Ray Tracer; Content: - An open source physically based renderer. - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. is an advanced open-source renderer. It uses modern rendering techniques to generate photorealistic images of complex scenes. This ray-tracer is also featured in the following YouTube videos on my channel : To get started, consider reading this tutorial: . Tutorials are continually added here: This project was recently migrated to CMake and the setup instructions have changed. They w",246 -kamaraju,32413220,74,1660143908,Celsius Network Files Chapter 11 Bankruptcy,https://dfr.vermont.gov/consumer-alert/celsius-network-files-chapter-11-bankruptcy," - - Celsius Network (“Celsius”) is a cryptocurrency company, unlicensed in Vermont, that offers its customers interest-bearing crypto accounts.  On June 12, 2022, Celsius announced it was pausing all withdrawals, swaps, and transfers between customer accounts.  On July 13, 2022, Celsius and several of its affiliates commenced voluntary Chapter 11 bankruptcy proceedings in the U.S. Bankruptcy Court for the Southern District of New York.  Chapter 11 is a type of bankruptcy designed to allow insolvent companies to restructure their financial obligations, through reorganization, sale or otherwise. Public filings are available through a portal accessible at: . It is possible (and easy) to register on that site to receive email updates regarding future court filings. Very few cryptocurrency com",Hacker News,33695157,"Title: Celsius Network Files Chapter 11 Bankruptcy; Content: - - Celsius Network (“Celsius”) is a cryptocurrency company, unlicensed in Vermont, that offers its customers interest-bearing crypto accounts.  On June 12, 2022, Celsius announced it was pausing all withdrawals, swaps, and transfers between customer accounts.  On July 13, 2022, Celsius and several of its affiliates commenced voluntary Chapter 11 bankruptcy proceedings in the U.S. Bankruptcy Court for the Southern District of New York.  Chapter 11 is a type of bankruptcy designed to allow insolvent companies to restructure their financial obligations, through reorganization, sale or otherwise. Public filings are available through a portal accessible at: . It is possible (and easy) to register on that site to receive email updates regarding future court filings. Very few cryptocurrency com",174 -some_random,32398923,205,1660057069,Saskatoon Freezing Deaths,https://en.wikipedia.org/wiki/Saskatoon_freezing_deaths," - The were a series of deaths of in , , in the early 2000s, which were confirmed to have been caused by members of the . The police officers would arrest Indigenous people, usually men, for alleged drunkenness and/or disorderly behaviour, sometimes without cause. The officers would then drive them to the outskirts of the city at night in the winter, and abandon them, leaving them stranded in sub-zero temperatures. - The practice was known as taking Indigenous people for ""starlight tours"" and dates back to 1976. As of 2021, despite convictions for related offences, no Saskatoon police officer has been convicted specifically for having caused freezing deaths. - Victims who died from include Rodney Naistus, Lawrence Wegner, and . Naistus and Wegner died in 2000, and their bodies w",Hacker News,73545304,"Title: Saskatoon Freezing Deaths; Content: - The were a series of deaths of in , , in the early 2000s, which were confirmed to have been caused by members of the . The police officers would arrest Indigenous people, usually men, for alleged drunkenness and/or disorderly behaviour, sometimes without cause. The officers would then drive them to the outskirts of the city at night in the winter, and abandon them, leaving them stranded in sub-zero temperatures. - The practice was known as taking Indigenous people for ""starlight tours"" and dates back to 1976. As of 2021, despite convictions for related offences, no Saskatoon police officer has been convicted specifically for having caused freezing deaths. - Victims who died from include Rodney Naistus, Lawrence Wegner, and . Naistus and Wegner died in 2000, and their bodies w",189 -ivanvas,32383943,122,1659954160,Teardown of a quartz crystal oscillator and the tiny IC inside,https://www.righto.com/2021/02/teardown-of-quartz-crystal-oscillator.html,"The quartz oscillator is an important electronic circuit, providing highly-accurate timing signals at a low cost. -A quartz crystal has the special property of piezoelectricity, changing its electrical properties as it vibrates. -Since a crystal can be cut to vibrate at a very precise frequency, quartz oscillators are useful for many applications. -Quartz oscillators were introduced in the 1920s and provided accurate frequencies for radio stations. -Wristwatches were revolutionized in the 1970s by the use of highly-accurate quartz oscillators. -Computers use quartz oscillators to generate their clock signals, from in the 1940s to modern computers. A quartz crystal requires additional circuitry to make it oscillate, and this analog circuitry can be tricky to design. -In the 1970s, crystal oscil",Hacker News,28101375,"Title: Teardown of a quartz crystal oscillator and the tiny IC inside; Content: The quartz oscillator is an important electronic circuit, providing highly-accurate timing signals at a low cost. -A quartz crystal has the special property of piezoelectricity, changing its electrical properties as it vibrates. -Since a crystal can be cut to vibrate at a very precise frequency, quartz oscillators are useful for many applications. -Quartz oscillators were introduced in the 1920s and provided accurate frequencies for radio stations. -Wristwatches were revolutionized in the 1970s by the use of highly-accurate quartz oscillators. -Computers use quartz oscillators to generate their clock signals, from in the 1940s to modern computers. A quartz crystal requires additional circuitry to make it oscillate, and this analog circuitry can be tricky to design. -In the 1970s, crystal oscil",190 -ducaale,32405848,12,1660086790,Assorted thoughts on Zig and Rust (2020),https://www.scattered-thoughts.net/writing/assorted-thoughts-on-zig-and-rust/,,Hacker News,54670815,Title: Assorted thoughts on Zig and Rust (2020); Content: ,15 -smartmic,32379066,381,1659900395,Mysterious holes on the seafloor,https://oceanexplorer.noaa.gov/news/oer-updates/2022/mysterious-holes-seafloor/mysterious-holes-seafloor.html,"During of the second expedition, we observed several sublinear sets of holes in the sediment on the seafloor at a depth of approximately 2,540 meters (1.6 miles). While the holes look almost human made, the little piles of sediment around them suggest they had been excavated. We attempted but were not able to take a peek into the holes and poke them with the tools on the remotely operated vehicle. It was also not apparent as to whether the holes were connected beneath the sediment surface. To view this video please enable JavaScript, and consider upgrading to a web browser that During Dive 04 of the second Voyage to the Ridge 2022 expedition, we observed several sublinear sets of holes in the sediment on the seafloor at a depth of approximately 2,540 meters (1.6 miles). We saw the hol",Hacker News,291005,"Title: Mysterious holes on the seafloor; Content: During of the second expedition, we observed several sublinear sets of holes in the sediment on the seafloor at a depth of approximately 2,540 meters (1.6 miles). While the holes look almost human made, the little piles of sediment around them suggest they had been excavated. We attempted but were not able to take a peek into the holes and poke them with the tools on the remotely operated vehicle. It was also not apparent as to whether the holes were connected beneath the sediment surface. To view this video please enable JavaScript, and consider upgrading to a web browser that During Dive 04 of the second Voyage to the Ridge 2022 expedition, we observed several sublinear sets of holes in the sediment on the seafloor at a depth of approximately 2,540 meters (1.6 miles). We saw the hol",183 -Trouble_007,32418853,7,1660167978,FDA Monkeypox Response,https://www.fda.gov/emergency-preparedness-and-response/mcm-issues/fda-monkeypox-response,"Federal government websites often end in .gov or .mil. Before sharing sensitive information, make sure you're on a federal government site. The ensures that you are connecting to the official website and that any information you provide is encrypted and transmitted securely. | | | | |   |   | |   The U.S. Food and Drug Administration plays a critical role in protecting the U.S. from chemical, biological, radiological, nuclear (CBRN) attacks, and emerging infectious disease threats. The FDA's roles in monkeypox preparedness and response during this include: is a rare disease that is caused by infection with monkeypox virus. This virus can spread to anyone through close, personal, often skin-to-skin contact. Currently, a high rate of the known cases in the U.S. are among g",Hacker News,15078092,"Title: FDA Monkeypox Response; Content: Federal government websites often end in .gov or .mil. Before sharing sensitive information, make sure you're on a federal government site. The ensures that you are connecting to the official website and that any information you provide is encrypted and transmitted securely. | | | | |   |   | |   The U.S. Food and Drug Administration plays a critical role in protecting the U.S. from chemical, biological, radiological, nuclear (CBRN) attacks, and emerging infectious disease threats. The FDA's roles in monkeypox preparedness and response during this include: is a rare disease that is caused by infection with monkeypox virus. This virus can spread to anyone through close, personal, often skin-to-skin contact. Currently, a high rate of the known cases in the U.S. are among g",197 -bookofjoe,32392937,165,1660006298,A biochemist’s view of life’s origin reframes cancer and aging,https://www.quantamagazine.org/a-biochemists-view-of-lifes-origin-reframes-cancer-and-aging-20220808/,"In contrast to many other researchers who study the origin of life, Nick Lane, a professor of evolutionary biochemistry at University College London, suggests that some form of primitive metabolism may have arisen in deep-sea hydrothermal vents before the appearance of genetic information. Philipp Ammon for Quanta Magazine All living cells power themselves by coaxing energetic electrons from one side of a membrane to the other. Membrane-based mechanisms for accomplishing this are, in a sense, as universal a feature of life as the genetic code. But unlike the genetic code, these mechanisms are not the same everywhere: The two simplest categories of cells, bacteria and archaea, have membranes and protein complexes for producing energy that are chemically and structurally dissimilar. Those di",Hacker News,8458488,"Title: A biochemist’s view of life’s origin reframes cancer and aging; Content: In contrast to many other researchers who study the origin of life, Nick Lane, a professor of evolutionary biochemistry at University College London, suggests that some form of primitive metabolism may have arisen in deep-sea hydrothermal vents before the appearance of genetic information. Philipp Ammon for Quanta Magazine All living cells power themselves by coaxing energetic electrons from one side of a membrane to the other. Membrane-based mechanisms for accomplishing this are, in a sense, as universal a feature of life as the genetic code. But unlike the genetic code, these mechanisms are not the same everywhere: The two simplest categories of cells, bacteria and archaea, have membranes and protein complexes for producing energy that are chemically and structurally dissimilar. Those di",176 -thesecretceo,32421054,4,1660186787,Texting between iPhone and Android is broken': Google puts Apple on blast for,https://www.businessinsider.com/google-tells-apple-fix-texting-between-android-iphone-green-bubbles-2022-8," - On Tuesday, Google took a blatant jab at Apple on its over what it says is Apple's failure to improve the user experience of messaging between iPhone and Android devices. Some users have long lamented the green message bubbles that come with cross-device messaging, as well as poor-quality compressed videos, the lack of read receipts, and other headaches. Google blames Apple, as the company converts texts sent between iPhones and Androids into what's called SMS and MMS, both of which are decades-old methods of sending text-only messages from device to device.  Instead, Google says, Apple should use something called Rich Communication Services, which it says is the ""modern industry standard"" meant to improve how people can send not only texts but also media, such as emojis, videos, and p",Hacker News,1060368,"Title: Texting between iPhone and Android is broken': Google puts Apple on blast for; Content: - On Tuesday, Google took a blatant jab at Apple on its over what it says is Apple's failure to improve the user experience of messaging between iPhone and Android devices. Some users have long lamented the green message bubbles that come with cross-device messaging, as well as poor-quality compressed videos, the lack of read receipts, and other headaches. Google blames Apple, as the company converts texts sent between iPhones and Androids into what's called SMS and MMS, both of which are decades-old methods of sending text-only messages from device to device.  Instead, Google says, Apple should use something called Rich Communication Services, which it says is the ""modern industry standard"" meant to improve how people can send not only texts but also media, such as emojis, videos, and p",186 -obert,32383835,132,1659952808,Uses for an old Android device,https://www.computerworld.com/article/2487680/20-great-uses-for-an-old-android-device.html," - - - - - Contributing Editor, - - - - - - - - - - - - - - - - - - Got extra smartphones sitting around your office? How about tablets? As we move multiple generations into mobile technology, more and more of us are building up collections of old, dated devices from both our work and our personal lives. And more often than not, those devices do little more than take up space and gather dust. Here's a little secret, though: Your abandoned Android gadgets are actually virtual gold mines. You just have to find the right way to tap into their potential and give them new life. So grab the nearest DustBuster and get ready: Here are 20 ways to make your old phone or tablet useful again. With the right software and a couple minutes of configuration, your old Android device c",Hacker News,30899087,"Title: Uses for an old Android device; Content: - - - - - Contributing Editor, - - - - - - - - - - - - - - - - - - Got extra smartphones sitting around your office? How about tablets? As we move multiple generations into mobile technology, more and more of us are building up collections of old, dated devices from both our work and our personal lives. And more often than not, those devices do little more than take up space and gather dust. Here's a little secret, though: Your abandoned Android gadgets are actually virtual gold mines. You just have to find the right way to tap into their potential and give them new life. So grab the nearest DustBuster and get ready: Here are 20 ways to make your old phone or tablet useful again. With the right software and a couple minutes of configuration, your old Android device c",220 -alschwalm,32405526,12,1660085035,Wikidata Query Service,https://query.wikidata.org/,,Hacker News,68119458,Title: Wikidata Query Service; Content: ,11 -strzalek,32380769,323,1659913159,Why does gRPC insist on trailers?,https://carlmastrangelo.com/blog/why-does-grpc-insist-on-trailers,"A programming and hobby blog. comes up occasionally on the - , often with a redress of -grievences in the comment section. One of the major complaints people have -with gRPC is that it requires HTTP trailers. This one misstep has caused -so much heartache and trouble, I think it probably is reason gRPC -failed to achieve its goal. Since I was closely involved with the project, -I wanted to rebut some misconceptions I see posted a lot, and warn future -protocol designers against the mistakes we made. gRPC was reared by two parents trying to solve similar problems: The push to Cloud was coming on strong from the top, and the two teams joined -forces to ease the communication from the outside world, to the inside. Rather -than boil the ocean, they decided to reuse the newly minted HTTP/2 protoc",Hacker News,66427074,"Title: Why does gRPC insist on trailers?; Content: A programming and hobby blog. comes up occasionally on the - , often with a redress of -grievences in the comment section. One of the major complaints people have -with gRPC is that it requires HTTP trailers. This one misstep has caused -so much heartache and trouble, I think it probably is reason gRPC -failed to achieve its goal. Since I was closely involved with the project, -I wanted to rebut some misconceptions I see posted a lot, and warn future -protocol designers against the mistakes we made. gRPC was reared by two parents trying to solve similar problems: The push to Cloud was coming on strong from the top, and the two teams joined -forces to ease the communication from the outside world, to the inside. Rather -than boil the ocean, they decided to reuse the newly minted HTTP/2 protoc",201 -sumul,32376154,405,1659877289,Show HN: Figure is a daily logic puzzle game,https://figure.game,"Hello, HN! Figure is a little side project I’ve been working on. Someone described it as Bejeweled meets Wordle.

I built the puzzle interface and website in Next.js and React, which was a first for me and overall a great learning experience. The daily puzzle data is queued up in a PostgreSQL table. Another table stores anonymous solve stats. Once a day, a cron job hits a serverless API that promotes the next puzzle as “live” and prompts Next.js to update the prebaked static site with the new data. The game state is managed with Redux and your stats are persisted to localStorage. Framer Motion for animations. Styling is mostly Tailwind CSS. I use Figma for design and Logic Pro to make the sounds.

I get a lot of questions about how the puzzles are generated. It’s not super sexy. I generate random grids of tiles and then run them through a brute force solver (sounds rough but the puzzles don’t feel anything). Every few days, I play through puzzles that look promising based on the solution space and pick some good ones to go into the queue. The rest are sent back to the void (again, painless).

I’ve spent a little bit of time tinkering with a procedural generator, but so far the random ones are better. The downsides of the random approach are (1) the curation effort required, and (2) the high variability in puzzle difficulty. I have a feeling there’s a whole body of math and CS knowledge where Figure is an example of something that I don’t know the name for (imposter syndrome intensifies).

As for the future of Figure, I feel strongly about keeping it free of ads, login walls, in-app purchases, or anything else that infringes on enjoyment or privacy. I’d also like to make sure Figure is accessible to everyone. English isn’t exactly required to play, but translations for the UI and website would be nice. I’ve tried to build Figure to be friendly to people who have color vision deficiency and people who rely on screen readers and keyboard navigation, but I have no idea if it’s actually any fun in these cases.

Here are some miscellaneous thoughts…

1. It’s been surprisingly satisfying to build a web game with a modern frontend stack. I’ve noticed a lot of grumbling on HN over the years from OG web developers who yearn for the days of semantic HTML, a sprinkling of CSS, and vanilla JS. I was in that boat too and have grumbled plenty about the breakneck pace of frontend evolution. One of my goals with this project was to pick some popular frameworks and give them an honest try. I’m now a believer, but there’s still no way I can keep up with all the progress.

2. I found Tailwind awkward at first, but after a while I realized I was using Figma a lot less and just designing in code with utility classes, which is great for focus and flow. Having lived through the Web 2.0 standards revolution, it was hard to let go of some deeply rooted opinions about semantic purity, but overall I’m sold.

3. I really love side projects. At most jobs, you’re pushed toward specialization. Side projects allow you to build out a generalist skillset, which makes you better at your core job function and better at collaborating with others. It’s also liberating to explore and pivot around without time pressure. Figure started out as a 3D fidget toy in Unity where you fling projectiles at floating objects…

4. I made this game on my trusty 2013 MacBook Pro, which has been almost completely sufficient (ahem Docker ಠ_ಠ). I’ll probably get an M2 Air soon, but I’m reluctant to say goodbye to the best computer I’ve ever owned.

5. I’m very grateful for the people who build and maintain open source projects. It’s also delightful how many paid services offer generous free tiers to let developers play around: Figma, GitHub, Vercel, Supabase, and Pipedream, just to name a few that I’m currently using actively. If you work on FOSS and/or these excellent platforms, thank you.

Anyway, hope you like it. Happy to answer any questions.",Hacker News,38391990,"Title: Show HN: Figure is a daily logic puzzle game; Content: Hello, HN! Figure is a little side project I’ve been working on. Someone described it as Bejeweled meets Wordle.

I built the puzzle interface and website in Next.js and React, which was a first for me and overall a great learning experience. The daily puzzle data is queued up in a PostgreSQL table. Another table stores anonymous solve stats. Once a day, a cron job hits a serverless API that promotes the next puzzle as “live” and prompts Next.js to update the prebaked static site with the new data. The game state is managed with Redux and your stats are persisted to localStorage. Framer Motion for animations. Styling is mostly Tailwind CSS. I use Figma for design and Logic Pro to make the sounds.

I get a lot of questions about how the puzzles are generated. It’s not super sexy. I generate random grids of tiles and then run them through a brute force solver (sounds rough but the puzzles don’t feel anything). Every few days, I play through puzzles that look promising based on the solution space and pick some good ones to go into the queue. The rest are sent back to the void (again, painless).

I’ve spent a little bit of time tinkering with a procedural generator, but so far the random ones are better. The downsides of the random approach are (1) the curation effort required, and (2) the high variability in puzzle difficulty. I have a feeling there’s a whole body of math and CS knowledge where Figure is an example of something that I don’t know the name for (imposter syndrome intensifies).

As for the future of Figure, I feel strongly about keeping it free of ads, login walls, in-app purchases, or anything else that infringes on enjoyment or privacy. I’d also like to make sure Figure is accessible to everyone. English isn’t exactly required to play, but translations for the UI and website would be nice. I’ve tried to build Figure to be friendly to people who have color vision deficiency and people who rely on screen readers and keyboard navigation, but I have no idea if it’s actually any fun in these cases.

Here are some miscellaneous thoughts…

1. It’s been surprisingly satisfying to build a web game with a modern frontend stack. I’ve noticed a lot of grumbling on HN over the years from OG web developers who yearn for the days of semantic HTML, a sprinkling of CSS, and vanilla JS. I was in that boat too and have grumbled plenty about the breakneck pace of frontend evolution. One of my goals with this project was to pick some popular frameworks and give them an honest try. I’m now a believer, but there’s still no way I can keep up with all the progress.

2. I found Tailwind awkward at first, but after a while I realized I was using Figma a lot less and just designing in code with utility classes, which is great for focus and flow. Having lived through the Web 2.0 standards revolution, it was hard to let go of some deeply rooted opinions about semantic purity, but overall I’m sold.

3. I really love side projects. At most jobs, you’re pushed toward specialization. Side projects allow you to build out a generalist skillset, which makes you better at your core job function and better at collaborating with others. It’s also liberating to explore and pivot around without time pressure. Figure started out as a 3D fidget toy in Unity where you fling projectiles at floating objects…

4. I made this game on my trusty 2013 MacBook Pro, which has been almost completely sufficient (ahem Docker ಠ_ಠ). I’ll probably get an M2 Air soon, but I’m reluctant to say goodbye to the best computer I’ve ever owned.

5. I’m very grateful for the people who build and maintain open source projects. It’s also delightful how many paid services offer generous free tiers to let developers play around: Figma, GitHub, Vercel, Supabase, and Pipedream, just to name a few that I’m currently using actively. If you work on FOSS and/or these excellent platforms, thank you.

Anyway, hope you like it. Happy to answer any questions.",972 -seansh,32395831,29,1660037713,One Word Broke C,https://web.archive.org/web/20210307213745/https://news.quelsolaar.com/2020/03/16/how-one-word-broke-c/,"A lot have been written about the dangers of “Undefined behavior” in C. Its an often cited reason why C is a “Dangerous” language that invites hard to find bugs, and security issues. In my opinion Undefined behavior is not inherently bad. C is meant to be implementable on lots of different platforms and, to require all of them to behave in the exact same way would be impractical, it would limit hardware development and make C less future proof. Some of the concerns around undefined behavior in C are based on the fact that C is a small enough language that all corners of the language are explored and actually matter. Undefined behavior — behavior, upon use of a nonportable or -   erroneous program construct, of erroneous data, or of -   indeterminately-valued objects, for which the Standard",Hacker News,31729979,"Title: One Word Broke C; Content: A lot have been written about the dangers of “Undefined behavior” in C. Its an often cited reason why C is a “Dangerous” language that invites hard to find bugs, and security issues. In my opinion Undefined behavior is not inherently bad. C is meant to be implementable on lots of different platforms and, to require all of them to behave in the exact same way would be impractical, it would limit hardware development and make C less future proof. Some of the concerns around undefined behavior in C are based on the fact that C is a small enough language that all corners of the language are explored and actually matter. Undefined behavior — behavior, upon use of a nonportable or -   erroneous program construct, of erroneous data, or of -   indeterminately-valued objects, for which the Standard",188 -elsewhen,32417460,17,1660160927,Domino's tried to sell pizza to Italians. It failed,https://www.cnn.com/2022/08/10/business-food/dominos-exits-italy/index.html,"Updated 1509 GMT (2309 HKT) August 10, 2022 Italian job was harder than it looked. ",Hacker News,48911747,"Title: Domino's tried to sell pizza to Italians. It failed; Content: Updated 1509 GMT (2309 HKT) August 10, 2022 Italian job was harder than it looked. ",42 -vanilla-almond,32416236,8,1660155250,Tell HN: YouTube prioritises health-related searches 'From health sources',,"I only recently noticed this. It may be country-specific. Try searching for a medical condition or health issue. The YouTube search results are labelled 'From health sources'.

I'm not sure what to think of this change. Is it right to remove or deprioritise popular videos from search results if those videos come from unqualified "Doctors". I presume this also applies to anyone discussing a health topic who is not a health professional.

On the other hand, I understand why YouTube has taken this approach. There is a lot of misleading health advice too - it's impossible to police it all. YouTube's approach is to populate search results from health professionals or "credible health sources".

It's a difficult problem to tackle. What do think of this change to YouTube search? Do you think health videos should be unfiltered in search results - no matter the content, or who it comes from?

-----

Some links from YouTube:

Authoritative health information: https://www.youtube.com/howyoutubeworks/product-features/health-information/

Introducing new ways to help you find answers to your health questions: -https://blog.youtube/news-and-events/introducing-new-ways-help-you-find-answers-your-health-questions/",Hacker News,50972458,"Title: Tell HN: YouTube prioritises health-related searches 'From health sources'; Content: I only recently noticed this. It may be country-specific. Try searching for a medical condition or health issue. The YouTube search results are labelled 'From health sources'.

I'm not sure what to think of this change. Is it right to remove or deprioritise popular videos from search results if those videos come from unqualified "Doctors". I presume this also applies to anyone discussing a health topic who is not a health professional.

On the other hand, I understand why YouTube has taken this approach. There is a lot of misleading health advice too - it's impossible to police it all. YouTube's approach is to populate search results from health professionals or "credible health sources".

It's a difficult problem to tackle. What do think of this change to YouTube search? Do you think health videos should be unfiltered in search results - no matter the content, or who it comes from?

-----

Some links from YouTube:

Authoritative health information: https://www.youtube.com/howyoutubeworks/product-features/health-information/

Introducing new ways to help you find answers to your health questions: -https://blog.youtube/news-and-events/introducing-new-ways-help-you-find-answers-your-health-questions/",413 -jgillich,32397510,144,1660051560,AppLovin offers to buy Unity Software in $17.5 bln deal,https://www.reuters.com/markets/deals/applovin-offers-buy-unity-software-2022-08-09/,"People play ""Pokemon GO"" on the Pokequan GoBoat Adventure Cruise in the Occoquan River in the small town of Occoquan, Virginia, U.S. August 14, 2016. REUTERS/Sait Serkan Gurbuz Aug 9 (Reuters) - Gaming software company AppLovin Corp made an offer on Tuesday to buy its peer Unity Software Inc in a $17.54 billion all-stock deal, threatening to derail Unity's announced plan to acquire AppLovin's smaller competitor ironSource . AppLovin has offered $58.85 for each Unity share, which represents a premium of 18% to Unity's Monday closing price. Unity will own 55% of the combined company's outstanding shares, representing about 49% of the voting rights. AppLovin hired advisers to work out an offer after Unity last month said it would buy ironSource in a $4.4 billion all-stock transaction, sou",Hacker News,21274238,"Title: AppLovin offers to buy Unity Software in $17.5 bln deal; Content: People play ""Pokemon GO"" on the Pokequan GoBoat Adventure Cruise in the Occoquan River in the small town of Occoquan, Virginia, U.S. August 14, 2016. REUTERS/Sait Serkan Gurbuz Aug 9 (Reuters) - Gaming software company AppLovin Corp made an offer on Tuesday to buy its peer Unity Software Inc in a $17.54 billion all-stock deal, threatening to derail Unity's announced plan to acquire AppLovin's smaller competitor ironSource . AppLovin has offered $58.85 for each Unity share, which represents a premium of 18% to Unity's Monday closing price. Unity will own 55% of the combined company's outstanding shares, representing about 49% of the voting rights. AppLovin hired advisers to work out an offer after Unity last month said it would buy ironSource in a $4.4 billion all-stock transaction, sou",219 -feross,32386276,66,1659970915,Why we chose Clojure,https://blog.kaleidos.net/penpot-chose-clojure-as-its-language-and-here-is-why/,"This is probably the question we’ve been asked the most at . We have a vague explanation in our , so with this article I’ll try to explain a bit the motivations and spirit behind each decision. The rationale is multi-faceted. A small team, at one of our Personal Innovation Weeks ( ) in 2015, began the project from the initial idea of making an open-source prototyping tool and released a working prototype after a week of hard work and lots of fun (you can check it : no credentials needed, just hit the login button). This was the first static prototype, i.e. without a backend). Personally, I was not part of the initial team. (around December 2015) to build a prototype for a hackathon in just one week but I think the most important reason was probably because it was fun. It offered a func",Hacker News,83755549,"Title: Why we chose Clojure; Content: This is probably the question we’ve been asked the most at . We have a vague explanation in our , so with this article I’ll try to explain a bit the motivations and spirit behind each decision. The rationale is multi-faceted. A small team, at one of our Personal Innovation Weeks ( ) in 2015, began the project from the initial idea of making an open-source prototyping tool and released a working prototype after a week of hard work and lots of fun (you can check it : no credentials needed, just hit the login button). This was the first static prototype, i.e. without a backend). Personally, I was not part of the initial team. (around December 2015) to build a prototype for a hackathon in just one week but I think the most important reason was probably because it was fun. It offered a func",190 -zegl,32395076,95,1660029381,$5.6B cloud company Fivetran acquired its way to survival,https://www.forbes.com/sites/kenrickcai/2022/08/08/the-56-billion-internet-plumbers/,"George Fraser was trying to relax at his family’s lakeside cabin deep in the woods of Wisconsin. Instead, the CEO and cofounder of Fivetran was worrying about his job and the company he had spent nine long years building with his childhood friend Taylor Brown, whose family also summered in the same patch of northern pines. The two had a great idea: Help companies gather data from all sorts of disparate sources—Twitter mentions, credit card transactions—then charge them to funnel it to a big-data analytics firm like or , which could, ideally, tell them what it all meant. Fraser and Brown had gone through Y Combinator together. They had raised about $160 million. They had spent countless hours sweating the technical details. But they still didn’t have a product designed for large compani",Hacker News,77207121,"Title: $5.6B cloud company Fivetran acquired its way to survival; Content: George Fraser was trying to relax at his family’s lakeside cabin deep in the woods of Wisconsin. Instead, the CEO and cofounder of Fivetran was worrying about his job and the company he had spent nine long years building with his childhood friend Taylor Brown, whose family also summered in the same patch of northern pines. The two had a great idea: Help companies gather data from all sorts of disparate sources—Twitter mentions, credit card transactions—then charge them to funnel it to a big-data analytics firm like or , which could, ideally, tell them what it all meant. Fraser and Brown had gone through Y Combinator together. They had raised about $160 million. They had spent countless hours sweating the technical details. But they still didn’t have a product designed for large compani",191 -MilnerRoute,32420409,6,1660180039,Inflation drops to zero in July due to falling gas prices,https://www.axios.com/2022/08/10/inflation-cpi-report-july,"Consumer prices were unchanged in July, as dragged the Consumer Price Index down to zero. Core inflation, which excludes energy and food, rose only 0.3%, below what analysts expected. The Labor Department reported that overall consumer prices rose 0% last month, and are up 8.5% over the past year. That compares to a 9.1% year-over-year reported in June. Falling gasoline prices are clearly some inflation relief, and the broader inflation picture was more favorable in July than economists had expected. Gasoline prices fell 7.7% in July, dragging down headline inflation. Other items with falling prices included used cars and trucks (-0.4%) and airfares (down 7.8%). The Federal Reserve has indicated it intends to keep raising interest rates until there is clear evidence inflation is wanin",Hacker News,8332731,"Title: Inflation drops to zero in July due to falling gas prices; Content: Consumer prices were unchanged in July, as dragged the Consumer Price Index down to zero. Core inflation, which excludes energy and food, rose only 0.3%, below what analysts expected. The Labor Department reported that overall consumer prices rose 0% last month, and are up 8.5% over the past year. That compares to a 9.1% year-over-year reported in June. Falling gasoline prices are clearly some inflation relief, and the broader inflation picture was more favorable in July than economists had expected. Gasoline prices fell 7.7% in July, dragging down headline inflation. Other items with falling prices included used cars and trucks (-0.4%) and airfares (down 7.8%). The Federal Reserve has indicated it intends to keep raising interest rates until there is clear evidence inflation is wanin",189 -grumblingdev,32411741,18,1660138833,Why are systems languages always overly complex?,,"I do most of my programming in Node and TypeScript. It's nice and simple.

I always wonder why we don't just use this syntax to write low-level system code. The module system is nice; functions, objects, and arrays are nice to work with; and the syntax is simple and familiar.

A systems language essentially just adds access to pointers.

In most of these systems languages, the raw memory management is often abstracted away into libraries, and we are just writing basic logic in a new convoluted syntax that a single dev happened to like. Think Rust, Zig, etc.

It's quite clear that TypeScript is going to be around forever. Why don't we just use this syntax for a systems language, and add a few constraints to make it low-level.

Imagine the same syntax/tooling for embedded, kernel, system (browsers, interpreters), backend, and frontend.

I just don't know why there is not more interest in this.",Hacker News,93374987,"Title: Why are systems languages always overly complex?; Content: I do most of my programming in Node and TypeScript. It's nice and simple.

I always wonder why we don't just use this syntax to write low-level system code. The module system is nice; functions, objects, and arrays are nice to work with; and the syntax is simple and familiar.

A systems language essentially just adds access to pointers.

In most of these systems languages, the raw memory management is often abstracted away into libraries, and we are just writing basic logic in a new convoluted syntax that a single dev happened to like. Think Rust, Zig, etc.

It's quite clear that TypeScript is going to be around forever. Why don't we just use this syntax for a systems language, and add a few constraints to make it low-level.

Imagine the same syntax/tooling for embedded, kernel, system (browsers, interpreters), backend, and frontend.

I just don't know why there is not more interest in this.",254 -flywind,32411178,6,1660136426,The Nim team's efforts in mitigating the false postives on the Nim binaries,https://forum.nim-lang.org/t/9358,,Hacker News,73034292,Title: The Nim team's efforts in mitigating the false postives on the Nim binaries; Content: ,21 -neverminder,32396685,230,1660046617,Ask HN: Why did smartphones become a single point of failure?,,"i can't log in to any of my banks without my phone. Most of the systems in my workplace also require phone app authentication. I can't do any of those things with just a PC or laptop. Smartphones being the smallest and portable are surely the most lost and stolen. If someone got a hold of my PC or laptop - they would be able to do some damage, but not even close to if they were able to access my phone. Everything everywhere nowadays requires some app.",Hacker News,58959572,"Title: Ask HN: Why did smartphones become a single point of failure?; Content: i can't log in to any of my banks without my phone. Most of the systems in my workplace also require phone app authentication. I can't do any of those things with just a PC or laptop. Smartphones being the smallest and portable are surely the most lost and stolen. If someone got a hold of my PC or laptop - they would be able to do some damage, but not even close to if they were able to access my phone. Everything everywhere nowadays requires some app.",127 -hlship,32415184,4,1660150857,The Big Acquisition: What Nubank's Cognitect Acquisition Means for Clojure,https://www.juxt.pro/blog/the-big-acquisition,"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere. Engineer Jamie Walkerdine jam@juxt.pro jam@juxt.pro Analysis Opinion A technological revolution is going on in Brazil. -In 2011, . -Brazil was estimated to be the most c",Hacker News,80373963,"Title: The Big Acquisition: What Nubank's Cognitect Acquisition Means for Clojure; Content: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere. Engineer Jamie Walkerdine jam@juxt.pro jam@juxt.pro Analysis Opinion A technological revolution is going on in Brazil. -In 2011, . -Brazil was estimated to be the most c",283 -pwillia7,32384646,231,1659961494,Run your own DALL-E-like image generator,https://reticulated.net/dailyai/running-your-own-ai-image-generator-with-latent-diffusion/,"Helmsman full ahead! Get more video cards down to the engine. In this post, we’ll look at getting setup with running your own A.I. image generator. You need a Linux system with a CUDA enabled card to get this working through to the end. I did get the basic txt-2img script working in Windows. Unfortunately, for the July released , you need in order to index the openimages dataset, which is only available on Linux. worked fine for me. Here’s roughly what I gather you’ll need: I randomly stumbled upon the while I was browsing AI subreddits. A few posts mentioned it and I didn’t know what it was so I went googling. I am not a computer scientist, mathmatician, or any of the things that would be required to really understand what’s going on here. The paper about the new RAD models are und",Hacker News,14209353,"Title: Run your own DALL-E-like image generator; Content: Helmsman full ahead! Get more video cards down to the engine. In this post, we’ll look at getting setup with running your own A.I. image generator. You need a Linux system with a CUDA enabled card to get this working through to the end. I did get the basic txt-2img script working in Windows. Unfortunately, for the July released , you need in order to index the openimages dataset, which is only available on Linux. worked fine for me. Here’s roughly what I gather you’ll need: I randomly stumbled upon the while I was browsing AI subreddits. A few posts mentioned it and I didn’t know what it was so I went googling. I am not a computer scientist, mathmatician, or any of the things that would be required to really understand what’s going on here. The paper about the new RAD models are und",214 -jmerrick,32401413,12,1660067882,"Show HN: MOS, an application to help you deploy mathematical optimization models",https://fuinn.github.io/mos-docs/,"We built MOS in response to the frictions we experienced in deploying optimization solutions.

Some of the key benefits provided are the following: -- Models can be easily uploaded to the application after adding simple annotations to the model code. -- Models can be accessed via various available interfaces, including a REST API, a web graphical user interface, and client libraries in popular programming languages such as Python and Julia. -- Models can be run with different inputs by workers running locally or distributed over the network. -- Intermediate and end results can be extracted, browsed, and analyzed.

This is all available without the need for (the typically required) custom ad-hoc code.",Hacker News,6764307,"Title: Show HN: MOS, an application to help you deploy mathematical optimization models; Content: We built MOS in response to the frictions we experienced in deploying optimization solutions.

Some of the key benefits provided are the following: -- Models can be easily uploaded to the application after adding simple annotations to the model code. -- Models can be accessed via various available interfaces, including a REST API, a web graphical user interface, and client libraries in popular programming languages such as Python and Julia. -- Models can be run with different inputs by workers running locally or distributed over the network. -- Intermediate and end results can be extracted, browsed, and analyzed.

This is all available without the need for (the typically required) custom ad-hoc code.",161 -mountainview,32410630,8,1660133689,"Show HN:JuiceFS 1.0, A POSIX, HDFS, and S3 compliant cloud file system",https://juicefs.com/blog/en/posts/juicefs-release-v1/,"Today we are very pleased to release JuiceFS v1.0, which is the first Long Term Support(LTS) release after 18 months of continuous iteration and extensive validation in a large number of production environments. JuiceFS v1.0 is compatible with all previous releases and can be upgraded directly. JuiceFS is a distributed file system designed for the cloud environment. It is compatible with POSIX, HDFS, and S3 protocols. JuiceFS can be used as PV in Kubernetes through CSI driver, and it can also be widely used in big data, machine learning, and other scenarios that require shared file storage. Stable and reliable software cannot be achieved without a comprehensive testing system. JuiceFS’ testing system has covered daily basic testing, compatibility testing, third-party tool testing, and pr",Hacker News,52991502,"Title: Show HN:JuiceFS 1.0, A POSIX, HDFS, and S3 compliant cloud file system; Content: Today we are very pleased to release JuiceFS v1.0, which is the first Long Term Support(LTS) release after 18 months of continuous iteration and extensive validation in a large number of production environments. JuiceFS v1.0 is compatible with all previous releases and can be upgraded directly. JuiceFS is a distributed file system designed for the cloud environment. It is compatible with POSIX, HDFS, and S3 protocols. JuiceFS can be used as PV in Kubernetes through CSI driver, and it can also be widely used in big data, machine learning, and other scenarios that require shared file storage. Stable and reliable software cannot be achieved without a comprehensive testing system. JuiceFS’ testing system has covered daily basic testing, compatibility testing, third-party tool testing, and pr",198 -Fendy,32422387,6,1660201016,Ask HN: What are the alternatives of HN for hackers?,,Don't get me wrong. I think Hacker News are great and I often read good posts/news/works here.

I am wondering if there are alternatives/peers beyond my knowledge and are as hacker-friendly as HN. Thanks.,Hacker News,56290696,Title: Ask HN: What are the alternatives of HN for hackers?; Content: Don't get me wrong. I think Hacker News are great and I often read good posts/news/works here.

I am wondering if there are alternatives/peers beyond my knowledge and are as hacker-friendly as HN. Thanks.,91 -boeingUH60,32387345,139,1659975034,The AK-47,https://coolmilitarystuff.com/the-ak-47/," - Explore Interesting Things From Global Militaries The , popularly known as the AK-47, is an assault rifle originally developed for the Soviet Union by the famous arms designer and Russian general . Avtomat Kalashnikova translates to “automatic Kalashnikov,” named after its designer who developed the accepted version of it in 1947. The AK-47 and its variants are the most popular and widely adopted rifles globally, owing to their relatively low production cost, ease of use, and reliability under harsh conditions. You can find it in service with organized armed forces as well as militias and insurgencies across virtually every geographic region. It’s approximately 20% of worldwide firearms belong to the Kalashnikov family, three-quarters of which are AK-47s. Mikhail Kala",Hacker News,29867545,"Title: The AK-47; Content: - Explore Interesting Things From Global Militaries The , popularly known as the AK-47, is an assault rifle originally developed for the Soviet Union by the famous arms designer and Russian general . Avtomat Kalashnikova translates to “automatic Kalashnikov,” named after its designer who developed the accepted version of it in 1947. The AK-47 and its variants are the most popular and widely adopted rifles globally, owing to their relatively low production cost, ease of use, and reliability under harsh conditions. You can find it in service with organized armed forces as well as militias and insurgencies across virtually every geographic region. It’s approximately 20% of worldwide firearms belong to the Kalashnikov family, three-quarters of which are AK-47s. Mikhail Kala",191 -smartblondeva,32399266,266,1660058674,Don’t call it a comeback: Java is still champ,https://github.com/readme/featured/java-programming-language," - Artwork: - - Far from dead, the perpetually-popular language is up to speed and ready for the future. - - Mike Melanson // August 9, 2022 - amplifies the voices of the open source community: the maintainers, developers, and teams whose contributions move the world forward every day. No matter what ranking system you look at, whether the TIOBE Index, the Popularity of Programming Language Index, , or GitHub’s yearly , Java has been sitting among the top three languages since shortly after its launch in 1995. To listen to the general scuttlebutt of the developer crowd over time, however, you might think that Java was in fact in a period of great decline, or even . Take a closer look at some of these popularity numbers and you might argue that Java has slowly giv",Hacker News,90045539,"Title: Don’t call it a comeback: Java is still champ; Content: - Artwork: - - Far from dead, the perpetually-popular language is up to speed and ready for the future. - - Mike Melanson // August 9, 2022 - amplifies the voices of the open source community: the maintainers, developers, and teams whose contributions move the world forward every day. No matter what ranking system you look at, whether the TIOBE Index, the Popularity of Programming Language Index, , or GitHub’s yearly , Java has been sitting among the top three languages since shortly after its launch in 1995. To listen to the general scuttlebutt of the developer crowd over time, however, you might think that Java was in fact in a period of great decline, or even . Take a closer look at some of these popularity numbers and you might argue that Java has slowly giv",220 -themodelplumber,32417031,11,1660158840,34 Years Ago: 11 y.o. hacker Zero Cool causes 7 pt. drop in stock exchange,https://twitter.com/hakluke/status/1557242086423871488,"We’ve detected that JavaScript is disabled in this browser. Please enable JavaScript or switch to a supported browser to continue using twitter.com. You can see a list of supported browsers in our Help Center. - - - - - - © 2022 Twitter, Inc. - ",Hacker News,44348018,"Title: 34 Years Ago: 11 y.o. hacker Zero Cool causes 7 pt. drop in stock exchange; Content: We’ve detected that JavaScript is disabled in this browser. Please enable JavaScript or switch to a supported browser to continue using twitter.com. You can see a list of supported browsers in our Help Center. - - - - - - © 2022 Twitter, Inc. - ",95 -cp9,32385102,208,1659965276,Using unwrap() in Rust is okay,https://blog.burntsushi.net/unwrap/,"One day before Rust 1.0 was released, I published a - . -A particularly important but small section buried in the middle of the article -is named “ ”. That section briefly -described that, broadly speaking, using is okay if it’s in -test/example code or when panicking indicates a bug. I generally still hold that belief today. That belief is put into practice in -Rust’s standard library and in many core ecosystem crates. (And that practice -predates my blog post.) Yet, there still seems to be widespread confusion about -when it is and isn’t okay to use . This post will talk about that -in more detail and respond specifically to a number of positions I’ve seen -expressed. This blog post is written somewhat as a FAQ, but it’s meant to be read in -sequence. Each question builds on the one before it. :",Hacker News,28249810,"Title: Using unwrap() in Rust is okay; Content: One day before Rust 1.0 was released, I published a - . -A particularly important but small section buried in the middle of the article -is named “ ”. That section briefly -described that, broadly speaking, using is okay if it’s in -test/example code or when panicking indicates a bug. I generally still hold that belief today. That belief is put into practice in -Rust’s standard library and in many core ecosystem crates. (And that practice -predates my blog post.) Yet, there still seems to be widespread confusion about -when it is and isn’t okay to use . This post will talk about that -in more detail and respond specifically to a number of positions I’ve seen -expressed. This blog post is written somewhat as a FAQ, but it’s meant to be read in -sequence. Each question builds on the one before it. :",208 -tuyenhx,32410576,11,1660133355,Ask HN: How do you collect payment as Startup from Stripe none support country?,,"I wanted to use Stripe to collect payment. But I'm a founder from Stripe's none support countries.

I see there is an option Stripe Atlas. I'm a little hesitate about this option. I totally understand the cost, set up fee and yearly fee. But is there any other hidden fee after this? Like taxes? ...

I did research and saw a few posts tell that, it costed them about 10k/year (When using Stripe + Stripe Atlas) with many hidden fees.

I asked a lot of people around me, they avoided answering this and I don't know why. I even contacted Stripe's support, and they redirected my to a lawyer site with no clear answer. I'm so frustrated.

I have a dumb question.

How do you collect payment if you're in my situation?

Paypal seems a better option for this.",Hacker News,44757877,"Title: Ask HN: How do you collect payment as Startup from Stripe none support country?; Content: I wanted to use Stripe to collect payment. But I'm a founder from Stripe's none support countries.

I see there is an option Stripe Atlas. I'm a little hesitate about this option. I totally understand the cost, set up fee and yearly fee. But is there any other hidden fee after this? Like taxes? ...

I did research and saw a few posts tell that, it costed them about 10k/year (When using Stripe + Stripe Atlas) with many hidden fees.

I asked a lot of people around me, they avoided answering this and I don't know why. I even contacted Stripe's support, and they redirected my to a lawyer site with no clear answer. I'm so frustrated.

I have a dumb question.

How do you collect payment if you're in my situation?

Paypal seems a better option for this.",254 -feross,32385470,114,1659967248,DevDash: A highly configurable terminal dashboard,https://thedevdash.com/,"Built with from and . It will allow you to choose and display the most up-to-date metrics you need, at one place, from: The data will be automatically refreshed while you’re doing other productive tasks.",Hacker News,62038789,"Title: DevDash: A highly configurable terminal dashboard; Content: Built with from and . It will allow you to choose and display the most up-to-date metrics you need, at one place, from: The data will be automatically refreshed while you’re doing other productive tasks.",65 -travisgriggs,32421377,6,1660189834,Turkey’s underground city of 20k people,https://www.bbc.com/travel/article/20220810-derinkuyu-turkeys-underground-city-of-20000-people,"Culture Food Discovery Adventure Destinations Collections About us 50 Reasons to Love the World Untold America More Violent gusts whipped loose soil into the air as I hiked through Cappadocia's Love Valley. Pink- and yellow-hued hillsides coloured the rolling landscape scarred with deep red canyons, and chimneystack rock formations loomed in the distance. It was arid, hot, windy and devastatingly beautiful. Millennia ago, this volatile, volcanic environment naturally sculpted the spires surrounding me into their conical, mushroom-capped shapes, which now draw millions of visitors to hike or hot-air balloon in the central Turkish region. But beneath Cappadocia's crumbling surface, a marvel of equally gargantuan proportions lay hidden away for centuries; a subterranean city that could concea",Hacker News,23992756,"Title: Turkey’s underground city of 20k people; Content: Culture Food Discovery Adventure Destinations Collections About us 50 Reasons to Love the World Untold America More Violent gusts whipped loose soil into the air as I hiked through Cappadocia's Love Valley. Pink- and yellow-hued hillsides coloured the rolling landscape scarred with deep red canyons, and chimneystack rock formations loomed in the distance. It was arid, hot, windy and devastatingly beautiful. Millennia ago, this volatile, volcanic environment naturally sculpted the spires surrounding me into their conical, mushroom-capped shapes, which now draw millions of visitors to hike or hot-air balloon in the central Turkish region. But beneath Cappadocia's crumbling surface, a marvel of equally gargantuan proportions lay hidden away for centuries; a subterranean city that could concea",185 -pdrummond,32379927,253,1659906577,From throwaway side project to Switch in 2 years: my indie gamedev story,https://kellsgame.com/how-kells-came-to-be/,"I started this game back in 2020 as a fun little side-project to pass the time during the pandemic with lots of help from my son. Back then we didn’t even expect it to be playable, never mind it turning into a real game with 100+ levels and being released on Steam/PC. But even after that milestone, I never dreamed my son and I would be able to play it together around the TV on our favourite console! …my son Ben (19) had no idea I was working on a game. When I first sat down to start planning it out on the 4th of January 2020, I originally wanted to make a 2D platformer game. Super Mario World is my favourite game of all time and I still remember being totally in awe of the World Map the first time I played it as a kid and I wanted to use that as inspiration for my game. As I played around ",Hacker News,46412643,"Title: From throwaway side project to Switch in 2 years: my indie gamedev story; Content: I started this game back in 2020 as a fun little side-project to pass the time during the pandemic with lots of help from my son. Back then we didn’t even expect it to be playable, never mind it turning into a real game with 100+ levels and being released on Steam/PC. But even after that milestone, I never dreamed my son and I would be able to play it together around the TV on our favourite console! …my son Ben (19) had no idea I was working on a game. When I first sat down to start planning it out on the 4th of January 2020, I originally wanted to make a 2D platformer game. Super Mario World is my favourite game of all time and I still remember being totally in awe of the World Map the first time I played it as a kid and I wanted to use that as inspiration for my game. As I played around ",209 -donohoe,32410162,32,1660130227,Will Europe Force a Facebook Blackout?,https://www.wired.com/story/facebook-eu-us-data-transfers/,"To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . in Europe—and Meta wants you to know about it. Every three months since June 2018, the company has used its financial results to warn that it could be forced to stop running Facebook and Instagram across the continent—potentially pulling its apps from millions of people and thousands of businesses—if it can’t . Whether Meta’s bluffing will become clear soon enough. This content can also be viewed on the site it from. Data regulators are on the verge of making a historic ruling in a years-long case, and they are expected to say Facebook’s data transfers across the Atlantic should be blocked",Hacker News,98369744,"Title: Will Europe Force a Facebook Blackout?; Content: To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . in Europe—and Meta wants you to know about it. Every three months since June 2018, the company has used its financial results to warn that it could be forced to stop running Facebook and Instagram across the continent—potentially pulling its apps from millions of people and thousands of businesses—if it can’t . Whether Meta’s bluffing will become clear soon enough. This content can also be viewed on the site it from. Data regulators are on the verge of making a historic ruling in a years-long case, and they are expected to say Facebook’s data transfers across the Atlantic should be blocked",194 -melenaboija,32420642,7,1660182116,Miraculin,https://en.wikipedia.org/wiki/Miraculin," is a , a extracted from the fruit of . The berry, also known as the miracle fruit, was documented by explorer , who searched for many different fruits during a 1725 excursion to its native West Africa. - Miraculin itself does not taste . When are exposed to miraculin, the protein binds to the sweetness receptors. This causes normally sour-tasting acidic foods, such as , to be perceived as sweet. The effect lasts up to about an hour. - The sweetening properties of berries were first noted by des Marchais during expeditions to West Africa in the 18th century. The term derived from experiments to isolate and purify the active that gave the berries their sweetening effects, results that were published simultaneously by Japanese and Dutch scientists working independently in th",Hacker News,3623271,"Title: Miraculin; Content: is a , a extracted from the fruit of . The berry, also known as the miracle fruit, was documented by explorer , who searched for many different fruits during a 1725 excursion to its native West Africa. - Miraculin itself does not taste . When are exposed to miraculin, the protein binds to the sweetness receptors. This causes normally sour-tasting acidic foods, such as , to be perceived as sweet. The effect lasts up to about an hour. - The sweetening properties of berries were first noted by des Marchais during expeditions to West Africa in the 18th century. The term derived from experiments to isolate and purify the active that gave the berries their sweetening effects, results that were published simultaneously by Japanese and Dutch scientists working independently in th",185 -dougabug,32387746,43,1659976598,Solving and explaining university math problems with Deep Learning,https://www.pnas.org/doi/10.1073/pnas.2123433119,Please enable Cookies and reload the page. This process is automatic. Your browser will redirect to your requested content shortly. Please allow up to 5 seconds… Redirecting…,Hacker News,41539629,Title: Solving and explaining university math problems with Deep Learning; Content: Please enable Cookies and reload the page. This process is automatic. Your browser will redirect to your requested content shortly. Please allow up to 5 seconds… Redirecting…,49 -goncalo-r,32384662,53,1659961645,Show HN: Build for any cloud with the same code,https://github.com/multycloud/multy,"We have been working on Multy, an open-source[1] tool that enables developers to deploy and switch to any cloud - AWS, Azure and GCP for now.

We realized that, even when using Terraform, writing infrastructure code is very different for each cloud provider. This means changing clouds or deploying the same infrastructure in multiple clouds requires rewriting the same thing multiple times. And even though most core resources have the same functionality, developers need to learn a new provider and all its nuances when choosing a new cloud. This is why we built Multy.

Multy is currently available as a Terraform provider. You can write cloud-agnostic code and then just choose which cloud you want to deploy to. Multy will then call the cloud provider APIs on your behalf. For example, the following Terraform code deploys a virtual network in AWS and can be easily changed to deploy to Azure or GCP:

``` -resource "multy_virtual_network" "vn" {

  cloud      = "aws" // or azure, or gcp
-
-  name       = "multy_vn"
-  cidr_block = "10.0.0.0/16"
-  location   = "eu_west_1"
-} -```

Our goal is to expose any configuration that is common across all clouds, but there’s always specific features that are not available in all of them. For example, if you want a very specific AWS CPU for your Virtual Machine or use a region that is only available in GCP. To enable this, we implemented overrides [2] - a way to configure the underlying infrastructure for cloud-specific purposes. You can also mix other Terraform code that uses the cloud-specific providers with Multy. While this makes you somewhat locked in, having your 80% or 90% of your infrastructure cloud-agnostic is still very powerful.

You can see more complex examples in our documentation - https://docs.multy.dev/examples/.

We’re still in early days and looking for feedback from other developers on our approach. Let us know what you think!

[1] https://github.com/multycloud/multy

[2] https://docs.multy.dev/overrides",Hacker News,6626854,"Title: Show HN: Build for any cloud with the same code; Content: We have been working on Multy, an open-source[1] tool that enables developers to deploy and switch to any cloud - AWS, Azure and GCP for now.

We realized that, even when using Terraform, writing infrastructure code is very different for each cloud provider. This means changing clouds or deploying the same infrastructure in multiple clouds requires rewriting the same thing multiple times. And even though most core resources have the same functionality, developers need to learn a new provider and all its nuances when choosing a new cloud. This is why we built Multy.

Multy is currently available as a Terraform provider. You can write cloud-agnostic code and then just choose which cloud you want to deploy to. Multy will then call the cloud provider APIs on your behalf. For example, the following Terraform code deploys a virtual network in AWS and can be easily changed to deploy to Azure or GCP:

``` -resource "multy_virtual_network" "vn" {

  cloud      = "aws" // or azure, or gcp
-
-  name       = "multy_vn"
-  cidr_block = "10.0.0.0/16"
-  location   = "eu_west_1"
-} -```

Our goal is to expose any configuration that is common across all clouds, but there’s always specific features that are not available in all of them. For example, if you want a very specific AWS CPU for your Virtual Machine or use a region that is only available in GCP. To enable this, we implemented overrides [2] - a way to configure the underlying infrastructure for cloud-specific purposes. You can also mix other Terraform code that uses the cloud-specific providers with Multy. While this makes you somewhat locked in, having your 80% or 90% of your infrastructure cloud-agnostic is still very powerful.

You can see more complex examples in our documentation - https://docs.multy.dev/examples/.

We’re still in early days and looking for feedback from other developers on our approach. Let us know what you think!

[1] https://github.com/multycloud/multy

[2] https://docs.multy.dev/overrides",783 -behnamoh,32421269,4,1660188960,This Cute Feature Summarizes Why I Prefer Mac to Windows and Linux,https://medium.com/@parttimeben/this-cute-feature-summarizes-why-i-prefer-mac-to-windows-and-linux-f87d46f09299,"Member-only There are love Mac, and it. On my blog, you probably have seen some of them. As with some forms of perfectionist emotions, the love and hatred come entangled; the love is there, and it’s exactly the reason you get annoyed by things that could have been even better, hence the hatred. Therefore, you don’t really have feelings of hatred towards that thing, you just get disappointed when things aren’t perfect. https://medium.com/@parttimeben/membership | PhD Candidate, writes mainly about Mac, Windows, Linux, Programming, Life | https://medium.com/@parttimeben/about Love podcasts or audiobooks? Learn on the go with our new app. | PhD Candidate, writes mainly about Mac, Windows, Linux, Programming, Life | Ahmad Ali in Geek Culture Jean-marc Buchert in UX Collective Dan",Hacker News,70789286,"Title: This Cute Feature Summarizes Why I Prefer Mac to Windows and Linux; Content: Member-only There are love Mac, and it. On my blog, you probably have seen some of them. As with some forms of perfectionist emotions, the love and hatred come entangled; the love is there, and it’s exactly the reason you get annoyed by things that could have been even better, hence the hatred. Therefore, you don’t really have feelings of hatred towards that thing, you just get disappointed when things aren’t perfect. https://medium.com/@parttimeben/membership | PhD Candidate, writes mainly about Mac, Windows, Linux, Programming, Life | https://medium.com/@parttimeben/about Love podcasts or audiobooks? Learn on the go with our new app. | PhD Candidate, writes mainly about Mac, Windows, Linux, Programming, Life | Ahmad Ali in Geek Culture Jean-marc Buchert in UX Collective Dan",222 -Jimmc414,32393536,142,1660011201,Three people in critical condition from Google data center 'electrical incident',https://www.sfgate.com/news/article/google-electrical-incident-injures-3-17360321.php,"A Google Maps image of the Google Data Center in Council Bluffs, Iowa. Three electricians who were transported to a local hospital with burn injuries after an arc flash outside a Google data center are now in stable condition, according to a Google spokesperson. The full extent of their injuries is unknown; the Council Bluffs Fire Department and Police Department, in addition to the Nebraska Medical Center, don't have more details to share at this time, they each told SFGATE. The three individuals who were injured are not Google employees, according to multiple sources with knowledge of the situation.  Google users worldwide reported a brief outage on Monday that affected Gmail, Maps. and Images search, but Google says that was due to a software update issue, and was unrelated to the arc ",Hacker News,26964144,"Title: Three people in critical condition from Google data center 'electrical incident'; Content: A Google Maps image of the Google Data Center in Council Bluffs, Iowa. Three electricians who were transported to a local hospital with burn injuries after an arc flash outside a Google data center are now in stable condition, according to a Google spokesperson. The full extent of their injuries is unknown; the Council Bluffs Fire Department and Police Department, in addition to the Nebraska Medical Center, don't have more details to share at this time, they each told SFGATE. The three individuals who were injured are not Google employees, according to multiple sources with knowledge of the situation.  Google users worldwide reported a brief outage on Monday that affected Gmail, Maps. and Images search, but Google says that was due to a software update issue, and was unrelated to the arc ",175 -segfaultbuserr,32399672,49,1660060730,The do-it-yourself cyclotron (2010),https://www.symmetrymagazine.org/article/august-2010/the-do-it-yourself-cyclotron,"Amateur cyclotron builders are dedicated, tenacious, and obsessed. Another thing they have in common: The experience changes their lives. the only thing amateur car builders needed was a ride to work, they wouldn’t ever build cars. While it’s certainly nice to take the finished product around the block to show the neighbors, there’s something more than transportation motivating a hot-rod builder. That’s the analogy Mark Yuly uses for a project he’s working on with his undergraduate physics students at Houghton College: building a particle accelerator. Yuly belongs to a rare breed of people who have a deep fascination—you could even call it an obsession—with cyclotrons. For many of those obsessed, the only way to satiate their hunger for these machines is to build their own. There are no g",Hacker News,69860065,"Title: The do-it-yourself cyclotron (2010); Content: Amateur cyclotron builders are dedicated, tenacious, and obsessed. Another thing they have in common: The experience changes their lives. the only thing amateur car builders needed was a ride to work, they wouldn’t ever build cars. While it’s certainly nice to take the finished product around the block to show the neighbors, there’s something more than transportation motivating a hot-rod builder. That’s the analogy Mark Yuly uses for a project he’s working on with his undergraduate physics students at Houghton College: building a particle accelerator. Yuly belongs to a rare breed of people who have a deep fascination—you could even call it an obsession—with cyclotrons. For many of those obsessed, the only way to satiate their hunger for these machines is to build their own. There are no g",192 -todsacerdoti,32413349,8,1660144483,The Security Pros and Cons of Using Email Aliases,https://krebsonsecurity.com/2022/08/the-security-pros-and-cons-of-using-email-aliases/,"One way to tame your email inbox is to get in the habit of using unique email aliases when signing up for new accounts online. Adding a “+” character after the username portion of your email address — followed by a notation specific to the site you’re signing up at — lets you create an infinite number of unique email addresses tied to the same account. Aliases can help users detect breaches and fight spam. But not all websites allow aliases, and they can complicate account recovery. Here’s a look at the pros and cons of adopting a unique alias for each website. What is an email alias? When you sign up at a site that requires an email address, think of a word or phrase that represents that site for you, and then add that prefaced by a “+” sign just to the left of the “@” sign in your email ",Hacker News,60210447,"Title: The Security Pros and Cons of Using Email Aliases; Content: One way to tame your email inbox is to get in the habit of using unique email aliases when signing up for new accounts online. Adding a “+” character after the username portion of your email address — followed by a notation specific to the site you’re signing up at — lets you create an infinite number of unique email addresses tied to the same account. Aliases can help users detect breaches and fight spam. But not all websites allow aliases, and they can complicate account recovery. Here’s a look at the pros and cons of adopting a unique alias for each website. What is an email alias? When you sign up at a site that requires an email address, think of a word or phrase that represents that site for you, and then add that prefaced by a “+” sign just to the left of the “@” sign in your email ",197 -Tomte,32401075,57,1660066540,Unrepresentative big surveys significantly overestimated US vaccine uptake,https://www.nature.com/articles/s41586-021-04198-4,"Thank you for visiting nature.com. You are using a browser version with limited support for CSS. To obtain - the best experience, we recommend you use a more up to date browser (or turn off compatibility mode in - Internet Explorer). In the meantime, to ensure continued support, we are displaying the site without styles - and JavaScript. Advertisement - - ,  695–700 ( ) - 63k 28 1539 Surveys are a crucial tool for understanding public opinion and behaviour, and their accuracy depends on maintaining statistical representativeness of their target populations by minimizing biases from all sources. Increasing data size shrinks confidence intervals but magnifies the effect of survey bias: an instance of the Big Data Paradox . Here we demonstrate this paradox in ",Hacker News,25843652,"Title: Unrepresentative big surveys significantly overestimated US vaccine uptake; Content: Thank you for visiting nature.com. You are using a browser version with limited support for CSS. To obtain - the best experience, we recommend you use a more up to date browser (or turn off compatibility mode in - Internet Explorer). In the meantime, to ensure continued support, we are displaying the site without styles - and JavaScript. Advertisement - - ,  695–700 ( ) - 63k 28 1539 Surveys are a crucial tool for understanding public opinion and behaviour, and their accuracy depends on maintaining statistical representativeness of their target populations by minimizing biases from all sources. Increasing data size shrinks confidence intervals but magnifies the effect of survey bias: an instance of the Big Data Paradox . Here we demonstrate this paradox in ",206 -Tomte,32383099,62,1659943387,Blosxom: The Zen of Blogging,http://www.blosxom.com/," -about - - -documentation for users - - - -documentation for developers - - - -downloads - - - -powered by - - - - coming soon - - About Blosxom -Blosxom (pronounced ""blossom"") is a lightweight yet feature-packed weblog -application designed from the ground up with simplicity, usability, -and interoperability in mind. - - Simplicity -Blogging--and, indeed, any online publishing-- should be as simple as typing away in your favourite text editor and hitting Save. Fundamental is Blosxom's reliance upon the file system, folders and files as its content database. Entries are plain text files like any other. - - Usability -Create, edit, rename, and delete entries on the command-line, via FTP, WebDAV, or anything else you might use to manipulate your files. There's no import or export;",Hacker News,166545,"Title: Blosxom: The Zen of Blogging; Content: -about - - -documentation for users - - - -documentation for developers - - - -downloads - - - -powered by - - - - coming soon - - About Blosxom -Blosxom (pronounced ""blossom"") is a lightweight yet feature-packed weblog -application designed from the ground up with simplicity, usability, -and interoperability in mind. - - Simplicity -Blogging--and, indeed, any online publishing-- should be as simple as typing away in your favourite text editor and hitting Save. Fundamental is Blosxom's reliance upon the file system, folders and files as its content database. Entries are plain text files like any other. - - Usability -Create, edit, rename, and delete entries on the command-line, via FTP, WebDAV, or anything else you might use to manipulate your files. There's no import or export;",247 -shreythecray,32404957,17,1660082435,What is product-led growth?,https://www.productled.org/foundations/what-is-product-led-growth,"The path to product-led is a long one. We started the Product-Led Growth Collective because we wanted to be part of a community—to talk shop, trade ideas, and learn from like-minded folks on their own product-led growth journeys. If that includes you, then grab a seat and gather 'round the table. We are in the middle of a massive shift in the way people use and buy software. ‍ It’s been well over a decade since Salesforce brought software to the cloud. Apple put digital experiences in people’s pockets back in 2009 with the first iPhone. And in the years since, the market has been flooded with consumer and B2B products that promise to meet just about every need under the sun. Yesterday’s most exceptional product experiences are no longer exciting—they’re expected. That’s w",Hacker News,77981192,"Title: What is product-led growth?; Content: The path to product-led is a long one. We started the Product-Led Growth Collective because we wanted to be part of a community—to talk shop, trade ideas, and learn from like-minded folks on their own product-led growth journeys. If that includes you, then grab a seat and gather 'round the table. We are in the middle of a massive shift in the way people use and buy software. ‍ It’s been well over a decade since Salesforce brought software to the cloud. Apple put digital experiences in people’s pockets back in 2009 with the first iPhone. And in the years since, the market has been flooded with consumer and B2B products that promise to meet just about every need under the sun. Yesterday’s most exceptional product experiences are no longer exciting—they’re expected. That’s w",219 -Tomte,32402661,18,1660072501,Tarot for Hackers (2019),https://xeiaso.net/blog/tarot-for-hackers-2019-07-24,"""Oh no, she's finally lost it"" were the words a very close friend of mine said -when I first told her I was experimenting with reading tarot cards. Tarot cards -are a stereotypical staple of the occult/The Spoop™. Every card represents an -idea (or a meme) that can be expressed in a few ways. They act to your soul -like iron filings do to a magnet. When you shuffle the cards, the Universe (via -entropy) examines all of those myriad inputs and helpfully orders them so you -get exactly the message you need most. It's actually an extremely philosophical act to draw from a tarot deck and -interpret the results. Over the years there have been many interpretations and -frameworks of interpretations about tarot; but I would like to introduce a -meta-framework for using tarot cards as a debugging tool. As ",Hacker News,1388144,"Title: Tarot for Hackers (2019); Content: ""Oh no, she's finally lost it"" were the words a very close friend of mine said -when I first told her I was experimenting with reading tarot cards. Tarot cards -are a stereotypical staple of the occult/The Spoop™. Every card represents an -idea (or a meme) that can be expressed in a few ways. They act to your soul -like iron filings do to a magnet. When you shuffle the cards, the Universe (via -entropy) examines all of those myriad inputs and helpfully orders them so you -get exactly the message you need most. It's actually an extremely philosophical act to draw from a tarot deck and -interpret the results. Over the years there have been many interpretations and -frameworks of interpretations about tarot; but I would like to introduce a -meta-framework for using tarot cards as a debugging tool. As ",196 -aseemk,32379245,227,1659901619,"Ignore the haters, and other lessons learned from creating JSON5",https://aseemk.substack.com/p/ignore-the-f-ing-haters-json5,"I wasn’t upset or offended by any of this. I was mainly just surprised and shell-shocked. These results are in such stark contrast to the reception I originally got. So what gives? I take three lessons from this experience that I’d love to share now, ten years later. But there’s nuance here, and some notable implications. But there’s something to be said about actually listening to feedback and criticism, right? And not just blindly building in a vacuum, ignoring the world around you? This lesson applies broadly. This batch of… users should not impact your product strategy in any way. They’ll request distracting features, present ill-fitting use cases and probably be very vocal, all before they churn out and leave you with a mangled, muddled roadmap. As surprising or painful as it may seem",Hacker News,93544274,"Title: Ignore the haters, and other lessons learned from creating JSON5; Content: I wasn’t upset or offended by any of this. I was mainly just surprised and shell-shocked. These results are in such stark contrast to the reception I originally got. So what gives? I take three lessons from this experience that I’d love to share now, ten years later. But there’s nuance here, and some notable implications. But there’s something to be said about actually listening to feedback and criticism, right? And not just blindly building in a vacuum, ignoring the world around you? This lesson applies broadly. This batch of… users should not impact your product strategy in any way. They’ll request distracting features, present ill-fitting use cases and probably be very vocal, all before they churn out and leave you with a mangled, muddled roadmap. As surprising or painful as it may seem",193 -benbreen,32394533,14,1660023558,Breaking the news of the fall of Richard II,https://blogs.bl.uk/digitisedmanuscripts/2022/08/breaking-news.html," 09 August 2022 The oldest item in the British Library’s current exhibition (open until 21 August 2022) is an account of the Battle of Flodden in 1513. This small pamphlet is the earliest surviving example of printed news in Britain, but of course written records of contemporary events and experiences survive from ancient times, and from many parts of the world. A key focus of the current exhibition is the biases revealed in the way news is reported. Though they may not have been as immediate, or intended for circulation in the same way that news is today, medieval historical chronicles are evidence of the way events were seen and recorded by eyewitnesses at the time or shortly afterwards. The material that writers of chronicles chose to include or omit can tell us as much about their v",Hacker News,14606499,"Title: Breaking the news of the fall of Richard II; Content: 09 August 2022 The oldest item in the British Library’s current exhibition (open until 21 August 2022) is an account of the Battle of Flodden in 1513. This small pamphlet is the earliest surviving example of printed news in Britain, but of course written records of contemporary events and experiences survive from ancient times, and from many parts of the world. A key focus of the current exhibition is the biases revealed in the way news is reported. Though they may not have been as immediate, or intended for circulation in the same way that news is today, medieval historical chronicles are evidence of the way events were seen and recorded by eyewitnesses at the time or shortly afterwards. The material that writers of chronicles chose to include or omit can tell us as much about their v",175 -kiyanwang,32378752,252,1659898363,Oncall Compensation for Software Engineers,https://blog.pragmaticengineer.com/oncall-compensation/,"This issue is the second part and final article in a series about oncall. Part 1 – published last week – covers . In this issue, we dive into: In this issue, we’ll go through more than 80 data points on how much different companies pay for oncall. A preview of some of the data we’ll discuss: Looking across the industry, there are several different philosophies. Some companies hire dedicated tech people whose only job is to be oncall, handle alerts, and improve the oncall infrastructure. This role is called ‘DevOps Engineer’ at some companies, SRE (Site Reliability Engineer) at others, and may also be called ‘Operations Engineer.’ The role is constructed so expectations are clear and shifts are staggered, so the workload is reasonable. These roles are typical at more traditional companies,",Hacker News,7727216,"Title: Oncall Compensation for Software Engineers; Content: This issue is the second part and final article in a series about oncall. Part 1 – published last week – covers . In this issue, we dive into: In this issue, we’ll go through more than 80 data points on how much different companies pay for oncall. A preview of some of the data we’ll discuss: Looking across the industry, there are several different philosophies. Some companies hire dedicated tech people whose only job is to be oncall, handle alerts, and improve the oncall infrastructure. This role is called ‘DevOps Engineer’ at some companies, SRE (Site Reliability Engineer) at others, and may also be called ‘Operations Engineer.’ The role is constructed so expectations are clear and shifts are staggered, so the workload is reasonable. These roles are typical at more traditional companies,",186 -mitchbob,32386984,111,1659973665,The Reluctant Prophet of Effective Altruism,https://www.newyorker.com/magazine/2022/08/15/the-reluctant-prophet-of-effective-altruism,"To revisit this article, select My Account, then   To revisit this article, visit My Profile, then This content can also be viewed on the site it from. The philosopher William MacAskill credits his personal transfiguration to an undergraduate seminar at Cambridge. Before this shift, MacAskill liked to drink too many pints of beer and frolic about in the nude, climbing pitched roofs by night for the life-affirming flush; he was the saxophonist in a campus funk band that played the May Balls, and was known as a hopeless romantic. But at eighteen, when he was first exposed to “Famine, Affluence, and Morality,” a 1972 essay by the radical utilitarian Peter Singer, MacAskill felt a slight click as he was shunted onto a track of rigorous and uncompromising moralism. Singer, prompted by w",Hacker News,80344235,"Title: The Reluctant Prophet of Effective Altruism; Content: To revisit this article, select My Account, then   To revisit this article, visit My Profile, then This content can also be viewed on the site it from. The philosopher William MacAskill credits his personal transfiguration to an undergraduate seminar at Cambridge. Before this shift, MacAskill liked to drink too many pints of beer and frolic about in the nude, climbing pitched roofs by night for the life-affirming flush; he was the saxophonist in a campus funk band that played the May Balls, and was known as a hopeless romantic. But at eighteen, when he was first exposed to “Famine, Affluence, and Morality,” a 1972 essay by the radical utilitarian Peter Singer, MacAskill felt a slight click as he was shunted onto a track of rigorous and uncompromising moralism. Singer, prompted by w",199 -jart,32376322,238,1659879055,Using Landlock to Sandbox GNU Make,https://justine.lol/make/," -Aug 7 , 2022 @ - - - -I've modified GNU Make to support strict dependency checking. This is -all thanks to the system -calls which were introduced in Linux Kernel 5.13 twelve months ago. What -it means is that Make can now solve the cache invalidation problem -similar to except with 5x -better performance. - - - -I blogged last month about our work - as part of -the -project. The thought occurred to me that sandboxes aren't just good for -security: they have applications in build systems too. So I used -unveil() to patch GNU Make so it can function like a zero-configuration -sandbox, and I'm making this work available to the community using -the format. - - - -The basic idea is when Make runs a command, that command should only -have access to a limited number of files: - - - -That way, if some ro",Hacker News,24970701,"Title: Using Landlock to Sandbox GNU Make; Content: -Aug 7 , 2022 @ - - - -I've modified GNU Make to support strict dependency checking. This is -all thanks to the system -calls which were introduced in Linux Kernel 5.13 twelve months ago. What -it means is that Make can now solve the cache invalidation problem -similar to except with 5x -better performance. - - - -I blogged last month about our work - as part of -the -project. The thought occurred to me that sandboxes aren't just good for -security: they have applications in build systems too. So I used -unveil() to patch GNU Make so it can function like a zero-configuration -sandbox, and I'm making this work available to the community using -the format. - - - -The basic idea is when Make runs a command, that command should only -have access to a limited number of files: - - - -That way, if some ro",226 -brianrisk,32379430,244,1659903092,"In-browser retro-futuristic tank game, open source",https://synthblast.com," - The goal of Synth Blast is to complete as many levels as possible as quickly as possible. Levels are policed - by malevolent tanks that home in on your position. - - SYNTH BLAST is inspired by the first-person, futuristic tank shooter games of the 80's and early 90's as well as - classic synthesizer music. The neon colors, the Miami nights, the music, the - trees lining the road, the infinite road trip into the sunset that extends all through the night... - What's not to love about the 80's? - - Games similar to Synth Blast: - - - - - Synth*Blast soundtrack: The hit retro sound of swirling, driving synthesizers and ethereal vocals. - Songs about love, alienation, longing and the expanse of eternity. - - -",Hacker News,68348594,"Title: In-browser retro-futuristic tank game, open source; Content: - The goal of Synth Blast is to complete as many levels as possible as quickly as possible. Levels are policed - by malevolent tanks that home in on your position. - - SYNTH BLAST is inspired by the first-person, futuristic tank shooter games of the 80's and early 90's as well as - classic synthesizer music. The neon colors, the Miami nights, the music, the - trees lining the road, the infinite road trip into the sunset that extends all through the night... - What's not to love about the 80's? - - Games similar to Synth Blast: - - - - - Synth*Blast soundtrack: The hit retro sound of swirling, driving synthesizers and ethereal vocals. - Songs about love, alienation, longing and the expanse of eternity. - - -",275 -jordanmoconnor,32393545,396,1660011272,Write a note to your spouse every day,https://jdnoc.com/note/,"August 08, 2022 Writing a note to my wife every day has single-handedly made my life so much better in a lot of ways, and I want more people to experience the same thing. Before we get into the juicy stuff, I’m a husband who is 30. I also have 4 kids, ages 6 and under. I’m the sole-provider for the family (though my wife works harder). Between the job, the kids, and extrafamilial obligations, there’s not a lot of time for communication with my wife. We’re on the go from sun-up to sun-down, and at the end of the day we drop into bed exhausted to get just enough sleep for the next day. Very often in the past, a week or so would go by and I hadn’t even so much as checked in on my wife. Often times if something was stressing me out I wouldn’t mention it until I boiled over, and I would treat ",Hacker News,36482859,"Title: Write a note to your spouse every day; Content: August 08, 2022 Writing a note to my wife every day has single-handedly made my life so much better in a lot of ways, and I want more people to experience the same thing. Before we get into the juicy stuff, I’m a husband who is 30. I also have 4 kids, ages 6 and under. I’m the sole-provider for the family (though my wife works harder). Between the job, the kids, and extrafamilial obligations, there’s not a lot of time for communication with my wife. We’re on the go from sun-up to sun-down, and at the end of the day we drop into bed exhausted to get just enough sleep for the next day. Very often in the past, a week or so would go by and I hadn’t even so much as checked in on my wife. Often times if something was stressing me out I wouldn’t mention it until I boiled over, and I would treat ",221 -selimonder,32384074,51,1659955751,Diffsound: Discrete Diffusion Model for Text-to-Sound Generation,http://dongchaoyang.top/text-to-sound-synthesis-demo/,"This is a for our paper . Code and Pre-trained model can be found on . In the following, we will show some generated samples by our proposed method. If you want to find more samples, please refer to our . [ ] [ ] [ ] [ ] [ ] [ ]",Hacker News,66562652,"Title: Diffsound: Discrete Diffusion Model for Text-to-Sound Generation; Content: This is a for our paper . Code and Pre-trained model can be found on . In the following, we will show some generated samples by our proposed method. If you want to find more samples, please refer to our . [ ] [ ] [ ] [ ] [ ] [ ]",84 -thunderbong,32409479,5,1660122940,Tao: The Power of the Graph,https://engineering.fb.com/2013/06/25/core-data/tao-the-power-of-the-graph/,"Facebook puts an extremely demanding workload on its data backend. Every time any one of over a billion active users visits Facebook through a desktop browser or on a mobile device, they are presented with hundreds of pieces of information from the social graph. Users see News Feed stories; comments, likes, and shares for those stories; photos and check-ins from their friends — the list goes on. The high degree of output customization, combined with a high update rate of a typical user’s News Feed, makes it impossible to generate the views presented to users ahead of time. Thus, the data set must be retrieved and rendered on the fly in a few hundred milliseconds. This challenge is made more difficult because the data set is not easily partitionable, and by the tendency of some items, such ",Hacker News,19674944,"Title: Tao: The Power of the Graph; Content: Facebook puts an extremely demanding workload on its data backend. Every time any one of over a billion active users visits Facebook through a desktop browser or on a mobile device, they are presented with hundreds of pieces of information from the social graph. Users see News Feed stories; comments, likes, and shares for those stories; photos and check-ins from their friends — the list goes on. The high degree of output customization, combined with a high update rate of a typical user’s News Feed, makes it impossible to generate the views presented to users ahead of time. Thus, the data set must be retrieved and rendered on the fly in a few hundred milliseconds. This challenge is made more difficult because the data set is not easily partitionable, and by the tendency of some items, such ",171 -lucasfcosta,32382365,173,1659932498,Why your daily stand-ups don't work and how to fix them,https://lucasfcosta.com/2022/08/07/how-to-improve-daily-standups.html,"Daily stand-ups are a classic example of . We all know they’re useless, but we tell ourselves “that’s just how things are” and do nothing about it. These days, we do stand-ups because that’s what we’re told to, not because they solve any particular problems. The software industry has been doing daily stand-ups for so long that it doesn’t remember why they exist. At some point along the way, stand-ups went from a solution to a meaningless dogmatic ritual. Here are symptoms which indicate you’re doing your stand-ups in the wrong way, for the wrong reasons: . In this post, I’ll explain the actual goal of a stand-up and why it’s a productive meeting to have, providing teams to do it right. Furthermore, I’ll explain what “right” means and the nuance involved in tailor",Hacker News,12751235,"Title: Why your daily stand-ups don't work and how to fix them; Content: Daily stand-ups are a classic example of . We all know they’re useless, but we tell ourselves “that’s just how things are” and do nothing about it. These days, we do stand-ups because that’s what we’re told to, not because they solve any particular problems. The software industry has been doing daily stand-ups for so long that it doesn’t remember why they exist. At some point along the way, stand-ups went from a solution to a meaningless dogmatic ritual. Here are symptoms which indicate you’re doing your stand-ups in the wrong way, for the wrong reasons: . In this post, I’ll explain the actual goal of a stand-up and why it’s a productive meeting to have, providing teams to do it right. Furthermore, I’ll explain what “right” means and the nuance involved in tailor",257 -ETH_start,32395971,381,1660039651,GitHub deleted accounts of people who contributed to Tornado Cash repos,https://twitter.com/bantg/status/1556721709931175937,"We’ve detected that JavaScript is disabled in this browser. Please enable JavaScript or switch to a supported browser to continue using twitter.com. You can see a list of supported browsers in our Help Center. - - - - - - © 2022 Twitter, Inc. - ",Hacker News,55469302,"Title: GitHub deleted accounts of people who contributed to Tornado Cash repos; Content: We’ve detected that JavaScript is disabled in this browser. Please enable JavaScript or switch to a supported browser to continue using twitter.com. You can see a list of supported browsers in our Help Center. - - - - - - © 2022 Twitter, Inc. - ",87 -persiankat,32419699,4,1660173653,What are the best resources to learn SIMD and intrinsics?,,Mainly interested in applications of Machine Learning and Computer Vision algorithms?,Hacker News,13311841,Title: What are the best resources to learn SIMD and intrinsics?; Content: Mainly interested in applications of Machine Learning and Computer Vision algorithms?,31 -iamzamek,32409112,7,1660119214,Show HN: Layoffbase – the place where you can get a new tech job after layoff,https://layoffbase.com/,"I knew that layoffs in tech were coming. -When it started, I've created Layoffbase to collect people without a job and help them get a new one. Now, I try to manually connect them with companies.

What do you think about it? How can I improve this?",Hacker News,89673249,"Title: Show HN: Layoffbase – the place where you can get a new tech job after layoff; Content: I knew that layoffs in tech were coming. -When it started, I've created Layoffbase to collect people without a job and help them get a new one. Now, I try to manually connect them with companies.

What do you think about it? How can I improve this?",92 -franczesko,32420903,3,1660185198,How Airbnb is ruining local communities in north Wales,https://www.theguardian.com/technology/2022/aug/10/i-wanted-my-children-to-grow-up-here-how-airbnb-is-ruining-local-communities-in-north-wales,"Families in Gwynedd county are being evicted as swathes of property are converted to short-term rentals for the tourism industry – and the situation being played out across the country. Can anything be done to help? At the time, Houston was living in a four-bedroom cottage in the village of Dinorwig, in the county of Gwynedd, north . Houston, her two teenage children and their stepfather had lived there since January 2020 and never been late on their £800-a-month rent. She pulls out her phone. “Christmas was heaven,” she sighs, pausing on an image of the spacious kitchen with a flagstone floor and log-burning stove. “You’d just snuggle down and close the curtains.” Dinorwig is just 15 miles from the foot of Yr Wyddfa (Snowdon), Wales’s highest peak, which draws annually. Gwynedd is a la",Hacker News,14702523,"Title: How Airbnb is ruining local communities in north Wales; Content: Families in Gwynedd county are being evicted as swathes of property are converted to short-term rentals for the tourism industry – and the situation being played out across the country. Can anything be done to help? At the time, Houston was living in a four-bedroom cottage in the village of Dinorwig, in the county of Gwynedd, north . Houston, her two teenage children and their stepfather had lived there since January 2020 and never been late on their £800-a-month rent. She pulls out her phone. “Christmas was heaven,” she sighs, pausing on an image of the spacious kitchen with a flagstone floor and log-burning stove. “You’d just snuggle down and close the curtains.” Dinorwig is just 15 miles from the foot of Yr Wyddfa (Snowdon), Wales’s highest peak, which draws annually. Gwynedd is a la",214 -nsoonhui,32398010,38,1660053513,How the Physics of Nothing Underlies Everything,https://www.quantamagazine.org/how-the-physics-of-nothing-underlies-everything-20220809/,"An instability in the vacuum of space could suddenly spawn a rapidly expanding bubble with no interior — true nothingness. Merrill Sherman/Quanta Magazine Millennia ago, Aristotle asserted that nature abhors a vacuum, that objects would fly through truly empty space at impossible speeds. In 1277, the French bishop Etienne Tempier shot back, declaring that God could do anything, even create a vacuum. Then a mere scientist pulled it off. Otto von Guericke invented a pump to suck the air from within a hollow copper sphere, establishing perhaps the first high-quality vacuum on Earth. In a theatrical demonstration in 1654, he showed that not even two teams of horses straining to rip apart the watermelon-size ball could overcome the suction of nothing. Since then, the vacuum has become a bedro",Hacker News,71712570,"Title: How the Physics of Nothing Underlies Everything; Content: An instability in the vacuum of space could suddenly spawn a rapidly expanding bubble with no interior — true nothingness. Merrill Sherman/Quanta Magazine Millennia ago, Aristotle asserted that nature abhors a vacuum, that objects would fly through truly empty space at impossible speeds. In 1277, the French bishop Etienne Tempier shot back, declaring that God could do anything, even create a vacuum. Then a mere scientist pulled it off. Otto von Guericke invented a pump to suck the air from within a hollow copper sphere, establishing perhaps the first high-quality vacuum on Earth. In a theatrical demonstration in 1654, he showed that not even two teams of horses straining to rip apart the watermelon-size ball could overcome the suction of nothing. Since then, the vacuum has become a bedro",179 -zdw,32382868,98,1659940138,USB knob box doubles as a Blackmagic Designs camera remote,https://bikerglen.com/blog/usb-knobs-that-double-as-a-blackmagic-remote/,"The finished USB Knob Box. I have a Blackmagic Designs Micro Studio Camera I wanted to use as a webcam for video conferences. Even with a 16mm sensor, it has better quality than any small sensor webcam. The only issue is all the exposure and focus controls are manual. When connected to one of their ATEM video switchers, this isn’t a problem as the ATEM provides control of all connected cameras using data sent back to the camera embedded in  the HD-SDI return video feed. If you want to use the camera without an ATEM swtich, however, there’s no way to control the exposure without using the small awkward buttons on the front of the camera and no way to control the focus without reaching up and turning the lens’s focus ring. Being an engineer, hacker, and maker, there had to be a better way! A",Hacker News,70345619,"Title: USB knob box doubles as a Blackmagic Designs camera remote; Content: The finished USB Knob Box. I have a Blackmagic Designs Micro Studio Camera I wanted to use as a webcam for video conferences. Even with a 16mm sensor, it has better quality than any small sensor webcam. The only issue is all the exposure and focus controls are manual. When connected to one of their ATEM video switchers, this isn’t a problem as the ATEM provides control of all connected cameras using data sent back to the camera embedded in  the HD-SDI return video feed. If you want to use the camera without an ATEM swtich, however, there’s no way to control the exposure without using the small awkward buttons on the front of the camera and no way to control the focus without reaching up and turning the lens’s focus ring. Being an engineer, hacker, and maker, there had to be a better way! A",199 -amichail,32375868,85,1659874444,Replayability in game design,https://medium.com/super-jump/replayability-in-game-design-798fbb91a726,"SUPERJUMP this multi-part feature, I’m going to discuss several key design elements that contribute to making games replayable. Too often, both designers and consumers think that randomly-generated content is enough, but there’s a lot more to it than that. Let’s start by discussing in video games; not only what a biome means for creating game spaces, but also the content within them. A biome can best be described as a large, naturally occurring collection of fauna and flora in a given area. While that makes sense in a real-life context, game design is a different matter. For this reason, I’d like to define in this way: : A collection of all the predefined elements that can appear within a given gamespace. Any game that makes use of random or procedural-generated environments is built ",Hacker News,36977321,"Title: Replayability in game design; Content: SUPERJUMP this multi-part feature, I’m going to discuss several key design elements that contribute to making games replayable. Too often, both designers and consumers think that randomly-generated content is enough, but there’s a lot more to it than that. Let’s start by discussing in video games; not only what a biome means for creating game spaces, but also the content within them. A biome can best be described as a large, naturally occurring collection of fauna and flora in a given area. While that makes sense in a real-life context, game design is a different matter. For this reason, I’d like to define in this way: : A collection of all the predefined elements that can appear within a given gamespace. Any game that makes use of random or procedural-generated environments is built ",190 -FillardMillmore,32412087,14,1660140080,Never mind outrunning a T. rex – you could probably outwalk it,https://www.livescience.com/t-rex-slow-walker-tail.html,"Live Science is supported by its audience. When you purchase through links on our site, we may earn an affiliate commission. . -By - -published - New simulations calculated T. rex walking speed from the motion of its swaying tail. Could you run faster than a ? According to new research, you might be able to outpace one by walking. In the movie ""Jurassic Park"" (Warner Bros, 1993), a carful of terrified people famously tries to escape a loping but science quickly threw shade at the movie beast and demonstrated that the king of tyrannosaurs wouldn't have been fast enough to run down a jeep. Now, researchers have slowed down the big even more.  New simulations based on tail movement showed that wasn't even a quick walker. In fact, its preferred walking speed clocked in at just under 3 m",Hacker News,9983833,"Title: Never mind outrunning a T. rex – you could probably outwalk it; Content: Live Science is supported by its audience. When you purchase through links on our site, we may earn an affiliate commission. . -By - -published - New simulations calculated T. rex walking speed from the motion of its swaying tail. Could you run faster than a ? According to new research, you might be able to outpace one by walking. In the movie ""Jurassic Park"" (Warner Bros, 1993), a carful of terrified people famously tries to escape a loping but science quickly threw shade at the movie beast and demonstrated that the king of tyrannosaurs wouldn't have been fast enough to run down a jeep. Now, researchers have slowed down the big even more.  New simulations based on tail movement showed that wasn't even a quick walker. In fact, its preferred walking speed clocked in at just under 3 m",206 -pseudolus,32420843,3,1660184477,Most insane depiction of firenado I have seen in a while,https://twitter.com/ReedTimmerAccu/status/1557536321056358405,"We’ve detected that JavaScript is disabled in this browser. Please enable JavaScript or switch to a supported browser to continue using twitter.com. You can see a list of supported browsers in our Help Center. - - - - - - © 2022 Twitter, Inc. - ",Hacker News,63692799,"Title: Most insane depiction of firenado I have seen in a while; Content: We’ve detected that JavaScript is disabled in this browser. Please enable JavaScript or switch to a supported browser to continue using twitter.com. You can see a list of supported browsers in our Help Center. - - - - - - © 2022 Twitter, Inc. - ",88 -galogon,32415651,12,1660152704,What goes into efficiently powering the M1? Some pretty fancy technology,https://twitter.com/marcan42/status/1557233812954038272,"We’ve detected that JavaScript is disabled in this browser. Please enable JavaScript or switch to a supported browser to continue using twitter.com. You can see a list of supported browsers in our Help Center. - - - - - - © 2022 Twitter, Inc. - ",Hacker News,65999059,"Title: What goes into efficiently powering the M1? Some pretty fancy technology; Content: We’ve detected that JavaScript is disabled in this browser. Please enable JavaScript or switch to a supported browser to continue using twitter.com. You can see a list of supported browsers in our Help Center. - - - - - - © 2022 Twitter, Inc. - ",88 -samizdis,32407571,72,1660102009,Elon Musk sells $6.9B worth of Tesla stock,https://www.axios.com/2022/08/10/elon-musk-sells-nearly-7-billion-tesla-stock," sold more than $6.9 billion in Tesla shares, according to with the Securities and Exchange Commission published Tuesday. The selloff comes weeks after the Tesla CEO's bid to withdraw a $44 billion and with the tech giant, something Musk acknowledged on Tuesday night. A Twitter user asked Musk if he was ""done selling"" after his latest Tesla selloff, to which the replied: ""Yes."" Musk has now sold some $32 billion in Tesla stock in the past 10 months, . for its is due to take place in October. Street will read through this poker move that chances of Twitter deal more likely now,"" tweeted Wedbush Securities analyst in response to Musk's Twitter post late Tuesday.",Hacker News,79602460,"Title: Elon Musk sells $6.9B worth of Tesla stock; Content: sold more than $6.9 billion in Tesla shares, according to with the Securities and Exchange Commission published Tuesday. The selloff comes weeks after the Tesla CEO's bid to withdraw a $44 billion and with the tech giant, something Musk acknowledged on Tuesday night. A Twitter user asked Musk if he was ""done selling"" after his latest Tesla selloff, to which the replied: ""Yes."" Musk has now sold some $32 billion in Tesla stock in the past 10 months, . for its is due to take place in October. Street will read through this poker move that chances of Twitter deal more likely now,"" tweeted Wedbush Securities analyst in response to Musk's Twitter post late Tuesday.",171 -pjmlp,32383686,184,1659950969,Post-Apocalyptic Programming,https://zserge.com/posts/post-apocalyptic-programming/,"We got deadly viruses, nuclear war threats, economy heading from one crisis to another deeper crisis, politicians going out of control… You know that feeling. The end is near, isn’t it? But let’s talk about brighter things – technology. We are all smart people, working on valuable and complex software projects in great agile teams, copying code from Stack Overflow and using GitHub co-pilot to help us with the routine. Now, what if you are the only survivor with some programming skills sitting in front of a computer you’ve never heard of, with some hex pad to enter machine codes, with maybe some pen and paper. What will you do? In this not-so-short article we will try to go a full cycle from exploring the CPU, building an assembler, building the core of the Forth VM and finally building a r",Hacker News,74770049,"Title: Post-Apocalyptic Programming; Content: We got deadly viruses, nuclear war threats, economy heading from one crisis to another deeper crisis, politicians going out of control… You know that feeling. The end is near, isn’t it? But let’s talk about brighter things – technology. We are all smart people, working on valuable and complex software projects in great agile teams, copying code from Stack Overflow and using GitHub co-pilot to help us with the routine. Now, what if you are the only survivor with some programming skills sitting in front of a computer you’ve never heard of, with some hex pad to enter machine codes, with maybe some pen and paper. What will you do? In this not-so-short article we will try to go a full cycle from exploring the CPU, building an assembler, building the core of the Forth VM and finally building a r",187 -ahstilde,32384687,197,1659961809,Tricks to start working despite not feeling like it,https://www.deprocrastination.co/blog/3-tricks-to-start-working-despite-not-feeling-like-it,"Ever wish you felt like creating that presentation? Felt like doing that research? Felt like doing the dishes? Most of us do. It's easy to start when we feel like it. Unfortunately, we often don't. We don't feel ready. We don't feel like the work is going to be good enough. We don't feel like we  The list goes on. But here's the thing:  We can start writing, even if we think the words are rubbish. We can start creating, sketching, planning,... even though we're uncertain of the results of our efforts. This may sound like BS, but it's not. It's a simple fact. Everyone of us has started despite not feeling like it at some point in our lives because we promised something to a friend, or because it really mattered to us, or because we were tired off putting something off. And we can all train ",Hacker News,26830465,"Title: Tricks to start working despite not feeling like it; Content: Ever wish you felt like creating that presentation? Felt like doing that research? Felt like doing the dishes? Most of us do. It's easy to start when we feel like it. Unfortunately, we often don't. We don't feel ready. We don't feel like the work is going to be good enough. We don't feel like we  The list goes on. But here's the thing:  We can start writing, even if we think the words are rubbish. We can start creating, sketching, planning,... even though we're uncertain of the results of our efforts. This may sound like BS, but it's not. It's a simple fact. Everyone of us has started despite not feeling like it at some point in our lives because we promised something to a friend, or because it really mattered to us, or because we were tired off putting something off. And we can all train ",201 -mocko,32403498,10,1660075533,Crypto and Digital Assets All-Party Parliamentary Group Inquiry,https://cryptouk.io/appg/,"the first self-regulatory trade association for the UK cryptoasset industry more The group is chaired by Lisa Cameron MP, Scottish National Party (SNP) MP for East Kilbride, Strathaven and Lesmahagow. CryptoUK, an independent trade body which represents the UK Crypto and Digital Assets sector, provides the secretariat for the APPG. CryptoUK aims to work constructively with Parliamentarians, Government, Regulators and the wider sector to advance the UK’s approach to regulation of the crypto and digital assets sector. You can read the group’s full entry in the Houses of Parliament’s .   The Crypto and Digital Assets APPG is made up of cross party MPs and Lords who bring broad experience and expertise from a range of sectors including financial services, foreign affairs, digital innovation, ",Hacker News,53658387,"Title: Crypto and Digital Assets All-Party Parliamentary Group Inquiry; Content: the first self-regulatory trade association for the UK cryptoasset industry more The group is chaired by Lisa Cameron MP, Scottish National Party (SNP) MP for East Kilbride, Strathaven and Lesmahagow. CryptoUK, an independent trade body which represents the UK Crypto and Digital Assets sector, provides the secretariat for the APPG. CryptoUK aims to work constructively with Parliamentarians, Government, Regulators and the wider sector to advance the UK’s approach to regulation of the crypto and digital assets sector. You can read the group’s full entry in the Houses of Parliament’s .   The Crypto and Digital Assets APPG is made up of cross party MPs and Lords who bring broad experience and expertise from a range of sectors including financial services, foreign affairs, digital innovation, ",186 -baobob,32399148,71,1660058175,"Wildfires are destroying California's forest carbon credit reserves, study says",https://www.reuters.com/world/us/wildfires-are-destroying-californias-forest-carbon-credit-reserves-study-2022-08-05/,"The Washburn Fire burns between the Mariposa Grove and the southern entrance into Yosemite National Park in Wawona, California, U.S. July 11, 2022. REUTERS/Tracy Barbutes Aug 5 (Reuters) - Carbon offsets generated from forests to counteract future climate-warming emissions from California's big polluters are rapidly being depleted as trees are ravaged by wildfire and disease, new research published on Friday suggests. One of California's key policy tools to combat climate change may be falling far short of its goals, the researchers said - raising questions about similar carbon offset programs around the world. The study, published in the journal Frontiers in Forests and Global Change, was conducted by CarbonPlan, a San Francisco-based non-profit that researches the integrity of programs ",Hacker News,17947620,"Title: Wildfires are destroying California's forest carbon credit reserves, study says; Content: The Washburn Fire burns between the Mariposa Grove and the southern entrance into Yosemite National Park in Wawona, California, U.S. July 11, 2022. REUTERS/Tracy Barbutes Aug 5 (Reuters) - Carbon offsets generated from forests to counteract future climate-warming emissions from California's big polluters are rapidly being depleted as trees are ravaged by wildfire and disease, new research published on Friday suggests. One of California's key policy tools to combat climate change may be falling far short of its goals, the researchers said - raising questions about similar carbon offset programs around the world. The study, published in the journal Frontiers in Forests and Global Change, was conducted by CarbonPlan, a San Francisco-based non-profit that researches the integrity of programs ",177 -mooreds,32403353,19,1660074854,GoNoGo: Determine the upgrade confidence of your K8s cluster addons,https://github.com/FairwindsOps/gonogo," - Tool to evaluate upgrade confidence for Kubernetes cluster addons - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. GoNoGo is a utility to help users determine upgrade confidence around Kubernetes cluster addons. At this time, GoNoGo is currently in alpha. This means that we could change literally anything at any time without notice. Keep an eye out for major changes, and hopefully a v1 release at some point. Check out the A number factors can affect whether the upgrade of an ",Hacker News,44628276,"Title: GoNoGo: Determine the upgrade confidence of your K8s cluster addons; Content: - Tool to evaluate upgrade confidence for Kubernetes cluster addons - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. GoNoGo is a utility to help users determine upgrade confidence around Kubernetes cluster addons. At this time, GoNoGo is currently in alpha. This means that we could change literally anything at any time without notice. Keep an eye out for major changes, and hopefully a v1 release at some point. Check out the A number factors can affect whether the upgrade of an ",259 -evo_9,32380731,161,1659912906,The “bicameral mind” 30 years on (2007),https://pubmed.ncbi.nlm.nih.gov/17509238/,"An official website of the United States government - - - Federal government websites often end in .gov or .mil. Before - sharing sensitive information, make sure you’re on a federal - government site. - - - - The ensures that you are connecting to the - official website and that any information you provide is encrypted - and transmitted securely. - - - In 1976 Julian Jaynes published his controversial book The Origins of Consciousness in the Breakdown of the Bicameral Mind, introducing the hypothesis of a two-chambered brain-mind model that preceded the evolutionary development of the conscious mind. Jaynes' speculative model gave rise to a huge debate, which has reverberated throughout the current",Hacker News,77010125,"Title: The “bicameral mind” 30 years on (2007); Content: An official website of the United States government - - - Federal government websites often end in .gov or .mil. Before - sharing sensitive information, make sure you’re on a federal - government site. - - - - The ensures that you are connecting to the - official website and that any information you provide is encrypted - and transmitted securely. - - - In 1976 Julian Jaynes published his controversial book The Origins of Consciousness in the Breakdown of the Bicameral Mind, introducing the hypothesis of a two-chambered brain-mind model that preceded the evolutionary development of the conscious mind. Jaynes' speculative model gave rise to a huge debate, which has reverberated throughout the current",268 -pepys,32396618,8,1660045965,Georeferencing maps from George III’s atlases and albums,https://blogs.bl.uk/magnificentmaps/2022/03/georeferencing-maps-from-george-iiis-atlases-and-albums.html," 03 March 2022 The second tranche of maps from George III’s Topographical Collection have been released onto the Georeferencer platform recently and the platform is already a hive of activity! British Library colleagues have selected the 7891 images that depict maps from the 32,000 that comprise George III’s collection of atlases and albums of views, plans, diagrams, reports and surveys, produced between 1550 and 1820. You can find out more about the images themselves in this . There are some beautiful maps to georeference including multi-sheet maps in loose or bound format including  ,   ,  ,  ,   and  If you are new to the Georeferencer head over to our ‘how to use’ page ( ) where you can find detailed instructions. As ever, please do note that it might not be possible to georeference ",Hacker News,90910010,"Title: Georeferencing maps from George III’s atlases and albums; Content: 03 March 2022 The second tranche of maps from George III’s Topographical Collection have been released onto the Georeferencer platform recently and the platform is already a hive of activity! British Library colleagues have selected the 7891 images that depict maps from the 32,000 that comprise George III’s collection of atlases and albums of views, plans, diagrams, reports and surveys, produced between 1550 and 1820. You can find out more about the images themselves in this . There are some beautiful maps to georeference including multi-sheet maps in loose or bound format including  ,   ,  ,  ,   and  If you are new to the Georeferencer head over to our ‘how to use’ page ( ) where you can find detailed instructions. As ever, please do note that it might not be possible to georeference ",210 -Austin_Conlon,32420788,6,1660183598,Personal racket stringers for top tennis players [video],https://www.youtube.com/watch?v=4sRSqSupzyM,,Hacker News,64281106,Title: Personal racket stringers for top tennis players [video]; Content: ,16 -alhasaniq,32403121,9,1660074042,Golang Application runtime inspection tool,https://github.com/coretrix/clockwork," - Clockwork is a library used to communicate with Clockwork browser extension - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. - - - Mysql data source Redis data source Cache data source Timeline data source Request data source Logger(debugger) data source You should call this method The last thing u need to do is to send 2 special headers into the response: - Clockwork is a library used to communicate with Clockwork browser extension - ",Hacker News,60908893,"Title: Golang Application runtime inspection tool; Content: - Clockwork is a library used to communicate with Clockwork browser extension - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. - - - Mysql data source Redis data source Cache data source Timeline data source Request data source Logger(debugger) data source You should call this method The last thing u need to do is to send 2 special headers into the response: - Clockwork is a library used to communicate with Clockwork browser extension - ",243 -awanderingmind,32401564,135,1660068520,"The state of South Africa, 28ish years post-apartheid",https://www.awanderingmind.blog/posts/2022-07-30-state-of-south-africa.html,"I am South African. I have always wanted to write something about my country of birth - not out of a sense of patriotism, but in that curious way that people have of wanting to explain themselves to themselves, or of wanting to make the world seem more sane than it is. In an unconscious attempt to put off ever doing this I reached out to a blogger based in the States to ask whether he had any questions about South Africa. He suggested that I write about how relates to any current problems we have, and whether there were ‘discontinuous trends’ when apartheid ended. This ballooned into such a fraught undertaking that I almost succeeded in putting this off forever. But I persevered, trudging through some uncomfortable terrain to write what you have before you - a condensed look at the p",Hacker News,71811662,"Title: The state of South Africa, 28ish years post-apartheid; Content: I am South African. I have always wanted to write something about my country of birth - not out of a sense of patriotism, but in that curious way that people have of wanting to explain themselves to themselves, or of wanting to make the world seem more sane than it is. In an unconscious attempt to put off ever doing this I reached out to a blogger based in the States to ask whether he had any questions about South Africa. He suggested that I write about how relates to any current problems we have, and whether there were ‘discontinuous trends’ when apartheid ended. This ballooned into such a fraught undertaking that I almost succeeded in putting this off forever. But I persevered, trudging through some uncomfortable terrain to write what you have before you - a condensed look at the p",191 -spenvo,32399495,90,1660059933,Someone Is Trolling Celebs by Sending ETH from Tornado Cash,https://www.coindesk.com/policy/2022/08/09/someone-is-trolling-celebs-by-sending-eth-from-tornado-cash/,"Eli is a news reporter for CoinDesk. He holds ETH, SOL and AVAX. Follow @ elitanjourno on Twitter Oliver Knight is a CoinDesk reporter based between London and Lisbon. He does not own any crypto. Follow @ OKnightCrypto on Twitter Nikhilesh De is CoinDesk's managing editor for global policy and regulation. He owns marginal amounts of bitcoin and ether. Follow @ nikhileshde on Twitter An anonymous user sent a slew of Tornado Cash transactions to high-profile Ethereum addresses on Tuesday in what appears to be a troll implicating them in a potential regulatory mess. Affected wallets include those controlled by Coinbase CEO Brian Armstrong, TV host Jimmy Fallon, clothing brand Puma and a wallet created for donations to Ukraine, according to . Prominent crypto figures such as ar",Hacker News,9599567,"Title: Someone Is Trolling Celebs by Sending ETH from Tornado Cash; Content: Eli is a news reporter for CoinDesk. He holds ETH, SOL and AVAX. Follow @ elitanjourno on Twitter Oliver Knight is a CoinDesk reporter based between London and Lisbon. He does not own any crypto. Follow @ OKnightCrypto on Twitter Nikhilesh De is CoinDesk's managing editor for global policy and regulation. He owns marginal amounts of bitcoin and ether. Follow @ nikhileshde on Twitter An anonymous user sent a slew of Tornado Cash transactions to high-profile Ethereum addresses on Tuesday in what appears to be a troll implicating them in a potential regulatory mess. Affected wallets include those controlled by Coinbase CEO Brian Armstrong, TV host Jimmy Fallon, clothing brand Puma and a wallet created for donations to Ukraine, according to . Prominent crypto figures such as ar",198 -jpieper,32381448,165,1659920499,Debugging bare-metal STM32 from the seventh level of hell,https://jpieper.com/2022/08/05/debugging-bare-metal-stm32-from-the-seventh-level-of-hell/,"Here’s a not-so-brief story about troubleshooting a problem that was at times vexing, impossible, incredibly challenging, frustrating, and all around just a terrible time with the bare-metal STM32G4 firmware for the . First, some things for context: moteus has a variety of testing done on every firmware release. There are unit tests that run with pieces of the firmware compiled to . There is a hardware-in-the-loop that is used to . There is also an that is used to run tests on every board and some other firmware level performance tests. Because of all that testing, we’re pretty confident to release new firmware images once all the tests have passed, and try to ship out boards with firmware that is within a week or two of the newest on all boards and devices that go out the door. ",Hacker News,59364874,"Title: Debugging bare-metal STM32 from the seventh level of hell; Content: Here’s a not-so-brief story about troubleshooting a problem that was at times vexing, impossible, incredibly challenging, frustrating, and all around just a terrible time with the bare-metal STM32G4 firmware for the . First, some things for context: moteus has a variety of testing done on every firmware release. There are unit tests that run with pieces of the firmware compiled to . There is a hardware-in-the-loop that is used to . There is also an that is used to run tests on every board and some other firmware level performance tests. Because of all that testing, we’re pretty confident to release new firmware images once all the tests have passed, and try to ship out boards with firmware that is within a week or two of the newest on all boards and devices that go out the door. ",206 -cirrus-clouds,32417546,7,1660161379,Energy bills are soaring in Europe. What are countries doing?,https://www.euronews.com/next/2022/07/29/energy-bills-are-soaring-in-europe-what-are-countries-doing-to-help-you-pay-them,"The end of the month used to be a time to celebrate for many, who would joyously announce it was “payday” to friends and colleagues before declaring how they would reward themselves for their hard work - with a pint at the pub, a fancy dinner or a shopping spree. But things have changed in the past few years. First, there was the pandemic, now it’s a combination of inflation and a cost-of-living crisis that’s stripping the payday of its happiness. For many these days, money coming into their account almost immediately goes out or is already spent, as inflation drives up the cost of groceries and fuel, landlords increase rent and bills keep soaring. Inflation jumped to a new in July in Europe for the 19 countries bound by the euro, fueled by rising energy costs.  Electricity wholesale pri",Hacker News,59666786,"Title: Energy bills are soaring in Europe. What are countries doing?; Content: The end of the month used to be a time to celebrate for many, who would joyously announce it was “payday” to friends and colleagues before declaring how they would reward themselves for their hard work - with a pint at the pub, a fancy dinner or a shopping spree. But things have changed in the past few years. First, there was the pandemic, now it’s a combination of inflation and a cost-of-living crisis that’s stripping the payday of its happiness. For many these days, money coming into their account almost immediately goes out or is already spent, as inflation drives up the cost of groceries and fuel, landlords increase rent and bills keep soaring. Inflation jumped to a new in July in Europe for the 19 countries bound by the euro, fueled by rising energy costs.  Electricity wholesale pri",191 -Tomte,32402664,10,1660072509,How Not To Run an A/B Test (2010),https://www.evanmiller.org/how-not-to-run-an-ab-test.html,"By Translations: -       - If you run A/B tests on your website and regularly check ongoing experiments for significant results, you might be falling prey to what statisticians call . As a result, even though your dashboard says a result is statistically significant, there’s a good chance that it’s actually insignificant. This note explains why. When an A/B testing dashboard says there is a “95% chance of beating original” or “90% probability of statistical significance,” it’s asking the following question: Assuming there is no underlying difference between A and B, how often will we see a difference like we do in the data just by chance? The answer to that question is called the significance level, and “statistically significant results” mean that the significance le",Hacker News,61247860,"Title: How Not To Run an A/B Test (2010); Content: By Translations: -       - If you run A/B tests on your website and regularly check ongoing experiments for significant results, you might be falling prey to what statisticians call . As a result, even though your dashboard says a result is statistically significant, there’s a good chance that it’s actually insignificant. This note explains why. When an A/B testing dashboard says there is a “95% chance of beating original” or “90% probability of statistical significance,” it’s asking the following question: Assuming there is no underlying difference between A and B, how often will we see a difference like we do in the data just by chance? The answer to that question is called the significance level, and “statistically significant results” mean that the significance le",221 -angristan,32383448,97,1659947763,How we got customers to sign up to Monzo in the early years,https://tomblomfield.com/post/691384431502557184/monzo-growth," - Co-founded Monzo and GoCardless. Based in London. - - Notes: - - I’ve been asked a few times recently how we got customers to sign up to Monzo in the early years and I haven’t been able to give a satisfactory answer in a sufficiently short space of time. I thought I’d write out my thoughts in a longer piece so I can feel less bad about giving an incomplete answer - anyone who wants to know the details can read this instead. Let’s start with a rough timeline, which I’ll then flesh out below. — First, a note about the context. We started the company in the UK in February 2015, when “digital banks” weren’t yet a popular idea. BankSimple had launched in 2012 with some big plans, but sold to BBVA in early 2014 with about 100,000 accounts, having struggled to raise suffic",Hacker News,45588859,"Title: How we got customers to sign up to Monzo in the early years; Content: - Co-founded Monzo and GoCardless. Based in London. - - Notes: - - I’ve been asked a few times recently how we got customers to sign up to Monzo in the early years and I haven’t been able to give a satisfactory answer in a sufficiently short space of time. I thought I’d write out my thoughts in a longer piece so I can feel less bad about giving an incomplete answer - anyone who wants to know the details can read this instead. Let’s start with a rough timeline, which I’ll then flesh out below. — First, a note about the context. We started the company in the UK in February 2015, when “digital banks” weren’t yet a popular idea. BankSimple had launched in 2012 with some big plans, but sold to BBVA in early 2014 with about 100,000 accounts, having struggled to raise suffic",238 -nus07,32418728,8,1660167129,"GM Makes $1,500 OnStar Subscription Mandatory on GMC, Buick, Cadillac Models",https://www.thedrive.com/news/gm-makes-1500-onstar-subscription-mandatory-on-gmc-buick-cadillac-models,"_baldtires If you don't want to pay for every month, no problem: Just pay it all upfront. That's the line from today after news spread that it's making a three-year, $1,500 OnStar connected services subscription a mandatory ""option"" for new Buick, GMC, and Cadillac Escalade models. The subscription, which enables things like using your phone as a key fob, data-enabled navigation, audio streaming, and Amazon's Alexa virtual assistant, is still optional on other GM vehicles, with the Premium package running $49.99 a month. But don't be surprised if this new setup spreads across the automaker's full portfolio. Though it's getting attention today following a report, the news of Onstar becoming a mandatory subscription was first reported back on July 5 by . The $1,500 charge for OnStar wi",Hacker News,6905944,"Title: GM Makes $1,500 OnStar Subscription Mandatory on GMC, Buick, Cadillac Models; Content: _baldtires If you don't want to pay for every month, no problem: Just pay it all upfront. That's the line from today after news spread that it's making a three-year, $1,500 OnStar connected services subscription a mandatory ""option"" for new Buick, GMC, and Cadillac Escalade models. The subscription, which enables things like using your phone as a key fob, data-enabled navigation, audio streaming, and Amazon's Alexa virtual assistant, is still optional on other GM vehicles, with the Premium package running $49.99 a month. But don't be surprised if this new setup spreads across the automaker's full portfolio. Though it's getting attention today following a report, the news of Onstar becoming a mandatory subscription was first reported back on July 5 by . The $1,500 charge for OnStar wi",210 -jakobgreenfeld,32384613,556,1659961277,No More “Insight Porn”,https://jakobgreenfeld.com/insight-porn,"Experiments in Permissionless Entrepreneurship Here’s how anyone can make six figures: Offer a service for a business, something marketing or sales related, get 10 clients for $1000 per month and BOOM, you’re making six figures in a year. Easy right? Okay maybe you don’t care about making six figures. But surely everyone would love to become more productive. So here’s how you can easily triple your productivity: Simply decide that your days are 6 hours long. This allows you to get three days of work done in just one day. Now if you do the math, in one month, you will get 90-days worth of work done. Amazing right? These examples are obviously ridiculous. But at the same time, they are 100% real examples of pseudo-actionable advice proudly broadcasted into the world by insight porn artists. ",Hacker News,42119149,"Title: No More “Insight Porn”; Content: Experiments in Permissionless Entrepreneurship Here’s how anyone can make six figures: Offer a service for a business, something marketing or sales related, get 10 clients for $1000 per month and BOOM, you’re making six figures in a year. Easy right? Okay maybe you don’t care about making six figures. But surely everyone would love to become more productive. So here’s how you can easily triple your productivity: Simply decide that your days are 6 hours long. This allows you to get three days of work done in just one day. Now if you do the math, in one month, you will get 90-days worth of work done. Amazing right? These examples are obviously ridiculous. But at the same time, they are 100% real examples of pseudo-actionable advice proudly broadcasted into the world by insight porn artists. ",195 -hnburnsy,32401721,18,1660069111,Twitter paid $5000 bug bounty that resulted in 5.4mm leaked records,https://hackerone.com/reports/1439026,,Hacker News,68139814,Title: Twitter paid $5000 bug bounty that resulted in 5.4mm leaked records; Content: ,21 -rbanffy,32384868,84,1659963534,Chip Backdoors: Assessing the Threat,https://semiengineering.com/chip-backdoors-assessing-the-threat/,"Steps are being taken to minimize problems, but they will take years to implement. In 2018, Bloomberg Businessweek : Chinese spies had implanted backdoors in motherboards used by some high-profile customers, including the U.S. Department of Defense. All of those customers issued strongly worded denials. Most reports of hardware backdoors have ended up in exchanges like these. There are allegations and counter-allegations about specifics. But as hardware becomes increasingly used in safety-critical and mission critical applications, and as the attack surface widens from software to the underlying hardware and its global supply chain, the threat of backdoors is being taken much more seriously than in the past. So how serious is this issue? John Hallman, product manager for trust and securi",Hacker News,53743601,"Title: Chip Backdoors: Assessing the Threat; Content: Steps are being taken to minimize problems, but they will take years to implement. In 2018, Bloomberg Businessweek : Chinese spies had implanted backdoors in motherboards used by some high-profile customers, including the U.S. Department of Defense. All of those customers issued strongly worded denials. Most reports of hardware backdoors have ended up in exchanges like these. There are allegations and counter-allegations about specifics. But as hardware becomes increasingly used in safety-critical and mission critical applications, and as the attack surface widens from software to the underlying hardware and its global supply chain, the threat of backdoors is being taken much more seriously than in the past. So how serious is this issue? John Hallman, product manager for trust and securi",170 -owenwil,32404366,42,1660079439,"Coinbase earnings: $1.1B loss, lower-than-expected revenue",https://www.bloomberg.com/news/articles/2022-08-09/coinbase-falls-after-second-quarter-revenue-misses-estimates,"To continue, please click the box below to let us know you're not a robot. Please make sure your browser supports JavaScript and cookies and that you are not blocking them from loading. For more information you can review our and . For inquiries related to this message please and provide the reference ID below.",Hacker News,93360518,"Title: Coinbase earnings: $1.1B loss, lower-than-expected revenue; Content: To continue, please click the box below to let us know you're not a robot. Please make sure your browser supports JavaScript and cookies and that you are not blocking them from loading. For more information you can review our and . For inquiries related to this message please and provide the reference ID below.",86 -davidclark22,32404857,126,1660082010,Former Twitter employee convicted of charges related to spying for Saudis,https://politpost.com/2022/08/09/former-twitter-employee-convicted-of-charges-related-to-spying-for-saudis/,"SAN FRANCISCO — A former Twitter employee was convicted on Tuesday by a jury in federal court of six on the company’s users for Saudi Arabia. While at Twitter, Ahmad Abouammo, 44, managed media partnerships in the Middle East and North Africa. He developed relationships with prominent individuals in the region, receiving hundreds of thousands of dollars and a luxury watch from a top adviser to Saudi Arabia’s crown prince, Mohammed bin Salman. In return, prosecutors said, he shared the personal user information of dissidents with Saudi officials. The jury convicted Mr. Abouammo of two counts of wire fraud or conspiracy to commit wire fraud, two counts of money laundering, one count of falsifying records and one count of acting as an agent of a foreign government without properly disclosin",Hacker News,46521718,"Title: Former Twitter employee convicted of charges related to spying for Saudis; Content: SAN FRANCISCO — A former Twitter employee was convicted on Tuesday by a jury in federal court of six on the company’s users for Saudi Arabia. While at Twitter, Ahmad Abouammo, 44, managed media partnerships in the Middle East and North Africa. He developed relationships with prominent individuals in the region, receiving hundreds of thousands of dollars and a luxury watch from a top adviser to Saudi Arabia’s crown prince, Mohammed bin Salman. In return, prosecutors said, he shared the personal user information of dissidents with Saudi officials. The jury convicted Mr. Abouammo of two counts of wire fraud or conspiracy to commit wire fraud, two counts of money laundering, one count of falsifying records and one count of acting as an agent of a foreign government without properly disclosin",180 -a-user-you-like,32413860,22,1660146087,Ask HN: Amazon lying about shipping dates?,,"Lately Amazon told me that an item would arrive in 2 days when I placed the order. I just now received an email that the item I ordered had its shipping date adjusted. It was going to be a month from now, but now Amazon says they can get it to me in 4 days! How lucky am I?

Have others experienced the same, gaslighting from Amazon?",Hacker News,19314202,"Title: Ask HN: Amazon lying about shipping dates?; Content: Lately Amazon told me that an item would arrive in 2 days when I placed the order. I just now received an email that the item I ordered had its shipping date adjusted. It was going to be a month from now, but now Amazon says they can get it to me in 4 days! How lucky am I?

Have others experienced the same, gaslighting from Amazon?",94 -TekMol,32408322,22,1660111969,Ask HN: Is there a description of the file layout HN uses to store data?,,"As far as I know, HN uses no DB and just writes all data to plain text files.

Does this still hold true?

Is there a description of the layout somewhere? I wonder if it is just one file per comment and the name is the id. And what the internal structure of those files is.

I think it would be a very interesting example of a successful Web2 style project that writes to files instead of using a DB.",Hacker News,69732588,"Title: Ask HN: Is there a description of the file layout HN uses to store data?; Content: As far as I know, HN uses no DB and just writes all data to plain text files.

Does this still hold true?

Is there a description of the layout somewhere? I wonder if it is just one file per comment and the name is the id. And what the internal structure of those files is.

I think it would be a very interesting example of a successful Web2 style project that writes to files instead of using a DB.",120 -wepple,32385362,205,1659966669,Incident report: Employee and customer account compromise,https://www.twilio.com/blog/august-2022-social-engineering-attack,"Build the future of communications. Start today with Twilio's APIs and services. Posts by Stack Posts By Product Categories Languages Subscribe to the Developer Digest, a monthly dose of all things code. - You may unsubscribe at any time using the unsubscribe link in the digest email. See our for more information. - - - This is an evolving situation. Read to the bottom of the post for the latest updates. Twilio believes that the security of our customers’ data is of paramount importance, and when an incident occurs that might threaten that security, we communicate what happened in a transparent manner. To that end, we are providing an overview of this incident impacting customer information and our response. On August 4, 2022, Twilio became aware of unauthorized access to information",Hacker News,70040094,"Title: Incident report: Employee and customer account compromise; Content: Build the future of communications. Start today with Twilio's APIs and services. Posts by Stack Posts By Product Categories Languages Subscribe to the Developer Digest, a monthly dose of all things code. - You may unsubscribe at any time using the unsubscribe link in the digest email. See our for more information. - - - This is an evolving situation. Read to the bottom of the post for the latest updates. Twilio believes that the security of our customers’ data is of paramount importance, and when an incident occurs that might threaten that security, we communicate what happened in a transparent manner. To that end, we are providing an overview of this incident impacting customer information and our response. On August 4, 2022, Twilio became aware of unauthorized access to information",180 -sprkv5,32418808,3,1660167680,Ask HN: What are the skills and/or software(s) required to become an emcee?,,"I was just looking at the recent MultiVersus tournament hosted by a certain YouTube streamer live now; and I was kinda fascinated by how they were hosting, presenting the rules, tracking the players and their respective voice chatrooms, technical issues, etc. I do know that they've got some folks helping out behind the scenes. I wanted to know what it takes to setup such an event, especially for the host.",Hacker News,96687335,"Title: Ask HN: What are the skills and/or software(s) required to become an emcee?; Content: I was just looking at the recent MultiVersus tournament hosted by a certain YouTube streamer live now; and I was kinda fascinated by how they were hosting, presenting the rules, tracking the players and their respective voice chatrooms, technical issues, etc. I do know that they've got some folks helping out behind the scenes. I wanted to know what it takes to setup such an event, especially for the host.",117 -adrian_mrd,32415431,9,1660151756,You deserve the right to repair your stuff (Ted talk),https://www.ted.com/talks/gay_gordon_byrne_you_deserve_the_right_to_repair_your_stuff,,Hacker News,66531291,Title: You deserve the right to repair your stuff (Ted talk); Content: ,17 -yamrzou,32397432,58,1660051250,The End of Manual Transmission,https://www.theatlantic.com/technology/archive/2022/08/stick-shift-manual-transmission-cars/671078/,"Stick shifts are dying. When they go, something bigger than driving will be lost. I drive a stick shift. It’s a pain, sometimes. Clutching and shifting in bumper-to-bumper traffic wears you out. My wife can’t drive my car, which limits our transit options. And when I’m at the wheel, I can’t hold a cold, delicious in one hand, at least not safely. But despite the inconvenience, I love a manual transmission. I love the feeling that I am my car, not just driving it. That’s why I’ve driven stick shifts for the past 20 years. That streak may soon be over. When it comes time to replace my current car, I probably won’t be able to get another like it. In 2000, more than 15 percent of new and used cars sold by the auto retailer CarMax came with stick shifts; by 2020, that figure to 2.4 percen",Hacker News,46717281,"Title: The End of Manual Transmission; Content: Stick shifts are dying. When they go, something bigger than driving will be lost. I drive a stick shift. It’s a pain, sometimes. Clutching and shifting in bumper-to-bumper traffic wears you out. My wife can’t drive my car, which limits our transit options. And when I’m at the wheel, I can’t hold a cold, delicious in one hand, at least not safely. But despite the inconvenience, I love a manual transmission. I love the feeling that I am my car, not just driving it. That’s why I’ve driven stick shifts for the past 20 years. That streak may soon be over. When it comes time to replace my current car, I probably won’t be able to get another like it. In 2000, more than 15 percent of new and used cars sold by the auto retailer CarMax came with stick shifts; by 2020, that figure to 2.4 percen",221 -signa11,32376937,65,1659884030,How (and Why) Neil Gaiman Finally Adapted ‘The Sandman’ for TV,https://variety.com/2022/tv/features/the-sandman-premiere-preview-neil-gaiman-interview-1235328771/,"Variety Print Plus Subscriber Variety Print Plus Subscriber Variety Print Plus Subscriber Variety Print Plus Subscriber Variety Print Plus Subscriber didn’t have to do it. He could have left well enough alone. After 30 years of successfully shutting down every “bad” attempt to adapt his best-selling Vertigo graphic novel series “ ,” Gaiman could have decided to let dreams of an adaptation of “The Sandman” die with the nightmare that was the most recent attempt: a feature film starring and directed by Joseph Gordon-Levitt for Warner Bros.’ New Line, which fell apart in 2016. The Warner Bros. and DC Entertainment-produced “The Sandman” live-action TV series, which was ordered to series at in June 2019, finally launches Friday. So why did Gaiman try again? “In a lot of ways, it’s the only ",Hacker News,9004575,"Title: How (and Why) Neil Gaiman Finally Adapted ‘The Sandman’ for TV; Content: Variety Print Plus Subscriber Variety Print Plus Subscriber Variety Print Plus Subscriber Variety Print Plus Subscriber Variety Print Plus Subscriber didn’t have to do it. He could have left well enough alone. After 30 years of successfully shutting down every “bad” attempt to adapt his best-selling Vertigo graphic novel series “ ,” Gaiman could have decided to let dreams of an adaptation of “The Sandman” die with the nightmare that was the most recent attempt: a feature film starring and directed by Joseph Gordon-Levitt for Warner Bros.’ New Line, which fell apart in 2016. The Warner Bros. and DC Entertainment-produced “The Sandman” live-action TV series, which was ordered to series at in June 2019, finally launches Friday. So why did Gaiman try again? “In a lot of ways, it’s the only ",221 -nikolay,32382514,124,1659934968,"Trealla – A compact, efficient Prolog interpreter written in plain-old C",https://github.com/trealla-prolog/trealla," - A compact, efficient Prolog interpreter written in plain-old C. - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. A compact, efficient Prolog interpreter with ISO Prolog aspirations. Trealla is not WAM-based. It uses tree-walking, structure-sharing and -deep-binding. Source is byte-code compiled to an AST that is interpreted -at runtime. The name Trealla comes from the Liaden Universe books by Lee & Miller. -It is also a nod to the Trealla region of Western Australia. where option",Hacker News,65866082,"Title: Trealla – A compact, efficient Prolog interpreter written in plain-old C; Content: - A compact, efficient Prolog interpreter written in plain-old C. - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. A compact, efficient Prolog interpreter with ISO Prolog aspirations. Trealla is not WAM-based. It uses tree-walking, structure-sharing and -deep-binding. Source is byte-code compiled to an AST that is interpreted -at runtime. The name Trealla comes from the Liaden Universe books by Lee & Miller. -It is also a nod to the Trealla region of Western Australia. where option",265 -rbanffy,32384827,103,1659963189,Who owns Tesla’s data?,https://spectrum.ieee.org/tesla-autopilot-data-ownership,"IEEE websites place cookies on your device to give you the best user experience. By using our websites, you agree to the placement of these cookies. To learn more, read our Privacy Policy. The company, says the company—but other interpretations persist A Tesla user charges his Model S in Burbank, Calif. On 29 September 2020, a masked man entered a branch of the Wells Fargo bank in Washington, D.C., and handed the teller a note: “This is a robbery. Act calm give me all hundreds.” The teller complied. The man then fled the bank and jumped into a gray Tesla Model S. This was one of three bank robberies the man attempted the same day. When FBI agents began investigating, they reviewed Washington, D.C.’s camera footage, and spotted a Tesla matching the getaway vehicle’s description. The licen",Hacker News,98592711,"Title: Who owns Tesla’s data?; Content: IEEE websites place cookies on your device to give you the best user experience. By using our websites, you agree to the placement of these cookies. To learn more, read our Privacy Policy. The company, says the company—but other interpretations persist A Tesla user charges his Model S in Burbank, Calif. On 29 September 2020, a masked man entered a branch of the Wells Fargo bank in Washington, D.C., and handed the teller a note: “This is a robbery. Act calm give me all hundreds.” The teller complied. The man then fled the bank and jumped into a gray Tesla Model S. This was one of three bank robberies the man attempted the same day. When FBI agents began investigating, they reviewed Washington, D.C.’s camera footage, and spotted a Tesla matching the getaway vehicle’s description. The licen",195 -yamrzou,32386189,258,1659970580,U.S. Treasury sanctions virtual currency mixer Tornado Cash,https://home.treasury.gov/news/press-releases/jy0916,"        WASHINGTON – Today, the U.S. Department of the Treasury’s Office of Foreign Assets Control (OFAC) sanctioned virtual currency mixer Tornado Cash, which has been used to launder more than $7 billion worth of virtual currency since its creation in 2019. This includes over $455 million stolen by the Lazarus Group, a Democratic People’s Republic of Korea (DPRK) state-sponsored hacking group that was , in the . Tornado Cash was subsequently used to launder more than $96 million of malicious cyber actors’ funds derived from the June 24, 2022 Harmony Bridge Heist, and at least $7.8 million from the August 2, 2022 Nomad Heist. Today’s action is being taken pursuant to Executive Order (E.O.) 13694, as amended, and follows . “Today, Treasury is sanctioning Tornado Cash, a virtual currency",Hacker News,36617463,"Title: U.S. Treasury sanctions virtual currency mixer Tornado Cash; Content:         WASHINGTON – Today, the U.S. Department of the Treasury’s Office of Foreign Assets Control (OFAC) sanctioned virtual currency mixer Tornado Cash, which has been used to launder more than $7 billion worth of virtual currency since its creation in 2019. This includes over $455 million stolen by the Lazarus Group, a Democratic People’s Republic of Korea (DPRK) state-sponsored hacking group that was , in the . Tornado Cash was subsequently used to launder more than $96 million of malicious cyber actors’ funds derived from the June 24, 2022 Harmony Bridge Heist, and at least $7.8 million from the August 2, 2022 Nomad Heist. Today’s action is being taken pursuant to Executive Order (E.O.) 13694, as amended, and follows . “Today, Treasury is sanctioning Tornado Cash, a virtual currency",201 -mikhael,32419871,13,1660174985,America's Most Popular Sriracha Maker Confirms 'Unprecedented Shortage',https://www.foodandwine.com/news/sriracha-shortage-huy-fong-foods-pepper-supply,"In the past two years, we've all had to endure our way through countless product shortages, including everything from to , and to disposable . But although we seem to be past some of the most monumental — who could ever forget the Great of 2020? — that's not to say that we won't still find empty supermarket shelves where some of our favorite products used to be.  One item that might be increasingly hard to find is Huy Fong Foods Sriracha sauce, everyone's go-to green-capped hot sauce. The internet recently discovered a letter from Huy Fong Foods, Inc, the manufacturer of Sriracha, that warned of an impending shortage of not only Sriracha, but also its Chili Garlic and Sambal Oelek sauces. In the letter, which was posted on the website for wholesale food service distributor IFD, t",Hacker News,46668533,"Title: America's Most Popular Sriracha Maker Confirms 'Unprecedented Shortage'; Content: In the past two years, we've all had to endure our way through countless product shortages, including everything from to , and to disposable . But although we seem to be past some of the most monumental — who could ever forget the Great of 2020? — that's not to say that we won't still find empty supermarket shelves where some of our favorite products used to be.  One item that might be increasingly hard to find is Huy Fong Foods Sriracha sauce, everyone's go-to green-capped hot sauce. The internet recently discovered a letter from Huy Fong Foods, Inc, the manufacturer of Sriracha, that warned of an impending shortage of not only Sriracha, but also its Chili Garlic and Sambal Oelek sauces. In the letter, which was posted on the website for wholesale food service distributor IFD, t",208 -occamschainsaw,32403403,8,1660075051,Fusion Turns Up the Heat (Ignition Achieved),https://physics.aps.org/articles/v15/67,"The National Ignition Facility (NIF) uses the world’s largest laser to heat and compress a small capsule containing hydrogen fuel and thereby induce nuclear fusion reactions in the fuel (Fig. ), an approach known as inertial confinement fusion [ ]. In early 2021, a team at NIF achieved a major milestone by showing that they could produce a burning plasma [ ], a state in which the dominant source of fuel heating is self-heating due to fusion reactions—rather than external heating by the laser pulses. Today, NIF reports that they have reached another milestone in fusion research: they produced a plasma in which self-heating locally surpasses not only the external heating but also all loss mechanisms, fulfilling the so-called Lawson criterion for fusion ignition [ – ]. The result brings the",Hacker News,4958831,"Title: Fusion Turns Up the Heat (Ignition Achieved); Content: The National Ignition Facility (NIF) uses the world’s largest laser to heat and compress a small capsule containing hydrogen fuel and thereby induce nuclear fusion reactions in the fuel (Fig. ), an approach known as inertial confinement fusion [ ]. In early 2021, a team at NIF achieved a major milestone by showing that they could produce a burning plasma [ ], a state in which the dominant source of fuel heating is self-heating due to fusion reactions—rather than external heating by the laser pulses. Today, NIF reports that they have reached another milestone in fusion research: they produced a plasma in which self-heating locally surpasses not only the external heating but also all loss mechanisms, fulfilling the so-called Lawson criterion for fusion ignition [ – ]. The result brings the",177 -ksec,32396651,274,1660046272,France experiencing worst drought on record,https://www.bbc.co.uk/newsround/62456540,"France's Prime Minister, Elizabeth Borne, is asking the public to save as much water as they can, saying that France is experiencing its worst drought ever. Temperatures in the country have been extremely high during summer, with the country . July was France's driest month in more than 60 years, according to the national weather service Meteo-France. The dry weather is forecast to continue over the next few weeks. The small amount of rain has badly impacted food crops, with farmers warning that there might be less food available. According to France's Agriculture Ministry, the amount of corn crop the country produces could drop by 19%. This is a big concern for the French government, as if there is less food for people to eat, the price of food might go up as a result. The French govern",Hacker News,66850205,"Title: France experiencing worst drought on record; Content: France's Prime Minister, Elizabeth Borne, is asking the public to save as much water as they can, saying that France is experiencing its worst drought ever. Temperatures in the country have been extremely high during summer, with the country . July was France's driest month in more than 60 years, according to the national weather service Meteo-France. The dry weather is forecast to continue over the next few weeks. The small amount of rain has badly impacted food crops, with farmers warning that there might be less food available. According to France's Agriculture Ministry, the amount of corn crop the country produces could drop by 19%. This is a big concern for the French government, as if there is less food for people to eat, the price of food might go up as a result. The French govern",176 -torts,32383426,38,1659947404,The East African Federation experiment,https://www.karlsnotes.com/the-east-african-federation/,"The fastest growing region in Africa is also the site of an ongoing political experiment that aims, in the coming years, to have members of the East African Community band together and form the East African Federation - a single African superstate. The region in Africa is also the site of an ongoing political experiment that aims, in the coming years, to have members of the East African Community band together and form the East African Federation - a single African superstate. The region has had a long history of collaboration, especially between Kenya, Tanzania and Uganda, who cooperated under different agreements and organisations as early as 1917 when Kenya and Uganda formed a customs union. Between the 1960s and 1970s, the three countries created the East African Community (EAC), con",Hacker News,52040131,"Title: The East African Federation experiment; Content: The fastest growing region in Africa is also the site of an ongoing political experiment that aims, in the coming years, to have members of the East African Community band together and form the East African Federation - a single African superstate. The region in Africa is also the site of an ongoing political experiment that aims, in the coming years, to have members of the East African Community band together and form the East African Federation - a single African superstate. The region has had a long history of collaboration, especially between Kenya, Tanzania and Uganda, who cooperated under different agreements and organisations as early as 1917 when Kenya and Uganda formed a customs union. Between the 1960s and 1970s, the three countries created the East African Community (EAC), con",162 -cosmojg,32374113,279,1659849800,Our Roadmap for Nix,https://www.tweag.io/blog/2022-08-04-tweag-and-nix-future/,"I lead Tweag’s Nix team. The Nix ecosystem is at a turning point in its evolution. After more than a decade of slow but steady growth, Nix gained a lot of traction in the past few years, leading the community to expand at an astonishing rate. -But this growth hasn’t been without issue. As consultants, we see that nearly all of our clients that are using Nix are, at best, annoyed by the accidental complexity that comes with it. -Some of them even decide to back off because of that, left with a nondescript feeling that Nix is not ready for them. We care about Nix, and we want it to thrive. The way to get there is to strengthen Nix’s core as much as possible. -Instead of getting lost in many exciting things that Nix do, we must take a pragmatic approach in ensuring that the core functionality ",Hacker News,76011983,"Title: Our Roadmap for Nix; Content: I lead Tweag’s Nix team. The Nix ecosystem is at a turning point in its evolution. After more than a decade of slow but steady growth, Nix gained a lot of traction in the past few years, leading the community to expand at an astonishing rate. -But this growth hasn’t been without issue. As consultants, we see that nearly all of our clients that are using Nix are, at best, annoyed by the accidental complexity that comes with it. -Some of them even decide to back off because of that, left with a nondescript feeling that Nix is not ready for them. We care about Nix, and we want it to thrive. The way to get there is to strengthen Nix’s core as much as possible. -Instead of getting lost in many exciting things that Nix do, we must take a pragmatic approach in ensuring that the core functionality ",202 -_Microft,32400002,31,1660061979,New Tuberculosis vaccine candidate safe in HIV- and non-HIV-exposed newborns,https://www.mpg.de/19040549/0801-bich-tuberculosis-vaccine-candidate-vpm1002-safe-in-hiv-and-non-hiv-exposed-newborns-as-study-shows-17216463-x,"The vaccine candidate VPM1002 shows its safety in a study with HIV- and non-HIV-exposed newborns No other infectious disease has killed more people than tuberculosis. Currently, only one vaccine is available to prevent severe courses: (BCG). However, it is not equally effective against all types of tuberculosis. Especially infants and immunocompromised patients are therefore in urgent need for more effective tuberculosis vaccines. A clinical trial in South Africa has now shown that the new vaccine candidate VPM1002, developed by Max Planck researcher Stefan H.E. Kaufmann and his team, is equally safe for newborns with and without HIV exposure and has fewer side effects compared to BCG. Stefan H.E. Kaufmann (right) performs immunogenicity testing of human samples. - © Max Planck ",Hacker News,67945001,"Title: New Tuberculosis vaccine candidate safe in HIV- and non-HIV-exposed newborns; Content: The vaccine candidate VPM1002 shows its safety in a study with HIV- and non-HIV-exposed newborns No other infectious disease has killed more people than tuberculosis. Currently, only one vaccine is available to prevent severe courses: (BCG). However, it is not equally effective against all types of tuberculosis. Especially infants and immunocompromised patients are therefore in urgent need for more effective tuberculosis vaccines. A clinical trial in South Africa has now shown that the new vaccine candidate VPM1002, developed by Max Planck researcher Stefan H.E. Kaufmann and his team, is equally safe for newborns with and without HIV exposure and has fewer side effects compared to BCG. Stefan H.E. Kaufmann (right) performs immunogenicity testing of human samples. - © Max Planck ",207 -maverickJ,32375667,137,1659871743,"To Become Wise, Do Less",https://leveragethoughts.substack.com/p/to-become-wise-do-less,"Sirach 38: 24-26 According to ancient wisdom, leisure appears to be a necessary condition to acquire wisdom. Wisdom generates insights which can lead to breakthroughs that creates immense productivity. We need to have time where we can reflect, think and generate insights. With leisure one can allow the unconscious mind to bring forth new ideas and solve present challenges. You must focus and work hard on a thing/subject first. It’s the leisure after the focused work that creates the step up in value. Henri Poincare, the mathematical genius and polymath mentioned “the role of the unconscious work in mathematical invention appears to me incontestable”. In his words: Often when one works at a hard question, nothing good is accomplished at the first attack. The one takes a rest, longer or ",Hacker News,52295345,"Title: To Become Wise, Do Less; Content: Sirach 38: 24-26 According to ancient wisdom, leisure appears to be a necessary condition to acquire wisdom. Wisdom generates insights which can lead to breakthroughs that creates immense productivity. We need to have time where we can reflect, think and generate insights. With leisure one can allow the unconscious mind to bring forth new ideas and solve present challenges. You must focus and work hard on a thing/subject first. It’s the leisure after the focused work that creates the step up in value. Henri Poincare, the mathematical genius and polymath mentioned “the role of the unconscious work in mathematical invention appears to me incontestable”. In his words: Often when one works at a hard question, nothing good is accomplished at the first attack. The one takes a rest, longer or ",179 -olalonde,32392997,429,1660006791,Man arrested for promoting jury nullification wins federal case,https://reason.com/2022/08/05/he-was-arrested-for-promoting-jury-nullification-a-federal-court-says-that-was-illegal/,"You are now logged in. - - - - - - Michael Picard, a civil libertarian activist, was taken into custody in late 2017 after police took issue with him passing out papers telling recipients to ""Google Jury Nullification,"" as law enforcement alleged he was in violation of a New York law barring people from standing within 200 feet of a courthouse ""calling for or demanding any specified action or determination by such court or jury"" in connection with an ongoing case. But Picard was not referencing a specific trial when he was arrested. He was referencing a general tactic he sees as a bulwark against government overreach. ""There are unjust laws,"" he says. ""This is a tool that a jury or a juror can use to express their disagreement with [those] law[s]."" Put differently, Picard was not trying to",Hacker News,67259793,"Title: Man arrested for promoting jury nullification wins federal case; Content: You are now logged in. - - - - - - Michael Picard, a civil libertarian activist, was taken into custody in late 2017 after police took issue with him passing out papers telling recipients to ""Google Jury Nullification,"" as law enforcement alleged he was in violation of a New York law barring people from standing within 200 feet of a courthouse ""calling for or demanding any specified action or determination by such court or jury"" in connection with an ongoing case. But Picard was not referencing a specific trial when he was arrested. He was referencing a general tactic he sees as a bulwark against government overreach. ""There are unjust laws,"" he says. ""This is a tool that a jury or a juror can use to express their disagreement with [those] law[s]."" Put differently, Picard was not trying to",185 -amin,32380079,254,1659907588,"Look at median, and not mean GDP per capita",https://medianism.org/," simply aims for economic policies that benefit the majority of ordinary people.  This simply applies democratic norms to economic questions. Democracy prioritizes the preferences of the median voter, and medianism extends this idea to economics. For example, when economists think about how “the economy” is doing, they have traditionally focused on total income (GDP) or per-capita income (mean GDP) as the most important measure. But GDP is biased in favor of rich elites because even if 90% of people’s incomes drop, if the richest 10% are getting a lot richer, GDP can still grow and it can look like “the economy” is doing great even though most people are doing terrible. A much measure of “the economy” is median income because that is a more accurate reflection of the economic well being ",Hacker News,95768672,"Title: Look at median, and not mean GDP per capita; Content: simply aims for economic policies that benefit the majority of ordinary people.  This simply applies democratic norms to economic questions. Democracy prioritizes the preferences of the median voter, and medianism extends this idea to economics. For example, when economists think about how “the economy” is doing, they have traditionally focused on total income (GDP) or per-capita income (mean GDP) as the most important measure. But GDP is biased in favor of rich elites because even if 90% of people’s incomes drop, if the richest 10% are getting a lot richer, GDP can still grow and it can look like “the economy” is doing great even though most people are doing terrible. A much measure of “the economy” is median income because that is a more accurate reflection of the economic well being ",194 -blinding-streak,32384765,19,1659962653,The radical scope of Tesla’s data hoard,https://spectrum.ieee.org/tesla-autopilot-data-scope,"IEEE websites place cookies on your device to give you the best user experience. By using our websites, you agree to the placement of these cookies. To learn more, read our Privacy Policy. Logs and records of its customers’ journeys fill out petabytes—and court case dockets You won’t see a single Tesla cruising the glamorous beachfront in Beidaihe, China, this summer. Elon Musk’s popular electric cars from the resort for two months while it hosts the , presumably fearing what their built-in cameras might capture and feed back to the United States. Back in Florida, Tesla recently faced a negligence lawsuit after two young men died in a fiery car crash while driving a Model S belonging to a father of one of the accident victims. As part of its defense, the company submitted a showing th",Hacker News,23694759,"Title: The radical scope of Tesla’s data hoard; Content: IEEE websites place cookies on your device to give you the best user experience. By using our websites, you agree to the placement of these cookies. To learn more, read our Privacy Policy. Logs and records of its customers’ journeys fill out petabytes—and court case dockets You won’t see a single Tesla cruising the glamorous beachfront in Beidaihe, China, this summer. Elon Musk’s popular electric cars from the resort for two months while it hosts the , presumably fearing what their built-in cameras might capture and feed back to the United States. Back in Florida, Tesla recently faced a negligence lawsuit after two young men died in a fiery car crash while driving a Model S belonging to a father of one of the accident victims. As part of its defense, the company submitted a showing th",188 -mkl,32390730,65,1659991223,Spaced Repetition for Mathematics (2021),https://cronokirby.com/posts/2021/02/spaced-repetition-for-mathematics/,"Recently, I’ve been experimenting with using -for self-studying “advanced” mathematics. This post goes through -my motivations for adopting this system, as well as a few techniques -I’ve used in adapting it to mathematics. After reviewing a fact, or re-working some problem, you’re -more familiar with it. If you’re quizzed about that problem -soon after, you’ll be able to effortlessly recall the solution. -But, if you don’t visit this problem for long enough, you’ll eventually forget -this solution. The better you understand something, the longer it takes -to forget it. The idea behind is to reintroduce ideas and problems -right you forget them, forcing you to engage with the idea, -and refreshing your memory. -This is , because the periods without -recall get longer and longer, as your knowledg",Hacker News,40437788,"Title: Spaced Repetition for Mathematics (2021); Content: Recently, I’ve been experimenting with using -for self-studying “advanced” mathematics. This post goes through -my motivations for adopting this system, as well as a few techniques -I’ve used in adapting it to mathematics. After reviewing a fact, or re-working some problem, you’re -more familiar with it. If you’re quizzed about that problem -soon after, you’ll be able to effortlessly recall the solution. -But, if you don’t visit this problem for long enough, you’ll eventually forget -this solution. The better you understand something, the longer it takes -to forget it. The idea behind is to reintroduce ideas and problems -right you forget them, forcing you to engage with the idea, -and refreshing your memory. -This is , because the periods without -recall get longer and longer, as your knowledg",215 -samueldebrule,32415972,8,1660154163,Spotify starts selling live music tickets to fans directly,https://techcrunch.com/2022/08/10/spotify-starts-selling-live-music-tickets-to-fans-directly/,"Spotify has launched a new site to sell fans tickets to live gigs directly from its platform instead of redirecting users to partners like Ticketmaster and Eventbrite. The company’s lists upcoming concerts and lets users purchase tickets to these shows through debit or credit card; users need to have a Spotify account to buy tickets, though. The company hasn’t officially announced the launch of its ticketing platform, but first noted the site being available for the public to book tickets earlier today. The site lists gigs that are available to book on the home page, and under the My events section, users can see their past and upcoming ticket bookings. Currently, the Spotify Tickets site lists gigs for artists like Limbeck, Crow, Annie DiRusso, Four Years Strong and TOKiMONSTA that ar",Hacker News,13552193,"Title: Spotify starts selling live music tickets to fans directly; Content: Spotify has launched a new site to sell fans tickets to live gigs directly from its platform instead of redirecting users to partners like Ticketmaster and Eventbrite. The company’s lists upcoming concerts and lets users purchase tickets to these shows through debit or credit card; users need to have a Spotify account to buy tickets, though. The company hasn’t officially announced the launch of its ticketing platform, but first noted the site being available for the public to book tickets earlier today. The site lists gigs that are available to book on the home page, and under the My events section, users can see their past and upcoming ticket bookings. Currently, the Spotify Tickets site lists gigs for artists like Limbeck, Crow, Annie DiRusso, Four Years Strong and TOKiMONSTA that ar",182 -susam,32392611,17,1660003465,"Sun, Earth and Moon Position – 3D Simulator",https://en.tutiempo.net/astronomy/sun-earth-moon-3d.html,"The server encountered an internal error or -misconfiguration and was unable to complete -your request. Please contact the server administrator at - root@localhost to inform them of the time this error occurred, - and the actions you performed just before this error. More information about this error may be available -in the server error log.",Hacker News,89897336,"Title: Sun, Earth and Moon Position – 3D Simulator; Content: The server encountered an internal error or -misconfiguration and was unable to complete -your request. Please contact the server administrator at - root@localhost to inform them of the time this error occurred, - and the actions you performed just before this error. More information about this error may be available -in the server error log.",82 -eatonphil,32412329,56,1660140914,Correcting the Record on Meta’s Involvement in Nebraska Case,https://about.fb.com/news/2022/08/meta-response-nebraska-abortion-case/," - - - Follow Us - © 2022 Meta To help personalize content, tailor and measure ads, and provide a safer experience, we use cookies. By clicking or navigating the site, you agree to allow our collection of information on and off Facebook through cookies. Learn more, including about available controls: ",Hacker News,72803046,"Title: Correcting the Record on Meta’s Involvement in Nebraska Case; Content: - - - Follow Us - © 2022 Meta To help personalize content, tailor and measure ads, and provide a safer experience, we use cookies. By clicking or navigating the site, you agree to allow our collection of information on and off Facebook through cookies. Learn more, including about available controls: ",87 -zdw,32382860,57,1659940054,Our BMCs are not great at keeping accurate time,https://utcc.utoronto.ca/~cks/space/blog/sysadmin/BMCsNotGreatAtKeepingTime,"A is an extra embedded computer -on your server motherboard (as opposed to ). As separate -computers running a separate operating system, keep time independently from -your server's time (the time, reusing terminology from -virtualization), and this time is visible in places like the IPMI -event log (as well as just asking what time the BMC has via IPMI). -I've been tracking the reported BMC time against the server's own -view of time on our servers for a while, and recently I summarized -the results of that : Having tracked how much an IPMI's idea of time drifts across our -modest fleet for a while, well, we're now resetting the IPMI time once -a day. The BMC time drift we're seeing isn't terrible, but it's enough to -add up significantly if left uncorrected for very long, especially -on some",Hacker News,62200869,"Title: Our BMCs are not great at keeping accurate time; Content: A is an extra embedded computer -on your server motherboard (as opposed to ). As separate -computers running a separate operating system, keep time independently from -your server's time (the time, reusing terminology from -virtualization), and this time is visible in places like the IPMI -event log (as well as just asking what time the BMC has via IPMI). -I've been tracking the reported BMC time against the server's own -view of time on our servers for a while, and recently I summarized -the results of that : Having tracked how much an IPMI's idea of time drifts across our -modest fleet for a while, well, we're now resetting the IPMI time once -a day. The BMC time drift we're seeing isn't terrible, but it's enough to -add up significantly if left uncorrected for very long, especially -on some",207 -signa11,32382977,79,1659941509,Wisp: Whitespace to Lisp,https://www.draketo.de/software/wisp," - - - - - — Christine Webber, 2015, - , and in their blog: - - — Christine Lemmer-Webber, 2021, . -♡ wow ♡ - - — Ricardo Wurmus in IRC, -paraphrasing the wisp statement from his - . -☺ Yay! ☺ - - - - -  - - (2022-02-04): - Inspired by the FOSDEM talk (video: ) -by Christine Lemmer-Webber, 0.3.0 now -provides — optional highlighting -of the semantic indentation level using a light background color: - - - -Also there is an experimental mode that highlights the current -indentation level, but being experimental means that it might go -away or receive bigger changes to behavior: - - - -You can get wisp-mode directly from . - -If you have additional questions, see the -and chat in . -That's it - have fun with ! - - (2021-12-20): - fixes a bug in 1.0.6 that broke the insta-rep",Hacker News,47237553,"Title: Wisp: Whitespace to Lisp; Content: - - - - - — Christine Webber, 2015, - , and in their blog: - - — Christine Lemmer-Webber, 2021, . -♡ wow ♡ - - — Ricardo Wurmus in IRC, -paraphrasing the wisp statement from his - . -☺ Yay! ☺ - - - - -  - - (2022-02-04): - Inspired by the FOSDEM talk (video: ) -by Christine Lemmer-Webber, 0.3.0 now -provides — optional highlighting -of the semantic indentation level using a light background color: - - - -Also there is an experimental mode that highlights the current -indentation level, but being experimental means that it might go -away or receive bigger changes to behavior: - - - -You can get wisp-mode directly from . - -If you have additional questions, see the -and chat in . -That's it - have fun with ! - - (2021-12-20): - fixes a bug in 1.0.6 that broke the insta-rep",313 -imartin2k,32385026,90,1659964749,Bridge Loans,https://avc.com/2022/08/bridge-loans/,"When fundraising gets tougher for startups, the existing investors (insiders) will often provide a bridge loan to the company to extend the runway for getting another round done. There is more of this sort of thing happening in today’s fundraising market and I thought I’d share some of the things I have learned about setting up bridge loans. First, bridge loans are a bridge to something else. Most commonly they are a bridge to a round of financing with new investors (outsiders). They can also be a bridge to the sale of the company. Occasionally, but not often, they can be a bridge to getting cash flow positive. If none of those things is going to happen in a relatively short period of time, then it is a bridge to nowhere and you really want to avoid that. A bridge to another bridge is neve",Hacker News,46793161,"Title: Bridge Loans; Content: When fundraising gets tougher for startups, the existing investors (insiders) will often provide a bridge loan to the company to extend the runway for getting another round done. There is more of this sort of thing happening in today’s fundraising market and I thought I’d share some of the things I have learned about setting up bridge loans. First, bridge loans are a bridge to something else. Most commonly they are a bridge to a round of financing with new investors (outsiders). They can also be a bridge to the sale of the company. Occasionally, but not often, they can be a bridge to getting cash flow positive. If none of those things is going to happen in a relatively short period of time, then it is a bridge to nowhere and you really want to avoid that. A bridge to another bridge is neve",176 -cheinyeanlim,32405062,10,1660082899,Scientists Revived Organs in Pigs an Hour After They Died,https://singularityhub.com/2022/08/09/how-scientists-revived-cells-in-pigs-organs-an-hour-after-they-died/,"Oxygen is the elixir of life. Stop its flow—during a stroke, heart attack, or death—and the body’s tissues respond in a biological storm that eventually leads to their death. It’s not great for organ transplants. Most donated organs struggle to survive beyond death. Deprived of oxygen, they rapidly lose their function. Cells turn into acidic, bloated blobs that leak, injuring their neighbors. The immune system ramps up, pumping out a deadly concoction of hormones and immune chemicals that send the brain and immune system into hyperdrive, damaging most organs in the process. In other words, once death sets in, there’s no turning back. Or is there? in suggests there might be. Using an external circulation system, a team of scientists partially revived organs in pigs hours after their deat",Hacker News,44946569,"Title: Scientists Revived Organs in Pigs an Hour After They Died; Content: Oxygen is the elixir of life. Stop its flow—during a stroke, heart attack, or death—and the body’s tissues respond in a biological storm that eventually leads to their death. It’s not great for organ transplants. Most donated organs struggle to survive beyond death. Deprived of oxygen, they rapidly lose their function. Cells turn into acidic, bloated blobs that leak, injuring their neighbors. The immune system ramps up, pumping out a deadly concoction of hormones and immune chemicals that send the brain and immune system into hyperdrive, damaging most organs in the process. In other words, once death sets in, there’s no turning back. Or is there? in suggests there might be. Using an external circulation system, a team of scientists partially revived organs in pigs hours after their deat",190 -cunidev,32375128,217,1659864957,Homebrew Bluetooth Headphones,https://homebrewheadphones.com/3d-printed-bluetooth-headphones/,"Want to build yourself an awesome sounding, decent looking pair of bluetooth headphones? You’ve come to the right place! Building these headphone doesn’t require much knowledge of electronics and beyond access to a 3D printer, only basic tools. The parts can easily be sourced from Amazon and eBay for approx USD$50. If you want to make the corded version, see . You will need to print the following parts in ABS. The default print settings for my machine work fine. If you have Autodesk Fusion 360 and want to customise the design, the source CAD files can be accessed . Print the headband with the channel facing up, covers with the outer face on the bed and baffles with the ear side on the bed. The parts used in these instructions have been coated in filler, sanded back and painted to give a ",Hacker News,26281610,"Title: Homebrew Bluetooth Headphones; Content: Want to build yourself an awesome sounding, decent looking pair of bluetooth headphones? You’ve come to the right place! Building these headphone doesn’t require much knowledge of electronics and beyond access to a 3D printer, only basic tools. The parts can easily be sourced from Amazon and eBay for approx USD$50. If you want to make the corded version, see . You will need to print the following parts in ABS. The default print settings for my machine work fine. If you have Autodesk Fusion 360 and want to customise the design, the source CAD files can be accessed . Print the headband with the channel facing up, covers with the outer face on the bed and baffles with the ear side on the bed. The parts used in these instructions have been coated in filler, sanded back and painted to give a ",186 -_shadi,32409415,11,1660122154,"Ask HN: Teams migrated from Nomad to Kubernetes,what pushed you to migrate?",,"we are trying to pick a self-hosted container orchestration engine to use, after evaluating the pros and cons of both we decided Nomad would be the better option for us.

I used both in the past, and for self-hosted solution I also prefer the simplicity of Nomad, but I realize that Kubernetes has much more functionality, so I'm wondering if there is something that we will realize that we are missing once we start using Nomad for production workloads.

So my question is targeted at people who used Nomad in production, and later found themselves migrating to Kubernetes, what is your story? and what functionality did you miss the most that pushed you to move to Kubernetes. -Blogs and articles are also welcome.",Hacker News,66650214,"Title: Ask HN: Teams migrated from Nomad to Kubernetes,what pushed you to migrate?; Content: we are trying to pick a self-hosted container orchestration engine to use, after evaluating the pros and cons of both we decided Nomad would be the better option for us.

I used both in the past, and for self-hosted solution I also prefer the simplicity of Nomad, but I realize that Kubernetes has much more functionality, so I'm wondering if there is something that we will realize that we are missing once we start using Nomad for production workloads.

So my question is targeted at people who used Nomad in production, and later found themselves migrating to Kubernetes, what is your story? and what functionality did you miss the most that pushed you to move to Kubernetes. -Blogs and articles are also welcome.",193 -kelsier1,32390083,96,1659987693,Automated Reasoning at Amazon: A Conversation,https://www.amazon.science/blog/automated-reasoning-at-federated-logic-conference-floc,"The Federated Logic Conference (FLoC) is a superconference that, like the Olympics, happens every four years. FLoC draws together 12 distinct conferences on logic-related topics, most of which meet annually. The individual conferences have their own invited speakers, but FLoC as a whole has several plenary speakers as well. At the last FLoC, in 2018, one of those plenary speakers was Byron Cook, who leads Amazon’s automated-reasoning group, and he was introduced by Daniel Kröning, then a professor of computer science at the University of Oxford “What makes me so proud that Byron is here,” Kröning said, is “he’s now at Amazon, and he’s going to run the next Bell Labs, he’s going to run the next Microsoft Research, from within Amazon. My prediction is that — not 10 years but 16 years; rememb",Hacker News,59484065,"Title: Automated Reasoning at Amazon: A Conversation; Content: The Federated Logic Conference (FLoC) is a superconference that, like the Olympics, happens every four years. FLoC draws together 12 distinct conferences on logic-related topics, most of which meet annually. The individual conferences have their own invited speakers, but FLoC as a whole has several plenary speakers as well. At the last FLoC, in 2018, one of those plenary speakers was Byron Cook, who leads Amazon’s automated-reasoning group, and he was introduced by Daniel Kröning, then a professor of computer science at the University of Oxford “What makes me so proud that Byron is here,” Kröning said, is “he’s now at Amazon, and he’s going to run the next Bell Labs, he’s going to run the next Microsoft Research, from within Amazon. My prediction is that — not 10 years but 16 years; rememb",209 -woofyman,32418223,23,1660164500,Mark Cuban: Buying real estate in the metaverse is ‘the dumbest’ idea ever,https://www.cnbc.com/2022/08/10/mark-cuban-buying-real-estate-in-the-metaverse-is-dumbest-idea-ever.html,"Buying digital land in the metaverse may not be the best use of your money, according to billionaire investor Mark Cuban. Although Cuban is a well-documented , he called purchasing virtual real estate in the metaverse ""the dumbest s--- ever"" in a on the Altcoin Daily YouTube channel. Despite being an investor in Yuga Labs, which owns popular NFT collections such as Bored Ape Yacht Club that has sold digital land plots, Cuban said buying virtual real estate is ""dumb."" ""It was great money for them, but that wasn't based off utility,"" he said. In the physical world, real estate is valuable because land is a scarce resource. However, that scarcity doesn't necessarily apply to the metaverse. In these virtual worlds, ""there's unlimited volumes that you can create,"" Cuban said during the inter",Hacker News,81188783,"Title: Mark Cuban: Buying real estate in the metaverse is ‘the dumbest’ idea ever; Content: Buying digital land in the metaverse may not be the best use of your money, according to billionaire investor Mark Cuban. Although Cuban is a well-documented , he called purchasing virtual real estate in the metaverse ""the dumbest s--- ever"" in a on the Altcoin Daily YouTube channel. Despite being an investor in Yuga Labs, which owns popular NFT collections such as Bored Ape Yacht Club that has sold digital land plots, Cuban said buying virtual real estate is ""dumb."" ""It was great money for them, but that wasn't based off utility,"" he said. In the physical world, real estate is valuable because land is a scarce resource. However, that scarcity doesn't necessarily apply to the metaverse. In these virtual worlds, ""there's unlimited volumes that you can create,"" Cuban said during the inter",200 -luu,32390495,5,1659989839,Dev Diary for Surfwords,https://novalis.org/blog/2022-08-03-dev-diary--surfwords.html,"Thanks to the success of Semantle, I decided to become a game -developer. I’m going to try it for a year, and see if I can make a -living at it. At the end of May, I quit my job, and started working -on a new game called . Now, at the beginning of August, I’m -nearly done. As soon as I get this released, it’s on to the next -thing (probably an archaeology-themed solitaire card game, although -maybe I’ll do a two-player version too). I love words, and I love word games. My favorite is Montage, which is -a cross between Taboo and a crossword puzzle. You have to figure out -a playable word, clue it, and have your partner guess before both -opponents do, all within a one-minute timer. That’s the level of -intensity I crave. I was also inspired by : -it’s simple, you lose a lot, and with practice",Hacker News,71400637,"Title: Dev Diary for Surfwords; Content: Thanks to the success of Semantle, I decided to become a game -developer. I’m going to try it for a year, and see if I can make a -living at it. At the end of May, I quit my job, and started working -on a new game called . Now, at the beginning of August, I’m -nearly done. As soon as I get this released, it’s on to the next -thing (probably an archaeology-themed solitaire card game, although -maybe I’ll do a two-player version too). I love words, and I love word games. My favorite is Montage, which is -a cross between Taboo and a crossword puzzle. You have to figure out -a playable word, clue it, and have your partner guess before both -opponents do, all within a one-minute timer. That’s the level of -intensity I crave. I was also inspired by : -it’s simple, you lose a lot, and with practice",240 -bonkerbits,32376256,28,1659878289,A Parachute Accident in 1992 jump-started the birth of Augmented Reality,https://spectrum.ieee.org/history-of-augmented-reality,"IEEE websites place cookies on your device to give you the best user experience. By using our websites, you agree to the placement of these cookies. To learn more, read our Privacy Policy. In 1992, hardware for the first interactive AR system literally fell from the skies Louis Rosenberg tests Virtual Fixtures, the first interactive augmented-reality system that he developed at Wright-Patterson Air Force Base, in 1992. an upper-body exoskeleton that’s covered in sensors, motors, gears, and bearings, and then lean forward, tilting my head up to press my face against the eyepieces of a vision system hanging from the ceiling. In front of me, I see a large wooden board, painted black and punctuated by a grid of metal holes. The board is real. So is the peg in my hand that I’m trying to move ",Hacker News,3680089,"Title: A Parachute Accident in 1992 jump-started the birth of Augmented Reality; Content: IEEE websites place cookies on your device to give you the best user experience. By using our websites, you agree to the placement of these cookies. To learn more, read our Privacy Policy. In 1992, hardware for the first interactive AR system literally fell from the skies Louis Rosenberg tests Virtual Fixtures, the first interactive augmented-reality system that he developed at Wright-Patterson Air Force Base, in 1992. an upper-body exoskeleton that’s covered in sensors, motors, gears, and bearings, and then lean forward, tilting my head up to press my face against the eyepieces of a vision system hanging from the ceiling. In front of me, I see a large wooden board, painted black and punctuated by a grid of metal holes. The board is real. So is the peg in my hand that I’m trying to move ",202 -rlawson,32397750,23,1660052589,Ask HN: Is ease in getting started the key for Python's success?,,"I am just an intermediate Python dev (but a senior Java dev with 20+ years). What I have come to realize is that Python is just as complicated as Java! However it is much much easier to get started with.

Java is aimed squarely at professional devs and requires a lot of tooling and support. -Python requires almost nothing (interpreter + editor + a basic understanding of lists/dicts and control flow) to get started.

But do a big project with a large team and you'll quickly discover the rough edges and debates - a few that have come up lately for me at work - typing or no typing, oop or functional? pytest or unittest? poetry vs pipenv vs ... ? Occasional runtime errors. Project layout and organization (makes me miss maven sometimes). -Don't get me wrong - I really enjoy working in Python but I believe it would be a niche language if it were not so approachable to the beginner.",Hacker News,78952162,"Title: Ask HN: Is ease in getting started the key for Python's success?; Content: I am just an intermediate Python dev (but a senior Java dev with 20+ years). What I have come to realize is that Python is just as complicated as Java! However it is much much easier to get started with.

Java is aimed squarely at professional devs and requires a lot of tooling and support. -Python requires almost nothing (interpreter + editor + a basic understanding of lists/dicts and control flow) to get started.

But do a big project with a large team and you'll quickly discover the rough edges and debates - a few that have come up lately for me at work - typing or no typing, oop or functional? pytest or unittest? poetry vs pipenv vs ... ? Occasional runtime errors. Project layout and organization (makes me miss maven sometimes). -Don't get me wrong - I really enjoy working in Python but I believe it would be a niche language if it were not so approachable to the beginner.",242 -Kaibeezy,32375095,111,1659864244,Ten years with a Citroën C6 (2021),https://driventowrite.com/2021/01/04/citroen-c6-long-term-test/,"Still The World's Least Influential Motoring Site On deciding that I would put something on record to mark a decade of C6 ownership via this most informative and thoughtful of automotive websites, the above quote involuntarily entered my mind and won’t now take its leave. Maybe it’s because it reflects the roller-coaster ride of the experience? Maybe it’s because the quote also relates to the French Revolution in as much as the C6 was Citroën’s final attempt to usurp the norms of what we used to call (well, I did) the  car market, before it became so multi-dimensional that it could now mean anything from a Skoda Superb to a BMW X7. Maybe it’s just my mind playing tricks on me, as it so often does as hindsight warps and discards memories of what actually was at the time. I came into C6 ow",Hacker News,40265379,"Title: Ten years with a Citroën C6 (2021); Content: Still The World's Least Influential Motoring Site On deciding that I would put something on record to mark a decade of C6 ownership via this most informative and thoughtful of automotive websites, the above quote involuntarily entered my mind and won’t now take its leave. Maybe it’s because it reflects the roller-coaster ride of the experience? Maybe it’s because the quote also relates to the French Revolution in as much as the C6 was Citroën’s final attempt to usurp the norms of what we used to call (well, I did) the  car market, before it became so multi-dimensional that it could now mean anything from a Skoda Superb to a BMW X7. Maybe it’s just my mind playing tricks on me, as it so often does as hindsight warps and discards memories of what actually was at the time. I came into C6 ow",213 -turtlegrids,32392474,20,1660002229,The Forbidden ARM Server That Is Banned in the US,https://www.servethehome.com/the-forbidden-arm-server-that-is-banned-in-the-us/2/,"For this piece, we are going to show more angles and photos than we normally do of some specific parts of the server’s internals. We realize this is an important industry platform, but it is also one that few of our readers will have seen. Taking a look at the front of the chassis, we can see the storage backplane, a large channel for cables, then the fan partition. The storage backplane supports up to eight PCIe Gen4 x4 NVMe SSDs. It also has provisions for the other sixteen slots being SATA/ SAS. For those wondering from photos, the backplane is not bent wildly. Instead, the sheet metal above the backplane has a curve to it. Something that is different here is that we see a lot of the industry move to backplanes that are segmented into thirds on 2U 24-bay designs. That allows flexibility",Hacker News,28549883,"Title: The Forbidden ARM Server That Is Banned in the US; Content: For this piece, we are going to show more angles and photos than we normally do of some specific parts of the server’s internals. We realize this is an important industry platform, but it is also one that few of our readers will have seen. Taking a look at the front of the chassis, we can see the storage backplane, a large channel for cables, then the fan partition. The storage backplane supports up to eight PCIe Gen4 x4 NVMe SSDs. It also has provisions for the other sixteen slots being SATA/ SAS. For those wondering from photos, the backplane is not bent wildly. Instead, the sheet metal above the backplane has a curve to it. Something that is different here is that we see a lot of the industry move to backplanes that are segmented into thirds on 2U 24-bay designs. That allows flexibility",194 -walterbell,32374227,77,1659851791,Wizard with a Time Machine,https://microship.com/wizard-with-a-time-machine/,"Located in an unassuming building in Friday Harbor is a magical place inhabited by a wizard of technology bringing history back to life for clients and friends. Steven K. Roberts is his name, digitizing old films, videos and slides is his game. , established in 2018 by Roberts, began as a personal project when he inherited a collection of 8mm movies taken by his father between 1936 through the 1970s. Within the collection, along with footage of his family, surfaced early footage that Roberts recognized had “considerable historical value.” Roberts spent a considerable amount of time researching an overwhelming range of conversion technology that would suit his needs and technological skills. Following an obsessive amount of research into professional digitizing tools and technologies, accor",Hacker News,69781432,"Title: Wizard with a Time Machine; Content: Located in an unassuming building in Friday Harbor is a magical place inhabited by a wizard of technology bringing history back to life for clients and friends. Steven K. Roberts is his name, digitizing old films, videos and slides is his game. , established in 2018 by Roberts, began as a personal project when he inherited a collection of 8mm movies taken by his father between 1936 through the 1970s. Within the collection, along with footage of his family, surfaced early footage that Roberts recognized had “considerable historical value.” Roberts spent a considerable amount of time researching an overwhelming range of conversion technology that would suit his needs and technological skills. Following an obsessive amount of research into professional digitizing tools and technologies, accor",157 -memorable,32374207,278,1659851483,How to stop being “terminally online”,https://nights.bearblog.dev/how-to-stop-being-terminally-online/," - - - to accomplish the tasks detailed further in the list, you have to do some soul-searching. this starts with acknowledging and accepting that you're terminally online, and determining why this is. understanding yourself will help you come up with a plan of action that best suits your needs. here's some questions to start you off: don't be ashamed if you can identify with some of the problems posed in these questions. nowadays, and especially since the pandemic, most of us are ""terminally online"" in some form unless we live alone on a mountain with no reception. your recognizing this already puts you ahead of most other people - a willingness to be honest with yourself shows a strength of character which will make improvement all the more feasible. it's hard to find someone who's ""termi",Hacker News,96308110,"Title: How to stop being “terminally online”; Content: - - - to accomplish the tasks detailed further in the list, you have to do some soul-searching. this starts with acknowledging and accepting that you're terminally online, and determining why this is. understanding yourself will help you come up with a plan of action that best suits your needs. here's some questions to start you off: don't be ashamed if you can identify with some of the problems posed in these questions. nowadays, and especially since the pandemic, most of us are ""terminally online"" in some form unless we live alone on a mountain with no reception. your recognizing this already puts you ahead of most other people - a willingness to be honest with yourself shows a strength of character which will make improvement all the more feasible. it's hard to find someone who's ""termi",182 -kjhughes,32376414,168,1659879814,Hacker’s Delight (2012),https://books.google.com/books/about/Hacker_s_Delight.html?id=VicPJYM0I5QC,"Kein E-Book verfügbar Stöbere im größten eBookstore der Welt und lies noch heute im Web, auf deinem Tablet, Telefon oder E-Reader. Weiter zu Google Play » --Josh Bloch (Praise for the first edition) In Hank Warren once again compiles an irresistible collection of programming hacks: timesaving techniques, algorithms, and tricks that help programmers build more elegant and efficient software, while also gaining deeper insights into their craft. Warren’s hacks are eminently practical, but they’re also intrinsically interesting, and sometimes unexpected, much like the solution to a great puzzle. They are, in a word, a delight to any programmer who is excited by the opportunity to improve. has had a fifty-year career with IBM, spanning from the IBM 704 to the PowerP",Hacker News,81593227,"Title: Hacker’s Delight (2012); Content: Kein E-Book verfügbar Stöbere im größten eBookstore der Welt und lies noch heute im Web, auf deinem Tablet, Telefon oder E-Reader. Weiter zu Google Play » --Josh Bloch (Praise for the first edition) In Hank Warren once again compiles an irresistible collection of programming hacks: timesaving techniques, algorithms, and tricks that help programmers build more elegant and efficient software, while also gaining deeper insights into their craft. Warren’s hacks are eminently practical, but they’re also intrinsically interesting, and sometimes unexpected, much like the solution to a great puzzle. They are, in a word, a delight to any programmer who is excited by the opportunity to improve. has had a fifty-year career with IBM, spanning from the IBM 704 to the PowerP",223 -todsacerdoti,32376542,154,1659880999,The pervasive effects of C's malloc() and free() on C APIs,https://utcc.utoronto.ca/~cks/space/blog/programming/CAPIsEffectsOfMalloc,"In , I touched on how from the beginning - -had an issue in its API, one that the BSD Unix people specifically -called out in its manual page's BUGS section: All information is contained in a static area so it must be copied if -it is to be saved. [...] This became a serious issue when Unix added threads (this static -area isn't thread safe), but was seen as a problem from the very -beginning. Given that the static return area was known as an issue, -why was the API written this way? While I don't know for sure, I think we can point fingers at the -hassles that dynamic memory allocation brings you in a C API. The - API returns a pointer to a ' ', -which is ( ): If this structure is dynamically allocated by and -returned to the caller, either you need an additional API function -to free it or you ",Hacker News,34693458,"Title: The pervasive effects of C's malloc() and free() on C APIs; Content: In , I touched on how from the beginning - -had an issue in its API, one that the BSD Unix people specifically -called out in its manual page's BUGS section: All information is contained in a static area so it must be copied if -it is to be saved. [...] This became a serious issue when Unix added threads (this static -area isn't thread safe), but was seen as a problem from the very -beginning. Given that the static return area was known as an issue, -why was the API written this way? While I don't know for sure, I think we can point fingers at the -hassles that dynamic memory allocation brings you in a C API. The - API returns a pointer to a ' ', -which is ( ): If this structure is dynamically allocated by and -returned to the caller, either you need an additional API function -to free it or you ",214 -ingve,32386085,30,1659970198,The ‘fat service’ pattern for Go web applications,https://www.alexedwards.net/blog/the-fat-service-pattern," My book guides you through the start-to-finish build of a real world web application in Go . In this post I'd like to talk about one of my favorite architectural patterns for building web applications and APIs in Go. It's kind of a mix between the and patterns — so I mentally refer to it as the 'fat service' pattern, but it might have a more formal name that I'm not aware of 🙃 It's certainly not a pattern (we'll discuss some of the pros and cons later) — but it is (deliberately) simple, pragmatic, and I find it often works well for small-to-medium sized projects. At a high-level, the fat service pattern splits your project code into two distinct 'layers': The layer. This contains your code related to reading and writing HTTP requests and responses, authenticating/authorizing reque",Hacker News,7853054,"Title: The ‘fat service’ pattern for Go web applications; Content: My book guides you through the start-to-finish build of a real world web application in Go . In this post I'd like to talk about one of my favorite architectural patterns for building web applications and APIs in Go. It's kind of a mix between the and patterns — so I mentally refer to it as the 'fat service' pattern, but it might have a more formal name that I'm not aware of 🙃 It's certainly not a pattern (we'll discuss some of the pros and cons later) — but it is (deliberately) simple, pragmatic, and I find it often works well for small-to-medium sized projects. At a high-level, the fat service pattern splits your project code into two distinct 'layers': The layer. This contains your code related to reading and writing HTTP requests and responses, authenticating/authorizing reque",206 -signa11,32374278,124,1659852489,Let's Talk SkipList,https://ketansingh.me/posts/lets-talk-skiplist/,"SkipLists often come up when discussing “obscure” data-structures but in reality they are not that obscure, in fact many of the production grade softwares actively use them. In this post I’ll try to go into SkipLists by describing how to make a toy implementation, potential optimizations and real world use cases of them. So what are SkipLists anyway? Well, SkipList are referential data structures inspired from linked list and binary trees. They are collection of sort linked list arranged in different levels, where levels are designed in such a way that it allows skipping nodes to get a logarithmic complexity when searching for the keys later. They are alternative to binary trees and even in some cases the legendary B-Tree, in fact last level of SkipList looks somewhat like a B+Tree. SkipLi",Hacker News,65459807,"Title: Let's Talk SkipList; Content: SkipLists often come up when discussing “obscure” data-structures but in reality they are not that obscure, in fact many of the production grade softwares actively use them. In this post I’ll try to go into SkipLists by describing how to make a toy implementation, potential optimizations and real world use cases of them. So what are SkipLists anyway? Well, SkipList are referential data structures inspired from linked list and binary trees. They are collection of sort linked list arranged in different levels, where levels are designed in such a way that it allows skipping nodes to get a logarithmic complexity when searching for the keys later. They are alternative to binary trees and even in some cases the legendary B-Tree, in fact last level of SkipList looks somewhat like a B+Tree. SkipLi",185 -sixhobbits,32385856,82,1659969140,Show HN: SaveSlack – create searchable knowledgebase from your Slack community,https://saveslack.com,"Upload a .zip file of your Slack dump and we will host a searchable public website of all conversations for you. Instructions on how to create it . Here's an . It - - - Once you upload your Slack dump, you'll get your own link like the one above within a couple of minutes. - There are currently 2 sites in the processing queue - - A lot of knowledge is locked up in Slack communities. Recently Slack announced a pricing change which meant that this knowlege would all disappear after 3 months (change effective 1 September - you can read the details .) - In order to free this knowledge and make it searchable by your community, you can export a .zip file of all public Slack channels in your community, parse the json files, and create a nice, searchable, public website for your community. But th",Hacker News,8617295,"Title: Show HN: SaveSlack – create searchable knowledgebase from your Slack community; Content: Upload a .zip file of your Slack dump and we will host a searchable public website of all conversations for you. Instructions on how to create it . Here's an . It - - - Once you upload your Slack dump, you'll get your own link like the one above within a couple of minutes. - There are currently 2 sites in the processing queue - - A lot of knowledge is locked up in Slack communities. Recently Slack announced a pricing change which meant that this knowlege would all disappear after 3 months (change effective 1 September - you can read the details .) - In order to free this knowledge and make it searchable by your community, you can export a .zip file of all public Slack channels in your community, parse the json files, and create a nice, searchable, public website for your community. But th",197 -feross,32388648,22,1659980678,The Ants and the Pheromones (2021),https://blog.acolyer.org/2021/02/08/the-ants-and-the-pheromones/,"TLDR; this is the last edition of The Morning Paper for now. Plus: one strand of research you won’t want to miss! I was listening to a BBC Radio 4 podcast recently ( ) in which the host Tim Harford is interviewing David Sumpter about his recent book, ‘ .’ One of those equations, the ‘reward equation’ models how ants communicate using pheromones, and our own brains keep track of rewards using dopamine. About 4 and a half minutes into the podcast Tim asks a fascinating question: the reward equation includes a decay or ‘forgetting’ parameter, so what happens if you disrupt established solutions for long enough that their hold is broken? For example, the complete disruption to our established routines that Covid has caused over the last year? The answer for ants, if you disrupt all of the pher",Hacker News,51143230,"Title: The Ants and the Pheromones (2021); Content: TLDR; this is the last edition of The Morning Paper for now. Plus: one strand of research you won’t want to miss! I was listening to a BBC Radio 4 podcast recently ( ) in which the host Tim Harford is interviewing David Sumpter about his recent book, ‘ .’ One of those equations, the ‘reward equation’ models how ants communicate using pheromones, and our own brains keep track of rewards using dopamine. About 4 and a half minutes into the podcast Tim asks a fascinating question: the reward equation includes a decay or ‘forgetting’ parameter, so what happens if you disrupt established solutions for long enough that their hold is broken? For example, the complete disruption to our established routines that Covid has caused over the last year? The answer for ants, if you disrupt all of the pher",196 -reimertz,32386323,164,1659971180,"Starting October 19, storage limit will be enforced on all Gitlab Free accounts",https://docs.gitlab.com/ee/user/usage_quotas.html#namespace-storage-limit-enforcement-schedule,"Help us learn about your current experience with the documentation. . Namespaces on a GitLab SaaS Free tier have a 5 GB storage limit. For more information, see our . -This limit is not visible on the storage quota page, but we plan to make it visible and enforced starting October 19, 2022. Storage types that add to the total namespace storage are: If your total namespace storage exceeds the available namespace storage quota, all projects under the namespace are locked. A locked project will not be able to push to the repository, run pipelines and jobs, or build and push packages. To prevent exceeding the namespace storage quota, you can: Starting October 19, 2022, a storage limit will be enforced on all GitLab Free namespaces. -We will start with a large limit enforcement and eventually r",Hacker News,93861906,"Title: Starting October 19, storage limit will be enforced on all Gitlab Free accounts; Content: Help us learn about your current experience with the documentation. . Namespaces on a GitLab SaaS Free tier have a 5 GB storage limit. For more information, see our . -This limit is not visible on the storage quota page, but we plan to make it visible and enforced starting October 19, 2022. Storage types that add to the total namespace storage are: If your total namespace storage exceeds the available namespace storage quota, all projects under the namespace are locked. A locked project will not be able to push to the repository, run pipelines and jobs, or build and push packages. To prevent exceeding the namespace storage quota, you can: Starting October 19, 2022, a storage limit will be enforced on all GitLab Free namespaces. -We will start with a large limit enforcement and eventually r",184 -nicbou,32379139,142,1659900864,Making Quieter Technology,https://nicolasbouliane.com/blog/silence," - Posted on - Technology's default mode is to constantly call for my attention. Attention is engagement, engagement is profit. And thus a big chunk of the economy devotes itself to grabbing my attention by increasingly coercive means. It took considerable effort to get technology to just . This is what this post is about; making technology quieter, and building a healthier relationship with it. I want to use technology on my own terms, for my own ends. I want that respects the boundaries I set for it. This includes respecting my time, my attention, my privacy and above all my consent. I should be the user, it should be the tool, not the other way around. I no longer want to get sidetracked by deliberately addictive technology when I meant to sit down and do work. I want ",Hacker News,41495939,"Title: Making Quieter Technology; Content: - Posted on - Technology's default mode is to constantly call for my attention. Attention is engagement, engagement is profit. And thus a big chunk of the economy devotes itself to grabbing my attention by increasingly coercive means. It took considerable effort to get technology to just . This is what this post is about; making technology quieter, and building a healthier relationship with it. I want to use technology on my own terms, for my own ends. I want that respects the boundaries I set for it. This includes respecting my time, my attention, my privacy and above all my consent. I should be the user, it should be the tool, not the other way around. I no longer want to get sidetracked by deliberately addictive technology when I meant to sit down and do work. I want ",193 -upzylon,32377646,137,1659889466,A generically typed pipe function in TypeScript,https://github.com/MathisBullinger/froebel," - A strictly typed utility library. - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. This is my (WIP) personal collection of TypeScript helper functions and utilities that -I use across different projects. -Think an opinionated version of lodash, but with first-class types. If you have an idea for a utility that might make a good addition to this collection, -please open an issue and suggest its inclusion. Runs in Deno, Node.js, and the Browser. Get it from -or . and — assuming a",Hacker News,18994240,"Title: A generically typed pipe function in TypeScript; Content: - A strictly typed utility library. - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. This is my (WIP) personal collection of TypeScript helper functions and utilities that -I use across different projects. -Think an opinionated version of lodash, but with first-class types. If you have an idea for a utility that might make a good addition to this collection, -please open an issue and suggest its inclusion. Runs in Deno, Node.js, and the Browser. Get it from -or . and — assuming a",259 -WebbWeaver,32418972,10,1660168838,All children under 10 in London to be offered polio vaccine after virus detected,https://metro.co.uk/2022/08/10/polio-all-children-under-10-in-london-to-be-offered-jab-17159536/,"NEWS... BUT NOT AS YOU KNOW IT Every child aged one to nine in London will be offered a polio vaccine after the virus was repeatedly detected in sewage during routine inspections. Health officials warned there has been ‘some transmission’ of the virus in the capital. The , but was officially eradicated in the UK in 2003. Now health workers are getting set to launch a rapid vaccination programme among youngsters in the city, amid concerns about low levels of uptake of the vaccine. It means almost a million youngsters will be offered the treatment. Those who are not yet fully vaccinated will be offered a catch-up dose, while those who have already been fully inoculated will be offered a booster. Vaccination rates in London are well below recommended levels and there is a risk that ‘under-v",Hacker News,31574040,"Title: All children under 10 in London to be offered polio vaccine after virus detected; Content: NEWS... BUT NOT AS YOU KNOW IT Every child aged one to nine in London will be offered a polio vaccine after the virus was repeatedly detected in sewage during routine inspections. Health officials warned there has been ‘some transmission’ of the virus in the capital. The , but was officially eradicated in the UK in 2003. Now health workers are getting set to launch a rapid vaccination programme among youngsters in the city, amid concerns about low levels of uptake of the vaccine. It means almost a million youngsters will be offered the treatment. Those who are not yet fully vaccinated will be offered a catch-up dose, while those who have already been fully inoculated will be offered a booster. Vaccination rates in London are well below recommended levels and there is a risk that ‘under-v",180 -sottol,32407298,24,1660098926,Robert Shiller predicted the 2008 housing bubble. Here’s his 2022 call,https://fortune.com/2022/08/09/housing-bubble-2022-call-robert-shiller-housing-market/,"Robert Shiller released a book in 2000 titled  , which proclaimed the stock market was a bubble. Soon afterward, the tech bubble burst. Then in 2004, the Yale economics professor called attention to spiking real estate prices with a paper titled  By 2007, Shiller predicted its bust was inevitable. Soon afterward, of course, the 2008 housing bubble burst. As the —which has pushed up —fizzles out, it raises the question: Does Shiller think we’re in another housing bubble? On Sunday, . He told the outlet that he once again thinks the U.S. housing market is headed for trouble. “Home prices haven’t fallen since the 2007–09 recession. Right now things look almost as bad,” Shiller said. “Existing home sales are down. Permits are down. A lot of signs that we’ll see something. It may not be ca",Hacker News,80928838,"Title: Robert Shiller predicted the 2008 housing bubble. Here’s his 2022 call; Content: Robert Shiller released a book in 2000 titled  , which proclaimed the stock market was a bubble. Soon afterward, the tech bubble burst. Then in 2004, the Yale economics professor called attention to spiking real estate prices with a paper titled  By 2007, Shiller predicted its bust was inevitable. Soon afterward, of course, the 2008 housing bubble burst. As the —which has pushed up —fizzles out, it raises the question: Does Shiller think we’re in another housing bubble? On Sunday, . He told the outlet that he once again thinks the U.S. housing market is headed for trouble. “Home prices haven’t fallen since the 2007–09 recession. Right now things look almost as bad,” Shiller said. “Existing home sales are down. Permits are down. A lot of signs that we’ll see something. It may not be ca",215 -aarondf,32398789,13,1660056582,Breaking Apart the maintainer Monolith (By Swyx),https://github.com/readme/guides/maintainer-monolith," - Artwork: - - The open source movement should really be modeled after social clubs and city governments. - - - amplifies the voices of the open source community: the maintainers, developers, and teams whose contributions move the world forward every day. Why must maintainers be “full stack”? In software engineering, it is completely normal to specialize, whether working on product, platform, infrastructure, creative coding, or data science.  But when it comes to open source, we expect maintainers to be consummate generalists: documentation, community, design, marketing, project management, support... oh, and code. And we expect them to deliver this full-stack maintainership for life. For independent open source to be sustainable and accessible to all, we must ex",Hacker News,25843766,"Title: Breaking Apart the maintainer Monolith (By Swyx); Content: - Artwork: - - The open source movement should really be modeled after social clubs and city governments. - - - amplifies the voices of the open source community: the maintainers, developers, and teams whose contributions move the world forward every day. Why must maintainers be “full stack”? In software engineering, it is completely normal to specialize, whether working on product, platform, infrastructure, creative coding, or data science.  But when it comes to open source, we expect maintainers to be consummate generalists: documentation, community, design, marketing, project management, support... oh, and code. And we expect them to deliver this full-stack maintainership for life. For independent open source to be sustainable and accessible to all, we must ex",207 -Kaibeezy,32375756,50,1659872915,The day the music died? Denmark Street’s new ‘digitally enabled streetscape’,https://www.theguardian.com/artanddesign/2022/aug/07/outernet-london-now-building-review-denmark-street-tottenham-court-road-redevelopment-soho,"The pleasingly ramshackle area of central London where punk was born and you went to buy a banjo now includes a multi-billion ‘super-flexible brand engagement platform’. So is it as awful as it sounds? An almost endless roll call of greats made music there: , the Rolling Stones, Jimi Hendrix, Elton John, George Michael, the Libertines, Adele, Ed Sheeran. The young David Bowie, desperate to be in the street where it happened, camped there in a converted ambulance. The Sex Pistols launched their career from a Denmark Street flat. Just across Charing Cross Road, in Soho proper, was the London Astoria, a venue big enough for 2,000 people. Many hundreds of millions of pounds’ worth of construction later, there is still a street of musical instrument shops, plus new venues and production facili",Hacker News,64515825,"Title: The day the music died? Denmark Street’s new ‘digitally enabled streetscape’; Content: The pleasingly ramshackle area of central London where punk was born and you went to buy a banjo now includes a multi-billion ‘super-flexible brand engagement platform’. So is it as awful as it sounds? An almost endless roll call of greats made music there: , the Rolling Stones, Jimi Hendrix, Elton John, George Michael, the Libertines, Adele, Ed Sheeran. The young David Bowie, desperate to be in the street where it happened, camped there in a converted ambulance. The Sex Pistols launched their career from a Denmark Street flat. Just across Charing Cross Road, in Soho proper, was the London Astoria, a venue big enough for 2,000 people. Many hundreds of millions of pounds’ worth of construction later, there is still a street of musical instrument shops, plus new venues and production facili",212 -Hooke,32375970,94,1659875433,The ejector seats that fire through the floor,https://www.bbc.com/future/article/20220802-why-some-aircraft-had-downward-firing-ejector-seats,"What is BBC Future? Future Planet Inner Space Follow the Food Health Gap Family Tree Best of BBC Future Food Fictions Towards Net Zero Latest More On 1 May 1957, Lockheed test pilot Jack ""Suitcase"" Simpson took off from an air base in Palmdale, California, on what was supposed to be a routine test flight of a new jet fighter. It wasn't long before the flight took a turn for the worse. Simpson was testing a prototype of the , the first US jet fighter capable of flying at more than twice the speed of sound. It was at the furthest limits of aircraft design at the time. After flying to 30,000ft, a malfunction with the ailerons (the hinged back sections of the wing which help a plane turn) caused Simpson's Starfighter to pitch straight down and tumble wildly, high above the ground. Simpson kne",Hacker News,22899210,"Title: The ejector seats that fire through the floor; Content: What is BBC Future? Future Planet Inner Space Follow the Food Health Gap Family Tree Best of BBC Future Food Fictions Towards Net Zero Latest More On 1 May 1957, Lockheed test pilot Jack ""Suitcase"" Simpson took off from an air base in Palmdale, California, on what was supposed to be a routine test flight of a new jet fighter. It wasn't long before the flight took a turn for the worse. Simpson was testing a prototype of the , the first US jet fighter capable of flying at more than twice the speed of sound. It was at the furthest limits of aircraft design at the time. After flying to 30,000ft, a malfunction with the ailerons (the hinged back sections of the wing which help a plane turn) caused Simpson's Starfighter to pitch straight down and tumble wildly, high above the ground. Simpson kne",190 -tim--,32383227,94,1659944865,Coqui TTS: a deep learning toolkit for Text-to-Speech,https://github.com/coqui-ai/TTS," - - a deep learning toolkit for Text-to-Speech, battle-tested in research and production - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. TTS is a library for advanced Text-to-Speech generation. It's built on the latest research, was designed to achieve the best trade-off among ease-of-training, speed and quality. - TTS comes with pretrained models, tools for measuring dataset quality and already used in for products and research projects. - - - - - - - - - - - - - - and Plea",Hacker News,47043214,"Title: Coqui TTS: a deep learning toolkit for Text-to-Speech; Content: - - a deep learning toolkit for Text-to-Speech, battle-tested in research and production - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. TTS is a library for advanced Text-to-Speech generation. It's built on the latest research, was designed to achieve the best trade-off among ease-of-training, speed and quality. - TTS comes with pretrained models, tools for measuring dataset quality and already used in for products and research projects. - - - - - - - - - - - - - - and Plea",290 -harel,32378085,123,1659893427,Cellular recovery after prolonged warm ischaemia of the whole body,https://www.nature.com/articles/s41586-022-05016-1,"Thank you for visiting nature.com. You are using a browser version with limited support for CSS. To obtain - the best experience, we recommend you use a more up to date browser (or turn off compatibility mode in - Internet Explorer). In the meantime, to ensure continued support, we are displaying the site without styles - and JavaScript. Advertisement - - ,  405–412 ( ) - 21k 1 1669 After cessation of blood flow or similar ischaemic exposures, deleterious molecular cascades commence in mammalian cells, eventually leading to their death . Yet with targeted interventions, these processes can be mitigated or reversed, even minutes or hours post mortem, as also reported in the isolated porcine brain using BrainEx technology . To date, translating single-organ i",Hacker News,13885096,"Title: Cellular recovery after prolonged warm ischaemia of the whole body; Content: Thank you for visiting nature.com. You are using a browser version with limited support for CSS. To obtain - the best experience, we recommend you use a more up to date browser (or turn off compatibility mode in - Internet Explorer). In the meantime, to ensure continued support, we are displaying the site without styles - and JavaScript. Advertisement - - ,  405–412 ( ) - 21k 1 1669 After cessation of blood flow or similar ischaemic exposures, deleterious molecular cascades commence in mammalian cells, eventually leading to their death . Yet with targeted interventions, these processes can be mitigated or reversed, even minutes or hours post mortem, as also reported in the isolated porcine brain using BrainEx technology . To date, translating single-organ i",214 -zdw,32376464,135,1659880301,Commit comments no longer appear in the pull request timeline,https://github.blog/changelog/2022-08-04-commit-comments-no-longer-appear-in-the-pull-request-timeline/,"Code review on GitHub has evolved a lot since we in 2008. Users today can propose a change using a pull request, which provides a first-class experience for reviewing, discussing, evolving, and ultimately accepting or rejecting a change. While pull requests are the recommended way to review and discuss proposed changes, commenting on individual commits is still currently supported. We recently rolled out a change to no longer show comments added to individual commits (comments added outside the context of a pull request) on the pull request timeline. Previously, if a pull request happened to include a commit that had commit comments, those comments would appear on that pull request’s timeline. Users often reported that these comments were irrelevant to the pull request or caused confusio",Hacker News,27200036,"Title: Commit comments no longer appear in the pull request timeline; Content: Code review on GitHub has evolved a lot since we in 2008. Users today can propose a change using a pull request, which provides a first-class experience for reviewing, discussing, evolving, and ultimately accepting or rejecting a change. While pull requests are the recommended way to review and discuss proposed changes, commenting on individual commits is still currently supported. We recently rolled out a change to no longer show comments added to individual commits (comments added outside the context of a pull request) on the pull request timeline. Previously, if a pull request happened to include a commit that had commit comments, those comments would appear on that pull request’s timeline. Users often reported that these comments were irrelevant to the pull request or caused confusio",164 -sebastianconcpt,32414165,9,1660147083,"Intel iAPX 432, a CPU with hardware Garbage Collector support",https://en.wikipedia.org/wiki/Intel_iAPX_432,"The ( ) is a discontinued introduced in 1981. It was 's first design. The main processor of the architecture, the , is implemented as a set of two separate integrated circuits, due to technical limitations at the time. Although some early 8086, 80186 and 80286-based systems and manuals also used the prefix for marketing reasons, the iAPX 432 and the 8086 processor lines are completely separate designs with completely different instruction sets. - The project started in 1975 as the (after the and the ) and was intended to be Intel's major design for the 1980s. Unlike the , which was designed the following year as a successor to the 8080, the iAPX 432 was a radical departure from Intel's previous designs meant for a different market niche, and completely unrelated to the 80",Hacker News,57933459,"Title: Intel iAPX 432, a CPU with hardware Garbage Collector support; Content: The ( ) is a discontinued introduced in 1981. It was 's first design. The main processor of the architecture, the , is implemented as a set of two separate integrated circuits, due to technical limitations at the time. Although some early 8086, 80186 and 80286-based systems and manuals also used the prefix for marketing reasons, the iAPX 432 and the 8086 processor lines are completely separate designs with completely different instruction sets. - The project started in 1975 as the (after the and the ) and was intended to be Intel's major design for the 1980s. Unlike the , which was designed the following year as a successor to the 8080, the iAPX 432 was a radical departure from Intel's previous designs meant for a different market niche, and completely unrelated to the 80",201 -als0,32409955,11,1660128213,How I wish I could organize my thoughts,https://drewdevault.com/2022/08/10/Organizing-my-thoughts.html,"I keep a pen & notebook on my desk, which I make liberal use of to jot down my -thoughts. It works pretty well: ad-hoc todo lists, notes on problems I’m working -on, tables, flowcharts, etc. It has some limitations, though. Sharing anything -out of my notebook online is an awful pain in the ass. I can’t draw a straight -line to save my life, so tables and flowcharts are a challenge. No edits, -either, so lots of crossed-out words and redrawn or rewritten pages. And of -course, my handwriting sucks and I can type much more efficiently than I can -write. I wish this was a digital medium, but there are not any applications -available which can support the note-taking paradigm that I wish I could have. -What would that look like? Well, like this (click for full size): I don’t have the bandwidth to take",Hacker News,22099622,"Title: How I wish I could organize my thoughts; Content: I keep a pen & notebook on my desk, which I make liberal use of to jot down my -thoughts. It works pretty well: ad-hoc todo lists, notes on problems I’m working -on, tables, flowcharts, etc. It has some limitations, though. Sharing anything -out of my notebook online is an awful pain in the ass. I can’t draw a straight -line to save my life, so tables and flowcharts are a challenge. No edits, -either, so lots of crossed-out words and redrawn or rewritten pages. And of -course, my handwriting sucks and I can type much more efficiently than I can -write. I wish this was a digital medium, but there are not any applications -available which can support the note-taking paradigm that I wish I could have. -What would that look like? Well, like this (click for full size): I don’t have the bandwidth to take",217 -rntn,32376059,34,1659876307,New Pompeii finds highlight middle-class life in doomed city,https://phys.org/news/2022-08-pompeii-highlight-middle-class-life-doomed.html,"Your browser sent an invalid request. - We highly recommend setting a meaningful User-Agent header. -",Hacker News,80525924,"Title: New Pompeii finds highlight middle-class life in doomed city; Content: Your browser sent an invalid request. - We highly recommend setting a meaningful User-Agent header. -",39 -beefman,32406435,19,1660090953,Chinese molten-salt reactor cleared for start up,https://world-nuclear-news.org/Articles/Chinese-molten-salt-reactor-cleared-for-start-up,"We use cookies to provide the best experience for you. To find out more check our cookies and privacy policy 09 August 2022 In January 2011, CAS launched a CNY3 billion (USD444 million) R&D programme on liquid fluoride thorium reactors (LFTRs), known there as the thorium-breeding molten-salt reactor (Th-MSR or TMSR), and claimed to have the world's largest national effort on it, hoping to obtain full intellectual property rights on the technology. This is also known as the fluoride salt-cooled high-temperature reactor (FHR). The TMSR Centre at SINAP at Jiading, Shanghai, is responsible. Construction of the 2 MWt TMSR-LF1 reactor began in September 2018 and was reportedly completed in August 2021. The prototype was scheduled to be completed in 2024, but work was accelerated. ""According to t",Hacker News,80351568,"Title: Chinese molten-salt reactor cleared for start up; Content: We use cookies to provide the best experience for you. To find out more check our cookies and privacy policy 09 August 2022 In January 2011, CAS launched a CNY3 billion (USD444 million) R&D programme on liquid fluoride thorium reactors (LFTRs), known there as the thorium-breeding molten-salt reactor (Th-MSR or TMSR), and claimed to have the world's largest national effort on it, hoping to obtain full intellectual property rights on the technology. This is also known as the fluoride salt-cooled high-temperature reactor (FHR). The TMSR Centre at SINAP at Jiading, Shanghai, is responsible. Construction of the 2 MWt TMSR-LF1 reactor began in September 2018 and was reportedly completed in August 2021. The prototype was scheduled to be completed in 2024, but work was accelerated. ""According to t",201 -trocado,32375955,170,1659875323,Learning algebra in my 60s,https://www.theguardian.com/books/2022/aug/07/could-learning-algebra-in-my-60s-make-me-smarter-alec-wilkinson-a-divine-language-extract,"New Yorker writer Alec Wilkinson struggled with maths at school, finding inspiration in literature instead. But aged 65, in the hope of unlocking a new part of his brain, he decided to put the limits of his intelligence to the test When I read , I felt a kinship with , who described math class as “sheer terror and torture”, since he was “ ”, which means something like nonmathematical. I am by nature a self-improver. I have read Gibbon, I have read Proust. I read the Old and New Testaments and most of Shakespeare. I studied French. I have meditated. I jogged. I learned to draw, using the right side of my brain. A few years ago I decided to see if I could learn simple math, adolescent math, what in the 18th century was called pure mathematics: algebra, geometry and calculus. I didn’t under",Hacker News,8185399,"Title: Learning algebra in my 60s; Content: New Yorker writer Alec Wilkinson struggled with maths at school, finding inspiration in literature instead. But aged 65, in the hope of unlocking a new part of his brain, he decided to put the limits of his intelligence to the test When I read , I felt a kinship with , who described math class as “sheer terror and torture”, since he was “ ”, which means something like nonmathematical. I am by nature a self-improver. I have read Gibbon, I have read Proust. I read the Old and New Testaments and most of Shakespeare. I studied French. I have meditated. I jogged. I learned to draw, using the right side of my brain. A few years ago I decided to see if I could learn simple math, adolescent math, what in the 18th century was called pure mathematics: algebra, geometry and calculus. I didn’t under",204 -georgia_peach,32374317,135,1659853159,Ivy – An interpreter for an APL-like language,https://pkg.go.dev/robpike.io/ivy,"This package is not in the latest version of its module. - The Go module system was introduced in Go 1.11 and is the official dependency management - solution for Go. - - Redistributable licenses place minimal restrictions on how software can be used, - modified, and redistributed. - Modules with tagged versions give importers more predictable builds. When a project reaches major version v1 it is considered stable. Ivy is an interpreter for an APL-like language. It is a plaything and a work in -progress. Ivy has a custom domain. Do not install using github directly. Instead, run: Documentation at . Try the demo: within ivy, type Prototype apps for iPhone, iPad, and Android are available in the App store and Google Play store. -To find them, se",Hacker News,43375055,"Title: Ivy – An interpreter for an APL-like language; Content: This package is not in the latest version of its module. - The Go module system was introduced in Go 1.11 and is the official dependency management - solution for Go. - - Redistributable licenses place minimal restrictions on how software can be used, - modified, and redistributed. - Modules with tagged versions give importers more predictable builds. When a project reaches major version v1 it is considered stable. Ivy is an interpreter for an APL-like language. It is a plaything and a work in -progress. Ivy has a custom domain. Do not install using github directly. Instead, run: Documentation at . Try the demo: within ivy, type Prototype apps for iPhone, iPad, and Android are available in the App store and Google Play store. -To find them, se",234 -benbreen,32374390,29,1659854247,"Kikkuli, 1345 BCE: Training the Chariot Horse",https://web.archive.org/web/20121102233704/http://imh.org/history-of-the-horse/legacy-of-the-horse/harnessing-the-horse/kikkuli-1345.html," - Approximately 1345 BCE, Kikkuli, horse-master to the Hittite king Suppililiuma, developed the first recorded plan for training and caring for horses. Many of Kikkuli's training methods are still considered sound and, in their time, they allowed the Hittites to become a mighty power rivaling Egypt. Suppililiuma yearned for Hittite supremacy, leading to his acquisition of a large number of horses and the services of a leading Mitannian horse-master, Kikkuli. Kikkuli's training program produced superb horses for the Hittites. His methods were preserved on four clay, cuneiform tablets known as The Kikkuli Text. Kikkuli used “interval” training, and stressed the leading of horses (from chariots) at a trot, canter and gallop, before subjecting them to the weight bearing stress of a rider or dr",Hacker News,29773761,"Title: Kikkuli, 1345 BCE: Training the Chariot Horse; Content: - Approximately 1345 BCE, Kikkuli, horse-master to the Hittite king Suppililiuma, developed the first recorded plan for training and caring for horses. Many of Kikkuli's training methods are still considered sound and, in their time, they allowed the Hittites to become a mighty power rivaling Egypt. Suppililiuma yearned for Hittite supremacy, leading to his acquisition of a large number of horses and the services of a leading Mitannian horse-master, Kikkuli. Kikkuli's training program produced superb horses for the Hittites. His methods were preserved on four clay, cuneiform tablets known as The Kikkuli Text. Kikkuli used “interval” training, and stressed the leading of horses (from chariots) at a trot, canter and gallop, before subjecting them to the weight bearing stress of a rider or dr",213 -thereare5lights,32401849,38,1660069621,'Forever chemicals' in rainwater exceed safe levels,https://www.bbc.com/news/science-environment-62391069,"These synthetic substances called PFAS are used in non-stick pans, fire-fighting foam and water-repellent clothes. Dubbed 'forever chemicals', they persist for years in the environment. Such is their prevalence now that scientists say there is no safe space on Earth to avoid them. The researchers from Stockholm University say it is ""vitally important"" that the use of these substances is rapidly restricted. Scientists fear PFAS may pose health risks including cancer, though research has so far been inconclusive. They have been growing increasingly concerned about the proliferation of PFAS in recent years. PFAS stands for poly- and perfluoroalkyl substances. There are around 4,500 of these fluorine-based compounds and they are found in almost every dwelling on Earth in hundreds of everyd",Hacker News,488805,"Title: 'Forever chemicals' in rainwater exceed safe levels; Content: These synthetic substances called PFAS are used in non-stick pans, fire-fighting foam and water-repellent clothes. Dubbed 'forever chemicals', they persist for years in the environment. Such is their prevalence now that scientists say there is no safe space on Earth to avoid them. The researchers from Stockholm University say it is ""vitally important"" that the use of these substances is rapidly restricted. Scientists fear PFAS may pose health risks including cancer, though research has so far been inconclusive. They have been growing increasingly concerned about the proliferation of PFAS in recent years. PFAS stands for poly- and perfluoroalkyl substances. There are around 4,500 of these fluorine-based compounds and they are found in almost every dwelling on Earth in hundreds of everyd",182 -rayascott,32375448,47,1659869058,The Apollo On-Board Computers,https://web.archive.org/web/20120827000829/http://history.nasa.gov/afj/compessay.htm," - -[For those who wish to read more about the application of computers to spaceflight, the NASA History site has by James E. Tomayko.] - -[We would like to thank Phill for contributing this essay to the Apollo Flight Journal.] - - - - - - - -One of the most important systems of the Apollo spacecraft is the Guidance and Navigation System (G&N), which played a leading role in landing the first men-on-the-moon at precise locations and helped in the three very successful ferry flights to the Skylab space station. The system will also be used in the July 1975 joint international mission of the Apollo-Soyuz Test Project (ASTP) between the United States and the Soviet Union. - -The G&N system is semi-automatic, directed and operated by the three-man crew. It performs the basic functions of inertial",Hacker News,66339584,"Title: The Apollo On-Board Computers; Content: - -[For those who wish to read more about the application of computers to spaceflight, the NASA History site has by James E. Tomayko.] - -[We would like to thank Phill for contributing this essay to the Apollo Flight Journal.] - - - - - - - -One of the most important systems of the Apollo spacecraft is the Guidance and Navigation System (G&N), which played a leading role in landing the first men-on-the-moon at precise locations and helped in the three very successful ferry flights to the Skylab space station. The system will also be used in the July 1975 joint international mission of the Apollo-Soyuz Test Project (ASTP) between the United States and the Soviet Union. - -The G&N system is semi-automatic, directed and operated by the three-man crew. It performs the basic functions of inertial",205 -manchoz,32383265,81,1659945334,Learn Effective C++ for Embedded Code,https://luckyresistor.me/knowledge/learn-cpp/,,Hacker News,78521714,Title: Learn Effective C++ for Embedded Code; Content: ,14 -silent1mezzo,32377129,47,1659885410,"So, you want to become an Engineering Manager?",https://mckerlie.com/posts/you-want-to-be-an-engineering-manager/,"Most developers at one point or another in their careers have thought about switching to management. Maybe your boss left suddenly and you were the most senior engineer on the team. Maybe you’ve spent a number of years in your current role and are wanting a new challenge. Or, if you’re lucky, your mentor brought up some traits they thought would make you a really good manager. Whatever the reason, you’re here now, trying to figure out whether this is the right move for you. Transitioning to any role is incredibly difficult. You have new responsibilities, new expectations, different ways of getting results and so on. Moving from an individual contributor (IC) role to that of a manager is even more difficult because you’re actually changing careers. One of the first shifts you’ll notice is t",Hacker News,90956115,"Title: So, you want to become an Engineering Manager?; Content: Most developers at one point or another in their careers have thought about switching to management. Maybe your boss left suddenly and you were the most senior engineer on the team. Maybe you’ve spent a number of years in your current role and are wanting a new challenge. Or, if you’re lucky, your mentor brought up some traits they thought would make you a really good manager. Whatever the reason, you’re here now, trying to figure out whether this is the right move for you. Transitioning to any role is incredibly difficult. You have new responsibilities, new expectations, different ways of getting results and so on. Moving from an individual contributor (IC) role to that of a manager is even more difficult because you’re actually changing careers. One of the first shifts you’ll notice is t",183 -beatthatflight,32419528,6,1660172517,World Excel Championship,https://www.youtube.com/watch?v=x1RVNGDSdw4,,Hacker News,75537268,Title: World Excel Championship; Content: ,9 -mrich,32405631,6,1660085608,Webb telescope reveals unpredicted bounty of bright galaxies in early universe,https://www.science.org/content/article/webb-telescope-reveals-unpredicted-bounty-bright-galaxies-early-universe,"The James Webb Space Telescope has only been watching the sky for a few weeks, and it has already delivered a startling finding: tens, hundreds, maybe even 1000 times more bright galaxies in the early universe than astronomers anticipated. “No one was expecting anything like this,” says Michael Boylan-Kolchin of the University of Texas, Austin. “Galaxies are exploding out of the woodwork,” says Rachel Somerville of the Flatiron Institute. Galaxy formation models may now need a revision, as current ones hold that gas clouds should be far slower to coalesce into stars and galaxies than is suggested by Webb’s galaxy-rich images of the early universe, less than 500 million years after the big bang. “This is way outside the box of what models were predicting,” says Garth Illingworth of the Univ",Hacker News,61753930,"Title: Webb telescope reveals unpredicted bounty of bright galaxies in early universe; Content: The James Webb Space Telescope has only been watching the sky for a few weeks, and it has already delivered a startling finding: tens, hundreds, maybe even 1000 times more bright galaxies in the early universe than astronomers anticipated. “No one was expecting anything like this,” says Michael Boylan-Kolchin of the University of Texas, Austin. “Galaxies are exploding out of the woodwork,” says Rachel Somerville of the Flatiron Institute. Galaxy formation models may now need a revision, as current ones hold that gas clouds should be far slower to coalesce into stars and galaxies than is suggested by Webb’s galaxy-rich images of the early universe, less than 500 million years after the big bang. “This is way outside the box of what models were predicting,” says Garth Illingworth of the Univ",193 -dnetesn,32375842,36,1659874094,How we perceive nature through our sense of smell,https://worldsensorium.com/how-we-perceive-nature-through-our-sense-of-smell/,"This article offers a glance into the olfactory world of nature, in which we first discuss nature and its odors, then describe the scents that these odors produce. The difference between odors and smells is that odors are molecules in the air and smells are the mental representations of these odors in our minds. That there is an (often ignored) distinction between these two concepts can be a little confusing, because in color perception, we use the same word for both concepts. The term “color” refers to both the physical pigments in the environment and how they appear to us mentally. In comparison, the olfactory world is much more complex. Most odors are generated by living things: plants, animals, and microorganisms. Some nonliving things also produce odors. Ozone and formaldehyde are for",Hacker News,42290637,"Title: How we perceive nature through our sense of smell; Content: This article offers a glance into the olfactory world of nature, in which we first discuss nature and its odors, then describe the scents that these odors produce. The difference between odors and smells is that odors are molecules in the air and smells are the mental representations of these odors in our minds. That there is an (often ignored) distinction between these two concepts can be a little confusing, because in color perception, we use the same word for both concepts. The term “color” refers to both the physical pigments in the environment and how they appear to us mentally. In comparison, the olfactory world is much more complex. Most odors are generated by living things: plants, animals, and microorganisms. Some nonliving things also produce odors. Ozone and formaldehyde are for",185 -marron,32391081,168,1659993192,Some Epson printers are programmed to stop working after a certain amount of use,https://gizmodo.com/epson-printer-end-of-service-life-error-not-working-dea-1849384045,"Advertisement Printers remain one of the most frustrating pieces of consumer electronics, but it turns out a thirst for pricey ink and occasionally chewing up and choking on paper aren’t the biggest challenges of using an Epson printer. As , the hardware might be , if used too frequently. The phrase ‘planned obsolescence’ gets thrown around a lot with consumer electronics, as a practice where a product is specifically designed and built with a limited lifespan so that it needs to be upgraded or replaced in just a few years’ time. Most companies deny using this approach, or will cite very specific but questionable reasons as to why it’s necessary, as , a writer and lecturer at the University of New Haven in Connecticut, recently discovered. to share a frustrating experience with their ",Hacker News,12605051,"Title: Some Epson printers are programmed to stop working after a certain amount of use; Content: Advertisement Printers remain one of the most frustrating pieces of consumer electronics, but it turns out a thirst for pricey ink and occasionally chewing up and choking on paper aren’t the biggest challenges of using an Epson printer. As , the hardware might be , if used too frequently. The phrase ‘planned obsolescence’ gets thrown around a lot with consumer electronics, as a practice where a product is specifically designed and built with a limited lifespan so that it needs to be upgraded or replaced in just a few years’ time. Most companies deny using this approach, or will cite very specific but questionable reasons as to why it’s necessary, as , a writer and lecturer at the University of New Haven in Connecticut, recently discovered. to share a frustrating experience with their ",184 -mikece,32417531,5,1660161269,Google Fiber announces expansion to five states in the U.S.,https://www.neowin.net/news/google-fiber-announces-expansion-to-five-states-in-the-us/," - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Google Fiber is getting an expansion, The internet service provider stated its plans to expand operations to five states: Idaho, Nevada, Colorado, Nebraska, and Arizona in the U.S. Google Fiber initially operated in 17 U.S. states, but the latest announcement adds five more to the list. The expansion is to happen over the next few years alongside the metro areas under service by Google Fiber currently. Residents in these areas will get access to “fiber-to-the-home” service from the company. Regarding the expansion, Jain stated, ""These states will be the main focus for our growth for the next",Hacker News,68278214,"Title: Google Fiber announces expansion to five states in the U.S.; Content: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Google Fiber is getting an expansion, The internet service provider stated its plans to expand operations to five states: Idaho, Nevada, Colorado, Nebraska, and Arizona in the U.S. Google Fiber initially operated in 17 U.S. states, but the latest announcement adds five more to the list. The expansion is to happen over the next few years alongside the metro areas under service by Google Fiber currently. Residents in these areas will get access to “fiber-to-the-home” service from the company. Regarding the expansion, Jain stated, ""These states will be the main focus for our growth for the next",347 -labrador,32392202,48,1659999789,A content model is not a design system (2021),https://alistapart.com/article/a-content-model-is-not-a-design-system/,"For people who make websites Do you remember when having a great website was enough? Now, people are getting answers from Siri, Google search snippets, and mobile apps, not just our websites. Forward-thinking organizations have adopted an , whose mission is to reach audiences across multiple digital channels and platforms. Northwestern’s Online MS in Information Design and Strategy. Choose from tracks in content strategy, data science and analytics, and learning design. A Book Apart: Brief books for people who make websites. An Event Apart: 3 days of design, code, and content for web & UX designers & devs. But how do you set up a content management system (CMS) to reach your audience now and in the future? I learned the hard way that creating a —a definition of content types, attribute",Hacker News,80373410,"Title: A content model is not a design system (2021); Content: For people who make websites Do you remember when having a great website was enough? Now, people are getting answers from Siri, Google search snippets, and mobile apps, not just our websites. Forward-thinking organizations have adopted an , whose mission is to reach audiences across multiple digital channels and platforms. Northwestern’s Online MS in Information Design and Strategy. Choose from tracks in content strategy, data science and analytics, and learning design. A Book Apart: Brief books for people who make websites. An Event Apart: 3 days of design, code, and content for web & UX designers & devs. But how do you set up a content management system (CMS) to reach your audience now and in the future? I learned the hard way that creating a —a definition of content types, attribute",180 -mellosouls,32376943,140,1659884086,Earbirding – How to Visualize Sounds,http://earbirding.com/blog/specs,An appropriate representation of the requested resource could not be found on this server. This error was generated by Mod_Security.,Hacker News,25684109,Title: Earbirding – How to Visualize Sounds; Content: An appropriate representation of the requested resource could not be found on this server. This error was generated by Mod_Security.,38 -abhiminator,32378309,124,1659895202,Ask HN: What are some of your favorite YouTube channels?,,"Wanted to post a 2022 version of this classic HN question. Figured a Sunday would be a good day for this post.

What are some of the YouTube channels that you enjoy, particularly as an engineer/entrepreneur?",Hacker News,42455682,"Title: Ask HN: What are some of your favorite YouTube channels?; Content: Wanted to post a 2022 version of this classic HN question. Figured a Sunday would be a good day for this post.

What are some of the YouTube channels that you enjoy, particularly as an engineer/entrepreneur?",77 -lsferreira42,32397162,33,1660049898,Ask HN: Better way to create Anki cards?,,"Hello HN, i've been trying to use spaced repetition to help with my studies but creating cards in anki is a pain, do you have a better way to create cards? ( or an anki alternative that makes this easier? )",Hacker News,64695277,"Title: Ask HN: Better way to create Anki cards?; Content: Hello HN, i've been trying to use spaced repetition to help with my studies but creating cards in anki is a pain, do you have a better way to create cards? ( or an anki alternative that makes this easier? )",71 -PaulHoule,32413023,7,1660143274,"Phishers who breached Twilio and fooled Cloudflare could easily get you, too",https://arstechnica.com/information-technology/2022/08/phishers-breach-twilio-and-target-cloudflare-using-workers-home-numbers/,"Front page layout Site theme Sign up or login to join the discussions! - - - - At least two security-sensitive companies—Twilio and Cloudflare—were targeted in a phishing attack by an advanced threat actor who had possession of home phone numbers of not just employees but employees' family members as well. In the case of Twilio, a San Francisco-based provider of two-factor authentication and communication services, the unknown hackers succeeded in phishing the credentials of an undisclosed number of employees and, from there, gained unauthorized access to the company's internal systems, the company . The threat actor then used that access to data in an undisclosed number of customer accounts. Two days after Twilio's disclosure, content delivery network Cloudflare, also headquartered ",Hacker News,87643728,"Title: Phishers who breached Twilio and fooled Cloudflare could easily get you, too; Content: Front page layout Site theme Sign up or login to join the discussions! - - - - At least two security-sensitive companies—Twilio and Cloudflare—were targeted in a phishing attack by an advanced threat actor who had possession of home phone numbers of not just employees but employees' family members as well. In the case of Twilio, a San Francisco-based provider of two-factor authentication and communication services, the unknown hackers succeeded in phishing the credentials of an undisclosed number of employees and, from there, gained unauthorized access to the company's internal systems, the company . The threat actor then used that access to data in an undisclosed number of customer accounts. Two days after Twilio's disclosure, content delivery network Cloudflare, also headquartered ",189 -marginalia_nu,32391424,54,1659994898,A history of storage media (2017),https://codewords.recurse.com/issues/seven/a-history-of-storage-media," - - - - Storage is an essential part of every computer architecture, from the hypothetical paper tape in a Turing machine to the registers and memory unit of the von Neumann architecture. Non-volatile storage media and volatile memory devices have both gone through several technological evolutions over the last century, including some delightfully strange mechanisms. This article is a very selective history, focusing on a handful of the earliest technologies that I find especially interesting: For a more comprehensive resource, the Computer History Museum has , featuring lovely photographs. Storage and memory have a rich history. While CPU architectures are quite diverse, they tend to use the same basic elements – switches, in the form of transistors or vacuum tubes, arranged in differe",Hacker News,22214272,"Title: A history of storage media (2017); Content: - - - - Storage is an essential part of every computer architecture, from the hypothetical paper tape in a Turing machine to the registers and memory unit of the von Neumann architecture. Non-volatile storage media and volatile memory devices have both gone through several technological evolutions over the last century, including some delightfully strange mechanisms. This article is a very selective history, focusing on a handful of the earliest technologies that I find especially interesting: For a more comprehensive resource, the Computer History Museum has , featuring lovely photographs. Storage and memory have a rich history. While CPU architectures are quite diverse, they tend to use the same basic elements – switches, in the form of transistors or vacuum tubes, arranged in differe",165 -fvrghl,32417264,8,1660159908,A Boy Bosses of Silicon Valley Are on Their Way Out,https://www.nytimes.com/2022/08/10/business/silicon-valley-boy-boss.html,Please enable JS and disable any ad blocker,Hacker News,24546686,Title: A Boy Bosses of Silicon Valley Are on Their Way Out; Content: Please enable JS and disable any ad blocker,25 -eastdakota,32399657,17,1660060691,The mechanics of a sophisticated phishing scam and how we stopped it,https://blog.cloudflare.com/2022-07-sms-phishing-attacks/,"Please stand by, while we are checking your browser... Redirecting... Please enable Cookies and reload the page. Completing the CAPTCHA proves you are a human and gives you temporary access to the web property. If you are on a personal connection, like at home, you can run an anti-virus scan on your device to make sure it is not infected with malware. If you are at an office or shared network, you can ask the network administrator to run a scan across the network looking for misconfigured or infected devices. - - - - -",Hacker News,61647512,"Title: The mechanics of a sophisticated phishing scam and how we stopped it; Content: Please stand by, while we are checking your browser... Redirecting... Please enable Cookies and reload the page. Completing the CAPTCHA proves you are a human and gives you temporary access to the web property. If you are on a personal connection, like at home, you can run an anti-virus scan on your device to make sure it is not infected with malware. If you are at an office or shared network, you can ask the network administrator to run a scan across the network looking for misconfigured or infected devices. - - - - -",138 -PikelEmi,32419192,3,1660170309,Perseid meteor shower: All you need to know in 2022,https://earthsky.org/astronomy-essentials/everything-you-need-to-know-perseid-meteor-shower/,"A daily update by email. Science news, great photos, sky alerts. August 13, 2022, at In most years, we’d be advising you to watch the Perseids’ peak on the mornings of August 11, 12 and 13. But … The parent comet responsible for the Perseid meteor shower is a rather large comet called The comet orbits the sun approximately every 133 years. Lewis Swift of Marathon, New York, visually discovered it on July 16, 1862, using an 11-centimeter (3.5-inch refractor lens) telescope. He did not report it immediately, believing that he was observing Comet Schmidt, which was found two weeks prior. Then, three days later, Horace Tuttle picked it up from Harvard Observatory. Scientists calculated that the comet would return in 120 years. That is, that we would see it again in 1982. So, 1982 came and",Hacker News,2330941,"Title: Perseid meteor shower: All you need to know in 2022; Content: A daily update by email. Science news, great photos, sky alerts. August 13, 2022, at In most years, we’d be advising you to watch the Perseids’ peak on the mornings of August 11, 12 and 13. But … The parent comet responsible for the Perseid meteor shower is a rather large comet called The comet orbits the sun approximately every 133 years. Lewis Swift of Marathon, New York, visually discovered it on July 16, 1862, using an 11-centimeter (3.5-inch refractor lens) telescope. He did not report it immediately, believing that he was observing Comet Schmidt, which was found two weeks prior. Then, three days later, Horace Tuttle picked it up from Harvard Observatory. Scientists calculated that the comet would return in 120 years. That is, that we would see it again in 1982. So, 1982 came and",207 -wooosh,32377597,97,1659889063,Computing Adler32 Checksums at 41 GB/s,https://wooo.sh/articles/adler32.html,"Using algebraic manipulation with loop unrolling to create a fast vectorized algorithm to compute adler32 checksums. While looking through the , I noticed that its seemed somewhat complicated, especially given how simple the scalar version of adler32 is. I was curious to see if I could come up with a simpler method, and in doing so, I came up with an algorithm that can be up to 7x faster than fpng's version, and 109x faster than the simple scalar version. If you are unfamiliar with adler32, it is a simple checksumming algorithm used by rsync and zlib (and by extension PNG), designed to optimize for speed over reliability. The 32-bit check value is composed of two unsigned 16 bit counters, modulo 65521 (the highest unsigned 16-bit prime): The final checksum is then created by setting the",Hacker News,452702,"Title: Computing Adler32 Checksums at 41 GB/s; Content: Using algebraic manipulation with loop unrolling to create a fast vectorized algorithm to compute adler32 checksums. While looking through the , I noticed that its seemed somewhat complicated, especially given how simple the scalar version of adler32 is. I was curious to see if I could come up with a simpler method, and in doing so, I came up with an algorithm that can be up to 7x faster than fpng's version, and 109x faster than the simple scalar version. If you are unfamiliar with adler32, it is a simple checksumming algorithm used by rsync and zlib (and by extension PNG), designed to optimize for speed over reliability. The 32-bit check value is composed of two unsigned 16 bit counters, modulo 65521 (the highest unsigned 16-bit prime): The final checksum is then created by setting the",196 -gmays,32404170,6,1660078567,Why Now’s the Perfect Time to Retool Your Hiring Process and Get Creative,https://review.firstround.com/why-nows-the-perfect-time-to-retool-your-hiring-process-and-get-creative,"This year, amidst a turbulent economic climate, it’s possible that your company’s hiring has slowed down, or paused altogether. So it may not feel like the right timing to put the microscope on your hiring and interviewing process. But we’d argue that it’s actually the perfect time — there’s more space to take a step back and get thoughtful about each step in your interview loop, as you’re likely not hiring at a break-neck pace. And as later-stage companies put the freeze on hiring (or even contend with layoffs), early-stage startups with runway can seize the chance to hone their message and stand out to top candidates. Whether your hiring is slowing down or keeping pace, there’s a real opportunity to get intentional in refining your entire hiring process, from job description to offer — ",Hacker News,62719807,"Title: Why Now’s the Perfect Time to Retool Your Hiring Process and Get Creative; Content: This year, amidst a turbulent economic climate, it’s possible that your company’s hiring has slowed down, or paused altogether. So it may not feel like the right timing to put the microscope on your hiring and interviewing process. But we’d argue that it’s actually the perfect time — there’s more space to take a step back and get thoughtful about each step in your interview loop, as you’re likely not hiring at a break-neck pace. And as later-stage companies put the freeze on hiring (or even contend with layoffs), early-stage startups with runway can seize the chance to hone their message and stand out to top candidates. Whether your hiring is slowing down or keeping pace, there’s a real opportunity to get intentional in refining your entire hiring process, from job description to offer — ",199 -ingve,32377735,517,1659890217,“Code” 2nd Edition Now Available,https://www.charlespetzold.com/blog/2022/08/Code-2nd-Edition-Now-Available.html,"August 7, 2022 Roscoe, N.Y. - In a startling disruption of the space-time continuum — and a violation of the basic maxim of publishing that nothing is ever on time — the publication date of the 2nd edition of my book was bumped up by 12 days. That means that the publication date is and the book might be available from your favorite book vendor. (Or perhaps not quite yet.) - - - - Here are a few links, but actually getting the book might take longer than you’d like: - - I don’t even have a copy of the book yet but I think that one may be waiting for me at my New York City apartment. - ",Hacker News,69467723,"Title: “Code” 2nd Edition Now Available; Content: August 7, 2022 Roscoe, N.Y. - In a startling disruption of the space-time continuum — and a violation of the basic maxim of publishing that nothing is ever on time — the publication date of the 2nd edition of my book was bumped up by 12 days. That means that the publication date is and the book might be available from your favorite book vendor. (Or perhaps not quite yet.) - - - - Here are a few links, but actually getting the book might take longer than you’d like: - - I don’t even have a copy of the book yet but I think that one may be waiting for me at my New York City apartment. - ",256 -conanxin,32410391,9,1660132178,The Dramatic Failure of Buckminster Fuller’s “Car of the Future”,https://slate.com/technology/2022/08/the-dymaxion-car-the-true-history-of-buckminster-fullers-failed-automobile.html,"On July 21, 1933, the architectural designer and inventor Buckminster Fuller unveiled the first prototype of his iconic Dymaxion Car. It was a streamlined, futuristic vehicle with three wheels, a periscope, and an ovoid body that reminded observers of a tadpole or a flying fish. Fuller—who became famous years later as the visionary behind the geodesic dome—hoped that it would revolutionize both transportation and urban design, but only three were ever made. Today, it endures in the form of a single surviving car, a small number of replicas, and a handful of evocative images captured in photographs and newsreels. According to Fuller, his astounding car was doomed by a freak accident in Chicago, where its driver was killed in a crash on Lake Shore Drive. A typical account appears in by Rob",Hacker News,9223395,"Title: The Dramatic Failure of Buckminster Fuller’s “Car of the Future”; Content: On July 21, 1933, the architectural designer and inventor Buckminster Fuller unveiled the first prototype of his iconic Dymaxion Car. It was a streamlined, futuristic vehicle with three wheels, a periscope, and an ovoid body that reminded observers of a tadpole or a flying fish. Fuller—who became famous years later as the visionary behind the geodesic dome—hoped that it would revolutionize both transportation and urban design, but only three were ever made. Today, it endures in the form of a single surviving car, a small number of replicas, and a handful of evocative images captured in photographs and newsreels. According to Fuller, his astounding car was doomed by a freak accident in Chicago, where its driver was killed in a crash on Lake Shore Drive. A typical account appears in by Rob",195 -jbegley,32385530,139,1659967539,Axios Sells for $525M,https://www.nytimes.com/2022/08/08/business/media/axios-cox-enterprises.html,Please enable JS and disable any ad blocker,Hacker News,43350613,Title: Axios Sells for $525M; Content: Please enable JS and disable any ad blocker,21 -cloudyporpoise,32403739,13,1660076591,Ask HN: How are platforms like Buffer and Hootsuite allowed to exist?,,"Companies like Meta and LinkedIn have taken a harsh stance against programmatic access, and scraping of their platforms. How is it that these companies like Buffer and Hootsuite can exist when it seems that what they do is directly a violation of the terms of use. For instance if I were to create a program to schedule my social media posts for some point in the future, wouldn't I be at risk for Instagram disabling my account?",Hacker News,57485883,"Title: Ask HN: How are platforms like Buffer and Hootsuite allowed to exist?; Content: Companies like Meta and LinkedIn have taken a harsh stance against programmatic access, and scraping of their platforms. How is it that these companies like Buffer and Hootsuite can exist when it seems that what they do is directly a violation of the terms of use. For instance if I were to create a program to schedule my social media posts for some point in the future, wouldn't I be at risk for Instagram disabling my account?",115 -darrenbuckner,32402844,5,1660073142,"Show HN: Create bespoke, always-on, virtual coworking rooms (called cafes)",https://workfrom.com/browse/j2lw5h,"Looking for a place to focus and be productive with others visitors? Try one of Workfrom's virtual coworking rooms. Open 24 hours a day — no matter what timezone or country you live in, there will always be a coworking room for you to work alongside other professionals. Suggest a new room via All welcome. No mics. Background music available. All welcome. No mics. Background music available. All welcome. No mics. Background music available. All welcome. No mics. Background music available.",Hacker News,93031875,"Title: Show HN: Create bespoke, always-on, virtual coworking rooms (called cafes); Content: Looking for a place to focus and be productive with others visitors? Try one of Workfrom's virtual coworking rooms. Open 24 hours a day — no matter what timezone or country you live in, there will always be a coworking room for you to work alongside other professionals. Suggest a new room via All welcome. No mics. Background music available. All welcome. No mics. Background music available. All welcome. No mics. Background music available. All welcome. No mics. Background music available.",131 -gmays,32406878,22,1660094676,TikTok bombards young men with misogynistic videos,https://www.theguardian.com/technology/2022/aug/06/revealed-how-tiktok-bombards-young-men-with-misogynistic-videos-andrew-tate,"Observer investigation shows how online platform’s algorithm pushed Andrew Tate posts to an imaginary teenager An investigation has revealed how is promoting misogynistic content to young people despite claiming to ban it. Videos of the online personality Andrew Tate, who has been criticised by domestic abuse campaigners for normalising extreme and outdated views about women, are among those pushed by the algorithm to users via the curated For You homepage. We conducted an experiment to get an insight into what young people are being shown on the platform, which allows users to join from the age of 13. To ensure the findings wouldn’t be influenced by our previous search history, we set up a new TikTok account for an imaginary teenager, using a fake name and date of birth. At first, the",Hacker News,79994438,"Title: TikTok bombards young men with misogynistic videos; Content: Observer investigation shows how online platform’s algorithm pushed Andrew Tate posts to an imaginary teenager An investigation has revealed how is promoting misogynistic content to young people despite claiming to ban it. Videos of the online personality Andrew Tate, who has been criticised by domestic abuse campaigners for normalising extreme and outdated views about women, are among those pushed by the algorithm to users via the curated For You homepage. We conducted an experiment to get an insight into what young people are being shown on the platform, which allows users to join from the age of 13. To ensure the findings wouldn’t be influenced by our previous search history, we set up a new TikTok account for an imaginary teenager, using a fake name and date of birth. At first, the",170 -rbanffy,32402657,6,1660072482,"Prefetch Side Channels Undermine Isolation Between User, Kernel on AMD CPUs",https://semiengineering.com/prefetch-side-channels-undermine-the-isolation-between-user-and-kernel-space-on-amd-cpus/,"This new technical paper titled “AMD Prefetch Attacks through Power and Time” is from researchers at Graz University of Technology and CISPA Helmholtz Center for Information Security. Note, this is a paper for the USENIX Security Symposium in Boston in August 2022.   This paper includes countermeasures and mitigation strategies, and the paper indicates that the findings were disclosed in AMD back in 2020 and AMD provided feedback in Feb 2021. “Modern operating systems fundamentally rely on the strict isolation of user applications from the kernel. This isolation is enforced by the hardware. On Intel CPUs, this isolation has been shown to be imperfect, for instance, with the prefetch side-channel. With Meltdown, it was even completely circumvented. Both the prefetch side channel and Meltd",Hacker News,67340178,"Title: Prefetch Side Channels Undermine Isolation Between User, Kernel on AMD CPUs; Content: This new technical paper titled “AMD Prefetch Attacks through Power and Time” is from researchers at Graz University of Technology and CISPA Helmholtz Center for Information Security. Note, this is a paper for the USENIX Security Symposium in Boston in August 2022.   This paper includes countermeasures and mitigation strategies, and the paper indicates that the findings were disclosed in AMD back in 2020 and AMD provided feedback in Feb 2021. “Modern operating systems fundamentally rely on the strict isolation of user applications from the kernel. This isolation is enforced by the hardware. On Intel CPUs, this isolation has been shown to be imperfect, for instance, with the prefetch side-channel. With Meltdown, it was even completely circumvented. Both the prefetch side channel and Meltd",184 -two_almonds,32385170,53,1659965615,The rise of ‘ARPA-everything’ and what it means for science (2021),https://www.nature.com/articles/d41586-021-01878-z,"Thank you for visiting nature.com. You are using a browser version with limited support for CSS. To obtain - the best experience, we recommend you use a more up to date browser (or turn off compatibility mode in - Internet Explorer). In the meantime, to ensure continued support, we are displaying the site without styles - and JavaScript. Advertisement You can also search for this author in You have full access to this article via your institution. US President Joe Biden’s administration wants to create a US$6.5-billion agency to accelerate innovations in health and medicine — and revealed new details about the unit last month . Dubbed ARPA-Health (ARPA-H), it is the latest in a line of global science agencies now being modelled on the renowned US Defense Adva",Hacker News,70852288,"Title: The rise of ‘ARPA-everything’ and what it means for science (2021); Content: Thank you for visiting nature.com. You are using a browser version with limited support for CSS. To obtain - the best experience, we recommend you use a more up to date browser (or turn off compatibility mode in - Internet Explorer). In the meantime, to ensure continued support, we are displaying the site without styles - and JavaScript. Advertisement You can also search for this author in You have full access to this article via your institution. US President Joe Biden’s administration wants to create a US$6.5-billion agency to accelerate innovations in health and medicine — and revealed new details about the unit last month . Dubbed ARPA-Health (ARPA-H), it is the latest in a line of global science agencies now being modelled on the renowned US Defense Adva",219 -marttt,32374428,33,1659854849,Plop Boot Managers,https://www.plop.at/en/bootmanagers.html,"I wrote different boot managers. Three boot managers are available as download. The Plop Boot Manager 5, PlopKexec and -the new boot manager PBM6. The new boot manager is under development. -* SATA drives can be used anyway. -** USB Keyboards can be used until the USB boot option has been selected. Then it will be usable again when Linux or Windows booted. - © 2022 by - - Elmar Hanlhofer   - ",Hacker News,36034996,"Title: Plop Boot Managers; Content: I wrote different boot managers. Three boot managers are available as download. The Plop Boot Manager 5, PlopKexec and -the new boot manager PBM6. The new boot manager is under development. -* SATA drives can be used anyway. -** USB Keyboards can be used until the USB boot option has been selected. Then it will be usable again when Linux or Windows booted. - © 2022 by - - Elmar Hanlhofer   - ",116 -Analemma_,32400852,29,1660065575,"SGX, Intel’s supposedly impregnable data fortress, has been breached yet again",https://arstechnica.com/information-technology/2022/08/architectural-bug-in-some-intel-cpus-is-more-bad-news-for-sgx-users/,"Front page layout Site theme Sign up or login to join the discussions! - - - - Intel’s latest generation of CPUs contains a vulnerability that allows attackers to obtain encryption keys and other confidential information protected by the company’s software guard extensions, the advanced feature that acts as a digital vault for security users’ most sensitive secrets. Abbreviated as SGX, the protection is designed to provide a fortress of sorts for the safekeeping of encryption keys and other sensitive data, even when the operating system or a virtual machine running on top is maliciously compromised. SGX works by creating trusted execution environments that protect sensitive code and the data it works with from monitoring or tampering by anything else on the system. SGX is a cornerston",Hacker News,24194531,"Title: SGX, Intel’s supposedly impregnable data fortress, has been breached yet again; Content: Front page layout Site theme Sign up or login to join the discussions! - - - - Intel’s latest generation of CPUs contains a vulnerability that allows attackers to obtain encryption keys and other confidential information protected by the company’s software guard extensions, the advanced feature that acts as a digital vault for security users’ most sensitive secrets. Abbreviated as SGX, the protection is designed to provide a fortress of sorts for the safekeeping of encryption keys and other sensitive data, even when the operating system or a virtual machine running on top is maliciously compromised. SGX works by creating trusted execution environments that protect sensitive code and the data it works with from monitoring or tampering by anything else on the system. SGX is a cornerston",183 -gilad,32406918,5,1660095028,Organize Python code like a pro,https://guicommits.com/organize-python-code-like-a-pro/,"Software Engineering, and Personal Failures Python is different from languages like C# or Java where they enforce you to have classes named after the file they live in. So far Python is one of the most flexible languages I had contact with and everything too flexible enhances the odds of bad decisions. This is not necessarily bad During this chapter, I'm going to present to you guidelines that worked for me over the past working in different companies and with many different people. Let's focus first on directory structure, file naming, and module organization. I recommend you to keep all your module files inside a dir, and all tests living side by side with it: Where is your main module. If in doubt, consider what people would and how you would like to . Frequently it has the same",Hacker News,52964749,"Title: Organize Python code like a pro; Content: Software Engineering, and Personal Failures Python is different from languages like C# or Java where they enforce you to have classes named after the file they live in. So far Python is one of the most flexible languages I had contact with and everything too flexible enhances the odds of bad decisions. This is not necessarily bad During this chapter, I'm going to present to you guidelines that worked for me over the past working in different companies and with many different people. Let's focus first on directory structure, file naming, and module organization. I recommend you to keep all your module files inside a dir, and all tests living side by side with it: Where is your main module. If in doubt, consider what people would and how you would like to . Frequently it has the same",176 -bouiboui,32391377,16,1659994681,"Show HN: Rewind 4, a Chrome extension for bookmark hoarders",https://chrome.google.com/webstore/detail/rewind/oghafdocdmlkkjipdmnikdcgekjpiapf,,Hacker News,29523076,"Title: Show HN: Rewind 4, a Chrome extension for bookmark hoarders; Content: ",21 -shcheklein,32418526,17,1660165894,SQLite is exploding on Hacker News,https://twitter.com/shcheklein/status/1557466590983032832,"We’ve detected that JavaScript is disabled in this browser. Please enable JavaScript or switch to a supported browser to continue using twitter.com. You can see a list of supported browsers in our Help Center. - - - - - - © 2022 Twitter, Inc. - ",Hacker News,3554477,"Title: SQLite is exploding on Hacker News; Content: We’ve detected that JavaScript is disabled in this browser. Please enable JavaScript or switch to a supported browser to continue using twitter.com. You can see a list of supported browsers in our Help Center. - - - - - - © 2022 Twitter, Inc. - ",82 -daxaxelrod,32392541,56,1660002835,Rejected.us,https://rejected.us/,,Hacker News,69488435,Title: Rejected.us; Content: ,10 -goindeep,32405399,18,1660084353,Ford Raises Prices of F-150 Lightning Electric Truck by Thousands of Dollars,https://www.nytimes.com/2022/08/09/business/ford-f-150-lightning-electric-truck-price.html,Please enable JS and disable any ad blocker,Hacker News,67754341,Title: Ford Raises Prices of F-150 Lightning Electric Truck by Thousands of Dollars; Content: Please enable JS and disable any ad blocker,28 -gautamcgoel,32418299,6,1660164831,Silicon Valley's Push into Transportation Has Been a Miserable Failure,https://gizmodo.com/silicon-valleys-transportation-failures-tesla-waymo-bir-1849382788,"Advertisement When I first started driving, I had to print out directions from MapQuest before embarking on a trip to unfamiliar destination. If I didn’t plan correctly, I’d just have to stop and ask someone for directions. The smartphone and GPS changed everything. Suddenly, everyone had a little navigator in their pocket and getting lost became a thing of the past. Then, well, the tech sector kind of stopped improving transportation. “We were promised flying cars. Instead we got 140 characters,” Peter Thiel famously once said. The irony is that few people were better positioned over the last two decades to make useful, world-changing technology. Instead, Thiel sat on the board at Facebook, expanded the surveillance state at , and shilled . Still, the “we were promised flying cars”",Hacker News,90566426,"Title: Silicon Valley's Push into Transportation Has Been a Miserable Failure; Content: Advertisement When I first started driving, I had to print out directions from MapQuest before embarking on a trip to unfamiliar destination. If I didn’t plan correctly, I’d just have to stop and ask someone for directions. The smartphone and GPS changed everything. Suddenly, everyone had a little navigator in their pocket and getting lost became a thing of the past. Then, well, the tech sector kind of stopped improving transportation. “We were promised flying cars. Instead we got 140 characters,” Peter Thiel famously once said. The irony is that few people were better positioned over the last two decades to make useful, world-changing technology. Instead, Thiel sat on the board at Facebook, expanded the surveillance state at , and shilled . Still, the “we were promised flying cars”",192 -Tomte,32415588,8,1660152422,"Microsoft open-sources over 1,500 of its cute 3D emoji designs for anyone to use",https://arstechnica.com/gadgets/2022/08/microsoft-open-sources-its-cute-3d-emoji-albeit-without-clippy/,"Front page layout Site theme Sign up or login to join the discussions! - - - - As part of its Windows 11 design push, Microsoft also published that added more character and texture than the older Windows 8- and 10-era versions. Today, the company is going one step further, open-sourcing the vast majority of these new ""Fluent"" emoji designs and for anyone to modify and use. Each open sourced emoji has three iterations: the fully 3D version, complete with texture and color gradients; a flat ""color"" version that retains the basic color but removes textures and gradients (these are the ones you'll see if you open Windows 11's emoji menu); and a monochromatic ""high contrast"" version. All emoji are being made available as .svg vector graphics files so that they can be resized and otherw",Hacker News,24701126,"Title: Microsoft open-sources over 1,500 of its cute 3D emoji designs for anyone to use; Content: Front page layout Site theme Sign up or login to join the discussions! - - - - As part of its Windows 11 design push, Microsoft also published that added more character and texture than the older Windows 8- and 10-era versions. Today, the company is going one step further, open-sourcing the vast majority of these new ""Fluent"" emoji designs and for anyone to modify and use. Each open sourced emoji has three iterations: the fully 3D version, complete with texture and color gradients; a flat ""color"" version that retains the basic color but removes textures and gradients (these are the ones you'll see if you open Windows 11's emoji menu); and a monochromatic ""high contrast"" version. All emoji are being made available as .svg vector graphics files so that they can be resized and otherw",210 -thiago_fm,32375394,119,1659868469,Tutors / tips to change your English accent,,"Let's start with that my accent is clear enough and I don't have communication issues at work. I actually feel quite comfortable.

But I'd love to have a perfect west coast American accent when I speak english. Having learned a few other languages myself, it feels pretty good when you can surprise a native.

Anybody that went through that process of improving their accent with a tutor or on their own could share their learnings on it?",Hacker News,16637223,"Title: Tutors / tips to change your English accent; Content: Let's start with that my accent is clear enough and I don't have communication issues at work. I actually feel quite comfortable.

But I'd love to have a perfect west coast American accent when I speak english. Having learned a few other languages myself, it feels pretty good when you can surprise a native.

Anybody that went through that process of improving their accent with a tutor or on their own could share their learnings on it?",121 -dnetesn,32375839,25,1659874052,Brain Fills in the Blanks with Experience,https://nautil.us/how-your-brain-fills-in-the-blanks-with-experience-22692/,,Hacker News,59766544,Title: Brain Fills in the Blanks with Experience; Content: ,15 -marcodiego,32418130,4,1660164094,Microsoft claims Sony pays for ‘blocking rights’ to keep games off Xbox GamePass,https://www.theverge.com/2022/8/10/23300133/microsoft-sony-xbox-game-pass-blocking-rights-accusation,"We use cookies and other tracking technologies to improve your browsing experience on our site, show personalized content and targeted ads, analyze site traffic, and understand where our audiences come from. To learn more or opt-out, read our . Please also read our and , which became effective December 20, 2019. By choosing , you consent to our use of cookies and other tracking technologies. Filed under: An explosive claim from Microsoft Microsoft has claimed Sony pays for “blocking rights” to stop developers from adding their content to Xbox Game Pass. The explosive claims are part of documents ( ) filed with Brazil’s national competition regulator and part of a review of Microsoft’s acquisition of Activision Blizzard. “Microsoft’s ability to continue expanding Game Pass has been ham",Hacker News,38937097,"Title: Microsoft claims Sony pays for ‘blocking rights’ to keep games off Xbox GamePass; Content: We use cookies and other tracking technologies to improve your browsing experience on our site, show personalized content and targeted ads, analyze site traffic, and understand where our audiences come from. To learn more or opt-out, read our . Please also read our and , which became effective December 20, 2019. By choosing , you consent to our use of cookies and other tracking technologies. Filed under: An explosive claim from Microsoft Microsoft has claimed Sony pays for “blocking rights” to stop developers from adding their content to Xbox Game Pass. The explosive claims are part of documents ( ) filed with Brazil’s national competition regulator and part of a review of Microsoft’s acquisition of Activision Blizzard. “Microsoft’s ability to continue expanding Game Pass has been ham",184 -feross,32378869,215,1659898985,Class Action Targets Experian over Account Security,https://krebsonsecurity.com/2022/08/class-action-targets-experian-over-account-security/,"A class action lawsuit has been filed against big-three consumer credit bureau over reports that the company did little to prevent identity thieves from hijacking consumer accounts. The legal filing cites liberally from an investigation KrebsOnSecurity published in July, which found that identity thieves were able to assume control over existing Experian accounts simply by signing up for new accounts using the victim’s personal information and a different email address. The lawsuit, filed July 28, 2022 in California Central District Court, argues that Experian’s documented practice of allowing the re-registration of accounts without first verifying that the existing account authorized the changes is a violation of the Fair Credit Reporting Act. In July’s , we heard from two different re",Hacker News,85041813,"Title: Class Action Targets Experian over Account Security; Content: A class action lawsuit has been filed against big-three consumer credit bureau over reports that the company did little to prevent identity thieves from hijacking consumer accounts. The legal filing cites liberally from an investigation KrebsOnSecurity published in July, which found that identity thieves were able to assume control over existing Experian accounts simply by signing up for new accounts using the victim’s personal information and a different email address. The lawsuit, filed July 28, 2022 in California Central District Court, argues that Experian’s documented practice of allowing the re-registration of accounts without first verifying that the existing account authorized the changes is a violation of the Fair Credit Reporting Act. In July’s , we heard from two different re",165 -VigneshBaskaran,32376170,95,1659877438,The Thousand Brains Theory of Intelligence (2019),https://numenta.com/blog/2019/01/16/the-thousand-brains-theory-of-intelligence/," Jeff Hawkins has a new book titled The book details how The Thousand Brains Theory will impact the future of machine intelligence and what an understanding of the brain says about the threats and opportunities facing humanity. Visit  for more information. In our most recent peer-reviewed paper, , we put forward a novel theory for how the neocortex works. The Thousand Brains Theory of Intelligence proposes that rather than learning one model of an object (or concept), the brain builds many models of each object. Each model is built using different inputs, whether from slightly different parts of the sensor (such as different fingers on your hand) or from different sensors altogether (eyes vs. skin). The models vote together to reach a consensus on what they are sensing, and the consensu",Hacker News,73346208,"Title: The Thousand Brains Theory of Intelligence (2019); Content: Jeff Hawkins has a new book titled The book details how The Thousand Brains Theory will impact the future of machine intelligence and what an understanding of the brain says about the threats and opportunities facing humanity. Visit  for more information. In our most recent peer-reviewed paper, , we put forward a novel theory for how the neocortex works. The Thousand Brains Theory of Intelligence proposes that rather than learning one model of an object (or concept), the brain builds many models of each object. Each model is built using different inputs, whether from slightly different parts of the sensor (such as different fingers on your hand) or from different sensors altogether (eyes vs. skin). The models vote together to reach a consensus on what they are sensing, and the consensu",172 -gmemstr,32400200,5,1660062853,Windows registry file format specification,https://github.com/msuhanov/regf/blob/master/Windows%20registry%20file%20format%20specification.md,"Stable registry hives consist of primary files, transaction log files, and backup copies of primary files. Primary files and their backup copies share the same format to hold actual data making up a Windows registry, transaction log files are used to perform fault-tolerant writes to primary files. Before writing modified (dirty) data to a primary file, a hive writer will store this data in a transaction log file. If an error (like a system crash) occurs when writing to a transaction log file, a primary file will remain consistent; if an error occurs when writing to a primary file, a transaction log file will contain enough data to recover a primary file and bring it back to the consistent state. Transactional registry, introduced in Windows Vista, is a feature that allows a program to accu",Hacker News,87661558,"Title: Windows registry file format specification; Content: Stable registry hives consist of primary files, transaction log files, and backup copies of primary files. Primary files and their backup copies share the same format to hold actual data making up a Windows registry, transaction log files are used to perform fault-tolerant writes to primary files. Before writing modified (dirty) data to a primary file, a hive writer will store this data in a transaction log file. If an error (like a system crash) occurs when writing to a transaction log file, a primary file will remain consistent; if an error occurs when writing to a primary file, a transaction log file will contain enough data to recover a primary file and bring it back to the consistent state. Transactional registry, introduced in Windows Vista, is a feature that allows a program to accu",171 -valzevul,32406258,3,1660089372,"Show HN: Tuesday Triage, weekly crème de la crème of the Internet",https://tuesdaytriage.com/,"For the past two years I curate a newsletter with ~10 posts I've enjoyed reading and ~10 things I didn't know before, as well as a tad of my ranting and a book or two.",Hacker News,33080528,"Title: Show HN: Tuesday Triage, weekly crème de la crème of the Internet; Content: For the past two years I curate a newsletter with ~10 posts I've enjoyed reading and ~10 things I didn't know before, as well as a tad of my ranting and a book or two.",78 -ollifi,32402185,25,1660070842,They Told Their Therapists Everything. Hackers Leaked It All (2021),https://www.wired.com/story/vastaamo-psychotherapy-patients-hack-data-breach/,"To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . This content can also be viewed on the site it from. on the morning of October 24, 2020, expecting what Finnish college students call , an ordinary day. It was a Saturday, and he’d slept in. The night before, he had gone drinking by the beach with some friends. They’d sipped cheap apple liqueur, listened to Billie Eilish on his boom box. Now Jere (pronounced “yeh-reh”) needed to clear his head. He was supposed to spend this gray fall day on campus, finishing a group physics project about solar energy. The 22-year-old took a walk around the lake near his apartment outside Helsinki. Then, fe",Hacker News,82902205,"Title: They Told Their Therapists Everything. Hackers Leaked It All (2021); Content: To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . This content can also be viewed on the site it from. on the morning of October 24, 2020, expecting what Finnish college students call , an ordinary day. It was a Saturday, and he’d slept in. The night before, he had gone drinking by the beach with some friends. They’d sipped cheap apple liqueur, listened to Billie Eilish on his boom box. Now Jere (pronounced “yeh-reh”) needed to clear his head. He was supposed to spend this gray fall day on campus, finishing a group physics project about solar energy. The 22-year-old took a walk around the lake near his apartment outside Helsinki. Then, fe",226 -leephillips,32417934,3,1660163214,Amazon begins large-scale rollout of palm print-based payments,https://arstechnica.com/gadgets/2022/08/amazon-begins-large-scale-rollout-of-palm-print-based-payments/,"Front page layout Site theme Sign up or login to join the discussions! - - - - Amazon will expand its palm print checkout system to dozens of Whole Foods locations, marking the most significant expansion of the technology that was introduced in 2020. Amazon One allows customers to speedily check out at retail locations using only their palm prints after storing a scan of their hand via an interface at Amazon's kiosks. The palm print data is encrypted and stored on Amazon's servers. And before you worry too much about COVID-19 transmission or future pandemics, Amazon One works when you hover your palm over the scanner—unlike some handprint tech. Amazon initially added the technology in its Amazon Go stores and the now-shuttered Amazon Books retail locations. It then made its way to s",Hacker News,61019072,"Title: Amazon begins large-scale rollout of palm print-based payments; Content: Front page layout Site theme Sign up or login to join the discussions! - - - - Amazon will expand its palm print checkout system to dozens of Whole Foods locations, marking the most significant expansion of the technology that was introduced in 2020. Amazon One allows customers to speedily check out at retail locations using only their palm prints after storing a scan of their hand via an interface at Amazon's kiosks. The palm print data is encrypted and stored on Amazon's servers. And before you worry too much about COVID-19 transmission or future pandemics, Amazon One works when you hover your palm over the scanner—unlike some handprint tech. Amazon initially added the technology in its Amazon Go stores and the now-shuttered Amazon Books retail locations. It then made its way to s",186 -pfdietz,32380471,87,1659910605,The Last Naval Battle of World War 2 (2018),https://www.navygeneralboard.com/the-last-naval-battle-of-world-war-2/,An appropriate representation of the requested resource could not be found on this server. This error was generated by Mod_Security.,Hacker News,58172648,Title: The Last Naval Battle of World War 2 (2018); Content: An appropriate representation of the requested resource could not be found on this server. This error was generated by Mod_Security.,39 -mywacaday,32415065,5,1660150429,Nowhere on Earth where rainwater safe to drink – study,https://www.rte.ie/news/newslens/2022/0810/1314927-rainwater-study/,"Rainwater everywhere on the planet is unsafe to drink due to levels of toxic chemicals known as PFAS that exceed the latest guidelines, according to a new study by Stockholm University scientists. Commonly known as 'forever chemicals' because they disintegrate extremely slowly, PFAS (per- and polyfluoroalkyl substances) were initially found in packaging, shampoo or makeup but have spread to the entire environment, including water and air. ""There is nowhere on Earth where the rain would be safe to drink, according to the measurements that we have taken,"" Ian Cousins, a professor at the university and the lead author of the study published in Environmental Science and Technology, said. A compilation of the data since 2010 that his team studied showed that ""even in Antarctica or the Tibetan p",Hacker News,16424868,"Title: Nowhere on Earth where rainwater safe to drink – study; Content: Rainwater everywhere on the planet is unsafe to drink due to levels of toxic chemicals known as PFAS that exceed the latest guidelines, according to a new study by Stockholm University scientists. Commonly known as 'forever chemicals' because they disintegrate extremely slowly, PFAS (per- and polyfluoroalkyl substances) were initially found in packaging, shampoo or makeup but have spread to the entire environment, including water and air. ""There is nowhere on Earth where the rain would be safe to drink, according to the measurements that we have taken,"" Ian Cousins, a professor at the university and the lead author of the study published in Environmental Science and Technology, said. A compilation of the data since 2010 that his team studied showed that ""even in Antarctica or the Tibetan p",173 -rguiscard,32407588,16,1660102153,"World is losing ‘magical’ tradition of human-animal mutualism, study warns",https://news.mongabay.com/2022/06/world-is-losing-magical-tradition-of-human-animal-mutualism-study-warns/,,Hacker News,14697987,"Title: World is losing ‘magical’ tradition of human-animal mutualism, study warns; Content: ",25 -nabla9,32378744,25,1659898322,The Singular Value Decomposition,https://peterbloem.nl/blog/pca-4,"In the previous parts of this series, we learned that principal components are vectors. Specifically, they are the eigenvectors of the covariance matrix $\bc{\S}$ of our data $\X$. In this part, we’ll develop a slightly different perspective: that the principal components are . Not of the covariance matrix $\bc{\S}$, but of the data matrix $\X$ itself. Singular vectors, which we will define below, are closely related to eigenvectors, but unlike eigenvectors they are defined for all matrices, even non-square ones. The two perspectives are complementary: they are simply different ways of looking at the same thing. The benefit we get from the singular vectors is that we can develop the (SVD). The SVD is firstly, the most popular and robust way of computing a principal component analysis. ",Hacker News,74125870,"Title: The Singular Value Decomposition; Content: In the previous parts of this series, we learned that principal components are vectors. Specifically, they are the eigenvectors of the covariance matrix $\bc{\S}$ of our data $\X$. In this part, we’ll develop a slightly different perspective: that the principal components are . Not of the covariance matrix $\bc{\S}$, but of the data matrix $\X$ itself. Singular vectors, which we will define below, are closely related to eigenvectors, but unlike eigenvectors they are defined for all matrices, even non-square ones. The two perspectives are complementary: they are simply different ways of looking at the same thing. The benefit we get from the singular vectors is that we can develop the (SVD). The SVD is firstly, the most popular and robust way of computing a principal component analysis. ",196 -triska,32376984,88,1659884370,Trealla Prolog embedded in Go using WASM,https://github.com/guregu/trealla-go," - Trealla Prolog embedded in Go using WASM - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. Prolog interface for Go using and . -It's pretty fast. Not as fast as native Trealla, but pretty dang fast (2-5x slower than native). : alpha This library uses WebAssembly to run Trealla, executing Prolog queries in an isolated environment. MIT. See ATTRIBUTION as well. - Trealla Prolog embedded in Go using WASM - ",Hacker News,28659871,"Title: Trealla Prolog embedded in Go using WASM; Content: - Trealla Prolog embedded in Go using WASM - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. Prolog interface for Go using and . -It's pretty fast. Not as fast as native Trealla, but pretty dang fast (2-5x slower than native). : alpha This library uses WebAssembly to run Trealla, executing Prolog queries in an isolated environment. MIT. See ATTRIBUTION as well. - Trealla Prolog embedded in Go using WASM - ",262 -Vaslo,32386778,159,1659972938,Amazon’s Roomba deal is about mapping your home,https://www.bloomberg.com/news/articles/2022-08-05/amazon-s-irobot-deal-is-about-roomba-s-data-collection,"To continue, please click the box below to let us know you're not a robot. Please make sure your browser supports JavaScript and cookies and that you are not blocking them from loading. For more information you can review our and . For inquiries related to this message please and provide the reference ID below.",Hacker News,8886099,"Title: Amazon’s Roomba deal is about mapping your home; Content: To continue, please click the box below to let us know you're not a robot. Please make sure your browser supports JavaScript and cookies and that you are not blocking them from loading. For more information you can review our and . For inquiries related to this message please and provide the reference ID below.",83 -barathr,32399347,19,1660059122,Show HN: PGPP (Pretty Good Phone Privacy) – a new type of mobile privacy service,https://play.google.com/store/apps/details?id=com.invisv.pgpp&hl=en_US&gl=US,"Hi, we're Barath and Paul. We co-founded INVISV to build Pretty Good Phone Privacy (PGPP) [https://invisv.com/pgpp], an app and service that provides mobile identifier privacy (IMSI) and Internet privacy (IP) so that neither we nor other providers learn your network identity. We've been thinking about how phones are tracking devices in disguise (at a few layers) and what we can do about it. But the problem is that mobile networks are hard to change, and existing companies are reluctant to change things.

A couple years ago we had the idea that we could decouple your identity from your SIM (IMSI), so the mobile operator wouldn't know who you are but still provides you service. We did research, figured it out, and published it last year at Usenix Security. Then we took it to every mobile operator we could to see if they'd do it, but mostly got shrugs, confusion, or hostility. (We still hold out hope they'll change their minds.) So we decided we had to build and deploy it ourselves. And the mobile network is just the first part -- we also provide decoupled IP privacy (Relay) in PGPP via a partnership with Fastly, for when you're on WiFi or mobile data.

The implementation is simple: for mobile privacy we decouple authentication from connectivity. Those are conflated today. We provide service using eSIMs (so you need an eSIM capable Android for this part). So we don't learn which eSIM your phone gets each time (your IMSI now changes periodically), we authenticate you with a cryptographic protocol (Chaum's blind signatures) that proves you should get a new eSIM but doesn't reveal your identity. Then you get mobile data service. This isn't something that exists today, despite the tracking/data collection that's happened both by third parties (SDRs / IMSI catchers) and operators themselves. It's like MAC randomization for mobile networks.

We figured users would like better IP privacy too, so we used IETF MASQUE and collaborated with Fastly to provide relay service in PGPP as well. Relay service works on almost any Android device. This uses TLS to tunnel your traffic (which itself will usually be TLS encrypted, for almost all Web traffic today) through two hops and then to the rest of the Internet. The first hop is us -- we hide your IP but learn nothing of your traffic or where it's headed. The second hop is Fastly, who then connects you to the IP of the server you're trying to reach, but all they see is an INVISV IP trying to connect to some other IP. The site you're connecting to terminates your TLS stream but just sees it coming from Fastly.

This is a beta and there are several things that aren't ideal. We don't have free plans because providing actual connectivity is pretty expensive. We know that data-only mobile service isn't for everyone (that's what our mobile plans provide -- no phone number). So we offer Relay service on its own for folks who want that. We also know eSIMs are not ideal either, so we'd like to generalize that down the road.

We're focused on privacy, not just on mobile, and we'd love your feedback on the service and ideas about this and where to go next.

Thanks!

Barath and Paul",Hacker News,25561788,"Title: Show HN: PGPP (Pretty Good Phone Privacy) – a new type of mobile privacy service; Content: Hi, we're Barath and Paul. We co-founded INVISV to build Pretty Good Phone Privacy (PGPP) [https://invisv.com/pgpp], an app and service that provides mobile identifier privacy (IMSI) and Internet privacy (IP) so that neither we nor other providers learn your network identity. We've been thinking about how phones are tracking devices in disguise (at a few layers) and what we can do about it. But the problem is that mobile networks are hard to change, and existing companies are reluctant to change things.

A couple years ago we had the idea that we could decouple your identity from your SIM (IMSI), so the mobile operator wouldn't know who you are but still provides you service. We did research, figured it out, and published it last year at Usenix Security. Then we took it to every mobile operator we could to see if they'd do it, but mostly got shrugs, confusion, or hostility. (We still hold out hope they'll change their minds.) So we decided we had to build and deploy it ourselves. And the mobile network is just the first part -- we also provide decoupled IP privacy (Relay) in PGPP via a partnership with Fastly, for when you're on WiFi or mobile data.

The implementation is simple: for mobile privacy we decouple authentication from connectivity. Those are conflated today. We provide service using eSIMs (so you need an eSIM capable Android for this part). So we don't learn which eSIM your phone gets each time (your IMSI now changes periodically), we authenticate you with a cryptographic protocol (Chaum's blind signatures) that proves you should get a new eSIM but doesn't reveal your identity. Then you get mobile data service. This isn't something that exists today, despite the tracking/data collection that's happened both by third parties (SDRs / IMSI catchers) and operators themselves. It's like MAC randomization for mobile networks.

We figured users would like better IP privacy too, so we used IETF MASQUE and collaborated with Fastly to provide relay service in PGPP as well. Relay service works on almost any Android device. This uses TLS to tunnel your traffic (which itself will usually be TLS encrypted, for almost all Web traffic today) through two hops and then to the rest of the Internet. The first hop is us -- we hide your IP but learn nothing of your traffic or where it's headed. The second hop is Fastly, who then connects you to the IP of the server you're trying to reach, but all they see is an INVISV IP trying to connect to some other IP. The site you're connecting to terminates your TLS stream but just sees it coming from Fastly.

This is a beta and there are several things that aren't ideal. We don't have free plans because providing actual connectivity is pretty expensive. We know that data-only mobile service isn't for everyone (that's what our mobile plans provide -- no phone number). So we offer Relay service on its own for folks who want that. We also know eSIMs are not ideal either, so we'd like to generalize that down the road.

We're focused on privacy, not just on mobile, and we'd love your feedback on the service and ideas about this and where to go next.

Thanks!

Barath and Paul",921 -mikece,32417696,4,1660162107,Facebook's Message Encryption Was Built to Fail,https://www.wired.com/story/facebook-message-encryption-abortion/,"To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . chilling. Police raiding a home, a teenager and her mother arrested, fetal remains exhumed from a rural burial plot. When police dragged off a 17-year-old Nebraska girl and charged her and her mother with self-administering a miscarriage, they were they could only access through the incompetence and cooperation of Meta. The intimate conversation between a mother and daughter in the days surrounding an alleged abortion was just one of the millions logged by Facebook every day, but for this family it will be devastating. After police obtained a warrant for the girl’s Facebook data, they used ",Hacker News,47290178,"Title: Facebook's Message Encryption Was Built to Fail; Content: To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . chilling. Police raiding a home, a teenager and her mother arrested, fetal remains exhumed from a rural burial plot. When police dragged off a 17-year-old Nebraska girl and charged her and her mother with self-administering a miscarriage, they were they could only access through the incompetence and cooperation of Meta. The intimate conversation between a mother and daughter in the days surrounding an alleged abortion was just one of the millions logged by Facebook every day, but for this family it will be devastating. After police obtained a warrant for the girl’s Facebook data, they used ",188 -falafelite,32384769,140,1659962691,Ask HN: Have you ever inherited a code base you thought was well done?,,"I see and hear a lot of complaints around inheriting code bases that are less than stellar. If anyone has, I'd love to hear about cases where you inherited a "good" code base, whatever that may mean: awesome test coverage, good documentation, solid organization, consistent styling/formatting, abundant best practices, whatever!",Hacker News,16133754,"Title: Ask HN: Have you ever inherited a code base you thought was well done?; Content: I see and hear a lot of complaints around inheriting code bases that are less than stellar. If anyone has, I'd love to hear about cases where you inherited a "good" code base, whatever that may mean: awesome test coverage, good documentation, solid organization, consistent styling/formatting, abundant best practices, whatever!",105 -sylens,32401228,29,1660067171,Why macOS Ventura Share menu is bad,https://lapcatsoftware.com/articles/VenturaShare.html,"The new macOS Ventura System Settings app has been widely criticized. I've personally written criticizing it. The new macOS Ventura Share menu, on the other hand, hasn't yet received much discussion or criticism. This is due partly to System Settings taking a lot of the rhetorical focus — it's so blatantly bad! — and partly to the Share menu's relative obscurity in the system. I feel that the time is overdue for us to look critically at the Ventura Share menu, because some of the design changes to the Share menu are as misguided and bad as those to System Settings. Here's the Share menu on macOS Monterey in Safari when I open the contextual menu on the link at the top of the front page. (You can see ""Sup"" at the upper left corner of the contextual menu, where I command-clicked.) An",Hacker News,10912258,"Title: Why macOS Ventura Share menu is bad; Content: The new macOS Ventura System Settings app has been widely criticized. I've personally written criticizing it. The new macOS Ventura Share menu, on the other hand, hasn't yet received much discussion or criticism. This is due partly to System Settings taking a lot of the rhetorical focus — it's so blatantly bad! — and partly to the Share menu's relative obscurity in the system. I feel that the time is overdue for us to look critically at the Ventura Share menu, because some of the design changes to the Share menu are as misguided and bad as those to System Settings. Here's the Share menu on macOS Monterey in Safari when I open the contextual menu on the link at the top of the front page. (You can see ""Sup"" at the upper left corner of the contextual menu, where I command-clicked.) An",187 -mw888,32397806,15,1660052798,Ask HN: Do you worry about CPU backdoors like IME?,,"On the surface these seem like a egregious affront on personal computing freedom and privacy, yet I rarely hear the topic brought up when the subject is being discussed. Perhaps the most damning claim to them is are government agencies’ ability to purchase CPUs with the ‘feature’ turned off.

What are the implications of such hardware on user security? Is the threat real, overblown, or relatively unexplored?",Hacker News,26232389,"Title: Ask HN: Do you worry about CPU backdoors like IME?; Content: On the surface these seem like a egregious affront on personal computing freedom and privacy, yet I rarely hear the topic brought up when the subject is being discussed. Perhaps the most damning claim to them is are government agencies’ ability to purchase CPUs with the ‘feature’ turned off.

What are the implications of such hardware on user security? Is the threat real, overblown, or relatively unexplored?",106 -uptown,32411428,13,1660137557,New Google site begs Apple for mercy in messaging war,https://arstechnica.com/gadgets/2022/08/new-google-site-begs-apple-for-mercy-in-messaging-war/,"Front page layout Site theme Sign up or login to join the discussions! - - - - Google has been unable to field a stable, competitive messaging platform for years and has thoroughly lost the messaging war to products with a long-term strategy. At least some divisions inside the company are waking up to how damaging this is to Google as a company, and now Google's latest strategy is to... beg its competition for mercy? Google—which has launched 13 different messaging apps since iMessage launched in 2011—now says, ""It's time for Apple to fix texting."" Google launched a new website called "" ""—a public pressure campaign with a call to ""tweet at @Apple to #GetTheMessage and fix texting."" Google hopes public pressure will get Apple to adopt RCS, a minor upgrade to the SMS standard that Apple",Hacker News,61594365,"Title: New Google site begs Apple for mercy in messaging war; Content: Front page layout Site theme Sign up or login to join the discussions! - - - - Google has been unable to field a stable, competitive messaging platform for years and has thoroughly lost the messaging war to products with a long-term strategy. At least some divisions inside the company are waking up to how damaging this is to Google as a company, and now Google's latest strategy is to... beg its competition for mercy? Google—which has launched 13 different messaging apps since iMessage launched in 2011—now says, ""It's time for Apple to fix texting."" Google launched a new website called "" ""—a public pressure campaign with a call to ""tweet at @Apple to #GetTheMessage and fix texting."" Google hopes public pressure will get Apple to adopt RCS, a minor upgrade to the SMS standard that Apple",191 -lawgimenez,32392793,136,1660005050,"Software Architecture Is Overrated, Clear and Simple Design Is Underrated (2019)",https://blog.pragmaticengineer.com/software-architecture-is-overrated/,"I had my fair share in designing and building large systems. I've taken part in rewriting Uber's , designing and shipping Skype on Xbox One and open-sourcing , Uber's mobile architecture framework. All of these systems had thorough designs, going through multiple iterations and had lots of whiteboarding and discussion. The designs then boiled down to a design document that was circulated for more feedback before we started building. All of these systems were large at scale: hundreds of developers build them - or on top of them - and they power systems used by millions of people per day. They were also not just greenfield projects. The payments system rewrite had to replace two, existing payments systems, used by tens of systems and dozens of teams, all without having any business impact.",Hacker News,95588404,"Title: Software Architecture Is Overrated, Clear and Simple Design Is Underrated (2019); Content: I had my fair share in designing and building large systems. I've taken part in rewriting Uber's , designing and shipping Skype on Xbox One and open-sourcing , Uber's mobile architecture framework. All of these systems had thorough designs, going through multiple iterations and had lots of whiteboarding and discussion. The designs then boiled down to a design document that was circulated for more feedback before we started building. All of these systems were large at scale: hundreds of developers build them - or on top of them - and they power systems used by millions of people per day. They were also not just greenfield projects. The payments system rewrite had to replace two, existing payments systems, used by tens of systems and dozens of teams, all without having any business impact.",175 -raybb,32417431,5,1660160790,The fall (and rise?) of unions in the US,https://www.youtube.com/watch?v=KtxITylE73U,,Hacker News,64614879,Title: The fall (and rise?) of unions in the US; Content: ,17 -abrax3141,32378999,11,1659899897,Artificial Intelligence and Machine Learning in Software as a Medical Device,https://www.fda.gov/medical-devices/software-medical-device-samd/artificial-intelligence-and-machine-learning-software-medical-device,"Federal government websites often end in .gov or .mil. Before sharing sensitive information, make sure you're on a federal government site. The ensures that you are connecting to the official website and that any information you provide is encrypted and transmitted securely.   The U.S. Food and Drug Administration (FDA) issued the “Artificial Intelligence/Machine Learning (AI/ML)-Based Software as a Medical Device (SaMD) Action Plan” from the Center for Devices and Radiological Health’s Digital Health Center of Excellence. The Action Plan is a direct response to stakeholder feedback to the April 2019 discussion paper, “Proposed Regulatory Framework for Modifications to Artificial Intelligence/Machine Learning-Based Software as a Medical Device” and outlines five actions the FDA intends ",Hacker News,99513126,"Title: Artificial Intelligence and Machine Learning in Software as a Medical Device; Content: Federal government websites often end in .gov or .mil. Before sharing sensitive information, make sure you're on a federal government site. The ensures that you are connecting to the official website and that any information you provide is encrypted and transmitted securely.   The U.S. Food and Drug Administration (FDA) issued the “Artificial Intelligence/Machine Learning (AI/ML)-Based Software as a Medical Device (SaMD) Action Plan” from the Center for Devices and Radiological Health’s Digital Health Center of Excellence. The Action Plan is a direct response to stakeholder feedback to the April 2019 discussion paper, “Proposed Regulatory Framework for Modifications to Artificial Intelligence/Machine Learning-Based Software as a Medical Device” and outlines five actions the FDA intends ",179 -belltaco,32417286,5,1660159987,FSD was never engaged during Tesla self-driving crash test by smear campaign,https://electrek.co/2022/08/10/tesla-self-driving-smear-campaign-releases-test-fails-fsd-never-engaged/,"Yesterday - - - - Aug. 10th 2022 8:56 am PT - - - A Tesla Full Self-Driving smear campaign started by a California billionaire running for Senate has a new attack ad based on a FSD Beta “test,” where they failed to realize they never engaged FSD Beta during the test. - Earlier this year, we reported on Dan O’Dowd, a self-described billionaire and founder of Green Hills Software, a privately owned company that makes operating systems and programming tools. O’Dowd had launched a Senate campaign in his home state of California, but the tech executive made it quite clear that he is making it a single-issue campaign, and that issue is Tesla’s Full Self-Driving program. Under the protection of political ads, he with the goal of having it banned from public roads in the US. Yesterd",Hacker News,4742369,"Title: FSD was never engaged during Tesla self-driving crash test by smear campaign; Content: Yesterday - - - - Aug. 10th 2022 8:56 am PT - - - A Tesla Full Self-Driving smear campaign started by a California billionaire running for Senate has a new attack ad based on a FSD Beta “test,” where they failed to realize they never engaged FSD Beta during the test. - Earlier this year, we reported on Dan O’Dowd, a self-described billionaire and founder of Green Hills Software, a privately owned company that makes operating systems and programming tools. O’Dowd had launched a Senate campaign in his home state of California, but the tech executive made it quite clear that he is making it a single-issue campaign, and that issue is Tesla’s Full Self-Driving program. Under the protection of political ads, he with the goal of having it banned from public roads in the US. Yesterd",231 -thomassmith65,32411020,6,1660135736,Drinking Bird,https://en.wikipedia.org/wiki/Drinking_bird,", also known as , , and “ ” are that mimic the motions of a bird drinking from a water source. They are sometimes incorrectly considered examples of a device. - A drinking bird consists of two glass bulbs joined by a glass tube (the bird's neck). The tube extends nearly all the way into the bottom bulb, and attaches to the top bulb but does not extend into it. - The space inside the bird contains a fluid, usually colored to make the liquid more visible. The dye might fade when exposed to light, with the rate depending on the dye/color. -The fluid is typically (DCM), also known as methylene chloride. -Earlier versions contained . -Miles V. Sullivan's 1945 patent suggested , , , or . - Air is removed from the apparatus during manufacture, so the space inside the body is fill",Hacker News,80157119,"Title: Drinking Bird; Content: , also known as , , and “ ” are that mimic the motions of a bird drinking from a water source. They are sometimes incorrectly considered examples of a device. - A drinking bird consists of two glass bulbs joined by a glass tube (the bird's neck). The tube extends nearly all the way into the bottom bulb, and attaches to the top bulb but does not extend into it. - The space inside the bird contains a fluid, usually colored to make the liquid more visible. The dye might fade when exposed to light, with the rate depending on the dye/color. -The fluid is typically (DCM), also known as methylene chloride. -Earlier versions contained . -Miles V. Sullivan's 1945 patent suggested , , , or . - Air is removed from the apparatus during manufacture, so the space inside the body is fill",202 -indus,32399064,19,1660057768,India's rocket fails to put satellites in right orbit in debut launch,https://www.space.com/india-sslv-rocket-first-launch,"Space is supported by its audience. When you purchase through links on our site, we may earn an affiliate commission. . -By - -published - India's new Small Satellite Launch Vehicle deployed its two payload in the wrong orbit. They are ""no longer usable."" India's new rocket launched for the first time on Saturday night (Aug. 6) but failed to deliver its satellite payloads into their intended orbit due to a sensor issue. The 112-foot-tall (34 meters) Small Satellite Launch Vehicle (SSLV) lifted off from Satish Dhawan Space Centre on India's southeastern coast on Saturday at 11:48 p.m. EDT (0348 GMT and 9:18 a.m. India Standard Time on Sunday, Aug. 7) with two onboard. The rocket's three solid-fueled stages performed well, but its fourth and final stage, a liquid-fueled ""velocity trimming",Hacker News,45484580,"Title: India's rocket fails to put satellites in right orbit in debut launch; Content: Space is supported by its audience. When you purchase through links on our site, we may earn an affiliate commission. . -By - -published - India's new Small Satellite Launch Vehicle deployed its two payload in the wrong orbit. They are ""no longer usable."" India's new rocket launched for the first time on Saturday night (Aug. 6) but failed to deliver its satellite payloads into their intended orbit due to a sensor issue. The 112-foot-tall (34 meters) Small Satellite Launch Vehicle (SSLV) lifted off from Satish Dhawan Space Centre on India's southeastern coast on Saturday at 11:48 p.m. EDT (0348 GMT and 9:18 a.m. India Standard Time on Sunday, Aug. 7) with two onboard. The rocket's three solid-fueled stages performed well, but its fourth and final stage, a liquid-fueled ""velocity trimming",211 -raunometsa,32376672,148,1659881981,Micro-SaaS Alternatives to BigTech/VC,https://microfounder.com/alternatives,"Hi HN

I started this crowdsourced list to find small internet products made by solo developers (or tiny teams) that can be used as alternatives to BigTech/VC-funded startups.

E.g. you can use Tally (by two devs, $14K MRR) instead of Typeform ($190M funding, 600+ employees)

or Plausible (by two devs, $83K MRR) instead of Google Analytics.

I added a link to a form where you can send me suggestions to alternatives, happy to add to the site!

Thanks, -Rauno",Hacker News,15307242,"Title: Micro-SaaS Alternatives to BigTech/VC; Content: Hi HN

I started this crowdsourced list to find small internet products made by solo developers (or tiny teams) that can be used as alternatives to BigTech/VC-funded startups.

E.g. you can use Tally (by two devs, $14K MRR) instead of Typeform ($190M funding, 600+ employees)

or Plausible (by two devs, $83K MRR) instead of Google Analytics.

I added a link to a form where you can send me suggestions to alternatives, happy to add to the site!

Thanks, -Rauno",154 -ripvanwinkle,32374345,106,1659853538,A Soviet test pilot ejected two seconds before the crash of his MiG-29 (2019),https://theaviationgeekclub.com/that-time-a-soviet-test-pilot-ejected-two-seconds-before-the-crash-of-his-mig-29/,"Taken on Jun. 8, 1989 the famous video in this post features MiG-29 ‘303 Blue’ (c/n 2960516767, f/n 3303) belonging to the Mikoyan OKB and flown by test pilot Anatoliy N. Kvochur while performing a demo flight at 38th . As explained by Yefim Gordon and Dmitriy Komissarov in their book , during a high-alpha/low-speed pass at 160 m (525 ft) concluding the Fulcrum-A’s aerobatics display a sheet of flame belched from the starboard engine nozzle as the engine surged. Kvochur  immediately selected for the good engine, but at only 180 km/h (111 mph) he had insufficient rudder and aileron authority to counter the thrust asymmetry and the result was inevitably an irrecoverable departure. The engine failed at 13 hrs 44 min 57 sec -local time; the stricken fighter immediately yawed and rolled t",Hacker News,4888565,"Title: A Soviet test pilot ejected two seconds before the crash of his MiG-29 (2019); Content: Taken on Jun. 8, 1989 the famous video in this post features MiG-29 ‘303 Blue’ (c/n 2960516767, f/n 3303) belonging to the Mikoyan OKB and flown by test pilot Anatoliy N. Kvochur while performing a demo flight at 38th . As explained by Yefim Gordon and Dmitriy Komissarov in their book , during a high-alpha/low-speed pass at 160 m (525 ft) concluding the Fulcrum-A’s aerobatics display a sheet of flame belched from the starboard engine nozzle as the engine surged. Kvochur  immediately selected for the good engine, but at only 180 km/h (111 mph) he had insufficient rudder and aileron authority to counter the thrust asymmetry and the result was inevitably an irrecoverable departure. The engine failed at 13 hrs 44 min 57 sec -local time; the stricken fighter immediately yawed and rolled t",241 -krstce,32404526,5,1660080252,Show HN: Convert eCommerce product pages to JSON with a simple API Call,https://ecom2json.com," - ecom2json scrapes eCommerce sites and extracts - product data in JSON format - with a single API call. - - Create custom landing pages with -
- Fastland that converts more visitors
- than any website. Easy & Fast. - We know you're sick of spending hours scraping product data - from various sites and having to deal with captcha, proxies, - and fragile CSS selectors. That's why we created ecom2json - - the only solution that can scrape 100+ eCommerce sites and - serves in JSON forma",Hacker News,96879332,"Title: Show HN: Convert eCommerce product pages to JSON with a simple API Call; Content: - ecom2json scrapes eCommerce sites and extracts - product data in JSON format - with a single API call. - - Create custom landing pages with -
- Fastland that converts more visitors
- than any website. Easy & Fast. - We know you're sick of spending hours scraping product data - from various sites and having to deal with captcha, proxies, - and fragile CSS selectors. That's why we created ecom2json - - the only solution that can scrape 100+ eCommerce sites and - serves in JSON forma",420 -samizdis,32417081,3,1660159036,Porsche Taycan Turbo S Sets Fastest Production EV Nürburgring Lap Record,https://www.thedrive.com/news/porsche-taycan-turbo-s-fastest-production-ev-nurburgring-lap-record,"kristenlee kristenleeeeeeee If you don't set a lap time, are you even for real? Clearly, this question was on Porsche's mind when it took the to —and then promptly set a new record there for the fastest production EV. Development driver Lars Kern was at the wheel and managed a lap time of seven minutes and 33 seconds. That's 7:33 if you want it written out in 'Ring-speak. In its , Porsche insists that the car was ""entirely"" stock. It just had a roll cage and racing seats, per track requirements. The car also had a performance kit and Porsche Dynamic Chassis Control—but, again, Porsche says that its weight was identical to a stock vehicle. You can watch the lap here: If you're curious, that performance kit is comprised of a software update to the onboard 4D Chassis Control so it wor",Hacker News,13539063,"Title: Porsche Taycan Turbo S Sets Fastest Production EV Nürburgring Lap Record; Content: kristenlee kristenleeeeeeee If you don't set a lap time, are you even for real? Clearly, this question was on Porsche's mind when it took the to —and then promptly set a new record there for the fastest production EV. Development driver Lars Kern was at the wheel and managed a lap time of seven minutes and 33 seconds. That's 7:33 if you want it written out in 'Ring-speak. In its , Porsche insists that the car was ""entirely"" stock. It just had a roll cage and racing seats, per track requirements. The car also had a performance kit and Porsche Dynamic Chassis Control—but, again, Porsche says that its weight was identical to a stock vehicle. You can watch the lap here: If you're curious, that performance kit is comprised of a software update to the onboard 4D Chassis Control so it wor",213 -pigtailgirl,32407440,10,1660100491,SoftBank Vision Fund posts a $21.6B quarterly loss,https://www.cnbc.com/2022/08/08/softbank-vision-fund-posts-a-21point6-billion-quarterly-loss-.html,"In this article posted one of its biggest losses at its Vision Fund investment unit for its fiscal first quarter, as technology stocks continue to get hammered amid rising interest rates. The Japanese giant's Vision Fund posted a 2.93 trillion Japanese yen ($21.68 billion) loss for the June quarter. This is the second-largest quarterly loss for the Vision Fund. That contributed to a 3.16 trillion yen net loss for the quarter for SoftBank versus a 761.5 billion yen profit in the same period last year. That is a record quarterly loss for the company. The company also authorized a 400 billion yen share buyback program on Monday. SoftBank's Vision Fund, which began in 2017 and invests in technology companies, has been hit by a slump in high-growth stocks as a result of rampant inflation that ",Hacker News,43636174,"Title: SoftBank Vision Fund posts a $21.6B quarterly loss; Content: In this article posted one of its biggest losses at its Vision Fund investment unit for its fiscal first quarter, as technology stocks continue to get hammered amid rising interest rates. The Japanese giant's Vision Fund posted a 2.93 trillion Japanese yen ($21.68 billion) loss for the June quarter. This is the second-largest quarterly loss for the Vision Fund. That contributed to a 3.16 trillion yen net loss for the quarter for SoftBank versus a 761.5 billion yen profit in the same period last year. That is a record quarterly loss for the company. The company also authorized a 400 billion yen share buyback program on Monday. SoftBank's Vision Fund, which began in 2017 and invests in technology companies, has been hit by a slump in high-growth stocks as a result of rampant inflation that ",184 -porknubbins,32402075,10,1660070371,Ask HN: What Happened to Open Courseware?,,"I learned CS from online courses and have been trying to learn basic EE as well. to It seems to me that free online courses by places like MIT or similar institutions have been declining for the past 5 years at least.

It is too cynical to think that institutions recognized that STEM classes by great professors are a rare and valuable resource, and that by sharing them freely they undermined the value of attending one of these elite institutions? Cost alone cannot be the full explanation as existing resources that were excellent have been actively taken down.

I know that UC Berkley's videos were taken down for failing to conform to accessibility laws so that it kind of a special case, but it wouldn't have been impossible to get them subtitled if the motivation were there.

Of course many of these resources can still be found if you search hard enough, and individual Youtube creators have been getting better and better, but I would really be fascinated to hear why there was such an institutional flourish and decline?",Hacker News,20821969,"Title: Ask HN: What Happened to Open Courseware?; Content: I learned CS from online courses and have been trying to learn basic EE as well. to It seems to me that free online courses by places like MIT or similar institutions have been declining for the past 5 years at least.

It is too cynical to think that institutions recognized that STEM classes by great professors are a rare and valuable resource, and that by sharing them freely they undermined the value of attending one of these elite institutions? Cost alone cannot be the full explanation as existing resources that were excellent have been actively taken down.

I know that UC Berkley's videos were taken down for failing to conform to accessibility laws so that it kind of a special case, but it wouldn't have been impossible to get them subtitled if the motivation were there.

Of course many of these resources can still be found if you search hard enough, and individual Youtube creators have been getting better and better, but I would really be fascinated to hear why there was such an institutional flourish and decline?",226 -anonimouse1234,32377084,59,1659885049,Ask HN: Where should I move to meet interesting tech people?,,"Hey everybody,

So after about 8 years of various unsuccessful startup attempts I bit the bullet and got a job.

Classical 6 figures tech job in AI for bigtech. Fully remote chill work hours you know the deal.

I used to live for work pouring all my heart into an idea talking to customers iterating working day and night.

Now, I want to work to live travel and most importantly I want to meet as many interesting tech people as possible.

Now my question. Where should I go? Ideally, I want to be able to go back to Germany at least for 3 months a year the rest I am open for suggestions.

Should I move to a digital nomad place like Bali or Portugal? Or a tech hub like San Francisco or Austin?

Time zone wise Hong Kong would be ideal but I am mostly working on my own so it isn't a deal breaker.

Also wherever I am, should I go to conferences ? Meetups? Dm random people on Twitter and Hackernews? Otherwise, il just keep chatting up a bunch of people in co-working spaces.

I feel like nowadays there must be quite a few people in this situation. Would love to hear your thoughts.",Hacker News,93130168,"Title: Ask HN: Where should I move to meet interesting tech people?; Content: Hey everybody,

So after about 8 years of various unsuccessful startup attempts I bit the bullet and got a job.

Classical 6 figures tech job in AI for bigtech. Fully remote chill work hours you know the deal.

I used to live for work pouring all my heart into an idea talking to customers iterating working day and night.

Now, I want to work to live travel and most importantly I want to meet as many interesting tech people as possible.

Now my question. Where should I go? Ideally, I want to be able to go back to Germany at least for 3 months a year the rest I am open for suggestions.

Should I move to a digital nomad place like Bali or Portugal? Or a tech hub like San Francisco or Austin?

Time zone wise Hong Kong would be ideal but I am mostly working on my own so it isn't a deal breaker.

Also wherever I am, should I go to conferences ? Meetups? Dm random people on Twitter and Hackernews? Otherwise, il just keep chatting up a bunch of people in co-working spaces.

I feel like nowadays there must be quite a few people in this situation. Would love to hear your thoughts.",285 -armchairguy,32383525,41,1659948831,Ask HN: What Is the Lisp “Enlightment”?,,"Every time I read about Lisp I hear about the _enlightment_ phase, -but what is it?

I checked Lisp and what stands out most for me is the syntax and -the powerful REPL but aside from that, why is it so praised -compared to modern languages? I don't see many projects -using it either aside from certain exceptions.

Apologies for my ignorance _in advance_",Hacker News,55429025,"Title: Ask HN: What Is the Lisp “Enlightment”?; Content: Every time I read about Lisp I hear about the _enlightment_ phase, -but what is it?

I checked Lisp and what stands out most for me is the syntax and -the powerful REPL but aside from that, why is it so praised -compared to modern languages? I don't see many projects -using it either aside from certain exceptions.

Apologies for my ignorance _in advance_",117 -boredemployee,32384742,33,1659962375,Tell HN: Recruiters misusing HN's “Who wants to be hired”,,"It's getting worse each time and I'm sure I'm not alone on this. Taking advantage on "Who wants to be hired" recruiters are sending completely random (web scrap?) positions in our inboxes which leads me to think: if you don't care about your recruitment process, imagine how fcked up is your whole business. I stopped to use linkedin because of the same bs. Any idea on how to solve it here?",Hacker News,75874841,"Title: Tell HN: Recruiters misusing HN's “Who wants to be hired”; Content: It's getting worse each time and I'm sure I'm not alone on this. Taking advantage on "Who wants to be hired" recruiters are sending completely random (web scrap?) positions in our inboxes which leads me to think: if you don't care about your recruitment process, imagine how fcked up is your whole business. I stopped to use linkedin because of the same bs. Any idea on how to solve it here?",143 -elvio,32403407,3,1660075083,Shopify Releases React Native Skia: High Performance 2D Graphics,https://shopify.github.io//react-native-skia/,High Performance 2D Graphics,Hacker News,84090957,Title: Shopify Releases React Native Skia: High Performance 2D Graphics; Content: High Performance 2D Graphics,23 -stakkur,32390378,28,1659989169,Ask HN: Does anyone use FreeBSD or OpenBSD as a daily environment?,,"Over the years, I've used MacOS and Linux, sometimes switching between the two. I'm curious to know if any readers use one of these BSD distros as a daily driver/dev environment, especially on laptops.

NOTE: Not seeking to start an OS flame war or info dump of what BSD is.",Hacker News,12580966,"Title: Ask HN: Does anyone use FreeBSD or OpenBSD as a daily environment?; Content: Over the years, I've used MacOS and Linux, sometimes switching between the two. I'm curious to know if any readers use one of these BSD distros as a daily driver/dev environment, especially on laptops.

NOTE: Not seeking to start an OS flame war or info dump of what BSD is.",103 -empressplay,32402942,6,1660073404,Logo and the Language Microworld,https://turtlespaces.org/2022/08/09/logo-and-the-language-microworld/,"Logo isn’t just all about the turtles! When Logo was first being developed, there were no graphical displays — output was simple text on teletypes, which printed out interactions with the computer on paper. When the developers of Logo went into classrooms to test out their invention on students, all they had were teletypes. As a result, the first Logo ‘microworld’ was the language microworld, not the geometry microworld which is more often associated with Logo. Logo was designed with many powerful commands used to manipulate strings and lists. Logo is based on Lisp, which stands for List Processing, a programming language in which data and code are the same, and are interchangeable and manipulatable by the running program. In Lisp, as in Logo, programs can modify, create and run themselves",Hacker News,55123368,"Title: Logo and the Language Microworld; Content: Logo isn’t just all about the turtles! When Logo was first being developed, there were no graphical displays — output was simple text on teletypes, which printed out interactions with the computer on paper. When the developers of Logo went into classrooms to test out their invention on students, all they had were teletypes. As a result, the first Logo ‘microworld’ was the language microworld, not the geometry microworld which is more often associated with Logo. Logo was designed with many powerful commands used to manipulate strings and lists. Logo is based on Lisp, which stands for List Processing, a programming language in which data and code are the same, and are interchangeable and manipulatable by the running program. In Lisp, as in Logo, programs can modify, create and run themselves",175 -arispen,32374137,32,1659850285,Show HN: Dungeons and Business Cards,https://arispen.itch.io/dnbc,A downloadable game Dungeons & Business Cards is a fantasy role-playing dungeon crawl-style game that fits in a business card. You just need a pen or pencil and a 6-sided die. You can play it solo or with your friends. A small and fun game that fits in your wallet. Playable at parties and with kids. Roll your character. Disarm traps. Kill monsters. Find treasure. Advance to the next levels on the next business cards. Make layouts of dungeons from business cards. Slay the dragon. Find the amulet! The printed version is available in my  Dungeon illustration from amazing  Click download now to get access to the following files: to leave a comment.,Hacker News,37334202,Title: Show HN: Dungeons and Business Cards; Content: A downloadable game Dungeons & Business Cards is a fantasy role-playing dungeon crawl-style game that fits in a business card. You just need a pen or pencil and a 6-sided die. You can play it solo or with your friends. A small and fun game that fits in your wallet. Playable at parties and with kids. Roll your character. Disarm traps. Kill monsters. Find treasure. Advance to the next levels on the next business cards. Make layouts of dungeons from business cards. Slay the dragon. Find the amulet! The printed version is available in my  Dungeon illustration from amazing  Click download now to get access to the following files: to leave a comment.,157 -robin_reala,32384495,75,1659960162,Adtech giant Criteo faces $65M fine in France for GDPR consent breaches,https://techcrunch.com/2022/08/05/criteo-gdpr-breaches-cnil/,"In the latest blow to the creepy ‘tracking-ads’ complex, French adtech giant Criteo has been found in breach of European Union data protection regulation and hit with a €60 million sanction (~$65 million) by the country’s national privacy watchdog in a preliminary decision following a multi-year investigation. Digital rights advocacy group Privacy International, which lodged a formal complaint against the surveillance adtech giant back in 2018, when the bloc’s General Data Protection Regulation (GDPR) came into application, news of the sanction today. BREAKING: Nearly 4 years after our complaint and 2 after starting their investigation, the French data protection authority CNIL finds breaches in Criteo's activities, and proposes a fine of €60 million. Why did this happen and why does i",Hacker News,13184118,"Title: Adtech giant Criteo faces $65M fine in France for GDPR consent breaches; Content: In the latest blow to the creepy ‘tracking-ads’ complex, French adtech giant Criteo has been found in breach of European Union data protection regulation and hit with a €60 million sanction (~$65 million) by the country’s national privacy watchdog in a preliminary decision following a multi-year investigation. Digital rights advocacy group Privacy International, which lodged a formal complaint against the surveillance adtech giant back in 2018, when the bloc’s General Data Protection Regulation (GDPR) came into application, news of the sanction today. BREAKING: Nearly 4 years after our complaint and 2 after starting their investigation, the French data protection authority CNIL finds breaches in Criteo's activities, and proposes a fine of €60 million. Why did this happen and why does i",189 -thatsamonad,32392190,25,1659999671,Ask HN: Is there any worthwhile management training out there?,,"Hi HN,

I recently made the move from technical lead to full-blown engineering manager about 6 months ago. I was aware at the time that I’d be using a different set of skills than what I was used to when I was doing technical work. That being said, I picked up some of my technical skills and knowledge by attending some quality trainings, online courses, etc, so I know those kinds of things are out there for technical topics.

Are there any good/quality training courses or learning paths for engineering managers out there that you would recommend? A lot of the things I’ve been exposed to so far are pretty “fluffy”, so I’m hoping to find some good resources that will aid me in building the skills I need to help my team succeed.",Hacker News,41539864,"Title: Ask HN: Is there any worthwhile management training out there?; Content: Hi HN,

I recently made the move from technical lead to full-blown engineering manager about 6 months ago. I was aware at the time that I’d be using a different set of skills than what I was used to when I was doing technical work. That being said, I picked up some of my technical skills and knowledge by attending some quality trainings, online courses, etc, so I know those kinds of things are out there for technical topics.

Are there any good/quality training courses or learning paths for engineering managers out there that you would recommend? A lot of the things I’ve been exposed to so far are pretty “fluffy”, so I’m hoping to find some good resources that will aid me in building the skills I need to help my team succeed.",193 -michaelwm,32402540,4,1660072127,Lem: Common Lisp editor/IDE with high expansibility,https://github.com/lem-project/lem," - Common Lisp editor/IDE with high expansibility - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. - After installing lem, you can start developing in Common Lisp at once. You can skip over writing tidy settings or installing many plugins as you do on Emacs.    You can try Lem by running it in a docker container: Please install roswell at first. After that, please follow the steps bellow. You can watch the screencast on Youtube. Lem loads when starting up. You can see an exam",Hacker News,71918078,"Title: Lem: Common Lisp editor/IDE with high expansibility; Content: - Common Lisp editor/IDE with high expansibility - - Use Git or checkout with SVN using the web URL. - - Work fast with our official CLI. - . - - If nothing happens, and try again. - - If nothing happens, and try again. - - If nothing happens, and try again. - Your codespace will open once ready. There was a problem preparing your codespace, please try again. - After installing lem, you can start developing in Common Lisp at once. You can skip over writing tidy settings or installing many plugins as you do on Emacs.    You can try Lem by running it in a docker container: Please install roswell at first. After that, please follow the steps bellow. You can watch the screencast on Youtube. Lem loads when starting up. You can see an exam",262 -n8ta,32380045,50,1659907354,Ask HN: Best free software to read text aloud,,"What is the best software to read arbitrary text aloud in a decently human sounding voice? I'd be happy with a CLI tool or a website I can just paste text into.

There are many articles I'd rather hear than read so I can rest my eyes. I've tried the builtin macOS say cmd, naturalreaders (dot) com and they both suck.",Hacker News,33314814,"Title: Ask HN: Best free software to read text aloud; Content: What is the best software to read arbitrary text aloud in a decently human sounding voice? I'd be happy with a CLI tool or a website I can just paste text into.

There are many articles I'd rather hear than read so I can rest my eyes. I've tried the builtin macOS say cmd, naturalreaders (dot) com and they both suck.",108 -plasticbugs,32407533,27,1660101564,Facebook turned over chat messages of mother and daughter charged over abortion,https://www.nbcnews.com/tech/tech-news/facebook-turned-chat-messages-mother-daughter-now-charged-abortion-rcna42185,"Profile Sections tv Featured More From NBC Follow NBC News Facebook turned over the chats of a mother and her daughter to Nebraska police after they were served with a warrant as part of an investigation into an illegal abortion, show. The investigation, which was launched in April before the Supreme Court overturned Roe v. Wade, is one of the few known instances of Facebook’s turning over information to help law enforcement officials pursue an abortion case — but it is also an example of a scenario that abortion rights experts have warned will be more common as all abortions becomes . Madison County prosecutors say Jessica Burgess, 41, acquired and gave abortion pills to her daughter, Celeste, who was 17 at the time, and then helped her bury and then rebury the fetus. The Norfolk Daily ",Hacker News,75513668,"Title: Facebook turned over chat messages of mother and daughter charged over abortion; Content: Profile Sections tv Featured More From NBC Follow NBC News Facebook turned over the chats of a mother and her daughter to Nebraska police after they were served with a warrant as part of an investigation into an illegal abortion, show. The investigation, which was launched in April before the Supreme Court overturned Roe v. Wade, is one of the few known instances of Facebook’s turning over information to help law enforcement officials pursue an abortion case — but it is also an example of a scenario that abortion rights experts have warned will be more common as all abortions becomes . Madison County prosecutors say Jessica Burgess, 41, acquired and gave abortion pills to her daughter, Celeste, who was 17 at the time, and then helped her bury and then rebury the fetus. The Norfolk Daily ",173 -mkosmul,32374737,17,1659858952,Growing Up as an Origamist,https://origami.kosmulski.org/blog/2022-08-07-growing-up-origamist," - - - - - - - - - I’ve been doing lots of origami lately, but very little folding. Between -Shuzo Fujimoto’s designs, diagramming my own models, preparing and giving workshops, writing blog posts, and managing the ever-increasing pile of prototypes, -I find it hard to find time for actually folding my designs much. Fujimoto’s recent -reminded me that the year he died, 2015, was also the year I got into tessellations and when my origami design skills really took off. So, I’ve been seriously engaged in origami for the last seven years (and on and off for thirty), and notice how much the notion of “doing origami” has -changed for me over time. This should come as no surprise as the same has happened in my professional life: with growing experience, I’ve been spending -more and mo",Hacker News,91806193,"Title: Growing Up as an Origamist; Content: - - - - - - - - - I’ve been doing lots of origami lately, but very little folding. Between -Shuzo Fujimoto’s designs, diagramming my own models, preparing and giving workshops, writing blog posts, and managing the ever-increasing pile of prototypes, -I find it hard to find time for actually folding my designs much. Fujimoto’s recent -reminded me that the year he died, 2015, was also the year I got into tessellations and when my origami design skills really took off. So, I’ve been seriously engaged in origami for the last seven years (and on and off for thirty), and notice how much the notion of “doing origami” has -changed for me over time. This should come as no surprise as the same has happened in my professional life: with growing experience, I’ve been spending -more and mo",243 -philk10,32401078,75,1660066557,"Tesla’s self-driving technology fails to detect children in the road, tests find",https://www.theguardian.com/technology/2022/aug/09/tesla-self-driving-technology-safety-children,"Professional test driver using Tesla’s Full Self-Driving mode repeatedly hit a child-sized mannequin in its path A safe-technology advocacy group issued claimed on Tuesday that Tesla’s full self-driving software represents a potentially lethal threat to child pedestrians, the latest in a series of claims and investigations into the technology to hit the world’s leading electric carmaker. According to a safety test conducted by the Dawn Project, the latest version of Tesla Full Self-Driving (FSD) Beta software repeatedly hit a stationary, child-sized mannequin in its path. The claims that the technology apparently has trouble recognizing children form part of an urging the public to pressure Congress to ban Tesla’s auto-driving technology. In several , a professional test driver found th",Hacker News,29929863,"Title: Tesla’s self-driving technology fails to detect children in the road, tests find; Content: Professional test driver using Tesla’s Full Self-Driving mode repeatedly hit a child-sized mannequin in its path A safe-technology advocacy group issued claimed on Tuesday that Tesla’s full self-driving software represents a potentially lethal threat to child pedestrians, the latest in a series of claims and investigations into the technology to hit the world’s leading electric carmaker. According to a safety test conducted by the Dawn Project, the latest version of Tesla Full Self-Driving (FSD) Beta software repeatedly hit a stationary, child-sized mannequin in its path. The claims that the technology apparently has trouble recognizing children form part of an urging the public to pressure Congress to ban Tesla’s auto-driving technology. In several , a professional test driver found th",187 -dovhyi,32395937,7,1660039161,The unsaid truth about working from home,https://www.alexscamp.com/the-unsaid-truth-about-working-from-home/,"I'm sure you've often heard those tips about working from home. And if you failed to apply any of that obvious advice, here are the real underlying challenges.  If you're not a paid subscriber, here's what you missed last month:‌‌ I'm sure you've often heard those tips about working from home. And if you failed to apply any of that obvious advice, here are the real underlying challenges. Working from home is not a new concept today. Over the past few years, the WFH force increased from 5% to 60%. Yet, many people struggle to adapt to the new ways of working. At this very moment, you might be here: You've been following all the apparent tips on how to work from home: Don't get me wrong — all of these are excellent advice. Yet, you feel distracted, unproductive, stressed, and unhappy. And th",Hacker News,71558435,"Title: The unsaid truth about working from home; Content: I'm sure you've often heard those tips about working from home. And if you failed to apply any of that obvious advice, here are the real underlying challenges.  If you're not a paid subscriber, here's what you missed last month:‌‌ I'm sure you've often heard those tips about working from home. And if you failed to apply any of that obvious advice, here are the real underlying challenges. Working from home is not a new concept today. Over the past few years, the WFH force increased from 5% to 60%. Yet, many people struggle to adapt to the new ways of working. At this very moment, you might be here: You've been following all the apparent tips on how to work from home: Don't get me wrong — all of these are excellent advice. Yet, you feel distracted, unproductive, stressed, and unhappy. And th",195 -susam,32374981,58,1659862444,Emacs Manual for ITS Users (1981),https://dspace.mit.edu/handle/1721.1/6329," - - - - - - - - - - - - - - - - Find us on",Hacker News,42278398,"Title: Emacs Manual for ITS Users (1981); Content: - - - - - - - - - - - - - - - - Find us on",47 -mooreds,32411793,6,1660139060,"Cannabis Could Transform Moffat into Kush, a Mecca of Marijuana Tourism",https://www.westword.com/news/cannabis-tourism-colorado-kush-moffat-area-420-san-luis-valley-marijuana-14659973," -Denver's independent source of -local news and culture - - - - - - - - - - - ""I don't need some dope smokers to tell me there's something wrong with the name of the town I live in."" ""They're trimming weed on Main Street. The cops don't give a shit here."" ""Me and my wife are investing our life's income into a bed-and-breakfast, and I'll be go to hell if it's going to be in the town of Kush."" ""I guess it's up to us to sell more weed to bring more money into this town."" -Inside Controversial Protective-Custody Unit - -By Michael Roberts - -More Than 2,000 Openings at Local Schools - -By Michael Roberts - -All About the New Colorado COVID Variant - -By Michael Roberts - Join the Westword community and help support -independent local journalism in Denver. -Get the latest updates in news, food, music a",Hacker News,17756413,"Title: Cannabis Could Transform Moffat into Kush, a Mecca of Marijuana Tourism; Content: -Denver's independent source of -local news and culture - - - - - - - - - - - ""I don't need some dope smokers to tell me there's something wrong with the name of the town I live in."" ""They're trimming weed on Main Street. The cops don't give a shit here."" ""Me and my wife are investing our life's income into a bed-and-breakfast, and I'll be go to hell if it's going to be in the town of Kush."" ""I guess it's up to us to sell more weed to bring more money into this town."" -Inside Controversial Protective-Custody Unit - -By Michael Roberts - -More Than 2,000 Openings at Local Schools - -By Michael Roberts - -All About the New Colorado COVID Variant - -By Michael Roberts - Join the Westword community and help support -independent local journalism in Denver. -Get the latest updates in news, food, music a",237 -martialg,32375737,36,1659872606,Harnessing public entrepreneurship,https://elgl.org/podcast-harnessing-public-entrepreneurship-with-mitchell-weiss/,"      -Powered by - This content is for decoration only .",Hacker News,97267838,"Title: Harnessing public entrepreneurship; Content:       -Powered by - This content is for decoration only .",28 -firstSpeaker,32415604,5,1660152486,Lumina is working on a smart standing desk that has a built-in display,https://www.engadget.com/lumina-sit-stand-desk-oled-display-150033942.html,"Is there much more space for , I hear you ask? After all, now that we’ve made them , there are no new worlds worth conquering. Not so, says , makers of its eponymous AI webcam that’s been described as the equal of a DSLR in some corners. Now, the company is turning its attention to building a smart desk with a programmable, 24-inch OLED screen nestled in its top, designed to offer you a place to put passive data in easy view. The Lumina Desk, as it’s called, is a powered sit-stand desk, with a display that sits between your laptop (or monitor) and your keyboard and mouse. The idea, as you can see, is to offer you space to add in a view for your Google Calendar, stock view from Robinhood or a Twitter feed. All things that it’d be nice to always have in view, but you may not necessarily w",Hacker News,23160602,"Title: Lumina is working on a smart standing desk that has a built-in display; Content: Is there much more space for , I hear you ask? After all, now that we’ve made them , there are no new worlds worth conquering. Not so, says , makers of its eponymous AI webcam that’s been described as the equal of a DSLR in some corners. Now, the company is turning its attention to building a smart desk with a programmable, 24-inch OLED screen nestled in its top, designed to offer you a place to put passive data in easy view. The Lumina Desk, as it’s called, is a powered sit-stand desk, with a display that sits between your laptop (or monitor) and your keyboard and mouse. The idea, as you can see, is to offer you space to add in a view for your Google Calendar, stock view from Robinhood or a Twitter feed. All things that it’d be nice to always have in view, but you may not necessarily w",220 -dbingham,32376133,68,1659877121,A Possible Fix for Scientific Publishing,https://blog.peer-review.io/we-might-have-a-way-to-fix-scientific-publishing,"Follow our progress on GitHub. Donate through GitHub Sponsors. Sign up to give feedback on the alpha or join the closed beta. Scientific and academic publishing is broken. The vast majority of the -journals have been privatized by publishers who charge astronomical fees for -access to the literature. The fees have gotten so high that even well funded universities have -started to walk away from negotiations. Universities with less funding have long been -unable to afford them. The average citizen has no hope of affording them. With the results of the scientific process locked away behind paywalls, science -is no longer an open and transparent process. Worse, the ultimate deciders of -policy in a democracy, average citizens, are being denied access to the primary -source materials necessary to m",Hacker News,80356460,"Title: A Possible Fix for Scientific Publishing; Content: Follow our progress on GitHub. Donate through GitHub Sponsors. Sign up to give feedback on the alpha or join the closed beta. Scientific and academic publishing is broken. The vast majority of the -journals have been privatized by publishers who charge astronomical fees for -access to the literature. The fees have gotten so high that even well funded universities have -started to walk away from negotiations. Universities with less funding have long been -unable to afford them. The average citizen has no hope of affording them. With the results of the scientific process locked away behind paywalls, science -is no longer an open and transparent process. Worse, the ultimate deciders of -policy in a democracy, average citizens, are being denied access to the primary -source materials necessary to m",171 -ecliptik,32400562,5,1660064380,Prelinger Archives – “ephemeral” films from the 20th century,https://archive.org/details/prelinger,"Due to a planned power outage on Friday, 1/14, between 8am-1pm PST, some services may be impacted. View thousands of films from the Prelinger Archives! - - -Prelinger Archives was founded in 1983 by Rick Prelinger in New York City. Over the next twenty years, it grew into a collection of over 60,000 ""ephemeral"" (advertising, educational, industrial, and amateur) films. In 2002, the film collection was acquired by the . Prelinger Archives remains in existence, holding approximately 11,000 digitized and videotape titles (all originally derived from film) and a large collection of home movies, amateur and industrial films acquired since 2002. Its primary collection emphasis has turned toward home movies and amateur films, with approximately 18,000 items held as of Spring 2021. Its goal ",Hacker News,50539542,"Title: Prelinger Archives – “ephemeral” films from the 20th century; Content: Due to a planned power outage on Friday, 1/14, between 8am-1pm PST, some services may be impacted. View thousands of films from the Prelinger Archives! - - -Prelinger Archives was founded in 1983 by Rick Prelinger in New York City. Over the next twenty years, it grew into a collection of over 60,000 ""ephemeral"" (advertising, educational, industrial, and amateur) films. In 2002, the film collection was acquired by the . Prelinger Archives remains in existence, holding approximately 11,000 digitized and videotape titles (all originally derived from film) and a large collection of home movies, amateur and industrial films acquired since 2002. Its primary collection emphasis has turned toward home movies and amateur films, with approximately 18,000 items held as of Spring 2021. Its goal ",200 -sharno,32374009,76,1659848139,Intel expands Oregon Fab building; 18A Node now 2024,https://chipsandcheese.com/2022/04/12/intel-renames-oregon-fab-gordon-moore-park-adds-270k-sq-ft-18a-node-now-2024/,"If there’s one thing that’s cheaper than building a new fab, it’s expanding an existing one. Intel’s Oregon D1 facility has been the hub of all of its technology advancements over the past 20 years, whereby Intel will trial new manufacturing processes before transferring them to other fabs around the world. As you can imagine, the site in Hillsboro is a big facility, sprawling over some 530 acres and hiring 14000 employees, making Intel the biggest employer in Portland. As was previously announced, Intel would be expanding its fab at Hillsboro to accommodate more tools, more capacity, and more research. Today, that expansion is officially being opened: enter D1X Mod 3. The new Mod 3 extension of the D1X fab is an impressive, with Intel stating that it has created 270,000 square foot more c",Hacker News,98882264,"Title: Intel expands Oregon Fab building; 18A Node now 2024; Content: If there’s one thing that’s cheaper than building a new fab, it’s expanding an existing one. Intel’s Oregon D1 facility has been the hub of all of its technology advancements over the past 20 years, whereby Intel will trial new manufacturing processes before transferring them to other fabs around the world. As you can imagine, the site in Hillsboro is a big facility, sprawling over some 530 acres and hiring 14000 employees, making Intel the biggest employer in Portland. As was previously announced, Intel would be expanding its fab at Hillsboro to accommodate more tools, more capacity, and more research. Today, that expansion is officially being opened: enter D1X Mod 3. The new Mod 3 extension of the D1X fab is an impressive, with Intel stating that it has created 270,000 square foot more c",190 -rntn,32411174,4,1660136414,"iRobot’s Roomba will soon be owned by Amazon, which raises privacy questions",https://theconversation.com/irobots-roomba-will-soon-be-owned-by-amazon-which-raises-privacy-questions-188355," - Professor of Cyber Security Practice, Edith Cowan University - provides funding as a member of The Conversation AU. Less than two weeks after the announcement of its acquisition of US healthcare company One Medical, Amazon is continuing its expansion with a for iRobot, the manufacturer of Roomba automated vacuum cleaners. The acquisition will bolster Amazon’s line of smart home products and add to the retail giant’s vast store of consumer data. The move also raises a number of questions. Why is Amazon doing this? Should we, as consumers, be concerned? What will Amazon do with yet another product that generates large volumes of data about its users? - - The purchase seems like a natural fit for Amazon’s apparent plan to conquer the home. The tech giant already has a foothold i",Hacker News,10562342,"Title: iRobot’s Roomba will soon be owned by Amazon, which raises privacy questions; Content: - Professor of Cyber Security Practice, Edith Cowan University - provides funding as a member of The Conversation AU. Less than two weeks after the announcement of its acquisition of US healthcare company One Medical, Amazon is continuing its expansion with a for iRobot, the manufacturer of Roomba automated vacuum cleaners. The acquisition will bolster Amazon’s line of smart home products and add to the retail giant’s vast store of consumer data. The move also raises a number of questions. Why is Amazon doing this? Should we, as consumers, be concerned? What will Amazon do with yet another product that generates large volumes of data about its users? - - The purchase seems like a natural fit for Amazon’s apparent plan to conquer the home. The tech giant already has a foothold i",202 -cyanbane,32402455,14,1660071839,Two player mode in Super Punch Out ( SNES ) discovered,https://www.nintendolife.com/news/2022/08/super-punch-out-hidden-two-player-mode-discovered-28-years-later,"Guest or or No hacks or mods required There's been a historic discovery made within the 1994 Super Nintendo release today. A Twitter account known as ' ' has uncovered a hidden two player mode in the game. To access this option, on the game's start screen you'll have to hold the 'Y' and 'R' buttons on the second player's controller and then press 'Start' or the 'A' button on the first player's controller. You then select the boxer for player two and have the second player hold down the 'B' and 'Y' buttons on their controller until the match begins. What's also exciting about this is that it's all on the cartridge - meaning no special hardware, accessories or hacks are required to access it. So you should be able to test it out yourself if you have a copy of the original game. Otherwi",Hacker News,33570542,"Title: Two player mode in Super Punch Out ( SNES ) discovered; Content: Guest or or No hacks or mods required There's been a historic discovery made within the 1994 Super Nintendo release today. A Twitter account known as ' ' has uncovered a hidden two player mode in the game. To access this option, on the game's start screen you'll have to hold the 'Y' and 'R' buttons on the second player's controller and then press 'Start' or the 'A' button on the first player's controller. You then select the boxer for player two and have the second player hold down the 'B' and 'Y' buttons on their controller until the match begins. What's also exciting about this is that it's all on the cartridge - meaning no special hardware, accessories or hacks are required to access it. So you should be able to test it out yourself if you have a copy of the original game. Otherwi",197 -bratao,32384350,10,1659958741,AppBlock – App with more than 1M/downloads was blocked on Play Store,https://www.appblock.app/appblock-is-temporarily-unavailable-on-google-play,"03.08.2022 We’re an app that is helping people around the whole world fight phone addiction, people with ADHD and teaching people use their phone in a way that deserves its purpose and not to procrastinate. Unfortunately, we’re struggling with the fact, that Google, out of nowhere, deleted our application from the Google Play Store - without any reasonable explanation as to why this happened. This may result in, among others, the inability to find us on the Play Store and buy Premium products. We are 100% sure that we are not violating the regulations, rules and policies that Google requires. We have taken all the precautions that Google has required in the past so that we can offer our app in accordance with the changes in the Google Play policies. We have appealed to Google Play, stating",Hacker News,12719040,"Title: AppBlock – App with more than 1M/downloads was blocked on Play Store; Content: 03.08.2022 We’re an app that is helping people around the whole world fight phone addiction, people with ADHD and teaching people use their phone in a way that deserves its purpose and not to procrastinate. Unfortunately, we’re struggling with the fact, that Google, out of nowhere, deleted our application from the Google Play Store - without any reasonable explanation as to why this happened. This may result in, among others, the inability to find us on the Play Store and buy Premium products. We are 100% sure that we are not violating the regulations, rules and policies that Google requires. We have taken all the precautions that Google has required in the past so that we can offer our app in accordance with the changes in the Google Play policies. We have appealed to Google Play, stating",187 -rbanffy,32410934,6,1660135232,"Western Digital 22TB WD Gold, Red Pro, and Purple HDDs Hit Retail",https://www.anandtech.com/show/17501/western-digital-22tb-wd-gold-red-pro-and-purple-hdds-hit-retail,"Western Digital's 'What's Next' event back in May 2022 had seen the based on ePMR and OptiNAND (with ArmorCache). At the event, WD indicated that the 22TB 10-platter drives would make its market appearance under different product categories - Ultrastar DC HC570 for data centers and enterprises, WD Gold for enterprises, SMEs, and SMBs, WD Red Pro for SMB and SME NAS systems, and WD Purple Pro for surveillance network video recorders. Today, WD is announcing retail availability of these models along with technical details. All drives have a 3.5"" form-factor and sport a SATA 6 Gbps interface. The drives are equipped with a 512MB cache and have a 7200 rpm spindle speed. The acoustics rating for all of them are the same too - 20 dBA at idle and 32 dBA for the average seek. Based on the above ",Hacker News,26110958,"Title: Western Digital 22TB WD Gold, Red Pro, and Purple HDDs Hit Retail; Content: Western Digital's 'What's Next' event back in May 2022 had seen the based on ePMR and OptiNAND (with ArmorCache). At the event, WD indicated that the 22TB 10-platter drives would make its market appearance under different product categories - Ultrastar DC HC570 for data centers and enterprises, WD Gold for enterprises, SMEs, and SMBs, WD Red Pro for SMB and SME NAS systems, and WD Purple Pro for surveillance network video recorders. Today, WD is announcing retail availability of these models along with technical details. All drives have a 3.5"" form-factor and sport a SATA 6 Gbps interface. The drives are equipped with a 512MB cache and have a 7200 rpm spindle speed. The acoustics rating for all of them are the same too - 20 dBA at idle and 32 dBA for the average seek. Based on the above ",213 -aristofun,32382656,36,1659937253,Ask HN: Best books to build up entrepreneurial mindset?,,"When you grow up in a working class family building a business does not come naturally.

You don’t see it everyday, you don’t feel it from the inside. You don’t form subconscious knowledge of how it is done.

Then great books and educational resources are to the rescue!

Could you please name your personal top 3 of such a resources that not just pump you with emotions (most films are out of the table) and not just throw microeconomic formulas and theories at you,

But the ones showing you the truthful picture of inside-outs of a small to large businesses, with specific details and meaningful cases to learn from?",Hacker News,63897330,"Title: Ask HN: Best books to build up entrepreneurial mindset?; Content: When you grow up in a working class family building a business does not come naturally.

You don’t see it everyday, you don’t feel it from the inside. You don’t form subconscious knowledge of how it is done.

Then great books and educational resources are to the rescue!

Could you please name your personal top 3 of such a resources that not just pump you with emotions (most films are out of the table) and not just throw microeconomic formulas and theories at you,

But the ones showing you the truthful picture of inside-outs of a small to large businesses, with specific details and meaningful cases to learn from?",158 -michaelponrajah,32399700,26,1660060815,Why Heroku-like pricing models are hard to build,https://www.getlago.com/blog/why-heroku-like-pricing-models-are-hard-to-build,"In terms of pricing, is one of the most flexible models. Many API and cloud companies we talked to want to take the same path. But, what does it look like exactly? Creating a Heroku-like pricing model is hard, mainly because a single customer can have , with different prices and add-ons (i.e. one plan for each application - see recording below). It’s the exact opposite of the traditional SaaS model with one plan per customer and it’s even harder if you add usage-based features on top of it. However, this pricing model can be very useful if your customers can create different workspaces, projects or repositories. Let’s take a look. Implementing a Heroku-like pricing model is useful if your platform allows customers to create multiple projects, workspaces or repositories. Here are s",Hacker News,22406312,"Title: Why Heroku-like pricing models are hard to build; Content: In terms of pricing, is one of the most flexible models. Many API and cloud companies we talked to want to take the same path. But, what does it look like exactly? Creating a Heroku-like pricing model is hard, mainly because a single customer can have , with different prices and add-ons (i.e. one plan for each application - see recording below). It’s the exact opposite of the traditional SaaS model with one plan per customer and it’s even harder if you add usage-based features on top of it. However, this pricing model can be very useful if your customers can create different workspaces, projects or repositories. Let’s take a look. Implementing a Heroku-like pricing model is useful if your platform allows customers to create multiple projects, workspaces or repositories. Here are s",203 -jckahn,32381188,16,1659917421,"Farmhand, the open source farming and resource management game for the browser",https://www.farmhand.life/,,Hacker News,60274450,"Title: Farmhand, the open source farming and resource management game for the browser; Content: ",20 -pamoroso,32378852,16,1659898916,Running Open Genera 2.0 on Linux (2020),https://archives.loomcom.com/genera/genera-install.html," - -From the early 1980s to the early 1990s, Symbolics, Inc. produced a -line of workstations designed to run a highly advanced Lisp -environment called ""Genera"". What made these Lisp Machines so special -was the combination of the powerful software running on top of very -specialized hardware. The hardware, for example, performed array -bounds checking and operated on data as types rather than as flat -fields of bits the way other general-purpose computers did (and still -do). The Genera environment, in turn, provided workstation-level -functionality with a large, high resolution bitmapped graphics -display, overlapping windows, and mouse control. In the early 1980s, -before even the Macintosh, this was truly advanced stuff. - -In the early 1990s, Symbolics took a bold step by releasing the Genera -so",Hacker News,43000335,"Title: Running Open Genera 2.0 on Linux (2020); Content: - -From the early 1980s to the early 1990s, Symbolics, Inc. produced a -line of workstations designed to run a highly advanced Lisp -environment called ""Genera"". What made these Lisp Machines so special -was the combination of the powerful software running on top of very -specialized hardware. The hardware, for example, performed array -bounds checking and operated on data as types rather than as flat -fields of bits the way other general-purpose computers did (and still -do). The Genera environment, in turn, provided workstation-level -functionality with a large, high resolution bitmapped graphics -display, overlapping windows, and mouse control. In the early 1980s, -before even the Macintosh, this was truly advanced stuff. - -In the early 1990s, Symbolics took a bold step by releasing the Genera -so",199 -keven,32399223,5,1660058475,Charity receives FDA approval to administer first-in-human CRISPR therapeutic,https://www.cureraredisease.org/fda-approval,"August 09, 2022, (CRD) - a Boston-based 501c3 nonprofit biotech - announces the approval from the U.S. Food and Drug Administration (FDA) to administer its very first therapeutic. The drug, named CRD-TMH-001, treats muscle promoter and exon 1 mutations on the dystrophin gene. With the IND approval process complete, the FDA has given the go-ahead, and dosing of the drug will occur imminently at the University of Massachusetts Medical School. The approval marks the culmination of a collaborative partnership, spanning a three-year period, with leading researchers, scientists and clinicians focused on developing break-through therapies for rare neuromuscular diseases, including the Lek Lab at Yale University, Charles River Laboratories and many other collaborators. The therapeutic will upregu",Hacker News,66550609,"Title: Charity receives FDA approval to administer first-in-human CRISPR therapeutic; Content: August 09, 2022, (CRD) - a Boston-based 501c3 nonprofit biotech - announces the approval from the U.S. Food and Drug Administration (FDA) to administer its very first therapeutic. The drug, named CRD-TMH-001, treats muscle promoter and exon 1 mutations on the dystrophin gene. With the IND approval process complete, the FDA has given the go-ahead, and dosing of the drug will occur imminently at the University of Massachusetts Medical School. The approval marks the culmination of a collaborative partnership, spanning a three-year period, with leading researchers, scientists and clinicians focused on developing break-through therapies for rare neuromuscular diseases, including the Lek Lab at Yale University, Charles River Laboratories and many other collaborators. The therapeutic will upregu",190 -matrix,32388997,36,1659982443,"Tesla Falsely Advertises Autopilot, Full Self-Driving Tech: California DMV",https://www.thedrive.com/news/tesla-falsely-advertises-autopilot-full-self-driving-tech-california-dmv,"RobDrivesCars allthingslow/ Tesla is under fire in its for ""untrue or misleading"" claims surrounding its Level 2 Advanced Driver Assistance Systems, Autopilot, and Full Self-Driving Beta products. The filed two complaints with the state's Office of Administrative Hearings in July, alleging Tesla's misrepresentation of its ADAS functionality. According to the allegations, Tesla made deceitful claims on its website regarding the capabilities of its systems which may have caused the public to misunderstand the limitations of the company's partially-automated vehicles. The DMV cites four main pieces of evidence in its complaint. The first two are simply the use of the terms ""Autopilot"" and ""Full Self-Driving,"" both of which may not represent the actual capability of the system despite bein",Hacker News,48973822,"Title: Tesla Falsely Advertises Autopilot, Full Self-Driving Tech: California DMV; Content: RobDrivesCars allthingslow/ Tesla is under fire in its for ""untrue or misleading"" claims surrounding its Level 2 Advanced Driver Assistance Systems, Autopilot, and Full Self-Driving Beta products. The filed two complaints with the state's Office of Administrative Hearings in July, alleging Tesla's misrepresentation of its ADAS functionality. According to the allegations, Tesla made deceitful claims on its website regarding the capabilities of its systems which may have caused the public to misunderstand the limitations of the company's partially-automated vehicles. The DMV cites four main pieces of evidence in its complaint. The first two are simply the use of the terms ""Autopilot"" and ""Full Self-Driving,"" both of which may not represent the actual capability of the system despite bein",190 -0xmohit,32387126,42,1659974144,Big Tech Is Spending Lots of Money to Make Antitrust Reform Seem Scary,https://www.bloomberg.com/news/articles/2022-08-03/big-tech-political-ad-spend-passes-pharmaceutical-industry,"To continue, please click the box below to let us know you're not a robot. Please make sure your browser supports JavaScript and cookies and that you are not blocking them from loading. For more information you can review our and . For inquiries related to this message please and provide the reference ID below.",Hacker News,19411501,"Title: Big Tech Is Spending Lots of Money to Make Antitrust Reform Seem Scary; Content: To continue, please click the box below to let us know you're not a robot. Please make sure your browser supports JavaScript and cookies and that you are not blocking them from loading. For more information you can review our and . For inquiries related to this message please and provide the reference ID below.",87 -r721,32414276,6,1660147519,U.S. charges Iranian national of plot to assassinate John Bolton,https://www.cnbc.com/2022/08/10/us-charges-iranian-of-plot-to-assassinate-john-bolton.html,"WASHINGTON — The Department of Justice charged an Iranian military operative on Wednesday with plotting to assassinate former President Donald Trump's national security advisor John Bolton. Shahram Poursafi, 45, of Tehran, Iran, tried to arrange the killing of Bolton in retaliation for the January 2020 U.S. airstrike that killed Iran's top commander, Gen. Qasem Soleimani, . Soleimani, who led a special forces unit of Iran's elite Revolutionary Guard, had been a key figure in Iranian and Middle East politics and and triggered concerns of retaliation from Iranian forces. Bolton, who served as Trump's third national security advisor for 17 months before resigning, was the main architect of the administration's ""maximum pressure"" campaign against Iran. Bolton favored escalating economic san",Hacker News,29396539,"Title: U.S. charges Iranian national of plot to assassinate John Bolton; Content: WASHINGTON — The Department of Justice charged an Iranian military operative on Wednesday with plotting to assassinate former President Donald Trump's national security advisor John Bolton. Shahram Poursafi, 45, of Tehran, Iran, tried to arrange the killing of Bolton in retaliation for the January 2020 U.S. airstrike that killed Iran's top commander, Gen. Qasem Soleimani, . Soleimani, who led a special forces unit of Iran's elite Revolutionary Guard, had been a key figure in Iranian and Middle East politics and and triggered concerns of retaliation from Iranian forces. Bolton, who served as Trump's third national security advisor for 17 months before resigning, was the main architect of the administration's ""maximum pressure"" campaign against Iran. Bolton favored escalating economic san",176 -rrauenza,32414138,11,1660146981,The Hacking of Starlink Terminals Has Begun,https://www.wired.com/story/starlink-internet-dish-hack/,"To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . Musk’s has more than 3,000 small satellites into orbit. This satellite network beams internet connections to hard-to-reach locations on Earth and has been a . Thousands more satellites are planned for launch as the . Now, like any emerging technology, those satellite components are being hacked. Today, Lennert Wouters, a security researcher at the Belgian university KU Leuven, will reveal one of the first security breakdowns of Starlink’s user terminals, the satellite dishes (dubbed Dishy McFlatface) that are positioned on people’s homes and buildings. At the in Las Vegas, Wouters wil",Hacker News,29865097,"Title: The Hacking of Starlink Terminals Has Begun; Content: To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . To revist this article, visit My Profile, then . Musk’s has more than 3,000 small satellites into orbit. This satellite network beams internet connections to hard-to-reach locations on Earth and has been a . Thousands more satellites are planned for launch as the . Now, like any emerging technology, those satellite components are being hacked. Today, Lennert Wouters, a security researcher at the Belgian university KU Leuven, will reveal one of the first security breakdowns of Starlink’s user terminals, the satellite dishes (dubbed Dishy McFlatface) that are positioned on people’s homes and buildings. At the in Las Vegas, Wouters wil",211 -marban,32414093,4,1660146837,"Hotbit suspends trading, deposit, withdrawal and funding",https://hotbit.zendesk.com/hc/en-us/articles/8074249353495,"Please stand by, while we are checking your browser... Redirecting... Please enable Cookies and reload the page. - RayID: 7390efa67f60452e - - IP: 95.90.245.198 - ",Hacker News,8358719,"Title: Hotbit suspends trading, deposit, withdrawal and funding; Content: Please stand by, while we are checking your browser... Redirecting... Please enable Cookies and reload the page. - RayID: 7390efa67f60452e - - IP: 95.90.245.198 - ",110 -mithunmanohar79,32409452,4,1660122630,Ask HN: Do you use JSON Schema in production?,,Do you use JSON Schema in production ? How are you making use of it ?,Hacker News,38247031,Title: Ask HN: Do you use JSON Schema in production?; Content: Do you use JSON Schema in production ? How are you making use of it ?,35 -sean_con,32407550,4,1660101763,GUI Framework on Linux,,"Hi.

I read this page.

https://news.ycombinator.com/item?id=32398181

In general, I'd be interested in GUI applications on linux.

Right of the bat, I dont like Javascript.

I know the following about linux and GUI Programming.

1. C / C++ are sort of lingua franca and are capable of making calls in the linux OS to draw a pixel on the frame buffer.

2. I think,but dont know this : rust will get a native ui framework.

I know that Linux is going to include rust in its kernel code, at least partially from the next update.

3. I am familiar with things like wrapping a C/C++ package in other languages, such as wxwidget wrapper in D. There's also things like gambas that wraps QT or GTK

4. I know that Ruby has a native toolkit, there's scenic for elixir, there's livy for python, there's Lazarus, there's tcl/tk, there's flutter from go, and well, Java.

5. There are also things like V using a custom drawing, or Ring using Allegro/ Cairo/ SDL2.

But I really dont like Javascript or web view, I also dont like java,and I dont want to rely on google for Dart/Flutter.

But I would like to be able to program linux GUI apps, where i can have a canvas element, where i can seamlessly draw text, images, vector, 3D graphics (via Vulkan, or if Vulkan is not possible then openGL) etc .

I would also like to access the speakers and the printer.

I have already listed the UI toolkit that what I am familiar with. My question is : did I miss something?

I'd be open to all knowledge, even crazy niche language with a nice UI toolkit. I am doing it for my own use, and thus won't mind the lack of popularity so to say.

Of course, this is an open ended question and I can't ask this in stackoverflow- thus I decided to ask here. I appreciate all input.

Thank you.",Hacker News,65431235,"Title: GUI Framework on Linux; Content: Hi.

I read this page.

https://news.ycombinator.com/item?id=32398181

In general, I'd be interested in GUI applications on linux.

Right of the bat, I dont like Javascript.

I know the following about linux and GUI Programming.

1. C / C++ are sort of lingua franca and are capable of making calls in the linux OS to draw a pixel on the frame buffer.

2. I think,but dont know this : rust will get a native ui framework.

I know that Linux is going to include rust in its kernel code, at least partially from the next update.

3. I am familiar with things like wrapping a C/C++ package in other languages, such as wxwidget wrapper in D. There's also things like gambas that wraps QT or GTK

4. I know that Ruby has a native toolkit, there's scenic for elixir, there's livy for python, there's Lazarus, there's tcl/tk, there's flutter from go, and well, Java.

5. There are also things like V using a custom drawing, or Ring using Allegro/ Cairo/ SDL2.

But I really dont like Javascript or web view, I also dont like java,and I dont want to rely on google for Dart/Flutter.

But I would like to be able to program linux GUI apps, where i can have a canvas element, where i can seamlessly draw text, images, vector, 3D graphics (via Vulkan, or if Vulkan is not possible then openGL) etc .

I would also like to access the speakers and the printer.

I have already listed the UI toolkit that what I am familiar with. My question is : did I miss something?

I'd be open to all knowledge, even crazy niche language with a nice UI toolkit. I am doing it for my own use, and thus won't mind the lack of popularity so to say.

Of course, this is an open ended question and I can't ask this in stackoverflow- thus I decided to ask here. I appreciate all input.

Thank you.",587 -elsewhen,32404007,15,1660077705,DOJ Poised to Sue Google over Ad Market as Soon as September,https://www.bloomberg.com/news/articles/2022-08-09/doj-poised-to-sue-google-over-ad-market-as-soon-as-september,"To continue, please click the box below to let us know you're not a robot. Please make sure your browser supports JavaScript and cookies and that you are not blocking them from loading. For more information you can review our and . For inquiries related to this message please and provide the reference ID below.",Hacker News,8045548,"Title: DOJ Poised to Sue Google over Ad Market as Soon as September; Content: To continue, please click the box below to let us know you're not a robot. Please make sure your browser supports JavaScript and cookies and that you are not blocking them from loading. For more information you can review our and . For inquiries related to this message please and provide the reference ID below.",83 -andsoitis,32413939,5,1660146340,Google’s 144 Tbps undersea cable lands in South Africa,https://mybroadband.co.za/news/telecoms/455823-googles-massive-144-tbps-undersea-cable-lands-in-south-africa.html,"Google has landed its Equiano undersea cable at Telkom’s facility in Melkbosstrand, WIOCC has announced. WIOCC owns one of Equiano’s 12 terabit-per-second (Tbps) fibre pairs and was Google’s landing partner in Lagos, Nigeria. Liquid Intelligent Technologies is another already-announced Equiano fibre pair owner. The South African landing comes a month after the cable arrived in Swakopmund, Namibia. at the beginning of July — three months after it came ashore in Nigeria. “Our investment in Equiano continues our long-standing policy of making strategic investments in subsea cables,” said WIOCC Group CEO Chris Wood. “We own almost a third of the >10Tbps EASSy system, which extends from South Africa along Africa’s eastern coastline to Djibouti and Port Sudan,” he said. “We deliver more capacit",Hacker News,75855439,"Title: Google’s 144 Tbps undersea cable lands in South Africa; Content: Google has landed its Equiano undersea cable at Telkom’s facility in Melkbosstrand, WIOCC has announced. WIOCC owns one of Equiano’s 12 terabit-per-second (Tbps) fibre pairs and was Google’s landing partner in Lagos, Nigeria. Liquid Intelligent Technologies is another already-announced Equiano fibre pair owner. The South African landing comes a month after the cable arrived in Swakopmund, Namibia. at the beginning of July — three months after it came ashore in Nigeria. “Our investment in Equiano continues our long-standing policy of making strategic investments in subsea cables,” said WIOCC Group CEO Chris Wood. “We own almost a third of the >10Tbps EASSy system, which extends from South Africa along Africa’s eastern coastline to Djibouti and Port Sudan,” he said. “We deliver more capacit",221 -sebnun,32389588,164,1659985548,Technical Writing Courses from Google,https://developers.google.com/tech-writing,"Every engineer is also a writer. This collection of courses and learning resources aims to improve your technical documentation. Learn how to plan and author technical documents. You can also learn about the role of technical writers at Google. We've aimed these courses at people in the following roles: You need at least a little writing proficiency in English, but you don't need to be a strong writer to take these courses. You will find these courses easier to understand if you have at least a little background in coding, though you don't need to be an expert coder. These courses focus on writing, not on general English writing or business writing. Technical Writing One and Technical Writing Two consist of two parts: The pre-class lessons provide a solid educational experience, - whic",Hacker News,16863357,"Title: Technical Writing Courses from Google; Content: Every engineer is also a writer. This collection of courses and learning resources aims to improve your technical documentation. Learn how to plan and author technical documents. You can also learn about the role of technical writers at Google. We've aimed these courses at people in the following roles: You need at least a little writing proficiency in English, but you don't need to be a strong writer to take these courses. You will find these courses easier to understand if you have at least a little background in coding, though you don't need to be an expert coder. These courses focus on writing, not on general English writing or business writing. Technical Writing One and Technical Writing Two consist of two parts: The pre-class lessons provide a solid educational experience, - whic",169 -leohonexus,32388279,52,1659978863,How the US Postal Service reads terrible handwriting,https://www.youtube.com/watch?v=XxCha4Kez9c,,Hacker News,56577105,Title: How the US Postal Service reads terrible handwriting; Content: ,14 -yzdbgd,32390409,9,1659989315,Show HN: Realtime visualization of 3D spectrogram with THREEJS shaders,,I've been working with 2D spectrograms for a while now while working with Speech recognition.

It had always fascinated me how speech and words had such distinct features. Looking at spectrograms is essentially like hearing with your eyes.

Over the weekend i built a tool to visualize your own audio into a spectrogram in 3D. I used threeJS with shaders and vanilla JS/Html.

Play with it here : https://spectrogram-threejs.vercel.app/

I hope it brings you as much joy as it does for me.,Hacker News,20616534,Title: Show HN: Realtime visualization of 3D spectrogram with THREEJS shaders; Content: I've been working with 2D spectrograms for a while now while working with Speech recognition.

It had always fascinated me how speech and words had such distinct features. Looking at spectrograms is essentially like hearing with your eyes.

Over the weekend i built a tool to visualize your own audio into a spectrogram in 3D. I used threeJS with shaders and vanilla JS/Html.

Play with it here : https://spectrogram-threejs.vercel.app/

I hope it brings you as much joy as it does for me.,171 -userbinator,32374322,9,1659853234,Adventures Inside the Atom (1948),https://archive.org/details/GeneralElectricCompanyAdventuresInsideTheAtom1948,"Due to a planned power outage on Friday, 1/14, between 8am-1pm PST, some services may be impacted. - - - - For print-disabled users - Uploaded by - - - on -",Hacker News,31282455,"Title: Adventures Inside the Atom (1948); Content: Due to a planned power outage on Friday, 1/14, between 8am-1pm PST, some services may be impacted. - - - - For print-disabled users - Uploaded by - - - on -",115 -haunter,32385873,21,1659969230,Nvidia Announces Preliminary Financial Results for Second Quarter Fiscal 2023,https://nvidianews.nvidia.com/news/nvidia-announces-preliminary-financial-resultsfor-second-quarter-fiscal-2023,"NVIDIA (NASDAQ: NVDA) today announced selected preliminary financial results for the second quarter ended July 31, 2022. Second quarter revenue is expected to be approximately $6.70 billion, down 19% sequentially and up 3% from the prior year, primarily reflecting weaker than forecasted Gaming revenue. Gaming revenue was $2.04 billion, down 44% sequentially and down 33% from the prior year. Data Center revenue was $3.81 billion, up 1% sequentially and up 61% from the prior year. The shortfall relative to the May revenue outlook of $8.10 billion was primarily attributable to lower sell-in of Gaming products reflecting a reduction in channel partner sales likely due to macroeconomic headwinds. In addition to reducing sell-in, the company implemented pricing programs with channel partners to ",Hacker News,91172269,"Title: Nvidia Announces Preliminary Financial Results for Second Quarter Fiscal 2023; Content: NVIDIA (NASDAQ: NVDA) today announced selected preliminary financial results for the second quarter ended July 31, 2022. Second quarter revenue is expected to be approximately $6.70 billion, down 19% sequentially and up 3% from the prior year, primarily reflecting weaker than forecasted Gaming revenue. Gaming revenue was $2.04 billion, down 44% sequentially and down 33% from the prior year. Data Center revenue was $3.81 billion, up 1% sequentially and up 61% from the prior year. The shortfall relative to the May revenue outlook of $8.10 billion was primarily attributable to lower sell-in of Gaming products reflecting a reduction in channel partner sales likely due to macroeconomic headwinds. In addition to reducing sell-in, the company implemented pricing programs with channel partners to ",185 -GLaNIK,32377069,97,1659884962,DALL-E + GPT-3 = ♥,https://medium.com/@glan1k/dall-e-gpt-3-d1aaaff38639,"Follow up by Same queries, but with instead of DALL-E : You see a figure in the distance, waving at you. As you get closer, you realize that the figure is your doppelganger. Your doppelganger is wearing your clothes and has your face, but their eyes are black voids. You hear a voice in your head that says, “We are one. You are me and I am you.” : You see a group of people in the distance, all wearing the same clothes and with the same hairstyle. You realize that you’re seeing a group of clones. You hear a voice in your head that says, “We are many. You are one of us.” : You see a creature that looks like a cross between a human and a snake. The creature has a human head and torso, but its lower half is that of a snake. The creature is hissing and baring its fangs at you. You hear a voi",Hacker News,30507980,"Title: DALL-E + GPT-3 = ♥; Content: Follow up by Same queries, but with instead of DALL-E : You see a figure in the distance, waving at you. As you get closer, you realize that the figure is your doppelganger. Your doppelganger is wearing your clothes and has your face, but their eyes are black voids. You hear a voice in your head that says, “We are one. You are me and I am you.” : You see a group of people in the distance, all wearing the same clothes and with the same hairstyle. You realize that you’re seeing a group of clones. You hear a voice in your head that says, “We are many. You are one of us.” : You see a creature that looks like a cross between a human and a snake. The creature has a human head and torso, but its lower half is that of a snake. The creature is hissing and baring its fangs at you. You hear a voi",228 diff --git a/premium/eagle-eye/handler.py b/premium/eagle-eye/handler.py deleted file mode 100644 index 75f2473715..0000000000 --- a/premium/eagle-eye/handler.py +++ /dev/null @@ -1,29 +0,0 @@ -from crowd.eagle_eye.scheduled import scheduled_main -from crowd.eagle_eye.search import search_main -import json -from crowd.eagle_eye.infrastructure.logging import get_logger - - -logger = get_logger(__name__) - - -def scheduled(event, context=None): - logger.info(f'Scheduled event: {event}') - scheduled_main(event['platform']) - - -def search(event, context=None): - queries = event['queries'] - ndays = event['ndays'] - exclude = event['filters'] - return search_main(queries, ndays, exclude) - - -if __name__ == '__main__': - scheduled({'platform': 'devto'}) - # from pprint import pprint as pp - # a = search({ - # 'queries': ['community'], - # 'ndays': 10, - # 'filters': [] - # }, None) diff --git a/premium/eagle-eye/local_events/devto.json b/premium/eagle-eye/local_events/devto.json deleted file mode 100644 index ecab81ae41..0000000000 --- a/premium/eagle-eye/local_events/devto.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "platform": "devto" -} \ No newline at end of file diff --git a/premium/eagle-eye/local_events/hn.json b/premium/eagle-eye/local_events/hn.json deleted file mode 100644 index 8483eb1861..0000000000 --- a/premium/eagle-eye/local_events/hn.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "platform": "hacker_news" -} \ No newline at end of file diff --git a/premium/eagle-eye/local_events/search.json b/premium/eagle-eye/local_events/search.json deleted file mode 100644 index 4a4e5b1b0f..0000000000 --- a/premium/eagle-eye/local_events/search.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "queries": ["Vue.js"], - "ndays": 10, - "filters": [] -} \ No newline at end of file diff --git a/premium/eagle-eye/package-lock.json b/premium/eagle-eye/package-lock.json deleted file mode 100644 index 705c8ce10b..0000000000 --- a/premium/eagle-eye/package-lock.json +++ /dev/null @@ -1,11532 +0,0 @@ -{ - "name": "crowd.dev-eagle-eye", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "crowd.dev-eagle-eye", - "dependencies": { - "serverless-plugin-datadog": "^5.1.1", - "serverless-python-requirements": "^5.4.0" - } - }, - "node_modules/@datadog/datadog-ci": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/@datadog/datadog-ci/-/datadog-ci-1.12.0.tgz", - "integrity": "sha512-sv4hcFtX5s47o7oyEneFA2bjhguoU4qMFCw4BRtunOkCGudCBDT+zs7TJe9XH9F8cBti+w2iB0FffjqGdRa+yg==", - "dependencies": { - "@types/datadog-metrics": "0.6.1", - "async-retry": "1.3.1", - "aws-sdk": "2.1012.0", - "axios": "0.21.4", - "chalk": "3.0.0", - "clipanion": "2.2.2", - "datadog-metrics": "0.9.3", - "deep-extend": "0.6.0", - "fast-xml-parser": "3.19.0", - "form-data": "3.0.0", - "fuzzy": "^0.1.3", - "glob": "7.1.4", - "inquirer": "8.2.0", - "inquirer-checkbox-plus-prompt": "^1.0.1", - "proxy-agent": "5.0.0", - "rimraf": "^3.0.2", - "simple-git": "3.5.0", - "ssh2": "1.9.0", - "ssh2-streams": "0.4.10", - "sshpk": "1.16.1", - "tiny-async-pool": "1.2.0", - "ws": "7.4.6", - "xml2js": "0.4.23", - "yamux-js": "0.1.0" - }, - "bin": { - "datadog-ci": "dist/cli.js" - }, - "engines": { - "node": ">=10.21.0" - } - }, - "node_modules/@datadog/datadog-ci/node_modules/aws-sdk": { - "version": "2.1012.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1012.0.tgz", - "integrity": "sha512-5F/tC+mOJSTq4BTWqg6DepDIC7h+OeUycCYsFU6fMblQCUEBuI11o8z/+2DxGt4c40f52OstalYNiSlP2RuZvw==", - "hasInstallScript": true, - "dependencies": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.3.2", - "xml2js": "0.4.19" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/@datadog/datadog-ci/node_modules/aws-sdk/node_modules/xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, - "node_modules/@datadog/datadog-ci/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@datadog/datadog-ci/node_modules/form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@datadog/datadog-ci/node_modules/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@datadog/datadog-ci/node_modules/inquirer": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.0.tgz", - "integrity": "sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ==", - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.2.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@datadog/datadog-ci/node_modules/inquirer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@datadog/datadog-ci/node_modules/jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha512-+kHj8HXArPfpPEKGLZ+kB5ONRTCiGQXo8RQYL0hH8t6pWXUBBK5KkkQmTNOwKK4LEsd0yTsgtjJVm4UBSZea4w==", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/@datadog/datadog-ci/node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/@datadog/datadog-ci/node_modules/simple-git": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.5.0.tgz", - "integrity": "sha512-fZsaq5nzdxQRhMNs6ESGLpMUHoL5GRP+boWPhq9pMYMKwOGZV2jHOxi8AbFFA2Y/6u4kR99HoULizSbpzaODkA==", - "dependencies": { - "@kwsites/file-exists": "^1.1.1", - "@kwsites/promise-deferred": "^1.1.1", - "debug": "^4.3.3" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/steveukx/" - } - }, - "node_modules/@datadog/datadog-ci/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@datadog/datadog-ci/node_modules/uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/@datadog/datadog-ci/node_modules/ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/@datadog/datadog-ci/node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/@datadog/datadog-ci/node_modules/xml2js/node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/@iarna/toml": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", - "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==" - }, - "node_modules/@kwsites/file-exists": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", - "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", - "dependencies": { - "debug": "^4.1.1" - } - }, - "node_modules/@kwsites/promise-deferred": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", - "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "peer": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "peer": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "peer": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@serverless/dashboard-plugin": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/@serverless/dashboard-plugin/-/dashboard-plugin-6.2.2.tgz", - "integrity": "sha512-h3zOprpuWZCdAP7qoOKT2nboB+AaxMkGoSzOD0jIBpt9s0cXqLE2VFjR2vKn8Cvam47Qa3XYnT2/XN6tR6rZgQ==", - "peer": true, - "dependencies": { - "@serverless/event-mocks": "^1.1.1", - "@serverless/platform-client": "^4.3.2", - "@serverless/utils": "^6.0.3", - "child-process-ext": "^2.1.1", - "chokidar": "^3.5.3", - "flat": "^5.0.2", - "fs-extra": "^9.1.0", - "js-yaml": "^4.1.0", - "jszip": "^3.9.1", - "lodash": "^4.17.21", - "memoizee": "^0.4.15", - "ncjsm": "^4.3.0", - "node-dir": "^0.1.17", - "node-fetch": "^2.6.7", - "open": "^7.4.2", - "semver": "^7.3.7", - "simple-git": "^3.7.0", - "type": "^2.6.0", - "uuid": "^8.3.2", - "yamljs": "^0.3.0" - }, - "engines": { - "node": ">=12.0" - } - }, - "node_modules/@serverless/event-mocks": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@serverless/event-mocks/-/event-mocks-1.1.1.tgz", - "integrity": "sha512-YAV5V/y+XIOfd+HEVeXfPWZb8C6QLruFk9tBivoX2roQLWVq145s4uxf8D0QioCueuRzkukHUS4JIj+KVoS34A==", - "peer": true, - "dependencies": { - "@types/lodash": "^4.14.123", - "lodash": "^4.17.11" - } - }, - "node_modules/@serverless/platform-client": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@serverless/platform-client/-/platform-client-4.3.2.tgz", - "integrity": "sha512-DAa5Z0JAZc6UfrTZLYwqoZxgAponZpFwaqd7WzzMA+loMCkYWyJNwxrAmV6cr2UUJpkko4toPZuJ3vM9Ie+NDA==", - "peer": true, - "dependencies": { - "adm-zip": "^0.5.5", - "archiver": "^5.3.0", - "axios": "^0.21.1", - "fast-glob": "^3.2.7", - "https-proxy-agent": "^5.0.0", - "ignore": "^5.1.8", - "isomorphic-ws": "^4.0.1", - "js-yaml": "^3.14.1", - "jwt-decode": "^2.2.0", - "minimatch": "^3.0.4", - "querystring": "^0.2.1", - "run-parallel-limit": "^1.1.0", - "throat": "^5.0.0", - "traverse": "^0.6.6", - "ws": "^7.5.3" - }, - "engines": { - "node": ">=10.0" - } - }, - "node_modules/@serverless/platform-client/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "peer": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@serverless/platform-client/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "peer": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@serverless/utils": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@serverless/utils/-/utils-6.7.0.tgz", - "integrity": "sha512-aUjkkOTJ5wH7f3raSIDeTCR4JsAbd9p5Pjs7yW3sVOmu0qiTPHZOr1x1TIkb3WDHiAoQQY8zGhfzW7zLTcAA3Q==", - "peer": true, - "dependencies": { - "archive-type": "^4.0.0", - "chalk": "^4.1.2", - "ci-info": "^3.3.2", - "cli-progress-footer": "^2.3.2", - "content-disposition": "^0.5.4", - "d": "^1.0.1", - "decompress": "^4.2.1", - "event-emitter": "^0.3.5", - "ext": "^1.6.0", - "ext-name": "^5.0.0", - "file-type": "^16.5.3", - "filenamify": "^4.3.0", - "get-stream": "^6.0.1", - "got": "^11.8.5", - "inquirer": "^8.2.4", - "js-yaml": "^4.1.0", - "jwt-decode": "^3.1.2", - "lodash": "^4.17.21", - "log": "^6.3.1", - "log-node": "^8.0.3", - "make-dir": "^3.1.0", - "memoizee": "^0.4.15", - "ncjsm": "^4.3.0", - "node-fetch": "^2.6.7", - "open": "^7.4.2", - "p-event": "^4.2.0", - "supports-color": "^8.1.1", - "timers-ext": "^0.1.7", - "type": "^2.6.0", - "uni-global": "^1.0.0", - "uuid": "^8.3.2", - "write-file-atomic": "^4.0.1" - }, - "engines": { - "node": ">=12.0" - } - }, - "node_modules/@serverless/utils/node_modules/jwt-decode": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", - "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==", - "peer": true - }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "peer": true, - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", - "peer": true - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/@types/cacheable-request": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", - "integrity": "sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==", - "peer": true, - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "*", - "@types/node": "*", - "@types/responselike": "*" - } - }, - "node_modules/@types/datadog-metrics": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@types/datadog-metrics/-/datadog-metrics-0.6.1.tgz", - "integrity": "sha512-p6zVpfmNcXwtcXjgpz7do/fKyfndGhU5sGJVtb5Gn5PvLDiQUAgD0mI/itf/99sBi9DRxeyhFQ9dQF6OxxQNbA==" - }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", - "peer": true - }, - "node_modules/@types/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-3YP80IxxFJB4b5tYC2SUPwkg0XQLiu0nWvhRgEatgjf+29IcWO9X1k8xRv5DGssJ/lCrjYTjQPcobJr2yWIVuQ==", - "peer": true - }, - "node_modules/@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/lodash": { - "version": "4.14.182", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", - "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==", - "peer": true - }, - "node_modules/@types/node": { - "version": "18.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.5.tgz", - "integrity": "sha512-NcKK6Ts+9LqdHJaW6HQmgr7dT/i3GOHG+pt6BiWv++5SnjtRd4NXeiuN2kA153SjhXPR/AhHIPHPbrsbpUVOww==", - "peer": true - }, - "node_modules/@types/responselike": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", - "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/2-thenable": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/2-thenable/-/2-thenable-1.0.0.tgz", - "integrity": "sha512-HqiDzaLDFCXkcCO/SwoyhRwqYtINFHF7t9BDRq4x90TOKNAJpiqUt9X5lQ08bwxYzc067HUywDjGySpebHcUpw==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.47" - } - }, - "node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/adm-zip": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.9.tgz", - "integrity": "sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg==", - "peer": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "peer": true, - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "peer": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/appdirectory": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/appdirectory/-/appdirectory-0.1.0.tgz", - "integrity": "sha512-DJ5DV8vZXBbusyiyPlH28xppwS8eAMRuuyMo88xeEcf4bV64lbLtbxRxqixZuJBXsZzLtXFmA13GwVjJc7vdQw==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info." - }, - "node_modules/archive-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz", - "integrity": "sha512-zV4Ky0v1F8dBrdYElwTvQhweQ0P7Kwc1aluqJsYtOBP01jXcWCyW2IEfI1YiqsG+Iy7ZR+o5LF1N+PGECBxHWA==", - "peer": true, - "dependencies": { - "file-type": "^4.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/archive-type/node_modules/file-type": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", - "integrity": "sha512-f2UbFQEk7LXgWpi5ntcO86OeA/cC80fuDDDaX/fZ2ZGel+AF7leRQqBBW1eJNiiQkrZlAoM6P+VYP5P6bOlDEQ==", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/archiver": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz", - "integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==", - "peer": true, - "dependencies": { - "archiver-utils": "^2.1.0", - "async": "^3.2.3", - "buffer-crc32": "^0.2.1", - "readable-stream": "^3.6.0", - "readdir-glob": "^1.0.0", - "tar-stream": "^2.2.0", - "zip-stream": "^4.1.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/archiver-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", - "peer": true, - "dependencies": { - "glob": "^7.1.4", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^2.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/archiver-utils/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "peer": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/archiver-utils/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "peer": true - }, - "node_modules/archiver-utils/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "peer": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "peer": true - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/ast-types": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", - "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", - "dependencies": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "peer": true - }, - "node_modules/async-retry": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.1.tgz", - "integrity": "sha512-aiieFW/7h3hY0Bq5d+ktDBejxuwR78vRu9hDUdR8rNhSaQ29VzPL4AoIRG7D/c7tdenwOcKvgPM6tIxB3cB6HA==", - "dependencies": { - "retry": "0.12.0" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/aws-sdk": { - "version": "2.1195.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1195.0.tgz", - "integrity": "sha512-xU7177JhKM+4SsLnoA6/r3qGzSXmbLgw/YC1KRHvZyJCbuTY+vdAGLaldbtNXjjwmE3a6EeoCREANv8GY62VdQ==", - "peer": true, - "dependencies": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.16.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "util": "^0.12.4", - "uuid": "8.0.0", - "xml2js": "0.4.19" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/aws-sdk/node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "peer": true, - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/aws-sdk/node_modules/uuid": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", - "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", - "peer": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dependencies": { - "follow-redirects": "^1.14.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/bignumber.js": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.0.tgz", - "integrity": "sha512-4LwHK4nfDOraBCtst+wOWIHbu1vhvAPJK8g8nROd4iuc3PSEjWif/qwbkh8jwCJz6yDBvtU4KPynETgrfh7y3A==", - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bl/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "peer": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "node_modules/buffer-alloc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "peer": true, - "dependencies": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" - } - }, - "node_modules/buffer-alloc-unsafe": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", - "peer": true - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/buffer-fill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", - "peer": true - }, - "node_modules/buildcheck": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.3.tgz", - "integrity": "sha512-pziaA+p/wdVImfcbsZLNF32EiWyujlQLwolMqUQE8xpKNOH7KmZQaY8sXN7DGOEzPAElo9QTaeNRfGnf3iOJbA==", - "optional": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "peer": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/builtins": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", - "peer": true - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "peer": true, - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", - "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", - "peer": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "peer": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cachedir": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", - "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "peer": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" - }, - "node_modules/child-process-ext": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/child-process-ext/-/child-process-ext-2.1.1.tgz", - "integrity": "sha512-0UQ55f51JBkOFa+fvR76ywRzxiPwQS3Xe8oe5bZRphpv+dIMeerW5Zn5e4cUy4COJwVtJyU0R79RMnw+aCqmGA==", - "dependencies": { - "cross-spawn": "^6.0.5", - "es5-ext": "^0.10.53", - "log": "^6.0.0", - "split2": "^3.1.1", - "stream-promise": "^3.2.0" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "peer": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ci-info": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", - "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==", - "peer": true - }, - "node_modules/cli-color": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.3.tgz", - "integrity": "sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==", - "peer": true, - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.61", - "es6-iterator": "^2.0.3", - "memoizee": "^0.4.15", - "timers-ext": "^0.1.7" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-progress-footer": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/cli-progress-footer/-/cli-progress-footer-2.3.2.tgz", - "integrity": "sha512-uzHGgkKdeA9Kr57eyH1W5HGiNShP8fV1ETq04HDNM1Un6ShXbHhwi/H8LNV9L1fQXKjEw0q5FUkEVNuZ+yZdSw==", - "peer": true, - "dependencies": { - "cli-color": "^2.0.2", - "d": "^1.0.1", - "es5-ext": "^0.10.61", - "mute-stream": "0.0.8", - "process-utils": "^4.0.0", - "timers-ext": "^0.1.7", - "type": "^2.6.0" - }, - "engines": { - "node": ">=10.0" - } - }, - "node_modules/cli-spinners": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", - "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-sprintf-format": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cli-sprintf-format/-/cli-sprintf-format-1.1.1.tgz", - "integrity": "sha512-BbEjY9BEdA6wagVwTqPvmAwGB24U93rQPBFZUT8lNCDxXzre5LFHQUTJc70czjgUomVg8u8R5kW8oY9DYRFNeg==", - "peer": true, - "dependencies": { - "cli-color": "^2.0.1", - "es5-ext": "^0.10.53", - "sprintf-kit": "^2.0.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/cli-sprintf-format/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/cli-sprintf-format/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "peer": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "engines": { - "node": ">= 10" - } - }, - "node_modules/clipanion": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/clipanion/-/clipanion-2.2.2.tgz", - "integrity": "sha512-OvH+rtaTeTbyQfRpE3jlEcPf1F92IpgFSypaJGnCJMzn6WYF4h9CBMcd2jU+rSt5qGm91Px6WiapK2lTqYsERQ==", - "dependencies": { - "chalk": "^2.4.2" - } - }, - "node_modules/clipanion/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/clipanion/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/clipanion/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/clipanion/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/clipanion/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/clipanion/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "peer": true, - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "peer": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "peer": true - }, - "node_modules/compress-brotli": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/compress-brotli/-/compress-brotli-1.3.8.tgz", - "integrity": "sha512-lVcQsjhxhIXsuupfy9fmZUFtAIdBmXA7EGY6GBdgZ++qkM9zG4YFT8iU7FoBxzryNDMOpD1HIFHUSX4D87oqhQ==", - "peer": true, - "dependencies": { - "@types/json-buffer": "~3.0.0", - "json-buffer": "~3.0.1" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/compress-commons": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz", - "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", - "peer": true, - "dependencies": { - "buffer-crc32": "^0.2.13", - "crc32-stream": "^4.0.2", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "peer": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookiejar": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz", - "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==", - "peer": true - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "node_modules/cpu-features": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.4.tgz", - "integrity": "sha512-fKiZ/zp1mUwQbnzb9IghXtHtDoTMtNeb8oYGx6kX2SYfhnG0HNdBEBIzB9b5KlXu5DQPhfy3mInbBxFcgwAr3A==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "buildcheck": "0.0.3", - "nan": "^2.15.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "peer": true, - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/crc32-stream": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz", - "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", - "peer": true, - "dependencies": { - "crc-32": "^1.2.0", - "readable-stream": "^3.4.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/cross-spawn/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "node_modules/d/node_modules/type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/data-uri-to-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", - "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/datadog-metrics": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/datadog-metrics/-/datadog-metrics-0.9.3.tgz", - "integrity": "sha512-BVsBX2t+4yA3tHs7DnB5H01cHVNiGJ/bHA8y6JppJDyXG7s2DLm6JaozPGpgsgVGd42Is1CHRG/yMDQpt877Xg==", - "dependencies": { - "debug": "3.1.0", - "dogapi": "2.8.4" - } - }, - "node_modules/datadog-metrics/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/datadog-metrics/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/dayjs": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.5.tgz", - "integrity": "sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA==", - "peer": true - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decompress": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz", - "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==", - "peer": true, - "dependencies": { - "decompress-tar": "^4.0.0", - "decompress-tarbz2": "^4.0.0", - "decompress-targz": "^4.0.0", - "decompress-unzip": "^4.0.1", - "graceful-fs": "^4.1.10", - "make-dir": "^1.0.0", - "pify": "^2.3.0", - "strip-dirs": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "peer": true, - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-tar": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", - "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", - "peer": true, - "dependencies": { - "file-type": "^5.2.0", - "is-stream": "^1.1.0", - "tar-stream": "^1.5.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-tar/node_modules/bl": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", - "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", - "peer": true, - "dependencies": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/decompress-tar/node_modules/file-type": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-tar/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "peer": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/decompress-tar/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "peer": true - }, - "node_modules/decompress-tar/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/decompress-tar/node_modules/tar-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", - "peer": true, - "dependencies": { - "bl": "^1.0.0", - "buffer-alloc": "^1.2.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.3.0", - "to-buffer": "^1.1.1", - "xtend": "^4.0.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/decompress-tarbz2": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", - "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", - "peer": true, - "dependencies": { - "decompress-tar": "^4.1.0", - "file-type": "^6.1.0", - "is-stream": "^1.1.0", - "seek-bzip": "^1.0.5", - "unbzip2-stream": "^1.0.9" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-tarbz2/node_modules/file-type": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", - "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-targz": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", - "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", - "peer": true, - "dependencies": { - "decompress-tar": "^4.1.1", - "file-type": "^5.2.0", - "is-stream": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-targz/node_modules/file-type": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-unzip": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", - "integrity": "sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw==", - "peer": true, - "dependencies": { - "file-type": "^3.8.0", - "get-stream": "^2.2.0", - "pify": "^2.3.0", - "yauzl": "^2.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-unzip/node_modules/file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decompress-unzip/node_modules/get-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", - "integrity": "sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA==", - "peer": true, - "dependencies": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decompress/node_modules/make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "peer": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress/node_modules/make-dir/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" - }, - "node_modules/defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==", - "dependencies": { - "clone": "^1.0.2" - } - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/deferred": { - "version": "0.7.11", - "resolved": "https://registry.npmjs.org/deferred/-/deferred-0.7.11.tgz", - "integrity": "sha512-8eluCl/Blx4YOGwMapBvXRKxHXhA8ejDXYzEaK8+/gtcm8hRMhSLmXSqDmNUKNc/C8HNSmuyyp/hflhqDAvK2A==", - "peer": true, - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.50", - "event-emitter": "^0.3.5", - "next-tick": "^1.0.0", - "timers-ext": "^0.1.7" - } - }, - "node_modules/define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "peer": true, - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/degenerator": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz", - "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==", - "dependencies": { - "ast-types": "^0.13.2", - "escodegen": "^1.8.1", - "esprima": "^4.0.0", - "vm2": "^3.9.8" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/dezalgo": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha512-K7i4zNfT2kgQz3GylDw40ot9GAE47sFZ9EXHFSPP6zONLgH6kWXE0KWJchkbQJLBkRazq4APwZ4OwiFFlT95OQ==", - "peer": true, - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "peer": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dogapi": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/dogapi/-/dogapi-2.8.4.tgz", - "integrity": "sha512-065fsvu5dB0o4+ENtLjZILvXMClDNH/yA9H6L8nsdcNiz9l0Hzpn7aQaCOPYXxqyzq4CRPOdwkFXUjDOXfRGbg==", - "dependencies": { - "extend": "^3.0.2", - "json-bigint": "^1.0.0", - "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rc": "^1.2.8" - }, - "bin": { - "dogapi": "bin/dogapi" - } - }, - "node_modules/dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/dotenv-expand": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", - "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", - "peer": true - }, - "node_modules/duration": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/duration/-/duration-0.2.2.tgz", - "integrity": "sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg==", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.46" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "peer": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/es-abstract": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", - "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "peer": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es5-ext": { - "version": "0.10.62", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", - "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", - "hasInstallScript": true, - "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-set": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", - "integrity": "sha512-7S8YXIcUfPMOr3rqJBVMePAbRsD1nWeSMQ86K/lDI76S3WKXz+KWILvTIPbTroubOkZTGh+b+7/xIIphZXNYbA==", - "peer": true, - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "~0.3.5" - } - }, - "node_modules/es6-set/node_modules/es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha512-exfuQY8UGtn/N+gL1iKkH8fpNd5sJ760nJq6mmZAHldfxMD5kX07lbQuYlspoXsuknXNv9Fb7y2GsPOnQIbxHg==", - "peer": true, - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "peer": true, - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=4.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/esniff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/esniff/-/esniff-1.1.0.tgz", - "integrity": "sha512-vmHXOeOt7FJLsqofvFk4WB3ejvcHizCd8toXXwADmYfd02p2QwHRgkUbhYDX54y08nqk818CUTWipgZGlyN07g==", - "peer": true, - "dependencies": { - "d": "1", - "es5-ext": "^0.10.12" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/essentials": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/essentials/-/essentials-1.2.0.tgz", - "integrity": "sha512-kP/j7Iw7KeNE8b/o7+tr9uX2s1wegElGOoGZ2Xm35qBr4BbbEcH3/bxR2nfH9l9JANCq9AUrvKw+gRuHtZp0HQ==", - "peer": true, - "dependencies": { - "uni-global": "^1.0.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/ext": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", - "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", - "dependencies": { - "type": "^2.5.0" - } - }, - "node_modules/ext-list": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", - "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", - "peer": true, - "dependencies": { - "mime-db": "^1.28.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ext-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", - "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", - "peer": true, - "dependencies": { - "ext-list": "^2.0.0", - "sort-keys-length": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "peer": true - }, - "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "peer": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "peer": true - }, - "node_modules/fast-xml-parser": { - "version": "3.19.0", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-3.19.0.tgz", - "integrity": "sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg==", - "bin": { - "xml2js": "cli.js" - }, - "funding": { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" - } - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "peer": true, - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "peer": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "peer": true, - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/file-type": { - "version": "16.5.4", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", - "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", - "peer": true, - "dependencies": { - "readable-web-to-node-stream": "^3.0.0", - "strtok3": "^6.2.4", - "token-types": "^4.1.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/file-type?sponsor=1" - } - }, - "node_modules/file-uri-to-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", - "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/filename-reserved-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", - "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/filenamify": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", - "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", - "peer": true, - "dependencies": { - "filename-reserved-regex": "^2.0.0", - "strip-outer": "^1.0.1", - "trim-repeated": "^1.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/filesize": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", - "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", - "peer": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "peer": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-requires": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-requires/-/find-requires-1.0.0.tgz", - "integrity": "sha512-UME7hNwBfzeISSFQcBEDemEEskpOjI/shPrpJM5PI4DSdn6hX0dmz+2dL70blZER2z8tSnTRL+2rfzlYgtbBoQ==", - "peer": true, - "dependencies": { - "es5-ext": "^0.10.49", - "esniff": "^1.1.0" - }, - "bin": { - "find-requires": "bin/find-requires.js" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "peer": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", - "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "peer": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "peer": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/formidable": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz", - "integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==", - "peer": true, - "dependencies": { - "dezalgo": "1.0.3", - "hexoid": "1.0.0", - "once": "1.4.0", - "qs": "6.9.3" - }, - "funding": { - "url": "https://ko-fi.com/tunnckoCore/commissions" - } - }, - "node_modules/formidable/node_modules/qs": { - "version": "6.9.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz", - "integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==", - "peer": true, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "peer": true - }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "peer": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fs2": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/fs2/-/fs2-0.3.9.tgz", - "integrity": "sha512-WsOqncODWRlkjwll+73bAxVW3JPChDgaPX3DT4iTTm73UmG4VgALa7LaFblP232/DN60itkOrPZ8kaP1feksGQ==", - "peer": true, - "dependencies": { - "d": "^1.0.1", - "deferred": "^0.7.11", - "es5-ext": "^0.10.53", - "event-emitter": "^0.3.5", - "ignore": "^5.1.8", - "memoizee": "^0.4.14", - "type": "^2.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/ftp": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", - "integrity": "sha512-faFVML1aBx2UoDStmLwv2Wptt4vw5x03xxX172nhA5Y5HBshW5JweqQ2W4xL4dezQTG8inJsuYcpPHHU3X5OTQ==", - "dependencies": { - "readable-stream": "1.1.x", - "xregexp": "2.0.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/ftp/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, - "node_modules/ftp/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/ftp/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "peer": true - }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/fuzzy": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/fuzzy/-/fuzzy-0.1.3.tgz", - "integrity": "sha512-/gZffu4ykarLrCiP3Ygsa86UAo1E5vEVlvTrpkKywXSbP9Xhln3oSp9QSV57gEq3JFFpGJ4GZ+5zdEp3FcUh4w==", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", - "peer": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-uri": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", - "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", - "dependencies": { - "@tootallnate/once": "1", - "data-uri-to-buffer": "3", - "debug": "4", - "file-uri-to-path": "2", - "fs-extra": "^8.1.0", - "ftp": "^0.3.10" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/get-uri/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/get-uri/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/get-uri/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-all": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/glob-all/-/glob-all-3.3.0.tgz", - "integrity": "sha512-30gCh9beSb+YSAh0vsoIlBRm4bSlyMa+5nayax1EJhjwYrCohX0aDxcxvWVe3heOrJikbHgRs75Af6kPLcumew==", - "dependencies": { - "glob": "^7.1.2", - "yargs": "^15.3.1" - }, - "bin": { - "glob-all": "bin/glob-all" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "peer": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "peer": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/got": { - "version": "11.8.5", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", - "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", - "peer": true, - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "node_modules/graphlib": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", - "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", - "peer": true, - "dependencies": { - "lodash": "^4.17.15" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "peer": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "peer": true, - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "peer": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hexoid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", - "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "peer": true - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "peer": true, - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" - }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "peer": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "peer": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "node_modules/inquirer": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", - "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", - "peer": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/inquirer-checkbox-plus-prompt": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/inquirer-checkbox-plus-prompt/-/inquirer-checkbox-plus-prompt-1.0.1.tgz", - "integrity": "sha512-qvD7D56B6mYZ/6gkdzDzO0/6yJqoDvIJ3XW6jKf09YBBIhP8mxcWAbZHMqxDVPoclLfXatRwToE/czcOVhHCwg==", - "dependencies": { - "cli-cursor": "^2.1.0", - "figures": "^2.0.0", - "inquirer": "^5.1.0", - "lodash": "^4.17.5" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha512-j/Toj7f1z98Hh2cYo2BVr85EpIRWqUi7rtRSGxh/cqUjqrnJe9l9UE7IUGd2vQ2p+kSHLkSzObQPZPLUC6TQwg==" - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", - "dependencies": { - "restore-cursor": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==" - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dependencies": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/inquirer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", - "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", - "dependencies": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.1.0", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^5.5.2", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==" - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", - "dependencies": { - "mimic-fn": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", - "dependencies": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/rxjs": { - "version": "5.5.12", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", - "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", - "dependencies": { - "symbol-observable": "1.0.1" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "peer": true, - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "peer": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "peer": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "peer": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "peer": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "peer": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-natural-number": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", - "integrity": "sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ==", - "peer": true - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "peer": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "peer": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-primitive": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-3.0.1.tgz", - "integrity": "sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "peer": true - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "peer": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "peer": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "peer": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", - "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", - "peer": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "peer": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isomorphic-ws": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", - "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", - "peer": true, - "peerDependencies": { - "ws": "*" - } - }, - "node_modules/jmespath": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", - "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", - "peer": true, - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "peer": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" - }, - "node_modules/json-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "dependencies": { - "bignumber.js": "^9.0.0" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "peer": true - }, - "node_modules/json-cycle": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/json-cycle/-/json-cycle-1.3.0.tgz", - "integrity": "sha512-FD/SedD78LCdSvJaOUQAXseT8oQBb5z6IVYaQaCrVUlu9zOAr1BDdKyVYQaSD/GDsAMrXpKcOyBD4LIl8nfjHw==", - "peer": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/json-refs": { - "version": "3.0.15", - "resolved": "https://registry.npmjs.org/json-refs/-/json-refs-3.0.15.tgz", - "integrity": "sha512-0vOQd9eLNBL18EGl5yYaO44GhixmImes2wiYn9Z3sag3QnehWrYWlB9AFtMxCL2Bj3fyxgDYkxGFEU/chlYssw==", - "peer": true, - "dependencies": { - "commander": "~4.1.1", - "graphlib": "^2.1.8", - "js-yaml": "^3.13.1", - "lodash": "^4.17.15", - "native-promise-only": "^0.8.1", - "path-loader": "^1.0.10", - "slash": "^3.0.0", - "uri-js": "^4.2.2" - }, - "bin": { - "json-refs": "bin/json-refs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/json-refs/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "peer": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/json-refs/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "peer": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "peer": true - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/jwt-decode": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz", - "integrity": "sha512-86GgN2vzfUu7m9Wcj63iUkuDzFNYFVmjeDm2GzWpUk+opB0pEpMsw6ePCMrhYkumz2C1ihqtZzOMAg7FiXcNoQ==", - "peer": true - }, - "node_modules/keyv": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.3.3.tgz", - "integrity": "sha512-AcysI17RvakTh8ir03+a3zJr5r0ovnAH/XTXei/4HIv3bL2K/jzvgivLK9UuI/JbU1aJjM3NSAnVvVVd3n+4DQ==", - "peer": true, - "dependencies": { - "compress-brotli": "^1.3.8", - "json-buffer": "3.0.1" - } - }, - "node_modules/lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", - "peer": true, - "dependencies": { - "readable-stream": "^2.0.5" - }, - "engines": { - "node": ">= 0.6.3" - } - }, - "node_modules/lazystream/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "peer": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/lazystream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "peer": true - }, - "node_modules/lazystream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dependencies": { - "immediate": "~3.0.5" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", - "peer": true - }, - "node_modules/lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", - "peer": true - }, - "node_modules/lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", - "peer": true - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "peer": true - }, - "node_modules/lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", - "peer": true - }, - "node_modules/lodash.uniqby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", - "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==" - }, - "node_modules/lodash.values": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.values/-/lodash.values-4.3.0.tgz", - "integrity": "sha512-r0RwvdCv8id9TUblb/O7rYPwVy6lerCbcawrfdo9iC/1t1wsNMJknO79WNBgwkH0hIeJ08jmvvESbFpNb4jH0Q==" - }, - "node_modules/log": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/log/-/log-6.3.1.tgz", - "integrity": "sha512-McG47rJEWOkXTDioZzQNydAVvZNeEkSyLJ1VWkFwfW+o1knW+QSi8D1KjPn/TnctV+q99lkvJNe1f0E1IjfY2A==", - "dependencies": { - "d": "^1.0.1", - "duration": "^0.2.2", - "es5-ext": "^0.10.53", - "event-emitter": "^0.3.5", - "sprintf-kit": "^2.0.1", - "type": "^2.5.0", - "uni-global": "^1.0.0" - } - }, - "node_modules/log-node": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/log-node/-/log-node-8.0.3.tgz", - "integrity": "sha512-1UBwzgYiCIDFs8A0rM2QdBFo8Wd8UQ0HrSTu/MNI+/2zN3NoHRj2fhplurAyuxTYUXu3Oohugq1jAn5s05u1MQ==", - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "cli-color": "^2.0.1", - "cli-sprintf-format": "^1.1.1", - "d": "^1.0.1", - "es5-ext": "^0.10.53", - "sprintf-kit": "^2.0.1", - "supports-color": "^8.1.1", - "type": "^2.5.0" - }, - "engines": { - "node": ">=10.0" - }, - "peerDependencies": { - "log": "^6.0.0" - } - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "peer": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", - "peer": true, - "dependencies": { - "es5-ext": "~0.10.2" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "peer": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/memoizee": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", - "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", - "peer": true, - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.53", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "peer": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "peer": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "peer": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "node_modules/minipass": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", - "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", - "peer": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "peer": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "peer": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" - }, - "node_modules/nan": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", - "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==", - "optional": true - }, - "node_modules/native-promise-only": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", - "integrity": "sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg==", - "peer": true - }, - "node_modules/ncjsm": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ncjsm/-/ncjsm-4.3.1.tgz", - "integrity": "sha512-5hy/Mr7KKLS/AFyY4Be8q0aXz8wYd2PN3cSSMBeQHfcrK6Sbd0EGoQxiNrUoKMAYhl67v4A975f6Gy1oEqfJlA==", - "peer": true, - "dependencies": { - "builtin-modules": "^3.3.0", - "deferred": "^0.7.11", - "es5-ext": "^0.10.61", - "es6-set": "^0.1.5", - "ext": "^1.6.0", - "find-requires": "^1.0.0", - "fs2": "^0.3.9", - "type": "^2.6.0" - } - }, - "node_modules/netmask": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", - "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, - "node_modules/node-dir": { - "version": "0.1.17", - "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", - "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", - "peer": true, - "dependencies": { - "minimatch": "^3.0.2" - }, - "engines": { - "node": ">= 0.10.5" - } - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-registry-utilities": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/npm-registry-utilities/-/npm-registry-utilities-1.0.0.tgz", - "integrity": "sha512-9xYfSJy2IFQw1i6462EJzjChL9e65EfSo2Cw6kl0EFeDp05VvU+anrQk3Fc0d1MbVCq7rWIxeer89O9SUQ/uOg==", - "peer": true, - "dependencies": { - "ext": "^1.6.0", - "fs2": "^0.3.9", - "memoizee": "^0.4.15", - "node-fetch": "^2.6.7", - "semver": "^7.3.5", - "type": "^2.6.0", - "validate-npm-package-name": "^3.0.0" - }, - "engines": { - "node": ">=12.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", - "peer": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "peer": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.3.tgz", - "integrity": "sha512-ZFJnX3zltyjcYJL0RoCJuzb+11zWGyaDbjgxZbdV7rFEcHQuYxrZqhow67aA7xpes6LhojyFDaBKAFfogQrikA==", - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", - "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", - "peer": true, - "dependencies": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-event": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", - "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", - "peer": true, - "dependencies": { - "p-timeout": "^3.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", - "peer": true, - "dependencies": { - "p-finally": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/pac-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", - "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4", - "get-uri": "3", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "5", - "pac-resolver": "^5.0.0", - "raw-body": "^2.2.0", - "socks-proxy-agent": "5" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/pac-resolver": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.1.tgz", - "integrity": "sha512-cy7u00ko2KVgBAjuhevqpPeHIkCIqPe1v24cydhWjmeuzaBfmUWFCZJ1iAh5TuVzVZoUzXIW7K8sMYOZ84uZ9Q==", - "dependencies": { - "degenerator": "^3.0.2", - "ip": "^1.1.5", - "netmask": "^2.0.2" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/path-loader": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/path-loader/-/path-loader-1.0.12.tgz", - "integrity": "sha512-n7oDG8B+k/p818uweWrOixY9/Dsr89o2TkCm6tOTex3fpdo2+BFDgR+KpB37mGKBRsBAlR8CIJMFN0OEy/7hIQ==", - "peer": true, - "dependencies": { - "native-promise-only": "^0.8.1", - "superagent": "^7.1.6" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path2": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/path2/-/path2-0.1.0.tgz", - "integrity": "sha512-TX+cz8Jk+ta7IvRy2FAej8rdlbrP0+uBIkP/5DTODez/AuL/vSb30KuAdDxGVREXzn8QfAiu5mJYJ1XjbOhEPA==", - "peer": true - }, - "node_modules/peek-readable": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", - "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", - "peer": true, - "engines": { - "node": ">=8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "peer": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "peer": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", - "peer": true, - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "node_modules/process-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/process-utils/-/process-utils-4.0.0.tgz", - "integrity": "sha512-fMyMQbKCxX51YxR7YGCzPjLsU3yDzXFkP4oi1/Mt5Ixnk7GO/7uUTj8mrCHUwuvozWzI+V7QSJR9cZYnwNOZPg==", - "peer": true, - "dependencies": { - "ext": "^1.4.0", - "fs2": "^0.3.9", - "memoizee": "^0.4.14", - "type": "^2.1.0" - }, - "engines": { - "node": ">=10.0" - } - }, - "node_modules/promise-queue": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz", - "integrity": "sha512-p/iXrPSVfnqPft24ZdNNLECw/UrtLTpT3jpAAMzl/o5/rDsGCPo3/CQS2611flL6LkoEJ3oQZw7C8Q80ZISXRQ==", - "peer": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", - "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", - "dependencies": { - "agent-base": "^6.0.0", - "debug": "4", - "http-proxy-agent": "^4.0.0", - "https-proxy-agent": "^5.0.0", - "lru-cache": "^5.1.1", - "pac-proxy-agent": "^5.0.0", - "proxy-from-env": "^1.0.0", - "socks-proxy-agent": "^5.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/proxy-agent/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/proxy-agent/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "peer": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "peer": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystring": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz", - "integrity": "sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "peer": true, - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peer": true - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "peer": true, - "dependencies": { - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/readdir-glob": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.2.tgz", - "integrity": "sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA==", - "peer": true, - "dependencies": { - "minimatch": "^5.1.0" - } - }, - "node_modules/readdir-glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", - "peer": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "peer": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "peer": true - }, - "node_modules/responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "peer": true, - "dependencies": { - "lowercase-keys": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "peer": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peer": true, - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/run-parallel-limit": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", - "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peer": true, - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.6.tgz", - "integrity": "sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" - }, - "node_modules/seek-bzip": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", - "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==", - "peer": true, - "dependencies": { - "commander": "^2.8.1" - }, - "bin": { - "seek-bunzip": "bin/seek-bunzip", - "seek-table": "bin/seek-bzip-table" - } - }, - "node_modules/seek-bzip/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "peer": true - }, - "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "peer": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serverless": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/serverless/-/serverless-3.22.0.tgz", - "integrity": "sha512-S/C4jbTFW95AwAw2wSqQa28FCordHwj+sUt3SHPgLNq0ryWcagR03C7vvIEnunmb7Rj5uEIcvArmjuaYNYN0+w==", - "hasInstallScript": true, - "peer": true, - "dependencies": { - "@serverless/dashboard-plugin": "^6.2.2", - "@serverless/platform-client": "^4.3.2", - "@serverless/utils": "^6.7.0", - "ajv": "^8.11.0", - "ajv-formats": "^2.1.1", - "archiver": "^5.3.1", - "aws-sdk": "^2.1195.0", - "bluebird": "^3.7.2", - "cachedir": "^2.3.0", - "chalk": "^4.1.2", - "child-process-ext": "^2.1.1", - "ci-info": "^3.3.2", - "cli-progress-footer": "^2.3.2", - "d": "^1.0.1", - "dayjs": "^1.11.5", - "decompress": "^4.2.1", - "dotenv": "^10.0.0", - "dotenv-expand": "^5.1.0", - "essentials": "^1.2.0", - "ext": "^1.6.0", - "fastest-levenshtein": "^1.0.16", - "filesize": "^8.0.7", - "fs-extra": "^9.1.0", - "get-stdin": "^8.0.0", - "globby": "^11.1.0", - "got": "^11.8.5", - "graceful-fs": "^4.2.10", - "https-proxy-agent": "^5.0.1", - "is-docker": "^2.2.1", - "js-yaml": "^4.1.0", - "json-cycle": "^1.3.0", - "json-refs": "^3.0.15", - "lodash": "^4.17.21", - "memoizee": "^0.4.15", - "micromatch": "^4.0.5", - "node-fetch": "^2.6.7", - "npm-registry-utilities": "^1.0.0", - "object-hash": "^2.2.0", - "open": "^7.4.2", - "path2": "^0.1.0", - "process-utils": "^4.0.0", - "promise-queue": "^2.2.5", - "require-from-string": "^2.0.2", - "semver": "^7.3.7", - "signal-exit": "^3.0.7", - "strip-ansi": "^6.0.1", - "supports-color": "^8.1.1", - "tar": "^6.1.11", - "timers-ext": "^0.1.7", - "type": "^2.7.2", - "untildify": "^4.0.0", - "uuid": "^8.3.2", - "yaml-ast-parser": "0.0.43" - }, - "bin": { - "serverless": "bin/serverless.js", - "sls": "bin/serverless.js" - }, - "engines": { - "node": ">=12.0" - } - }, - "node_modules/serverless-plugin-datadog": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/serverless-plugin-datadog/-/serverless-plugin-datadog-5.4.0.tgz", - "integrity": "sha512-BIXgcraJ8XTqxMC6X8Xp4HpljE+oV5jB5Bxb7pss6I4HS5e8mqBl3uX4NoRXIn8C48/bsISS7JlX93FFJ69b5A==", - "dependencies": { - "@datadog/datadog-ci": "^1.8.0", - "node-fetch": "^2.6.1", - "simple-git": "^3.3.0" - } - }, - "node_modules/serverless-python-requirements": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/serverless-python-requirements/-/serverless-python-requirements-5.4.0.tgz", - "integrity": "sha512-0ji96KayLG3G3vxtHS6GRcU2879tFPk6gAaRejRkPCf4RxmbebWjIbf56xljRi7DmBzhmxLJd93FVGPq9aundQ==", - "dependencies": { - "@iarna/toml": "^2.2.5", - "appdirectory": "^0.1.0", - "bluebird": "^3.7.2", - "child-process-ext": "^2.1.1", - "fs-extra": "^9.1.0", - "glob-all": "^3.3.0", - "is-wsl": "^2.2.0", - "jszip": "^3.7.1", - "lodash.get": "^4.4.2", - "lodash.uniqby": "^4.7.0", - "lodash.values": "^4.3.0", - "rimraf": "^3.0.2", - "set-value": "^4.1.0", - "sha256-file": "1.0.0", - "shell-quote": "^1.7.3" - }, - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "serverless": "^2.32 || 3" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" - }, - "node_modules/set-value": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-4.1.0.tgz", - "integrity": "sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==", - "funding": [ - "https://github.com/sponsors/jonschlinkert", - "https://paypal.me/jonathanschlinkert", - "https://jonschlinkert.dev/sponsor" - ], - "dependencies": { - "is-plain-object": "^2.0.4", - "is-primitive": "^3.0.1" - }, - "engines": { - "node": ">=11.0" - } - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/sha256-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/sha256-file/-/sha256-file-1.0.0.tgz", - "integrity": "sha512-nqf+g0veqgQAkDx0U2y2Tn2KWyADuuludZTw9A7J3D+61rKlIIl9V5TS4mfnwKuXZOH9B7fQyjYJ9pKRHIsAyg==" - }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==" - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "peer": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "node_modules/simple-git": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.12.0.tgz", - "integrity": "sha512-cy1RSRFHGZSrlYa3MnUuNVOXLUdifEZD2X8+AZjg8mKCdRvtCFSga6acq5N2g0ggb8lH3jBi369MrFZ+Y6sfsA==", - "dependencies": { - "@kwsites/file-exists": "^1.1.1", - "@kwsites/promise-deferred": "^1.1.1", - "debug": "^4.3.4" - }, - "funding": { - "type": "github", - "url": "https://github.com/steveukx/git-js?sponsor=1" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", - "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", - "dependencies": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", - "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", - "dependencies": { - "agent-base": "^6.0.2", - "debug": "4", - "socks": "^2.3.3" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/socks/node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" - }, - "node_modules/sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", - "peer": true, - "dependencies": { - "is-plain-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sort-keys-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", - "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", - "peer": true, - "dependencies": { - "sort-keys": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dependencies": { - "readable-stream": "^3.0.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "peer": true - }, - "node_modules/sprintf-kit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/sprintf-kit/-/sprintf-kit-2.0.1.tgz", - "integrity": "sha512-2PNlcs3j5JflQKcg4wpdqpZ+AjhQJ2OZEo34NXDtlB0tIPG84xaaXhpA8XFacFiwjKA4m49UOYG83y3hbMn/gQ==", - "dependencies": { - "es5-ext": "^0.10.53" - } - }, - "node_modules/ssh2": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.9.0.tgz", - "integrity": "sha512-rhhIZT0eMPvCBSOG8CpqZZ7gre2vgXaIqmb3Jb83t88rjsxIsFzDanqBJM9Ns8BmP1835A5IbQ199io4EUZwOA==", - "hasInstallScript": true, - "dependencies": { - "asn1": "^0.2.4", - "bcrypt-pbkdf": "^1.0.2" - }, - "engines": { - "node": ">=10.16.0" - }, - "optionalDependencies": { - "cpu-features": "~0.0.4", - "nan": "^2.15.0" - } - }, - "node_modules/ssh2-streams": { - "version": "0.4.10", - "resolved": "https://registry.npmjs.org/ssh2-streams/-/ssh2-streams-0.4.10.tgz", - "integrity": "sha512-8pnlMjvnIZJvmTzUIIA5nT4jr2ZWNNVHwyXfMGdRJbug9TpI3kd99ffglgfSWqujVv/0gxwMsDn9j9RVst8yhQ==", - "dependencies": { - "asn1": "~0.2.0", - "bcrypt-pbkdf": "^1.0.2", - "streamsearch": "~0.1.2" - }, - "engines": { - "node": ">=5.2.0" - } - }, - "node_modules/sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stream-promise": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/stream-promise/-/stream-promise-3.2.0.tgz", - "integrity": "sha512-P+7muTGs2C8yRcgJw/PPt61q7O517tDHiwYEzMWo1GSBCcZedUMT/clz7vUNsSxFphIlJ6QUL4GexQKlfJoVtA==", - "dependencies": { - "2-thenable": "^1.0.0", - "es5-ext": "^0.10.49", - "is-stream": "^1.1.0" - } - }, - "node_modules/streamsearch": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", - "integrity": "sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", - "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", - "peer": true, - "dependencies": { - "is-natural-number": "^4.0.1" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-outer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", - "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", - "peer": true, - "dependencies": { - "escape-string-regexp": "^1.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strtok3": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", - "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", - "peer": true, - "dependencies": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^4.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/superagent": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-7.1.6.tgz", - "integrity": "sha512-gZkVCQR1gy/oUXr+kxJMLDjla434KmSOKbx5iGD30Ql+AkJQ/YlPKECJy2nhqOsHLjGHzoDTXNSjhnvWhzKk7g==", - "deprecated": "Please downgrade to v7.1.5 if you need IE/ActiveXObject support OR upgrade to v8.0.0 as we no longer support IE and published an incorrect patch version (see https://github.com/visionmedia/superagent/issues/1731)", - "peer": true, - "dependencies": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.3", - "debug": "^4.3.4", - "fast-safe-stringify": "^2.1.1", - "form-data": "^4.0.0", - "formidable": "^2.0.1", - "methods": "^1.1.2", - "mime": "2.6.0", - "qs": "^6.10.3", - "readable-stream": "^3.6.0", - "semver": "^7.3.7" - }, - "engines": { - "node": ">=6.4.0 <13 || >=14" - } - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/symbol-observable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", - "integrity": "sha512-Kb3PrPYz4HanVF1LVGuAdW6LoVgIwjUYJGzFe7NDrBLCN4lsV/5J0MFurV+ygS4bRVwrCEt2c7MQ1R2a72oJDw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tar": { - "version": "6.1.11", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", - "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", - "peer": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "peer": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/throat": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", - "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", - "peer": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" - }, - "node_modules/timers-ext": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", - "peer": true, - "dependencies": { - "es5-ext": "~0.10.46", - "next-tick": "1" - } - }, - "node_modules/tiny-async-pool": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-1.2.0.tgz", - "integrity": "sha512-PY/OiSenYGBU3c1nTuP1HLKRkhKFDXsAibYI5GeHbHw2WVpt6OFzAPIRP94dGnS66Jhrkheim2CHAXUNI4XwMg==", - "dependencies": { - "semver": "^5.5.0", - "yaassertion": "^1.0.0" - } - }, - "node_modules/tiny-async-pool/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/to-buffer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", - "peer": true - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "peer": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/token-types": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", - "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", - "peer": true, - "dependencies": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/token-types/node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peer": true - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/traverse": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", - "integrity": "sha512-kdf4JKs8lbARxWdp7RKdNzoJBhGUcIalSYibuGyHJbmk40pOysQ0+QPvlkCOICOivDWU2IJo2rkrxyTK2AH4fw==", - "peer": true - }, - "node_modules/trim-repeated": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", - "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", - "peer": true, - "dependencies": { - "escape-string-regexp": "^1.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" - }, - "node_modules/type": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", - "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" - }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "peer": true, - "dependencies": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, - "node_modules/unbzip2-stream/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peer": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/uni-global": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/uni-global/-/uni-global-1.0.0.tgz", - "integrity": "sha512-WWM3HP+siTxzIWPNUg7hZ4XO8clKi6NoCAJJWnuRL+BAqyFXF8gC03WNyTefGoUXYc47uYgXxpKLIEvo65PEHw==", - "dependencies": { - "type": "^2.5.0" - } - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "peer": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, - "node_modules/url/node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" - }, - "node_modules/url/node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/util": { - "version": "0.12.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", - "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", - "peer": true, - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "safe-buffer": "^5.1.2", - "which-typed-array": "^1.1.2" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "peer": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/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": "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==", - "peer": true, - "dependencies": { - "builtins": "^1.0.3" - } - }, - "node_modules/vm2": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.10.tgz", - "integrity": "sha512-AuECTSvwu2OHLAZYhG716YzwodKCIJxB6u1zG7PgSQwIgAlEaoXH52bxdcvT8GkGjnYK7r7yWDW0m0sOsPuBjQ==", - "dependencies": { - "acorn": "^8.7.0", - "acorn-walk": "^8.2.0" - }, - "bin": { - "vm2": "bin/vm2" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "peer": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==" - }, - "node_modules/which-typed-array": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", - "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", - "peer": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "peer": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/write-file-atomic": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", - "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", - "peer": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" - } - }, - "node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "peer": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "peer": true, - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, - "node_modules/xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/xregexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", - "integrity": "sha512-xl/50/Cf32VsGq/1R8jJE5ajH1yMCQkpmoS10QbFZWl2Oor4H0Me64Pu2yxvsRWK3m6soJbmGfzSR7BYmDcWAA==", - "engines": { - "node": "*" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "peer": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, - "node_modules/yaassertion": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/yaassertion/-/yaassertion-1.0.2.tgz", - "integrity": "sha512-sBoJBg5vTr3lOpRX0yFD+tz7wv/l2UPMFthag4HGTMPrypBRKerjjS8jiEnNMjcAEtPXjbHiKE0UwRR1W1GXBg==" - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "peer": true - }, - "node_modules/yaml-ast-parser": { - "version": "0.0.43", - "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", - "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", - "peer": true - }, - "node_modules/yamljs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", - "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", - "peer": true, - "dependencies": { - "argparse": "^1.0.7", - "glob": "^7.0.5" - }, - "bin": { - "json2yaml": "bin/json2yaml", - "yaml2json": "bin/yaml2json" - } - }, - "node_modules/yamljs/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "peer": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/yamux-js": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yamux-js/-/yamux-js-0.1.0.tgz", - "integrity": "sha512-Bg/H2ZIV/FZ2O7LZ4nNYBoE69KPljE6Vo47p5gC7flCxSQQLmbCy1EKYqvq6tLBVBb/ep+6I2niKtPuNlj6hyw==" - }, - "node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "peer": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/zip-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", - "integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==", - "peer": true, - "dependencies": { - "archiver-utils": "^2.1.0", - "compress-commons": "^4.1.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - } - }, - "dependencies": { - "@datadog/datadog-ci": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/@datadog/datadog-ci/-/datadog-ci-1.12.0.tgz", - "integrity": "sha512-sv4hcFtX5s47o7oyEneFA2bjhguoU4qMFCw4BRtunOkCGudCBDT+zs7TJe9XH9F8cBti+w2iB0FffjqGdRa+yg==", - "requires": { - "@types/datadog-metrics": "0.6.1", - "async-retry": "1.3.1", - "aws-sdk": "2.1012.0", - "axios": "0.21.4", - "chalk": "3.0.0", - "clipanion": "2.2.2", - "datadog-metrics": "0.9.3", - "deep-extend": "0.6.0", - "fast-xml-parser": "3.19.0", - "form-data": "3.0.0", - "fuzzy": "^0.1.3", - "glob": "7.1.4", - "inquirer": "8.2.0", - "inquirer-checkbox-plus-prompt": "^1.0.1", - "proxy-agent": "5.0.0", - "rimraf": "^3.0.2", - "simple-git": "3.5.0", - "ssh2": "1.9.0", - "ssh2-streams": "0.4.10", - "sshpk": "1.16.1", - "tiny-async-pool": "1.2.0", - "ws": "7.4.6", - "xml2js": "0.4.23", - "yamux-js": "0.1.0" - }, - "dependencies": { - "aws-sdk": { - "version": "2.1012.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1012.0.tgz", - "integrity": "sha512-5F/tC+mOJSTq4BTWqg6DepDIC7h+OeUycCYsFU6fMblQCUEBuI11o8z/+2DxGt4c40f52OstalYNiSlP2RuZvw==", - "requires": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.3.2", - "xml2js": "0.4.19" - }, - "dependencies": { - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - } - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "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" - } - }, - "inquirer": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.0.tgz", - "integrity": "sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ==", - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.2.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - } - } - }, - "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha512-+kHj8HXArPfpPEKGLZ+kB5ONRTCiGQXo8RQYL0hH8t6pWXUBBK5KkkQmTNOwKK4LEsd0yTsgtjJVm4UBSZea4w==" - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==" - }, - "simple-git": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.5.0.tgz", - "integrity": "sha512-fZsaq5nzdxQRhMNs6ESGLpMUHoL5GRP+boWPhq9pMYMKwOGZV2jHOxi8AbFFA2Y/6u4kR99HoULizSbpzaODkA==", - "requires": { - "@kwsites/file-exists": "^1.1.1", - "@kwsites/promise-deferred": "^1.1.1", - "debug": "^4.3.3" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" - }, - "ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", - "requires": {} - }, - "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "dependencies": { - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" - } - } - } - } - }, - "@iarna/toml": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", - "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==" - }, - "@kwsites/file-exists": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", - "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", - "requires": { - "debug": "^4.1.1" - } - }, - "@kwsites/promise-deferred": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", - "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "peer": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "peer": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "peer": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@serverless/dashboard-plugin": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/@serverless/dashboard-plugin/-/dashboard-plugin-6.2.2.tgz", - "integrity": "sha512-h3zOprpuWZCdAP7qoOKT2nboB+AaxMkGoSzOD0jIBpt9s0cXqLE2VFjR2vKn8Cvam47Qa3XYnT2/XN6tR6rZgQ==", - "peer": true, - "requires": { - "@serverless/event-mocks": "^1.1.1", - "@serverless/platform-client": "^4.3.2", - "@serverless/utils": "^6.0.3", - "child-process-ext": "^2.1.1", - "chokidar": "^3.5.3", - "flat": "^5.0.2", - "fs-extra": "^9.1.0", - "js-yaml": "^4.1.0", - "jszip": "^3.9.1", - "lodash": "^4.17.21", - "memoizee": "^0.4.15", - "ncjsm": "^4.3.0", - "node-dir": "^0.1.17", - "node-fetch": "^2.6.7", - "open": "^7.4.2", - "semver": "^7.3.7", - "simple-git": "^3.7.0", - "type": "^2.6.0", - "uuid": "^8.3.2", - "yamljs": "^0.3.0" - } - }, - "@serverless/event-mocks": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@serverless/event-mocks/-/event-mocks-1.1.1.tgz", - "integrity": "sha512-YAV5V/y+XIOfd+HEVeXfPWZb8C6QLruFk9tBivoX2roQLWVq145s4uxf8D0QioCueuRzkukHUS4JIj+KVoS34A==", - "peer": true, - "requires": { - "@types/lodash": "^4.14.123", - "lodash": "^4.17.11" - } - }, - "@serverless/platform-client": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@serverless/platform-client/-/platform-client-4.3.2.tgz", - "integrity": "sha512-DAa5Z0JAZc6UfrTZLYwqoZxgAponZpFwaqd7WzzMA+loMCkYWyJNwxrAmV6cr2UUJpkko4toPZuJ3vM9Ie+NDA==", - "peer": true, - "requires": { - "adm-zip": "^0.5.5", - "archiver": "^5.3.0", - "axios": "^0.21.1", - "fast-glob": "^3.2.7", - "https-proxy-agent": "^5.0.0", - "ignore": "^5.1.8", - "isomorphic-ws": "^4.0.1", - "js-yaml": "^3.14.1", - "jwt-decode": "^2.2.0", - "minimatch": "^3.0.4", - "querystring": "^0.2.1", - "run-parallel-limit": "^1.1.0", - "throat": "^5.0.0", - "traverse": "^0.6.6", - "ws": "^7.5.3" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "peer": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "peer": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - } - } - }, - "@serverless/utils": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@serverless/utils/-/utils-6.7.0.tgz", - "integrity": "sha512-aUjkkOTJ5wH7f3raSIDeTCR4JsAbd9p5Pjs7yW3sVOmu0qiTPHZOr1x1TIkb3WDHiAoQQY8zGhfzW7zLTcAA3Q==", - "peer": true, - "requires": { - "archive-type": "^4.0.0", - "chalk": "^4.1.2", - "ci-info": "^3.3.2", - "cli-progress-footer": "^2.3.2", - "content-disposition": "^0.5.4", - "d": "^1.0.1", - "decompress": "^4.2.1", - "event-emitter": "^0.3.5", - "ext": "^1.6.0", - "ext-name": "^5.0.0", - "file-type": "^16.5.3", - "filenamify": "^4.3.0", - "get-stream": "^6.0.1", - "got": "^11.8.5", - "inquirer": "^8.2.4", - "js-yaml": "^4.1.0", - "jwt-decode": "^3.1.2", - "lodash": "^4.17.21", - "log": "^6.3.1", - "log-node": "^8.0.3", - "make-dir": "^3.1.0", - "memoizee": "^0.4.15", - "ncjsm": "^4.3.0", - "node-fetch": "^2.6.7", - "open": "^7.4.2", - "p-event": "^4.2.0", - "supports-color": "^8.1.1", - "timers-ext": "^0.1.7", - "type": "^2.6.0", - "uni-global": "^1.0.0", - "uuid": "^8.3.2", - "write-file-atomic": "^4.0.1" - }, - "dependencies": { - "jwt-decode": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", - "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==", - "peer": true - } - } - }, - "@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "peer": true - }, - "@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "peer": true, - "requires": { - "defer-to-connect": "^2.0.0" - } - }, - "@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", - "peer": true - }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" - }, - "@types/cacheable-request": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", - "integrity": "sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==", - "peer": true, - "requires": { - "@types/http-cache-semantics": "*", - "@types/keyv": "*", - "@types/node": "*", - "@types/responselike": "*" - } - }, - "@types/datadog-metrics": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@types/datadog-metrics/-/datadog-metrics-0.6.1.tgz", - "integrity": "sha512-p6zVpfmNcXwtcXjgpz7do/fKyfndGhU5sGJVtb5Gn5PvLDiQUAgD0mI/itf/99sBi9DRxeyhFQ9dQF6OxxQNbA==" - }, - "@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", - "peer": true - }, - "@types/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-3YP80IxxFJB4b5tYC2SUPwkg0XQLiu0nWvhRgEatgjf+29IcWO9X1k8xRv5DGssJ/lCrjYTjQPcobJr2yWIVuQ==", - "peer": true - }, - "@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "peer": true, - "requires": { - "@types/node": "*" - } - }, - "@types/lodash": { - "version": "4.14.182", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", - "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==", - "peer": true - }, - "@types/node": { - "version": "18.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.5.tgz", - "integrity": "sha512-NcKK6Ts+9LqdHJaW6HQmgr7dT/i3GOHG+pt6BiWv++5SnjtRd4NXeiuN2kA153SjhXPR/AhHIPHPbrsbpUVOww==", - "peer": true - }, - "@types/responselike": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", - "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", - "peer": true, - "requires": { - "@types/node": "*" - } - }, - "2-thenable": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/2-thenable/-/2-thenable-1.0.0.tgz", - "integrity": "sha512-HqiDzaLDFCXkcCO/SwoyhRwqYtINFHF7t9BDRq4x90TOKNAJpiqUt9X5lQ08bwxYzc067HUywDjGySpebHcUpw==", - "requires": { - "d": "1", - "es5-ext": "^0.10.47" - } - }, - "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==" - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" - }, - "adm-zip": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.9.tgz", - "integrity": "sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg==", - "peer": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "requires": { - "debug": "4" - } - }, - "ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", - "peer": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "peer": true, - "requires": { - "ajv": "^8.0.0" - } - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "requires": { - "type-fest": "^0.21.3" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "peer": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "appdirectory": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/appdirectory/-/appdirectory-0.1.0.tgz", - "integrity": "sha512-DJ5DV8vZXBbusyiyPlH28xppwS8eAMRuuyMo88xeEcf4bV64lbLtbxRxqixZuJBXsZzLtXFmA13GwVjJc7vdQw==" - }, - "archive-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz", - "integrity": "sha512-zV4Ky0v1F8dBrdYElwTvQhweQ0P7Kwc1aluqJsYtOBP01jXcWCyW2IEfI1YiqsG+Iy7ZR+o5LF1N+PGECBxHWA==", - "peer": true, - "requires": { - "file-type": "^4.2.0" - }, - "dependencies": { - "file-type": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", - "integrity": "sha512-f2UbFQEk7LXgWpi5ntcO86OeA/cC80fuDDDaX/fZ2ZGel+AF7leRQqBBW1eJNiiQkrZlAoM6P+VYP5P6bOlDEQ==", - "peer": true - } - } - }, - "archiver": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz", - "integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==", - "peer": true, - "requires": { - "archiver-utils": "^2.1.0", - "async": "^3.2.3", - "buffer-crc32": "^0.2.1", - "readable-stream": "^3.6.0", - "readdir-glob": "^1.0.0", - "tar-stream": "^2.2.0", - "zip-stream": "^4.1.0" - } - }, - "archiver-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", - "peer": true, - "requires": { - "glob": "^7.1.4", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^2.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "peer": 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" - } - }, - "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==", - "peer": true - }, - "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==", - "peer": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "peer": true - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "peer": true - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "peer": true - }, - "asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" - }, - "ast-types": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", - "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", - "requires": { - "tslib": "^2.0.1" - } - }, - "async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "peer": true - }, - "async-retry": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.1.tgz", - "integrity": "sha512-aiieFW/7h3hY0Bq5d+ktDBejxuwR78vRu9hDUdR8rNhSaQ29VzPL4AoIRG7D/c7tdenwOcKvgPM6tIxB3cB6HA==", - "requires": { - "retry": "0.12.0" - } - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" - }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "peer": true - }, - "aws-sdk": { - "version": "2.1195.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1195.0.tgz", - "integrity": "sha512-xU7177JhKM+4SsLnoA6/r3qGzSXmbLgw/YC1KRHvZyJCbuTY+vdAGLaldbtNXjjwmE3a6EeoCREANv8GY62VdQ==", - "peer": true, - "requires": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.16.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "util": "^0.12.4", - "uuid": "8.0.0", - "xml2js": "0.4.19" - }, - "dependencies": { - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", - "peer": true - }, - "uuid": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", - "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", - "peer": true - } - } - }, - "axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "requires": { - "follow-redirects": "^1.14.0" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "bignumber.js": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.0.tgz", - "integrity": "sha512-4LwHK4nfDOraBCtst+wOWIHbu1vhvAPJK8g8nROd4iuc3PSEjWif/qwbkh8jwCJz6yDBvtU4KPynETgrfh7y3A==" - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "peer": true - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - }, - "dependencies": { - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - } - } - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "peer": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "buffer-alloc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "peer": true, - "requires": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" - } - }, - "buffer-alloc-unsafe": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", - "peer": true - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "peer": true - }, - "buffer-fill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", - "peer": true - }, - "buildcheck": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.3.tgz", - "integrity": "sha512-pziaA+p/wdVImfcbsZLNF32EiWyujlQLwolMqUQE8xpKNOH7KmZQaY8sXN7DGOEzPAElo9QTaeNRfGnf3iOJbA==", - "optional": true - }, - "builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "peer": true - }, - "builtins": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", - "peer": true - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "peer": true - }, - "cacheable-request": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", - "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", - "peer": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "peer": true, - "requires": { - "pump": "^3.0.0" - } - } - } - }, - "cachedir": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", - "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", - "peer": true - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "peer": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" - }, - "child-process-ext": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/child-process-ext/-/child-process-ext-2.1.1.tgz", - "integrity": "sha512-0UQ55f51JBkOFa+fvR76ywRzxiPwQS3Xe8oe5bZRphpv+dIMeerW5Zn5e4cUy4COJwVtJyU0R79RMnw+aCqmGA==", - "requires": { - "cross-spawn": "^6.0.5", - "es5-ext": "^0.10.53", - "log": "^6.0.0", - "split2": "^3.1.1", - "stream-promise": "^3.2.0" - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "peer": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "peer": true - }, - "ci-info": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", - "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==", - "peer": true - }, - "cli-color": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.3.tgz", - "integrity": "sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==", - "peer": true, - "requires": { - "d": "^1.0.1", - "es5-ext": "^0.10.61", - "es6-iterator": "^2.0.3", - "memoizee": "^0.4.15", - "timers-ext": "^0.1.7" - } - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-progress-footer": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/cli-progress-footer/-/cli-progress-footer-2.3.2.tgz", - "integrity": "sha512-uzHGgkKdeA9Kr57eyH1W5HGiNShP8fV1ETq04HDNM1Un6ShXbHhwi/H8LNV9L1fQXKjEw0q5FUkEVNuZ+yZdSw==", - "peer": true, - "requires": { - "cli-color": "^2.0.2", - "d": "^1.0.1", - "es5-ext": "^0.10.61", - "mute-stream": "0.0.8", - "process-utils": "^4.0.0", - "timers-ext": "^0.1.7", - "type": "^2.6.0" - } - }, - "cli-spinners": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", - "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==" - }, - "cli-sprintf-format": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cli-sprintf-format/-/cli-sprintf-format-1.1.1.tgz", - "integrity": "sha512-BbEjY9BEdA6wagVwTqPvmAwGB24U93rQPBFZUT8lNCDxXzre5LFHQUTJc70czjgUomVg8u8R5kW8oY9DYRFNeg==", - "peer": true, - "requires": { - "cli-color": "^2.0.1", - "es5-ext": "^0.10.53", - "sprintf-kit": "^2.0.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "peer": true - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "peer": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==" - }, - "clipanion": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/clipanion/-/clipanion-2.2.2.tgz", - "integrity": "sha512-OvH+rtaTeTbyQfRpE3jlEcPf1F92IpgFSypaJGnCJMzn6WYF4h9CBMcd2jU+rSt5qGm91Px6WiapK2lTqYsERQ==", - "requires": { - "chalk": "^2.4.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - }, - "dependencies": { - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - } - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==" - }, - "clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "peer": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "peer": true - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "peer": true - }, - "compress-brotli": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/compress-brotli/-/compress-brotli-1.3.8.tgz", - "integrity": "sha512-lVcQsjhxhIXsuupfy9fmZUFtAIdBmXA7EGY6GBdgZ++qkM9zG4YFT8iU7FoBxzryNDMOpD1HIFHUSX4D87oqhQ==", - "peer": true, - "requires": { - "@types/json-buffer": "~3.0.0", - "json-buffer": "~3.0.1" - } - }, - "compress-commons": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz", - "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", - "peer": true, - "requires": { - "buffer-crc32": "^0.2.13", - "crc32-stream": "^4.0.2", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "peer": true, - "requires": { - "safe-buffer": "5.2.1" - } - }, - "cookiejar": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz", - "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==", - "peer": true - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "cpu-features": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.4.tgz", - "integrity": "sha512-fKiZ/zp1mUwQbnzb9IghXtHtDoTMtNeb8oYGx6kX2SYfhnG0HNdBEBIzB9b5KlXu5DQPhfy3mInbBxFcgwAr3A==", - "optional": true, - "requires": { - "buildcheck": "0.0.3", - "nan": "^2.15.0" - } - }, - "crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "peer": true - }, - "crc32-stream": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz", - "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", - "peer": true, - "requires": { - "crc-32": "^1.2.0", - "readable-stream": "^3.4.0" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - }, - "dependencies": { - "type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - } - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "data-uri-to-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", - "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==" - }, - "datadog-metrics": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/datadog-metrics/-/datadog-metrics-0.9.3.tgz", - "integrity": "sha512-BVsBX2t+4yA3tHs7DnB5H01cHVNiGJ/bHA8y6JppJDyXG7s2DLm6JaozPGpgsgVGd42Is1CHRG/yMDQpt877Xg==", - "requires": { - "debug": "3.1.0", - "dogapi": "2.8.4" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "dayjs": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.5.tgz", - "integrity": "sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA==", - "peer": true - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" - }, - "decompress": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz", - "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==", - "peer": true, - "requires": { - "decompress-tar": "^4.0.0", - "decompress-tarbz2": "^4.0.0", - "decompress-targz": "^4.0.0", - "decompress-unzip": "^4.0.1", - "graceful-fs": "^4.1.10", - "make-dir": "^1.0.0", - "pify": "^2.3.0", - "strip-dirs": "^2.0.0" - }, - "dependencies": { - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "peer": true, - "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "peer": true - } - } - } - } - }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "peer": true, - "requires": { - "mimic-response": "^3.1.0" - }, - "dependencies": { - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "peer": true - } - } - }, - "decompress-tar": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", - "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", - "peer": true, - "requires": { - "file-type": "^5.2.0", - "is-stream": "^1.1.0", - "tar-stream": "^1.5.2" - }, - "dependencies": { - "bl": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", - "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", - "peer": true, - "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } - }, - "file-type": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==", - "peer": true - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "peer": 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" - } - }, - "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==", - "peer": true - }, - "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==", - "peer": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "tar-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", - "peer": true, - "requires": { - "bl": "^1.0.0", - "buffer-alloc": "^1.2.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.3.0", - "to-buffer": "^1.1.1", - "xtend": "^4.0.0" - } - } - } - }, - "decompress-tarbz2": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", - "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", - "peer": true, - "requires": { - "decompress-tar": "^4.1.0", - "file-type": "^6.1.0", - "is-stream": "^1.1.0", - "seek-bzip": "^1.0.5", - "unbzip2-stream": "^1.0.9" - }, - "dependencies": { - "file-type": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", - "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", - "peer": true - } - } - }, - "decompress-targz": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", - "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", - "peer": true, - "requires": { - "decompress-tar": "^4.1.1", - "file-type": "^5.2.0", - "is-stream": "^1.1.0" - }, - "dependencies": { - "file-type": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==", - "peer": true - } - } - }, - "decompress-unzip": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", - "integrity": "sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw==", - "peer": true, - "requires": { - "file-type": "^3.8.0", - "get-stream": "^2.2.0", - "pify": "^2.3.0", - "yauzl": "^2.4.2" - }, - "dependencies": { - "file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", - "peer": true - }, - "get-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", - "integrity": "sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA==", - "peer": true, - "requires": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" - } - } - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" - }, - "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==", - "requires": { - "clone": "^1.0.2" - } - }, - "defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "peer": true - }, - "deferred": { - "version": "0.7.11", - "resolved": "https://registry.npmjs.org/deferred/-/deferred-0.7.11.tgz", - "integrity": "sha512-8eluCl/Blx4YOGwMapBvXRKxHXhA8ejDXYzEaK8+/gtcm8hRMhSLmXSqDmNUKNc/C8HNSmuyyp/hflhqDAvK2A==", - "peer": true, - "requires": { - "d": "^1.0.1", - "es5-ext": "^0.10.50", - "event-emitter": "^0.3.5", - "next-tick": "^1.0.0", - "timers-ext": "^0.1.7" - } - }, - "define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "peer": true, - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "degenerator": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz", - "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==", - "requires": { - "ast-types": "^0.13.2", - "escodegen": "^1.8.1", - "esprima": "^4.0.0", - "vm2": "^3.9.8" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "dezalgo": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha512-K7i4zNfT2kgQz3GylDw40ot9GAE47sFZ9EXHFSPP6zONLgH6kWXE0KWJchkbQJLBkRazq4APwZ4OwiFFlT95OQ==", - "peer": true, - "requires": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "peer": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "dogapi": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/dogapi/-/dogapi-2.8.4.tgz", - "integrity": "sha512-065fsvu5dB0o4+ENtLjZILvXMClDNH/yA9H6L8nsdcNiz9l0Hzpn7aQaCOPYXxqyzq4CRPOdwkFXUjDOXfRGbg==", - "requires": { - "extend": "^3.0.2", - "json-bigint": "^1.0.0", - "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rc": "^1.2.8" - } - }, - "dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", - "peer": true - }, - "dotenv-expand": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", - "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", - "peer": true - }, - "duration": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/duration/-/duration-0.2.2.tgz", - "integrity": "sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg==", - "requires": { - "d": "1", - "es5-ext": "~0.10.46" - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "peer": true, - "requires": { - "once": "^1.4.0" - } - }, - "es-abstract": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", - "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", - "peer": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "peer": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es5-ext": { - "version": "0.10.62", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", - "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", - "requires": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "next-tick": "^1.1.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-set": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", - "integrity": "sha512-7S8YXIcUfPMOr3rqJBVMePAbRsD1nWeSMQ86K/lDI76S3WKXz+KWILvTIPbTroubOkZTGh+b+7/xIIphZXNYbA==", - "peer": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "~0.3.5" - }, - "dependencies": { - "es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha512-exfuQY8UGtn/N+gL1iKkH8fpNd5sJ760nJq6mmZAHldfxMD5kX07lbQuYlspoXsuknXNv9Fb7y2GsPOnQIbxHg==", - "peer": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - } - } - }, - "es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "requires": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "peer": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - } - }, - "esniff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/esniff/-/esniff-1.1.0.tgz", - "integrity": "sha512-vmHXOeOt7FJLsqofvFk4WB3ejvcHizCd8toXXwADmYfd02p2QwHRgkUbhYDX54y08nqk818CUTWipgZGlyN07g==", - "peer": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.12" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - }, - "essentials": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/essentials/-/essentials-1.2.0.tgz", - "integrity": "sha512-kP/j7Iw7KeNE8b/o7+tr9uX2s1wegElGOoGZ2Xm35qBr4BbbEcH3/bxR2nfH9l9JANCq9AUrvKw+gRuHtZp0HQ==", - "peer": true, - "requires": { - "uni-global": "^1.0.0" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - }, - "event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==" - }, - "ext": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", - "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", - "requires": { - "type": "^2.5.0" - } - }, - "ext-list": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", - "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", - "peer": true, - "requires": { - "mime-db": "^1.28.0" - } - }, - "ext-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", - "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", - "peer": true, - "requires": { - "ext-list": "^2.0.0", - "sort-keys-length": "^1.0.0" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "peer": true - }, - "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "peer": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - } - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" - }, - "fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "peer": true - }, - "fast-xml-parser": { - "version": "3.19.0", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-3.19.0.tgz", - "integrity": "sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg==" - }, - "fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "peer": true - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "peer": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "peer": true, - "requires": { - "pend": "~1.2.0" - } - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-type": { - "version": "16.5.4", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", - "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", - "peer": true, - "requires": { - "readable-web-to-node-stream": "^3.0.0", - "strtok3": "^6.2.4", - "token-types": "^4.1.1" - } - }, - "file-uri-to-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", - "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==" - }, - "filename-reserved-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", - "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", - "peer": true - }, - "filenamify": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", - "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", - "peer": true, - "requires": { - "filename-reserved-regex": "^2.0.0", - "strip-outer": "^1.0.1", - "trim-repeated": "^1.0.0" - } - }, - "filesize": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", - "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", - "peer": true - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "peer": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-requires": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-requires/-/find-requires-1.0.0.tgz", - "integrity": "sha512-UME7hNwBfzeISSFQcBEDemEEskpOjI/shPrpJM5PI4DSdn6hX0dmz+2dL70blZER2z8tSnTRL+2rfzlYgtbBoQ==", - "peer": true, - "requires": { - "es5-ext": "^0.10.49", - "esniff": "^1.1.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "peer": true - }, - "follow-redirects": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", - "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "peer": true, - "requires": { - "is-callable": "^1.1.3" - } - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "peer": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "formidable": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz", - "integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==", - "peer": true, - "requires": { - "dezalgo": "1.0.3", - "hexoid": "1.0.0", - "once": "1.4.0", - "qs": "6.9.3" - }, - "dependencies": { - "qs": { - "version": "6.9.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz", - "integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==", - "peer": true - } - } - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "peer": true - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "peer": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "fs2": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/fs2/-/fs2-0.3.9.tgz", - "integrity": "sha512-WsOqncODWRlkjwll+73bAxVW3JPChDgaPX3DT4iTTm73UmG4VgALa7LaFblP232/DN60itkOrPZ8kaP1feksGQ==", - "peer": true, - "requires": { - "d": "^1.0.1", - "deferred": "^0.7.11", - "es5-ext": "^0.10.53", - "event-emitter": "^0.3.5", - "ignore": "^5.1.8", - "memoizee": "^0.4.14", - "type": "^2.1.0" - } - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true, - "peer": true - }, - "ftp": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", - "integrity": "sha512-faFVML1aBx2UoDStmLwv2Wptt4vw5x03xxX172nhA5Y5HBshW5JweqQ2W4xL4dezQTG8inJsuYcpPHHU3X5OTQ==", - "requires": { - "readable-stream": "1.1.x", - "xregexp": "2.0.0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "peer": true - }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "peer": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "peer": true - }, - "fuzzy": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/fuzzy/-/fuzzy-0.1.3.tgz", - "integrity": "sha512-/gZffu4ykarLrCiP3Ygsa86UAo1E5vEVlvTrpkKywXSbP9Xhln3oSp9QSV57gEq3JFFpGJ4GZ+5zdEp3FcUh4w==" - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", - "peer": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", - "peer": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "peer": true - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "peer": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "get-uri": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", - "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", - "requires": { - "@tootallnate/once": "1", - "data-uri-to-buffer": "3", - "debug": "4", - "file-uri-to-path": "2", - "fs-extra": "^8.1.0", - "ftp": "^0.3.10" - }, - "dependencies": { - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - } - } - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-all": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/glob-all/-/glob-all-3.3.0.tgz", - "integrity": "sha512-30gCh9beSb+YSAh0vsoIlBRm4bSlyMa+5nayax1EJhjwYrCohX0aDxcxvWVe3heOrJikbHgRs75Af6kPLcumew==", - "requires": { - "glob": "^7.1.2", - "yargs": "^15.3.1" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "peer": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "peer": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "got": { - "version": "11.8.5", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", - "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", - "peer": true, - "requires": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "graphlib": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", - "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", - "peer": true, - "requires": { - "lodash": "^4.17.15" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "peer": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "peer": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "peer": true, - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "peer": true - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "peer": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "hexoid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", - "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", - "peer": true - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "peer": true - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "peer": true, - "requires": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "peer": true - }, - "immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "peer": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "inquirer": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", - "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", - "peer": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^7.0.0" - } - }, - "inquirer-checkbox-plus-prompt": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/inquirer-checkbox-plus-prompt/-/inquirer-checkbox-plus-prompt-1.0.1.tgz", - "integrity": "sha512-qvD7D56B6mYZ/6gkdzDzO0/6yJqoDvIJ3XW6jKf09YBBIhP8mxcWAbZHMqxDVPoclLfXatRwToE/czcOVhHCwg==", - "requires": { - "cli-cursor": "^2.1.0", - "figures": "^2.0.0", - "inquirer": "^5.1.0", - "lodash": "^4.17.5" - }, - "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==" - }, - "ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha512-j/Toj7f1z98Hh2cYo2BVr85EpIRWqUi7rtRSGxh/cqUjqrnJe9l9UE7IUGd2vQ2p+kSHLkSzObQPZPLUC6TQwg==" - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==" - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - } - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "inquirer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", - "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.1.0", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^5.5.2", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - } - }, - "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": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" - }, - "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==" - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==" - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "rxjs": { - "version": "5.5.12", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", - "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", - "requires": { - "symbol-observable": "1.0.1" - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "peer": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "ip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" - }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "peer": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "peer": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "peer": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "peer": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "peer": true - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "peer": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "peer": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "peer": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "peer": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==" - }, - "is-natural-number": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", - "integrity": "sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ==", - "peer": true - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "peer": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "peer": true - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "peer": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "peer": true - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "requires": { - "isobject": "^3.0.1" - } - }, - "is-primitive": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-3.0.1.tgz", - "integrity": "sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w==" - }, - "is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "peer": true - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "peer": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "peer": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==" - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "peer": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "peer": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", - "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", - "peer": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0" - } - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "peer": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "requires": { - "is-docker": "^2.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" - }, - "isomorphic-ws": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", - "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", - "peer": true, - "requires": {} - }, - "jmespath": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", - "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", - "peer": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "peer": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" - }, - "json-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "requires": { - "bignumber.js": "^9.0.0" - } - }, - "json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "peer": true - }, - "json-cycle": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/json-cycle/-/json-cycle-1.3.0.tgz", - "integrity": "sha512-FD/SedD78LCdSvJaOUQAXseT8oQBb5z6IVYaQaCrVUlu9zOAr1BDdKyVYQaSD/GDsAMrXpKcOyBD4LIl8nfjHw==", - "peer": true - }, - "json-refs": { - "version": "3.0.15", - "resolved": "https://registry.npmjs.org/json-refs/-/json-refs-3.0.15.tgz", - "integrity": "sha512-0vOQd9eLNBL18EGl5yYaO44GhixmImes2wiYn9Z3sag3QnehWrYWlB9AFtMxCL2Bj3fyxgDYkxGFEU/chlYssw==", - "peer": true, - "requires": { - "commander": "~4.1.1", - "graphlib": "^2.1.8", - "js-yaml": "^3.13.1", - "lodash": "^4.17.15", - "native-promise-only": "^0.8.1", - "path-loader": "^1.0.10", - "slash": "^3.0.0", - "uri-js": "^4.2.2" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "peer": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "peer": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - } - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "peer": true - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "requires": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "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==" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "jwt-decode": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz", - "integrity": "sha512-86GgN2vzfUu7m9Wcj63iUkuDzFNYFVmjeDm2GzWpUk+opB0pEpMsw6ePCMrhYkumz2C1ihqtZzOMAg7FiXcNoQ==", - "peer": true - }, - "keyv": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.3.3.tgz", - "integrity": "sha512-AcysI17RvakTh8ir03+a3zJr5r0ovnAH/XTXei/4HIv3bL2K/jzvgivLK9UuI/JbU1aJjM3NSAnVvVVd3n+4DQ==", - "peer": true, - "requires": { - "compress-brotli": "^1.3.8", - "json-buffer": "3.0.1" - } - }, - "lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", - "peer": true, - "requires": { - "readable-stream": "^2.0.5" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "peer": 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" - } - }, - "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==", - "peer": true - }, - "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==", - "peer": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "requires": { - "immediate": "~3.0.5" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", - "peer": true - }, - "lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", - "peer": true - }, - "lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", - "peer": true - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "peer": true - }, - "lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", - "peer": true - }, - "lodash.uniqby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", - "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==" - }, - "lodash.values": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.values/-/lodash.values-4.3.0.tgz", - "integrity": "sha512-r0RwvdCv8id9TUblb/O7rYPwVy6lerCbcawrfdo9iC/1t1wsNMJknO79WNBgwkH0hIeJ08jmvvESbFpNb4jH0Q==" - }, - "log": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/log/-/log-6.3.1.tgz", - "integrity": "sha512-McG47rJEWOkXTDioZzQNydAVvZNeEkSyLJ1VWkFwfW+o1knW+QSi8D1KjPn/TnctV+q99lkvJNe1f0E1IjfY2A==", - "requires": { - "d": "^1.0.1", - "duration": "^0.2.2", - "es5-ext": "^0.10.53", - "event-emitter": "^0.3.5", - "sprintf-kit": "^2.0.1", - "type": "^2.5.0", - "uni-global": "^1.0.0" - } - }, - "log-node": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/log-node/-/log-node-8.0.3.tgz", - "integrity": "sha512-1UBwzgYiCIDFs8A0rM2QdBFo8Wd8UQ0HrSTu/MNI+/2zN3NoHRj2fhplurAyuxTYUXu3Oohugq1jAn5s05u1MQ==", - "peer": true, - "requires": { - "ansi-regex": "^5.0.1", - "cli-color": "^2.0.1", - "cli-sprintf-format": "^1.1.1", - "d": "^1.0.1", - "es5-ext": "^0.10.53", - "sprintf-kit": "^2.0.1", - "supports-color": "^8.1.1", - "type": "^2.5.0" - } - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "peer": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "peer": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", - "peer": true, - "requires": { - "es5-ext": "~0.10.2" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "peer": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "peer": true - } - } - }, - "memoizee": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", - "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", - "peer": true, - "requires": { - "d": "^1.0.1", - "es5-ext": "^0.10.53", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" - } - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "peer": true - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "peer": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "peer": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "peer": true - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "peer": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "minipass": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", - "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", - "peer": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "peer": true, - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "peer": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" - }, - "nan": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", - "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==", - "optional": true - }, - "native-promise-only": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", - "integrity": "sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg==", - "peer": true - }, - "ncjsm": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ncjsm/-/ncjsm-4.3.1.tgz", - "integrity": "sha512-5hy/Mr7KKLS/AFyY4Be8q0aXz8wYd2PN3cSSMBeQHfcrK6Sbd0EGoQxiNrUoKMAYhl67v4A975f6Gy1oEqfJlA==", - "peer": true, - "requires": { - "builtin-modules": "^3.3.0", - "deferred": "^0.7.11", - "es5-ext": "^0.10.61", - "es6-set": "^0.1.5", - "ext": "^1.6.0", - "find-requires": "^1.0.0", - "fs2": "^0.3.9", - "type": "^2.6.0" - } - }, - "netmask": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", - "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==" - }, - "next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, - "node-dir": { - "version": "0.1.17", - "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", - "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", - "peer": true, - "requires": { - "minimatch": "^3.0.2" - } - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "peer": true - }, - "normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "peer": true - }, - "npm-registry-utilities": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/npm-registry-utilities/-/npm-registry-utilities-1.0.0.tgz", - "integrity": "sha512-9xYfSJy2IFQw1i6462EJzjChL9e65EfSo2Cw6kl0EFeDp05VvU+anrQk3Fc0d1MbVCq7rWIxeer89O9SUQ/uOg==", - "peer": true, - "requires": { - "ext": "^1.6.0", - "fs2": "^0.3.9", - "memoizee": "^0.4.15", - "node-fetch": "^2.6.7", - "semver": "^7.3.5", - "type": "^2.6.0", - "validate-npm-package-name": "^3.0.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "peer": true - }, - "object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", - "peer": true - }, - "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "peer": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "peer": true - }, - "object.assign": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.3.tgz", - "integrity": "sha512-ZFJnX3zltyjcYJL0RoCJuzb+11zWGyaDbjgxZbdV7rFEcHQuYxrZqhow67aA7xpes6LhojyFDaBKAFfogQrikA==", - "peer": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "open": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", - "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", - "peer": true, - "requires": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "requires": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" - }, - "p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "peer": true - }, - "p-event": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", - "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", - "peer": true, - "requires": { - "p-timeout": "^3.1.0" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "peer": true - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", - "peer": true, - "requires": { - "p-finally": "^1.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "pac-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", - "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4", - "get-uri": "3", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "5", - "pac-resolver": "^5.0.0", - "raw-body": "^2.2.0", - "socks-proxy-agent": "5" - } - }, - "pac-resolver": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.1.tgz", - "integrity": "sha512-cy7u00ko2KVgBAjuhevqpPeHIkCIqPe1v24cydhWjmeuzaBfmUWFCZJ1iAh5TuVzVZoUzXIW7K8sMYOZ84uZ9Q==", - "requires": { - "degenerator": "^3.0.2", - "ip": "^1.1.5", - "netmask": "^2.0.2" - } - }, - "pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==" - }, - "path-loader": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/path-loader/-/path-loader-1.0.12.tgz", - "integrity": "sha512-n7oDG8B+k/p818uweWrOixY9/Dsr89o2TkCm6tOTex3fpdo2+BFDgR+KpB37mGKBRsBAlR8CIJMFN0OEy/7hIQ==", - "peer": true, - "requires": { - "native-promise-only": "^0.8.1", - "superagent": "^7.1.6" - } - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "peer": true - }, - "path2": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/path2/-/path2-0.1.0.tgz", - "integrity": "sha512-TX+cz8Jk+ta7IvRy2FAej8rdlbrP0+uBIkP/5DTODez/AuL/vSb30KuAdDxGVREXzn8QfAiu5mJYJ1XjbOhEPA==", - "peer": true - }, - "peek-readable": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", - "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", - "peer": true - }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "peer": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "peer": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "peer": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", - "peer": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", - "peer": true, - "requires": { - "pinkie": "^2.0.0" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==" - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "process-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/process-utils/-/process-utils-4.0.0.tgz", - "integrity": "sha512-fMyMQbKCxX51YxR7YGCzPjLsU3yDzXFkP4oi1/Mt5Ixnk7GO/7uUTj8mrCHUwuvozWzI+V7QSJR9cZYnwNOZPg==", - "peer": true, - "requires": { - "ext": "^1.4.0", - "fs2": "^0.3.9", - "memoizee": "^0.4.14", - "type": "^2.1.0" - } - }, - "promise-queue": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz", - "integrity": "sha512-p/iXrPSVfnqPft24ZdNNLECw/UrtLTpT3jpAAMzl/o5/rDsGCPo3/CQS2611flL6LkoEJ3oQZw7C8Q80ZISXRQ==", - "peer": true - }, - "proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", - "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", - "requires": { - "agent-base": "^6.0.0", - "debug": "4", - "http-proxy-agent": "^4.0.0", - "https-proxy-agent": "^5.0.0", - "lru-cache": "^5.1.1", - "pac-proxy-agent": "^5.0.0", - "proxy-from-env": "^1.0.0", - "socks-proxy-agent": "^5.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "requires": { - "yallist": "^3.0.2" - } - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - } - } - }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "peer": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "peer": true - }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "peer": true, - "requires": { - "side-channel": "^1.0.4" - } - }, - "querystring": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz", - "integrity": "sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==", - "peer": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "peer": true - }, - "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "peer": true - }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "peer": true, - "requires": { - "readable-stream": "^3.6.0" - } - }, - "readdir-glob": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.2.tgz", - "integrity": "sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA==", - "peer": true, - "requires": { - "minimatch": "^5.1.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "peer": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", - "peer": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "peer": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "peer": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "peer": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "peer": true - }, - "responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "peer": true, - "requires": { - "lowercase-keys": "^2.0.0" - } - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==" - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "peer": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - } - }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "peer": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "run-parallel-limit": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", - "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", - "peer": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "rxjs": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.6.tgz", - "integrity": "sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==", - "requires": { - "tslib": "^2.1.0" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" - }, - "seek-bzip": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", - "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==", - "peer": true, - "requires": { - "commander": "^2.8.1" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "peer": true - } - } - }, - "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "peer": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "serverless": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/serverless/-/serverless-3.22.0.tgz", - "integrity": "sha512-S/C4jbTFW95AwAw2wSqQa28FCordHwj+sUt3SHPgLNq0ryWcagR03C7vvIEnunmb7Rj5uEIcvArmjuaYNYN0+w==", - "peer": true, - "requires": { - "@serverless/dashboard-plugin": "^6.2.2", - "@serverless/platform-client": "^4.3.2", - "@serverless/utils": "^6.7.0", - "ajv": "^8.11.0", - "ajv-formats": "^2.1.1", - "archiver": "^5.3.1", - "aws-sdk": "^2.1195.0", - "bluebird": "^3.7.2", - "cachedir": "^2.3.0", - "chalk": "^4.1.2", - "child-process-ext": "^2.1.1", - "ci-info": "^3.3.2", - "cli-progress-footer": "^2.3.2", - "d": "^1.0.1", - "dayjs": "^1.11.5", - "decompress": "^4.2.1", - "dotenv": "^10.0.0", - "dotenv-expand": "^5.1.0", - "essentials": "^1.2.0", - "ext": "^1.6.0", - "fastest-levenshtein": "^1.0.16", - "filesize": "^8.0.7", - "fs-extra": "^9.1.0", - "get-stdin": "^8.0.0", - "globby": "^11.1.0", - "got": "^11.8.5", - "graceful-fs": "^4.2.10", - "https-proxy-agent": "^5.0.1", - "is-docker": "^2.2.1", - "js-yaml": "^4.1.0", - "json-cycle": "^1.3.0", - "json-refs": "^3.0.15", - "lodash": "^4.17.21", - "memoizee": "^0.4.15", - "micromatch": "^4.0.5", - "node-fetch": "^2.6.7", - "npm-registry-utilities": "^1.0.0", - "object-hash": "^2.2.0", - "open": "^7.4.2", - "path2": "^0.1.0", - "process-utils": "^4.0.0", - "promise-queue": "^2.2.5", - "require-from-string": "^2.0.2", - "semver": "^7.3.7", - "signal-exit": "^3.0.7", - "strip-ansi": "^6.0.1", - "supports-color": "^8.1.1", - "tar": "^6.1.11", - "timers-ext": "^0.1.7", - "type": "^2.7.2", - "untildify": "^4.0.0", - "uuid": "^8.3.2", - "yaml-ast-parser": "0.0.43" - } - }, - "serverless-plugin-datadog": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/serverless-plugin-datadog/-/serverless-plugin-datadog-5.4.0.tgz", - "integrity": "sha512-BIXgcraJ8XTqxMC6X8Xp4HpljE+oV5jB5Bxb7pss6I4HS5e8mqBl3uX4NoRXIn8C48/bsISS7JlX93FFJ69b5A==", - "requires": { - "@datadog/datadog-ci": "^1.8.0", - "node-fetch": "^2.6.1", - "simple-git": "^3.3.0" - } - }, - "serverless-python-requirements": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/serverless-python-requirements/-/serverless-python-requirements-5.4.0.tgz", - "integrity": "sha512-0ji96KayLG3G3vxtHS6GRcU2879tFPk6gAaRejRkPCf4RxmbebWjIbf56xljRi7DmBzhmxLJd93FVGPq9aundQ==", - "requires": { - "@iarna/toml": "^2.2.5", - "appdirectory": "^0.1.0", - "bluebird": "^3.7.2", - "child-process-ext": "^2.1.1", - "fs-extra": "^9.1.0", - "glob-all": "^3.3.0", - "is-wsl": "^2.2.0", - "jszip": "^3.7.1", - "lodash.get": "^4.4.2", - "lodash.uniqby": "^4.7.0", - "lodash.values": "^4.3.0", - "rimraf": "^3.0.2", - "set-value": "^4.1.0", - "sha256-file": "1.0.0", - "shell-quote": "^1.7.3" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" - }, - "set-value": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-4.1.0.tgz", - "integrity": "sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==", - "requires": { - "is-plain-object": "^2.0.4", - "is-primitive": "^3.0.1" - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "sha256-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/sha256-file/-/sha256-file-1.0.0.tgz", - "integrity": "sha512-nqf+g0veqgQAkDx0U2y2Tn2KWyADuuludZTw9A7J3D+61rKlIIl9V5TS4mfnwKuXZOH9B7fQyjYJ9pKRHIsAyg==" - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "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": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==" - }, - "shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==" - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "peer": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "simple-git": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.12.0.tgz", - "integrity": "sha512-cy1RSRFHGZSrlYa3MnUuNVOXLUdifEZD2X8+AZjg8mKCdRvtCFSga6acq5N2g0ggb8lH3jBi369MrFZ+Y6sfsA==", - "requires": { - "@kwsites/file-exists": "^1.1.1", - "@kwsites/promise-deferred": "^1.1.1", - "debug": "^4.3.4" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "peer": true - }, - "smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" - }, - "socks": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", - "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", - "requires": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - }, - "dependencies": { - "ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" - } - } - }, - "socks-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", - "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", - "requires": { - "agent-base": "^6.0.2", - "debug": "4", - "socks": "^2.3.3" - } - }, - "sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", - "peer": true, - "requires": { - "is-plain-obj": "^1.0.0" - } - }, - "sort-keys-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", - "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", - "peer": true, - "requires": { - "sort-keys": "^1.0.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true - }, - "split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "requires": { - "readable-stream": "^3.0.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "peer": true - }, - "sprintf-kit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/sprintf-kit/-/sprintf-kit-2.0.1.tgz", - "integrity": "sha512-2PNlcs3j5JflQKcg4wpdqpZ+AjhQJ2OZEo34NXDtlB0tIPG84xaaXhpA8XFacFiwjKA4m49UOYG83y3hbMn/gQ==", - "requires": { - "es5-ext": "^0.10.53" - } - }, - "ssh2": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.9.0.tgz", - "integrity": "sha512-rhhIZT0eMPvCBSOG8CpqZZ7gre2vgXaIqmb3Jb83t88rjsxIsFzDanqBJM9Ns8BmP1835A5IbQ199io4EUZwOA==", - "requires": { - "asn1": "^0.2.4", - "bcrypt-pbkdf": "^1.0.2", - "cpu-features": "~0.0.4", - "nan": "^2.15.0" - } - }, - "ssh2-streams": { - "version": "0.4.10", - "resolved": "https://registry.npmjs.org/ssh2-streams/-/ssh2-streams-0.4.10.tgz", - "integrity": "sha512-8pnlMjvnIZJvmTzUIIA5nT4jr2ZWNNVHwyXfMGdRJbug9TpI3kd99ffglgfSWqujVv/0gxwMsDn9j9RVst8yhQ==", - "requires": { - "asn1": "~0.2.0", - "bcrypt-pbkdf": "^1.0.2", - "streamsearch": "~0.1.2" - } - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" - }, - "stream-promise": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/stream-promise/-/stream-promise-3.2.0.tgz", - "integrity": "sha512-P+7muTGs2C8yRcgJw/PPt61q7O517tDHiwYEzMWo1GSBCcZedUMT/clz7vUNsSxFphIlJ6QUL4GexQKlfJoVtA==", - "requires": { - "2-thenable": "^1.0.0", - "es5-ext": "^0.10.49", - "is-stream": "^1.1.0" - } - }, - "streamsearch": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", - "integrity": "sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", - "peer": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", - "peer": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", - "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", - "peer": true, - "requires": { - "is-natural-number": "^4.0.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" - }, - "strip-outer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", - "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", - "peer": true, - "requires": { - "escape-string-regexp": "^1.0.2" - } - }, - "strtok3": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", - "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", - "peer": true, - "requires": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^4.1.0" - } - }, - "superagent": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-7.1.6.tgz", - "integrity": "sha512-gZkVCQR1gy/oUXr+kxJMLDjla434KmSOKbx5iGD30Ql+AkJQ/YlPKECJy2nhqOsHLjGHzoDTXNSjhnvWhzKk7g==", - "peer": true, - "requires": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.3", - "debug": "^4.3.4", - "fast-safe-stringify": "^2.1.1", - "form-data": "^4.0.0", - "formidable": "^2.0.1", - "methods": "^1.1.2", - "mime": "2.6.0", - "qs": "^6.10.3", - "readable-stream": "^3.6.0", - "semver": "^7.3.7" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "peer": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "symbol-observable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", - "integrity": "sha512-Kb3PrPYz4HanVF1LVGuAdW6LoVgIwjUYJGzFe7NDrBLCN4lsV/5J0MFurV+ygS4bRVwrCEt2c7MQ1R2a72oJDw==" - }, - "tar": { - "version": "6.1.11", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", - "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", - "peer": true, - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "peer": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - }, - "throat": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", - "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", - "peer": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" - }, - "timers-ext": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", - "peer": true, - "requires": { - "es5-ext": "~0.10.46", - "next-tick": "1" - } - }, - "tiny-async-pool": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-1.2.0.tgz", - "integrity": "sha512-PY/OiSenYGBU3c1nTuP1HLKRkhKFDXsAibYI5GeHbHw2WVpt6OFzAPIRP94dGnS66Jhrkheim2CHAXUNI4XwMg==", - "requires": { - "semver": "^5.5.0", - "yaassertion": "^1.0.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "to-buffer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", - "peer": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "peer": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" - }, - "token-types": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", - "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", - "peer": true, - "requires": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - }, - "dependencies": { - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "peer": true - } - } - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "traverse": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", - "integrity": "sha512-kdf4JKs8lbARxWdp7RKdNzoJBhGUcIalSYibuGyHJbmk40pOysQ0+QPvlkCOICOivDWU2IJo2rkrxyTK2AH4fw==", - "peer": true - }, - "trim-repeated": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", - "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", - "peer": true, - "requires": { - "escape-string-regexp": "^1.0.2" - } - }, - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" - }, - "type": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", - "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" - }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "peer": true, - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, - "unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "peer": true, - "requires": { - "buffer": "^5.2.1", - "through": "^2.3.8" - }, - "dependencies": { - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "peer": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - } - } - }, - "uni-global": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/uni-global/-/uni-global-1.0.0.tgz", - "integrity": "sha512-WWM3HP+siTxzIWPNUg7hZ4XO8clKi6NoCAJJWnuRL+BAqyFXF8gC03WNyTefGoUXYc47uYgXxpKLIEvo65PEHw==", - "requires": { - "type": "^2.5.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" - }, - "untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "peer": true - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "peer": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", - "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": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==" - } - } - }, - "util": { - "version": "0.12.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", - "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", - "peer": true, - "requires": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "safe-buffer": "^5.1.2", - "which-typed-array": "^1.1.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "peer": true - }, - "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": "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==", - "peer": true, - "requires": { - "builtins": "^1.0.3" - } - }, - "vm2": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.10.tgz", - "integrity": "sha512-AuECTSvwu2OHLAZYhG716YzwodKCIJxB6u1zG7PgSQwIgAlEaoXH52bxdcvT8GkGjnYK7r7yWDW0m0sOsPuBjQ==", - "requires": { - "acorn": "^8.7.0", - "acorn-walk": "^8.2.0" - } - }, - "wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "requires": { - "defaults": "^1.0.3" - } - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "peer": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==" - }, - "which-typed-array": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", - "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", - "peer": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.9" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "peer": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "write-file-atomic": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", - "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", - "peer": true, - "requires": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - } - }, - "ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "peer": true, - "requires": {} - }, - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "peer": true, - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ==" - }, - "xregexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", - "integrity": "sha512-xl/50/Cf32VsGq/1R8jJE5ajH1yMCQkpmoS10QbFZWl2Oor4H0Me64Pu2yxvsRWK3m6soJbmGfzSR7BYmDcWAA==" - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "peer": true - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, - "yaassertion": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/yaassertion/-/yaassertion-1.0.2.tgz", - "integrity": "sha512-sBoJBg5vTr3lOpRX0yFD+tz7wv/l2UPMFthag4HGTMPrypBRKerjjS8jiEnNMjcAEtPXjbHiKE0UwRR1W1GXBg==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "peer": true - }, - "yaml-ast-parser": { - "version": "0.0.43", - "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", - "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", - "peer": true - }, - "yamljs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", - "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", - "peer": true, - "requires": { - "argparse": "^1.0.7", - "glob": "^7.0.5" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "peer": true, - "requires": { - "sprintf-js": "~1.0.2" - } - } - } - }, - "yamux-js": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yamux-js/-/yamux-js-0.1.0.tgz", - "integrity": "sha512-Bg/H2ZIV/FZ2O7LZ4nNYBoE69KPljE6Vo47p5gC7flCxSQQLmbCy1EKYqvq6tLBVBb/ep+6I2niKtPuNlj6hyw==" - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "peer": true, - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "zip-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", - "integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==", - "peer": true, - "requires": { - "archiver-utils": "^2.1.0", - "compress-commons": "^4.1.0", - "readable-stream": "^3.6.0" - } - } - } -} diff --git a/premium/eagle-eye/package.json b/premium/eagle-eye/package.json deleted file mode 100644 index 738e4ca127..0000000000 --- a/premium/eagle-eye/package.json +++ /dev/null @@ -1,18 +0,0 @@ - -{ - "name": "crowd.dev-eagle-eye", - "description": "Eagle Eye stack for the Crowd project", - "author": "team@crowd.dev", - "scripts": { - "sls-deploy": "export CROWD_VERSION=$(git describe --tags --abbrev=0) && serverless deploy", - "sls-deploy-local": "serverless deploy --stage local", - "sls-deploy-prod": "export CROWD_VERSION=$(git describe --tags --abbrev=0) && serverless deploy --stage prod", - "invoke-local": "export CROWD_VERSION=$(git describe --tags --abbrev=0) && npx serverless invoke local", - "invoke": "export CROWD_VERSION=$(git describe --tags --abbrev=0) && npx serverless invoke", - "invoke-prod": "npx serverless invoke --stage prod" - }, - "dependencies": { - "serverless-python-requirements": "^5.4.0", - "serverless-plugin-datadog": "^5.1.1" - } - } \ No newline at end of file diff --git a/premium/eagle-eye/requirements-serverless.txt b/premium/eagle-eye/requirements-serverless.txt deleted file mode 100644 index 4c373925c4..0000000000 --- a/premium/eagle-eye/requirements-serverless.txt +++ /dev/null @@ -1 +0,0 @@ -./crowd-eagle-eye \ No newline at end of file diff --git a/premium/eagle-eye/requirements.txt b/premium/eagle-eye/requirements.txt deleted file mode 100644 index 3c121e98bd..0000000000 --- a/premium/eagle-eye/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -wheel --e ./crowd-eagle-eye -flask -boto3 -python-json-logger \ No newline at end of file diff --git a/premium/eagle-eye/server.py b/premium/eagle-eye/server.py deleted file mode 100644 index 33f918245e..0000000000 --- a/premium/eagle-eye/server.py +++ /dev/null @@ -1,41 +0,0 @@ -from flask import Flask -from crowd.eagle_eye.search import search_main, keyword_match_main -from crowd.eagle_eye.infrastructure.logging import get_logger -from flask import request -from flask.logging import default_handler - -app = Flask(__name__) - -app.logger.removeHandler(default_handler) -logger = get_logger(__name__) - - -@app.route("/search", methods=['POST']) -def search(): - try: - body = request.get_json() - logger.info(f"Eagle Eye: received request for search: {body}") - queries = body.get('queries', []) - ndays = body.get('nDays', 10) - exclude = body.get('filters', []) - exact_keywords = body.get('exactKeywords', False) - return search_main(queries, ndays, exclude, exact_keywords) - except Exception as e: - logger.error(f"Eagle Eye: error in search: {e}") - return {"error": str(e)} - - -@app.route("/keyword-match", methods=['POST']) -def keyword_match(): - try: - body = request.get_json() - logger.info(f"Eagle Eye: received request for keyword_match: {body}") - ndays = body.get('nDays', 10) - exclude = body.get('filters', []) - platform = body.get('platform', None) - exact_keywords = body.get('exactKeywords', []) - out = keyword_match_main(ndays, exclude, exact_keywords, platform) - return out - except Exception as e: - logger.error(f"Error in keyword_match: {e}") - return {"error": str(e)} diff --git a/premium/eagle-eye/serverless.yml b/premium/eagle-eye/serverless.yml deleted file mode 100644 index c7881b33df..0000000000 --- a/premium/eagle-eye/serverless.yml +++ /dev/null @@ -1,77 +0,0 @@ -service: EagleEye -frameworkVersion: '3' -useDotenv: true - -provider: - name: aws - runtime: python3.8 - stage: staging - memorySize: 3072 # optional, in MB, default is 1024 - timeout: 900 # optional, in seconds, default is 6 - iamRoleStatements: - - Effect: 'Allow' - Action: - - 'states:StartExecution' - - sqs:SendMessage - - secretsmanager:GetSecretValue - Resource: - - '*' - region: eu-central-1 - ecr: - # In this section you can define images that will be built locally and uploaded to ECR - images: - EagleEye: - path: ./ - - -custom: - currentStage: ${opt:stage, self:provider.stage} # 'staging' is default unless overriden by --stage flag - -functions: - scheduled: - image: ${env:AWS_ACCOUNT_ID}.dkr.ecr.${env:AWS_REGION}.amazonaws.com/python-eagle-eye-lambda:${env:CROWD_VERSION} - events: - - schedule: - rate: rate(2 hours) - input: - platform: hacker_news - - schedule: - rate: rate(2 hours) - input: - platform: devto - environment: - DD_ENV: ${env:NODE_ENV} - DD_CAPTURE_LAMBDA_PAYLOAD: true - DD_SITE: datadoghq.eu - DD_API_KEY_SECRET_ARN: ${env:DATADOG_API_KEY_SECRET_ARN} - DD_TRACE_ENABLED: true - DD_LAMBDA_HANDLER: handler.scheduled - DD_LOGS_ENABLED: true - DD_TAGS: 'context:eagleEye' - DD_SERVICE: 'eagleEye' - DD_LOGS_INJECTION: true - COHERE_API_KEY: ${env:COHERE_API_KEY} - VECTOR_API_KEY: ${env:VECTOR_API_KEY} - VECTOR_INDEX: ${env:VECTOR_INDEX} - - search: - image: ${env:AWS_ACCOUNT_ID}.dkr.ecr.${env:AWS_REGION}.amazonaws.com/python-eagle-eye-lambda:${env:CROWD_VERSION} - environment: - DD_ENV: ${env:NODE_ENV} - DD_CAPTURE_LAMBDA_PAYLOAD: true - DD_SITE: datadoghq.eu - DD_API_KEY_SECRET_ARN: ${env:DATADOG_API_KEY_SECRET_ARN} - DD_TRACE_ENABLED: true - DD_LAMBDA_HANDLER: handler.search - DD_LOGS_ENABLED: true - DD_TAGS: 'context:eagleEye' - DD_SERVICE: 'eagleEye' - DD_LOGS_INJECTION: true - COHERE_API_KEY: ${env:COHERE_API_KEY} - VECTOR_API_KEY: ${env:VECTOR_API_KEY} - VECTOR_INDEX: ${env:VECTOR_INDEX} - - -package: - patterns: - - '!venv*/**' diff --git a/premium/eagle-eye/start-premium-api.sh b/premium/eagle-eye/start-premium-api.sh deleted file mode 100755 index 159a96df71..0000000000 --- a/premium/eagle-eye/start-premium-api.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -CLI_HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -$CLI_HOME/venv/bin/python -u -m flask --app server --debug run --host=0.0.0.0 diff --git a/premium/eagle-eye/start-premium-python-worker.sh b/premium/eagle-eye/start-premium-python-worker.sh deleted file mode 100755 index 2147fe9ee9..0000000000 --- a/premium/eagle-eye/start-premium-python-worker.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -CLI_HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -$CLI_HOME/venv/bin/python -u $CLI_HOME/worker.py diff --git a/premium/eagle-eye/worker.py b/premium/eagle-eye/worker.py deleted file mode 100644 index f7820a30f5..0000000000 --- a/premium/eagle-eye/worker.py +++ /dev/null @@ -1,19 +0,0 @@ -import json - -from crowd.eagle_eye.infrastructure.sqs import SQS -from crowd.eagle_eye.infrastructure.logging import get_logger -from crowd.eagle_eye.config import PREMIUM_PYTHON_WORKER_QUEUE -from crowd.eagle_eye.scheduled import scheduled_main - -logger = get_logger(__name__) - -sqs = SQS(PREMIUM_PYTHON_WORKER_QUEUE) - -logger.info(f"Listening for messages on: {PREMIUM_PYTHON_WORKER_QUEUE}") - -while True: - msg = sqs.receive_message(delete=True, wait_time_seconds=15) - if msg is not None: - body = json.loads(msg['Body']) - platform = body['platform'] - scheduled_main(platform) diff --git a/premium/job-generator/.dockerignore b/premium/job-generator/.dockerignore deleted file mode 100644 index a8714c2596..0000000000 --- a/premium/job-generator/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -**/.git -**/node_modules -**/.webpack diff --git a/premium/job-generator/.eslintrc.js b/premium/job-generator/.eslintrc.js deleted file mode 100644 index 9897799b7f..0000000000 --- a/premium/job-generator/.eslintrc.js +++ /dev/null @@ -1,70 +0,0 @@ -module.exports = { - env: { - node: true, - es2021: true, - }, - extends: ['airbnb-base', 'prettier'], - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint'], - ignorePatterns: ['dist/*'], - rules: { - semi: ['error', 'never'], - 'prefer-destructuring': ['error', { object: false, array: false }], - 'no-param-reassign': 0, - 'no-underscore-dangle': 0, - '@typescript-eslint/naming-convention': [ - 'error', - { - selector: 'variableLike', - leadingUnderscore: 'allow', - trailingUnderscore: 'allow', - format: ['camelCase', 'PascalCase', 'UPPER_CASE'], - }, - ], - 'import/no-relative-packages': 0, - }, - settings: { - 'import/resolver': { - node: { - paths: ['src'], - extensions: ['.js', '.ts', '.d.ts', '.tsx'], - }, - }, - }, - overrides: [ - { - files: ['*.ts'], - extends: ['airbnb-base', 'airbnb-typescript/base', 'prettier'], - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - tsconfigRootDir: __dirname, - project: './tsconfig.json', - }, - rules: { - semi: ['error', 'never'], - 'prefer-destructuring': ['error', { object: false, array: false }], - 'no-param-reassign': 0, - 'no-underscore-dangle': 0, - '@typescript-eslint/naming-convention': [ - 'error', - { - selector: 'variableLike', - leadingUnderscore: 'allow', - trailingUnderscore: 'allow', - format: ['camelCase', 'PascalCase', 'UPPER_CASE'], - }, - ], - 'import/no-relative-packages': 0, - 'global-require': 0, - 'import/prefer-default-export': 0, - '@typescript-eslint/no-use-before-define': ['error', { functions: false, classes: false }], - 'no-restricted-syntax': 0, - 'no-plusplus': 0, - 'no-await-in-loop': 0, - '@typescript-eslint/no-shadow': 0, - 'no-console': 0, - }, - }, - ], -} diff --git a/premium/job-generator/.prettierignore b/premium/job-generator/.prettierignore deleted file mode 100644 index de4d1f007d..0000000000 --- a/premium/job-generator/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules diff --git a/premium/job-generator/.prettierrc b/premium/job-generator/.prettierrc deleted file mode 100644 index 529f793325..0000000000 --- a/premium/job-generator/.prettierrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "singleQuote": true, - "arrowParens": "always", - "printWidth": 100, - "trailingComma": "all", - "semi": false -} diff --git a/premium/job-generator/Dockerfile b/premium/job-generator/Dockerfile deleted file mode 100644 index f862c01698..0000000000 --- a/premium/job-generator/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -# syntax = docker/dockerfile:experimental -FROM node:16-alpine - -WORKDIR /usr/crowd/premium-job-generator -COPY package-lock.json package.json ./ - -RUN npm install - -COPY . . \ No newline at end of file diff --git a/premium/job-generator/babel.config.json b/premium/job-generator/babel.config.json deleted file mode 100644 index 15326ba58b..0000000000 --- a/premium/job-generator/babel.config.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - /* for jest to transpile typescript */ - "presets": ["@babel/preset-env"], - "plugins": ["@babel/plugin-transform-runtime"] -} diff --git a/premium/job-generator/config/custom-environment-variables.json b/premium/job-generator/config/custom-environment-variables.json deleted file mode 100644 index 424ce181b4..0000000000 --- a/premium/job-generator/config/custom-environment-variables.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "sqs": { - "host": "CROWD_SQS_HOST", - "port": "CROWD_SQS_PORT", - "nodejsWorkerQueue": "CROWD_SQS_NODEJS_WORKER_QUEUE", - "pythonWorkerQueue": "CROWD_SQS_PYTHON_WORKER_QUEUE", - "premiumPythonWorkerQueue": "CROWD_SQS_PREMIUM_PYTHON_WORKER_QUEUE", - "aws": { - "accountId": "CROWD_SQS_AWS_ACCOUNT_ID", - "accessKeyId": "CROWD_SQS_AWS_ACCESS_KEY_ID", - "secretAccessKey": "CROWD_SQS_AWS_SECRET_ACCESS_KEY", - "region": "CROWD_SQS_AWS_REGION" - } - } -} diff --git a/premium/job-generator/config/default.json b/premium/job-generator/config/default.json deleted file mode 100644 index d138e9be62..0000000000 --- a/premium/job-generator/config/default.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "sqs": {} -} diff --git a/premium/job-generator/config/docker.json b/premium/job-generator/config/docker.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/premium/job-generator/config/docker.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/premium/job-generator/config/production.json b/premium/job-generator/config/production.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/premium/job-generator/config/production.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/premium/job-generator/config/staging.json b/premium/job-generator/config/staging.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/premium/job-generator/config/staging.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/premium/job-generator/config/test.json b/premium/job-generator/config/test.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/premium/job-generator/config/test.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/premium/job-generator/package-lock.json b/premium/job-generator/package-lock.json deleted file mode 100644 index 5e00178c3e..0000000000 --- a/premium/job-generator/package-lock.json +++ /dev/null @@ -1,10527 +0,0 @@ -{ - "name": "premium-job-generator", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "premium-job-generator", - "dependencies": { - "aws-sdk": "2.814.0", - "bunyan": "^1.8.15", - "bunyan-format": "^0.2.1", - "config": "^3.3.8", - "cron": "^2.1.0", - "cron-time-generator": "^1.3.0", - "moment": "2.29.4", - "moment-timezone": "^0.5.34" - }, - "devDependencies": { - "@babel/plugin-transform-runtime": "^7.18.10", - "@babel/preset-env": "^7.16.10", - "@types/config": "^3.3.0", - "eslint": "^8.12.0", - "eslint-config-airbnb-base": "^15.0.0", - "eslint-config-airbnb-typescript": "^16.1.4", - "eslint-config-prettier": "^8.5.0", - "nodemon": "2.0.4", - "prettier": "^2.5.1", - "ts-node": "10.6.0", - "typescript": "^4.7.4" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.1.tgz", - "integrity": "sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.1.tgz", - "integrity": "sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==", - "dev": true, - "peer": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.1", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.1", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", - "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.19.0", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", - "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", - "dev": true, - "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.18.6", - "@babel/types": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz", - "integrity": "sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.19.1", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz", - "integrity": "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.9", - "@babel/helper-split-export-declaration": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", - "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "regexpu-core": "^5.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", - "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", - "dev": true, - "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", - "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", - "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-wrap-function": "^7.18.9", - "@babel/types": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", - "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", - "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", - "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", - "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.1.tgz", - "integrity": "sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", - "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", - "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", - "@babel/plugin-proposal-optional-chaining": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz", - "integrity": "sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-remap-async-to-generator": "^7.18.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", - "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", - "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", - "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", - "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", - "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", - "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", - "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.9.tgz", - "integrity": "sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.18.8", - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.18.8" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", - "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", - "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", - "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", - "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", - "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-remap-async-to-generator": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", - "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz", - "integrity": "sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz", - "integrity": "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-compilation-targets": "^7.19.0", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-replace-supers": "^7.18.9", - "@babel/helper-split-export-declaration": "^7.18.6", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-classes/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", - "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.18.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.13.tgz", - "integrity": "sha512-TodpQ29XekIsex2A+YJPj5ax2plkGa8YYY6mFjCohk/IG9IY42Rtuj1FuDeemfg2ipxIFLzPeA83SIBnlhSIow==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", - "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", - "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", - "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", - "dev": true, - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", - "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", - "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", - "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", - "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz", - "integrity": "sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz", - "integrity": "sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.0.tgz", - "integrity": "sha512-x9aiR0WXAWmOWsqcsnrzGR+ieaTMVyGyffPVA7F8cXAGt/UxefYv6uSHZLkAFChN5M5Iy1+wjE+xJuPt22H39A==", - "dev": true, - "dependencies": { - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-validator-identifier": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", - "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", - "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", - "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", - "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz", - "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", - "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", - "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "regenerator-transform": "^0.15.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", - "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.1.tgz", - "integrity": "sha512-2nJjTUFIzBMP/f/miLxEK9vxwW/KUXsdvN4sR//TmuDhe6yU2h57WmIOE12Gng3MDP/xpjUV/ToZRdcf8Yj4fA==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.19.0", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", - "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", - "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", - "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", - "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", - "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", - "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", - "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.1.tgz", - "integrity": "sha512-c8B2c6D16Lp+Nt6HcD+nHl0VbPKVnNPTpszahuxJJnurfMtKeZ80A+qUv48Y7wqvS+dTFuLuaM9oYxyNHbCLWA==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.19.1", - "@babel/helper-compilation-targets": "^7.19.1", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-async-generator-functions": "^7.19.1", - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-class-static-block": "^7.18.6", - "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.9", - "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", - "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.18.9", - "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.18.6", - "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.18.6", - "@babel/plugin-transform-async-to-generator": "^7.18.6", - "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.18.9", - "@babel/plugin-transform-classes": "^7.19.0", - "@babel/plugin-transform-computed-properties": "^7.18.9", - "@babel/plugin-transform-destructuring": "^7.18.13", - "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.9", - "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.18.8", - "@babel/plugin-transform-function-name": "^7.18.9", - "@babel/plugin-transform-literals": "^7.18.9", - "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.18.6", - "@babel/plugin-transform-modules-commonjs": "^7.18.6", - "@babel/plugin-transform-modules-systemjs": "^7.19.0", - "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", - "@babel/plugin-transform-new-target": "^7.18.6", - "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.18.8", - "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.18.6", - "@babel/plugin-transform-reserved-words": "^7.18.6", - "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.19.0", - "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.9", - "@babel/plugin-transform-typeof-symbol": "^7.18.9", - "@babel/plugin-transform-unicode-escapes": "^7.18.10", - "@babel/plugin-transform-unicode-regex": "^7.18.6", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.19.0", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "core-js-compat": "^3.25.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz", - "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.1.tgz", - "integrity": "sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.1", - "@babel/types": "^7.19.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", - "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.18.6", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@cspotcode/source-map-consumer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", - "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", - "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-consumer": "0.8.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", - "integrity": "sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dev": true, - "dependencies": { - "defer-to-connect": "^1.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, - "node_modules/@types/config": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@types/config/-/config-3.3.0.tgz", - "integrity": "sha512-9kZSbl3/X3TVNowLCu5HFQdQmD+4287Om55avknEYkuo6R2dDrsp/EXEHUFvfYeG7m1eJ0WYGj+cbcUIhARJAQ==", - "dev": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true, - "peer": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true, - "peer": true - }, - "node_modules/@types/node": { - "version": "18.7.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", - "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==", - "dev": true, - "peer": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.38.0.tgz", - "integrity": "sha512-GgHi/GNuUbTOeoJiEANi0oI6fF3gBQc3bGFYj40nnAPCbhrtEDf2rjBmefFadweBmO1Du1YovHeDP2h5JLhtTQ==", - "dev": true, - "peer": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.38.0", - "@typescript-eslint/type-utils": "5.38.0", - "@typescript-eslint/utils": "5.38.0", - "debug": "^4.3.4", - "ignore": "^5.2.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.38.0.tgz", - "integrity": "sha512-/F63giJGLDr0ms1Cr8utDAxP2SPiglaD6V+pCOcG35P2jCqdfR7uuEhz1GIC3oy4hkUF8xA1XSXmd9hOh/a5EA==", - "dev": true, - "peer": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.38.0", - "@typescript-eslint/types": "5.38.0", - "@typescript-eslint/typescript-estree": "5.38.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.38.0.tgz", - "integrity": "sha512-ByhHIuNyKD9giwkkLqzezZ9y5bALW8VNY6xXcP+VxoH4JBDKjU5WNnsiD4HJdglHECdV+lyaxhvQjTUbRboiTA==", - "dev": true, - "peer": true, - "dependencies": { - "@typescript-eslint/types": "5.38.0", - "@typescript-eslint/visitor-keys": "5.38.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.38.0.tgz", - "integrity": "sha512-iZq5USgybUcj/lfnbuelJ0j3K9dbs1I3RICAJY9NZZpDgBYXmuUlYQGzftpQA9wC8cKgtS6DASTvF3HrXwwozA==", - "dev": true, - "peer": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.38.0", - "@typescript-eslint/utils": "5.38.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.38.0.tgz", - "integrity": "sha512-HHu4yMjJ7i3Cb+8NUuRCdOGu2VMkfmKyIJsOr9PfkBVYLYrtMCK/Ap50Rpov+iKpxDTfnqvDbuPLgBE5FwUNfA==", - "dev": true, - "peer": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.38.0.tgz", - "integrity": "sha512-6P0RuphkR+UuV7Avv7MU3hFoWaGcrgOdi8eTe1NwhMp2/GjUJoODBTRWzlHpZh6lFOaPmSvgxGlROa0Sg5Zbyg==", - "dev": true, - "peer": true, - "dependencies": { - "@typescript-eslint/types": "5.38.0", - "@typescript-eslint/visitor-keys": "5.38.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.38.0.tgz", - "integrity": "sha512-6sdeYaBgk9Fh7N2unEXGz+D+som2QCQGPAf1SxrkEr+Z32gMreQ0rparXTNGRRfYUWk/JzbGdcM8NSSd6oqnTA==", - "dev": true, - "peer": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.38.0", - "@typescript-eslint/types": "5.38.0", - "@typescript-eslint/typescript-estree": "5.38.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.38.0.tgz", - "integrity": "sha512-MxnrdIyArnTi+XyFLR+kt/uNAcdOnmT+879os7qDRI+EYySR4crXJq9BXPfRzzLGq0wgxkwidrCJ9WCAoacm1w==", - "dev": true, - "peer": true, - "dependencies": { - "@typescript-eslint/types": "5.38.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "dependencies": { - "string-width": "^4.1.0" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/ansicolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz", - "integrity": "sha512-tOIuy1/SK/dr94ZA0ckDohKXNeBNqZ4us6PjMVLs5h1w2GBB6uPtOknp2+VF4F/zcy9LI70W+Z+pE2Soajky1w==" - }, - "node_modules/ansistyles": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz", - "integrity": "sha512-6QWEyvMgIXX0eO972y7YPBLSBsq7UWKFAoNNTLGaOJ9bstcEL9sCbcjf96dVfNDdUsRoGOK82vWFJlKApXds7g==" - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-includes": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", - "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", - "dev": true, - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", - "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", - "dev": true, - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/aws-sdk": { - "version": "2.814.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.814.0.tgz", - "integrity": "sha512-empd1m/J/MAkL6d9OeRpmg9thobULu0wk4v8W3JToaxGi2TD7PIdvE6yliZKyOVAdJINhBWEBhxR4OUIHhcGbQ==", - "dependencies": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.3.2", - "xml2js": "0.4.19" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "dependencies": { - "object.assign": "^4.1.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "devOptional": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/boxen": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", - "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", - "dev": true, - "dependencies": { - "ansi-align": "^3.0.0", - "camelcase": "^5.3.1", - "chalk": "^3.0.0", - "cli-boxes": "^2.2.0", - "string-width": "^4.1.0", - "term-size": "^2.1.0", - "type-fest": "^0.8.1", - "widest-line": "^3.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/boxen/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "devOptional": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "node_modules/bunyan": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.15.tgz", - "integrity": "sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==", - "engines": [ - "node >=0.10.0" - ], - "bin": { - "bunyan": "bin/bunyan" - }, - "optionalDependencies": { - "dtrace-provider": "~0.8", - "moment": "^2.19.3", - "mv": "~2", - "safe-json-stringify": "~1" - } - }, - "node_modules/bunyan-format": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/bunyan-format/-/bunyan-format-0.2.1.tgz", - "integrity": "sha512-xQs2LwWskjQdv7bVkMNwvMi7HnvDQoX4587H90nDGQGPPwHrmxsihBOIYHMVwjLMMOokITKPyFcbFneblvMEjQ==", - "dependencies": { - "ansicolors": "~0.2.1", - "ansistyles": "~0.1.1", - "xtend": "~2.1.1" - } - }, - "node_modules/cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cacheable-request/node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001409", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001409.tgz", - "integrity": "sha512-V0mnJ5dwarmhYv8/MzhJ//aW68UpvnQBXv8lJ2QUsvn2pHcmAuNtu8hQEDz37XnA1iE+lRR9CIfGWWpgJ5QedQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "node_modules/cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "devOptional": true - }, - "node_modules/config": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/config/-/config-3.3.8.tgz", - "integrity": "sha512-rFzF6VESOdp7wAXFlB9IOZI4ouL05g3A03v2eRcTHj2JBQaTNJ40zhAUl5wRbWHqLZ+uqp/7OE0BWWtAVgrong==", - "dependencies": { - "json5": "^2.2.1" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dev": true, - "dependencies": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/core-js-compat": { - "version": "3.25.2", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.25.2.tgz", - "integrity": "sha512-TxfyECD4smdn3/CjWxczVtJqVLEEC2up7/82t7vC0AzNogr+4nQ8vyF7abxAuTXWvjTClSbvGhU0RgqA4ToQaQ==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cron": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cron/-/cron-2.1.0.tgz", - "integrity": "sha512-Hq7u3P8y7UWYvsZbSKHHJDVG0VO9O7tp2qljxzTScelcTODBfCme8AIhnZsFwmQ9NchZ3hr2uNr+s3DSms7q6w==", - "dependencies": { - "luxon": "^1.23.x" - } - }, - "node_modules/cron-time-generator": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/cron-time-generator/-/cron-time-generator-1.3.0.tgz", - "integrity": "sha512-1w+26RkhSUOwGMA9AL6abEjCvbFvd5mbHvFpLdj8L83LR0B4j6AH1p2H3Bh90yjThb4nviSRtsk/4qaJQNQblA==" - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true - }, - "node_modules/define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dev": true, - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dtrace-provider": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz", - "integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "nan": "^2.14.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/duplexer3": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", - "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", - "dev": true - }, - "node_modules/electron-to-chromium": { - "version": "1.4.256", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.256.tgz", - "integrity": "sha512-x+JnqyluoJv8I0U9gVe+Sk2st8vF0CzMt78SXxuoWCooLLY2k5VerIBdpvG7ql6GKI4dzNnPjmqgDJ76EdaAKw==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/es-abstract": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.2.tgz", - "integrity": "sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.2", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "dev": true, - "peer": true, - "dependencies": { - "has": "^1.0.3" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.23.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.1.tgz", - "integrity": "sha512-w7C1IXCc6fNqjpuYd0yPlcTKKmHlHHktRkzmBPZ+7cvNBQuiNjx0xaMTjAJGCafJhQkrFJooREv0CtrVzmHwqg==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.3.2", - "@humanwhocodes/config-array": "^0.10.4", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", - "@humanwhocodes/module-importer": "^1.0.1", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-airbnb-base": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", - "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", - "dev": true, - "dependencies": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5", - "semver": "^6.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.2" - } - }, - "node_modules/eslint-config-airbnb-base/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-config-airbnb-typescript": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-16.2.0.tgz", - "integrity": "sha512-OUaMPZpTOZGKd5tXOjJ9PRU4iYNW/Z5DoHIynjsVK/FpkWdiY5+nxQW6TiJAlLwVI1l53xUOrnlZWtVBVQzuWA==", - "dev": true, - "dependencies": { - "eslint-config-airbnb-base": "^15.0.0" - }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.0.0", - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.3" - } - }, - "node_modules/eslint-config-prettier": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", - "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, - "peer": true, - "dependencies": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "peer": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", - "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", - "dev": true, - "peer": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "peer": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", - "dev": true, - "peer": true, - "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", - "has": "^1.0.3", - "is-core-module": "^2.8.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", - "tsconfig-paths": "^3.14.1" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "peer": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "peer": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "peer": true - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "peer": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/global-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", - "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", - "dev": true, - "dependencies": { - "ini": "1.3.7" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dev": true, - "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, - "node_modules/ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" - }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "devOptional": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "devOptional": true - }, - "node_modules/ini": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", - "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.6.tgz", - "integrity": "sha512-krO72EO2NptOGAX2KYyqbP9vYMlNAXdB53rq6f8LXY6RY7JdSR/3BD6wLUlPHSAesmY9vstNrjvqGaCiRK/91Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "dependencies": { - "ci-info": "^2.0.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-installed-globally": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", - "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", - "dev": true, - "dependencies": { - "global-dirs": "^2.0.1", - "is-path-inside": "^3.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-npm": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", - "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha512-+kHj8HXArPfpPEKGLZ+kB5ONRTCiGQXo8RQYL0hH8t6pWXUBBK5KkkQmTNOwKK4LEsd0yTsgtjJVm4UBSZea4w==", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/js-sdsl": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", - "integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.0" - } - }, - "node_modules/latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dev": true, - "dependencies": { - "package-json": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "peer": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/luxon": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", - "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==", - "engines": { - "node": "*" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "devOptional": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "devOptional": true - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "optional": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", - "engines": { - "node": "*" - } - }, - "node_modules/moment-timezone": { - "version": "0.5.37", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.37.tgz", - "integrity": "sha512-uEDzDNFhfaywRl+vwXxffjjq1q0Vzr+fcQpQ1bU0kbzorfS7zVtZnCnGc8mhWmF39d4g4YriF6kwA75mJKE/Zg==", - "dependencies": { - "moment": ">= 2.9.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/mv": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", - "integrity": "sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==", - "optional": true, - "dependencies": { - "mkdirp": "~0.5.1", - "ncp": "~2.0.0", - "rimraf": "~2.4.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/mv/node_modules/glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==", - "optional": true, - "dependencies": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mv/node_modules/rimraf": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", - "integrity": "sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==", - "optional": true, - "dependencies": { - "glob": "^6.0.1" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/nan": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", - "optional": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/ncp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", - "integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==", - "optional": true, - "bin": { - "ncp": "bin/ncp" - } - }, - "node_modules/node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "dev": true - }, - "node_modules/nodemon": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz", - "integrity": "sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "chokidar": "^3.2.2", - "debug": "^3.2.6", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.7", - "semver": "^5.7.1", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.2", - "update-notifier": "^4.0.0" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=8.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/nodemon/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/nodemon/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/nodemon/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", - "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "dev": true, - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "devOptional": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "dev": true, - "dependencies": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/package-json/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "devOptional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dev": true, - "dependencies": { - "escape-goat": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "dev": true - }, - "node_modules/regenerator-transform": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", - "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/regexpu-core": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz", - "integrity": "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsgen": "^0.7.1", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/registry-auth-token": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", - "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", - "dev": true, - "dependencies": { - "rc": "1.2.8" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dev": true, - "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/regjsgen": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", - "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", - "dev": true - }, - "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "dev": true, - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", - "dev": true, - "dependencies": { - "lowercase-keys": "^1.0.0" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "peer": true - }, - "node_modules/safe-json-stringify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", - "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", - "optional": true - }, - "node_modules/sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" - }, - "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "peer": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, - "dependencies": { - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semver-diff/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/term-size": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", - "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dev": true, - "dependencies": { - "nopt": "~1.0.10" - }, - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/ts-node": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.6.0.tgz", - "integrity": "sha512-CJen6+dfOXolxudBQXnVjRVvYTmTWbyz7cn+xq2XTsvnaXbHqr4gXSCNbS2Jj8yTZMuGwUoBESLaOkLascVVvg==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "0.7.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.0", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tsconfig-paths": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", - "dev": true, - "peer": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "peer": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "peer": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "peer": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/typescript": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", - "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "dependencies": { - "crypto-random-string": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/update-notifier": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", - "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", - "dev": true, - "dependencies": { - "boxen": "^4.2.0", - "chalk": "^3.0.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.3.1", - "is-npm": "^4.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.0.0", - "pupa": "^2.0.1", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/yeoman/update-notifier?sponsor=1" - } - }, - "node_modules/update-notifier/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, - "node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", - "dev": true, - "dependencies": { - "prepend-http": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/url/node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" - }, - "node_modules/uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "dependencies": { - "string-width": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "devOptional": true - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, - "node_modules/xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/xtend": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", - "integrity": "sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ==", - "dependencies": { - "object-keys": "~0.4.0" - }, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/xtend/node_modules/object-keys": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", - "integrity": "sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==" - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "peer": true - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "peer": true, - "requires": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/compat-data": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.1.tgz", - "integrity": "sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==", - "dev": true - }, - "@babel/core": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.1.tgz", - "integrity": "sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==", - "dev": true, - "peer": true, - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.1", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.1", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "peer": true - } - } - }, - "@babel/generator": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", - "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", - "dev": true, - "requires": { - "@babel/types": "^7.19.0", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", - "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", - "dev": true, - "requires": { - "@babel/helper-explode-assignable-expression": "^7.18.6", - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz", - "integrity": "sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.19.1", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz", - "integrity": "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.9", - "@babel/helper-split-export-declaration": "^7.18.6" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", - "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "regexpu-core": "^5.1.0" - } - }, - "@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", - "dev": true, - "requires": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", - "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", - "dev": true, - "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", - "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", - "dev": true, - "requires": { - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", - "dev": true - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", - "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-wrap-function": "^7.18.9", - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-replace-supers": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", - "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0" - } - }, - "@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", - "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", - "dev": true, - "requires": { - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true - }, - "@babel/helper-wrap-function": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", - "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - } - }, - "@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", - "dev": true, - "peer": true, - "requires": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - } - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "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": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.1.tgz", - "integrity": "sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==", - "dev": true - }, - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", - "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", - "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", - "@babel/plugin-proposal-optional-chaining": "^7.18.9" - } - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz", - "integrity": "sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-remap-async-to-generator": "^7.18.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-proposal-class-static-block": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", - "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", - "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - } - }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", - "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", - "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3" - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", - "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", - "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", - "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.9.tgz", - "integrity": "sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.18.8", - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.18.8" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", - "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-proposal-private-property-in-object": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", - "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-import-assertions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", - "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", - "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", - "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-remap-async-to-generator": "^7.18.6" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", - "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz", - "integrity": "sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz", - "integrity": "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-compilation-targets": "^7.19.0", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-replace-supers": "^7.18.9", - "@babel/helper-split-export-declaration": "^7.18.6", - "globals": "^11.1.0" - }, - "dependencies": { - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - } - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", - "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.18.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.13.tgz", - "integrity": "sha512-TodpQ29XekIsex2A+YJPj5ax2plkGa8YYY6mFjCohk/IG9IY42Rtuj1FuDeemfg2ipxIFLzPeA83SIBnlhSIow==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", - "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", - "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", - "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", - "dev": true, - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", - "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", - "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", - "dev": true, - "requires": { - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", - "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", - "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz", - "integrity": "sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz", - "integrity": "sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.0.tgz", - "integrity": "sha512-x9aiR0WXAWmOWsqcsnrzGR+ieaTMVyGyffPVA7F8cXAGt/UxefYv6uSHZLkAFChN5M5Iy1+wjE+xJuPt22H39A==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-validator-identifier": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", - "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", - "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", - "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", - "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.6" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz", - "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", - "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", - "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "regenerator-transform": "^0.15.0" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", - "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-runtime": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.1.tgz", - "integrity": "sha512-2nJjTUFIzBMP/f/miLxEK9vxwW/KUXsdvN4sR//TmuDhe6yU2h57WmIOE12Gng3MDP/xpjUV/ToZRdcf8Yj4fA==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.19.0", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", - "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", - "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", - "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", - "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", - "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", - "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", - "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/preset-env": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.1.tgz", - "integrity": "sha512-c8B2c6D16Lp+Nt6HcD+nHl0VbPKVnNPTpszahuxJJnurfMtKeZ80A+qUv48Y7wqvS+dTFuLuaM9oYxyNHbCLWA==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.19.1", - "@babel/helper-compilation-targets": "^7.19.1", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-async-generator-functions": "^7.19.1", - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-class-static-block": "^7.18.6", - "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.9", - "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", - "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.18.9", - "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.18.6", - "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.18.6", - "@babel/plugin-transform-async-to-generator": "^7.18.6", - "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.18.9", - "@babel/plugin-transform-classes": "^7.19.0", - "@babel/plugin-transform-computed-properties": "^7.18.9", - "@babel/plugin-transform-destructuring": "^7.18.13", - "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.9", - "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.18.8", - "@babel/plugin-transform-function-name": "^7.18.9", - "@babel/plugin-transform-literals": "^7.18.9", - "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.18.6", - "@babel/plugin-transform-modules-commonjs": "^7.18.6", - "@babel/plugin-transform-modules-systemjs": "^7.19.0", - "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", - "@babel/plugin-transform-new-target": "^7.18.6", - "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.18.8", - "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.18.6", - "@babel/plugin-transform-reserved-words": "^7.18.6", - "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.19.0", - "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.9", - "@babel/plugin-transform-typeof-symbol": "^7.18.9", - "@babel/plugin-transform-unicode-escapes": "^7.18.10", - "@babel/plugin-transform-unicode-regex": "^7.18.6", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.19.0", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "core-js-compat": "^3.25.1", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, - "@babel/runtime": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz", - "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==", - "dev": true, - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" - } - }, - "@babel/traverse": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.1.tgz", - "integrity": "sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.1", - "@babel/types": "^7.19.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", - "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.18.6", - "to-fast-properties": "^2.0.0" - } - }, - "@cspotcode/source-map-consumer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", - "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", - "dev": true - }, - "@cspotcode/source-map-support": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", - "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", - "dev": true, - "requires": { - "@cspotcode/source-map-consumer": "0.8.0" - } - }, - "@eslint/eslintrc": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", - "integrity": "sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", - "dev": true - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "peer": true, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "dev": true - }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dev": true, - "requires": { - "defer-to-connect": "^1.0.1" - } - }, - "@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, - "@types/config": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@types/config/-/config-3.3.0.tgz", - "integrity": "sha512-9kZSbl3/X3TVNowLCu5HFQdQmD+4287Om55avknEYkuo6R2dDrsp/EXEHUFvfYeG7m1eJ0WYGj+cbcUIhARJAQ==", - "dev": true - }, - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true, - "peer": true - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true, - "peer": true - }, - "@types/node": { - "version": "18.7.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", - "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==", - "dev": true, - "peer": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.38.0.tgz", - "integrity": "sha512-GgHi/GNuUbTOeoJiEANi0oI6fF3gBQc3bGFYj40nnAPCbhrtEDf2rjBmefFadweBmO1Du1YovHeDP2h5JLhtTQ==", - "dev": true, - "peer": true, - "requires": { - "@typescript-eslint/scope-manager": "5.38.0", - "@typescript-eslint/type-utils": "5.38.0", - "@typescript-eslint/utils": "5.38.0", - "debug": "^4.3.4", - "ignore": "^5.2.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/parser": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.38.0.tgz", - "integrity": "sha512-/F63giJGLDr0ms1Cr8utDAxP2SPiglaD6V+pCOcG35P2jCqdfR7uuEhz1GIC3oy4hkUF8xA1XSXmd9hOh/a5EA==", - "dev": true, - "peer": true, - "requires": { - "@typescript-eslint/scope-manager": "5.38.0", - "@typescript-eslint/types": "5.38.0", - "@typescript-eslint/typescript-estree": "5.38.0", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.38.0.tgz", - "integrity": "sha512-ByhHIuNyKD9giwkkLqzezZ9y5bALW8VNY6xXcP+VxoH4JBDKjU5WNnsiD4HJdglHECdV+lyaxhvQjTUbRboiTA==", - "dev": true, - "peer": true, - "requires": { - "@typescript-eslint/types": "5.38.0", - "@typescript-eslint/visitor-keys": "5.38.0" - } - }, - "@typescript-eslint/type-utils": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.38.0.tgz", - "integrity": "sha512-iZq5USgybUcj/lfnbuelJ0j3K9dbs1I3RICAJY9NZZpDgBYXmuUlYQGzftpQA9wC8cKgtS6DASTvF3HrXwwozA==", - "dev": true, - "peer": true, - "requires": { - "@typescript-eslint/typescript-estree": "5.38.0", - "@typescript-eslint/utils": "5.38.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/types": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.38.0.tgz", - "integrity": "sha512-HHu4yMjJ7i3Cb+8NUuRCdOGu2VMkfmKyIJsOr9PfkBVYLYrtMCK/Ap50Rpov+iKpxDTfnqvDbuPLgBE5FwUNfA==", - "dev": true, - "peer": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.38.0.tgz", - "integrity": "sha512-6P0RuphkR+UuV7Avv7MU3hFoWaGcrgOdi8eTe1NwhMp2/GjUJoODBTRWzlHpZh6lFOaPmSvgxGlROa0Sg5Zbyg==", - "dev": true, - "peer": true, - "requires": { - "@typescript-eslint/types": "5.38.0", - "@typescript-eslint/visitor-keys": "5.38.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/utils": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.38.0.tgz", - "integrity": "sha512-6sdeYaBgk9Fh7N2unEXGz+D+som2QCQGPAf1SxrkEr+Z32gMreQ0rparXTNGRRfYUWk/JzbGdcM8NSSd6oqnTA==", - "dev": true, - "peer": true, - "requires": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.38.0", - "@typescript-eslint/types": "5.38.0", - "@typescript-eslint/typescript-estree": "5.38.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.38.0.tgz", - "integrity": "sha512-MxnrdIyArnTi+XyFLR+kt/uNAcdOnmT+879os7qDRI+EYySR4crXJq9BXPfRzzLGq0wgxkwidrCJ9WCAoacm1w==", - "dev": true, - "peer": true, - "requires": { - "@typescript-eslint/types": "5.38.0", - "eslint-visitor-keys": "^3.3.0" - } - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "requires": { - "string-width": "^4.1.0" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "ansicolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz", - "integrity": "sha512-tOIuy1/SK/dr94ZA0ckDohKXNeBNqZ4us6PjMVLs5h1w2GBB6uPtOknp2+VF4F/zcy9LI70W+Z+pE2Soajky1w==" - }, - "ansistyles": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz", - "integrity": "sha512-6QWEyvMgIXX0eO972y7YPBLSBsq7UWKFAoNNTLGaOJ9bstcEL9sCbcjf96dVfNDdUsRoGOK82vWFJlKApXds7g==" - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "array-includes": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", - "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", - "dev": true, - "peer": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" - } - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "array.prototype.flat": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", - "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", - "dev": true, - "peer": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", - "es-shim-unscopables": "^1.0.0" - } - }, - "aws-sdk": { - "version": "2.814.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.814.0.tgz", - "integrity": "sha512-empd1m/J/MAkL6d9OeRpmg9thobULu0wk4v8W3JToaxGi2TD7PIdvE6yliZKyOVAdJINhBWEBhxR4OUIHhcGbQ==", - "requires": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.3.2", - "xml2js": "0.4.19" - } - }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "requires": { - "object.assign": "^4.1.0" - } - }, - "babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" - } - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.3" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "devOptional": true - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "boxen": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", - "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", - "dev": true, - "requires": { - "ansi-align": "^3.0.0", - "camelcase": "^5.3.1", - "chalk": "^3.0.0", - "cli-boxes": "^2.2.0", - "string-width": "^4.1.0", - "term-size": "^2.1.0", - "type-fest": "^0.8.1", - "widest-line": "^3.1.0" - }, - "dependencies": { - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "devOptional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - } - }, - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "bunyan": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.15.tgz", - "integrity": "sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==", - "requires": { - "dtrace-provider": "~0.8", - "moment": "^2.19.3", - "mv": "~2", - "safe-json-stringify": "~1" - } - }, - "bunyan-format": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/bunyan-format/-/bunyan-format-0.2.1.tgz", - "integrity": "sha512-xQs2LwWskjQdv7bVkMNwvMi7HnvDQoX4587H90nDGQGPPwHrmxsihBOIYHMVwjLMMOokITKPyFcbFneblvMEjQ==", - "requires": { - "ansicolors": "~0.2.1", - "ansistyles": "~0.1.1", - "xtend": "~2.1.1" - } - }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - } - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001409", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001409.tgz", - "integrity": "sha512-V0mnJ5dwarmhYv8/MzhJ//aW68UpvnQBXv8lJ2QUsvn2pHcmAuNtu8hQEDz37XnA1iE+lRR9CIfGWWpgJ5QedQ==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true - }, - "clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "devOptional": true - }, - "config": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/config/-/config-3.3.8.tgz", - "integrity": "sha512-rFzF6VESOdp7wAXFlB9IOZI4ouL05g3A03v2eRcTHj2JBQaTNJ40zhAUl5wRbWHqLZ+uqp/7OE0BWWtAVgrong==", - "requires": { - "json5": "^2.2.1" - } - }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - } - }, - "confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", - "dev": true - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "peer": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "core-js-compat": { - "version": "3.25.2", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.25.2.tgz", - "integrity": "sha512-TxfyECD4smdn3/CjWxczVtJqVLEEC2up7/82t7vC0AzNogr+4nQ8vyF7abxAuTXWvjTClSbvGhU0RgqA4ToQaQ==", - "dev": true, - "requires": { - "browserslist": "^4.21.4" - } - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "cron": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cron/-/cron-2.1.0.tgz", - "integrity": "sha512-Hq7u3P8y7UWYvsZbSKHHJDVG0VO9O7tp2qljxzTScelcTODBfCme8AIhnZsFwmQ9NchZ3hr2uNr+s3DSms7q6w==", - "requires": { - "luxon": "^1.23.x" - } - }, - "cron-time-generator": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/cron-time-generator/-/cron-time-generator-1.3.0.tgz", - "integrity": "sha512-1w+26RkhSUOwGMA9AL6abEjCvbFvd5mbHvFpLdj8L83LR0B4j6AH1p2H3Bh90yjThb4nviSRtsk/4qaJQNQblA==" - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true - }, - "define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dev": true, - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "dtrace-provider": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz", - "integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==", - "optional": true, - "requires": { - "nan": "^2.14.0" - } - }, - "duplexer3": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", - "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", - "dev": true - }, - "electron-to-chromium": { - "version": "1.4.256", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.256.tgz", - "integrity": "sha512-x+JnqyluoJv8I0U9gVe+Sk2st8vF0CzMt78SXxuoWCooLLY2k5VerIBdpvG7ql6GKI4dzNnPjmqgDJ76EdaAKw==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "es-abstract": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.2.tgz", - "integrity": "sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.2", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - } - }, - "es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "dev": true, - "peer": true, - "requires": { - "has": "^1.0.3" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "8.23.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.1.tgz", - "integrity": "sha512-w7C1IXCc6fNqjpuYd0yPlcTKKmHlHHktRkzmBPZ+7cvNBQuiNjx0xaMTjAJGCafJhQkrFJooREv0CtrVzmHwqg==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.3.2", - "@humanwhocodes/config-array": "^0.10.4", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", - "@humanwhocodes/module-importer": "^1.0.1", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "dependencies": { - "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "eslint-config-airbnb-base": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", - "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", - "dev": true, - "requires": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "eslint-config-airbnb-typescript": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-16.2.0.tgz", - "integrity": "sha512-OUaMPZpTOZGKd5tXOjJ9PRU4iYNW/Z5DoHIynjsVK/FpkWdiY5+nxQW6TiJAlLwVI1l53xUOrnlZWtVBVQzuWA==", - "dev": true, - "requires": { - "eslint-config-airbnb-base": "^15.0.0" - } - }, - "eslint-config-prettier": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", - "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", - "dev": true, - "requires": {} - }, - "eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, - "peer": true, - "requires": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "peer": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-module-utils": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", - "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", - "dev": true, - "peer": true, - "requires": { - "debug": "^3.2.7" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "peer": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", - "dev": true, - "peer": true, - "requires": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", - "has": "^1.0.3", - "is-core-module": "^2.8.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", - "tsconfig-paths": "^3.14.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "peer": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "peer": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "peer": true - } - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "peer": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - }, - "espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", - "dev": true, - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - } - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "peer": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==" - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "peer": true - }, - "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "global-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", - "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", - "dev": true, - "requires": { - "ini": "1.3.7" - } - }, - "globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dev": true, - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "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-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "dev": true - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true - }, - "ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "devOptional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "devOptional": true - }, - "ini": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", - "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", - "dev": true - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.6.tgz", - "integrity": "sha512-krO72EO2NptOGAX2KYyqbP9vYMlNAXdB53rq6f8LXY6RY7JdSR/3BD6wLUlPHSAesmY9vstNrjvqGaCiRK/91Q==", - "dev": true - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-installed-globally": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", - "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", - "dev": true, - "requires": { - "global-dirs": "^2.0.1", - "is-path-inside": "^3.0.1" - } - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true - }, - "is-npm": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", - "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha512-+kHj8HXArPfpPEKGLZ+kB5ONRTCiGQXo8RQYL0hH8t6pWXUBBK5KkkQmTNOwKK4LEsd0yTsgtjJVm4UBSZea4w==" - }, - "js-sdsl": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", - "integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" - }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dev": true, - "requires": { - "json-buffer": "3.0.0" - } - }, - "latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dev": true, - "requires": { - "package-json": "^6.3.0" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "peer": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "luxon": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", - "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==" - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "devOptional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "devOptional": true - }, - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "optional": true, - "requires": { - "minimist": "^1.2.6" - } - }, - "moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" - }, - "moment-timezone": { - "version": "0.5.37", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.37.tgz", - "integrity": "sha512-uEDzDNFhfaywRl+vwXxffjjq1q0Vzr+fcQpQ1bU0kbzorfS7zVtZnCnGc8mhWmF39d4g4YriF6kwA75mJKE/Zg==", - "requires": { - "moment": ">= 2.9.0" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "mv": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", - "integrity": "sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==", - "optional": true, - "requires": { - "mkdirp": "~0.5.1", - "ncp": "~2.0.0", - "rimraf": "~2.4.0" - }, - "dependencies": { - "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==", - "optional": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "rimraf": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", - "integrity": "sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==", - "optional": true, - "requires": { - "glob": "^6.0.1" - } - } - } - }, - "nan": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", - "optional": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "ncp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", - "integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==", - "optional": true - }, - "node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "dev": true - }, - "nodemon": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz", - "integrity": "sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ==", - "dev": true, - "requires": { - "chokidar": "^3.2.2", - "debug": "^3.2.6", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.7", - "semver": "^5.7.1", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.2", - "update-notifier": "^4.0.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dev": true, - "requires": { - "abbrev": "1" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "dev": true - }, - "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "object.entries": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", - "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "dev": true, - "peer": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "devOptional": true, - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "dev": true - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "dev": true, - "requires": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "devOptional": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", - "dev": true - }, - "prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", - "dev": true - }, - "pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "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 - }, - "pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dev": true, - "requires": { - "escape-goat": "^2.0.0" - } - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==" - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true - } - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "regenerate-unicode-properties": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", - "dev": true, - "requires": { - "regenerate": "^1.4.2" - } - }, - "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "dev": true - }, - "regenerator-transform": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", - "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", - "dev": true, - "requires": { - "@babel/runtime": "^7.8.4" - } - }, - "regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - } - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "regexpu-core": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz", - "integrity": "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==", - "dev": true, - "requires": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsgen": "^0.7.1", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - } - }, - "registry-auth-token": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", - "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", - "dev": true, - "requires": { - "rc": "1.2.8" - } - }, - "registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dev": true, - "requires": { - "rc": "^1.2.8" - } - }, - "regjsgen": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", - "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", - "dev": true - }, - "regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "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": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true - } - } - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", - "dev": true, - "requires": { - "lowercase-keys": "^1.0.0" - } - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "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, - "peer": true - }, - "safe-json-stringify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", - "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", - "optional": true - }, - "sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" - }, - "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "peer": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, - "requires": { - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "peer": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "term-size": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", - "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", - "dev": true - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true - }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dev": true, - "requires": { - "nopt": "~1.0.10" - } - }, - "ts-node": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.6.0.tgz", - "integrity": "sha512-CJen6+dfOXolxudBQXnVjRVvYTmTWbyz7cn+xq2XTsvnaXbHqr4gXSCNbS2Jj8yTZMuGwUoBESLaOkLascVVvg==", - "dev": true, - "requires": { - "@cspotcode/source-map-support": "0.7.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.0", - "yn": "3.1.1" - } - }, - "tsconfig-paths": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", - "dev": true, - "peer": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "peer": true, - "requires": { - "minimist": "^1.2.0" - } - } - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "peer": true - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "peer": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "typescript": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", - "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", - "dev": true - }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, - "undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true - }, - "unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true - }, - "unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "requires": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", - "dev": true - }, - "unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", - "dev": true - }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "requires": { - "crypto-random-string": "^2.0.0" - } - }, - "update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", - "dev": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "update-notifier": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", - "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", - "dev": true, - "requires": { - "boxen": "^4.2.0", - "chalk": "^3.0.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.3.1", - "is-npm": "^4.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.0.0", - "pupa": "^2.0.1", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "dependencies": { - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - } - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", - "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": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" - } - } - }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", - "dev": true, - "requires": { - "prepend-http": "^2.0.0" - } - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" - }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "requires": { - "string-width": "^4.0.0" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "devOptional": true - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "dev": true - }, - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ==" - }, - "xtend": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", - "integrity": "sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ==", - "requires": { - "object-keys": "~0.4.0" - }, - "dependencies": { - "object-keys": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", - "integrity": "sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==" - } - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "peer": true - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } - } -} diff --git a/premium/job-generator/package.json b/premium/job-generator/package.json deleted file mode 100644 index ad0d1647b1..0000000000 --- a/premium/job-generator/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "premium-job-generator", - "description": "Premium job generator", - "private": true, - "scripts": { - "start": "ts-node --transpile-only ./src/job-generator.ts", - "start:dev": "nodemon --watch \"src/**/*.ts\" -e ts,json --exec \"ts-node --transpile-only ./src/job-generator.ts\"" - }, - "dependencies": { - "aws-sdk": "2.814.0", - "bunyan": "^1.8.15", - "bunyan-format": "^0.2.1", - "config": "^3.3.8", - "cron": "^2.1.0", - "cron-time-generator": "^1.3.0", - "moment": "2.29.4", - "moment-timezone": "^0.5.34" - }, - "devDependencies": { - "@babel/plugin-transform-runtime": "^7.18.10", - "@babel/preset-env": "^7.16.10", - "@types/config": "^3.3.0", - "eslint": "^8.12.0", - "eslint-config-airbnb-base": "^15.0.0", - "eslint-config-airbnb-typescript": "^16.1.4", - "eslint-config-prettier": "^8.5.0", - "nodemon": "2.0.4", - "prettier": "^2.5.1", - "ts-node": "10.6.0", - "typescript": "^4.7.4" - } -} diff --git a/premium/job-generator/src/aws.ts b/premium/job-generator/src/aws.ts deleted file mode 100644 index 73b583bb88..0000000000 --- a/premium/job-generator/src/aws.ts +++ /dev/null @@ -1,17 +0,0 @@ -import AWS, { SQS } from 'aws-sdk' -import { IS_DEV_ENV, SQS_CONFIG } from './config' - -const awsSqsConfig = { - accessKeyId: SQS_CONFIG.aws.accessKeyId, - secretAccessKey: SQS_CONFIG.aws.secretAccessKey, - region: SQS_CONFIG.aws.region, -} - -const sqsInstance = IS_DEV_ENV - ? new AWS.SQS({ - endpoint: `http://${SQS_CONFIG.host}:${SQS_CONFIG.port}`, - ...awsSqsConfig, - }) - : new AWS.SQS(awsSqsConfig) - -export const sqs: SQS = sqsInstance diff --git a/premium/job-generator/src/config.ts b/premium/job-generator/src/config.ts deleted file mode 100644 index b7ee615a06..0000000000 --- a/premium/job-generator/src/config.ts +++ /dev/null @@ -1,23 +0,0 @@ -import config from 'config' -import { SQSConfiguration, TenantMode } from './types' - -export const TENANT_MODE: TenantMode = process.env.TENANT_MODE as TenantMode - -export const IS_TEST_ENV: boolean = process.env.NODE_ENV === 'test' - -export const IS_DEV_ENV: boolean = - process.env.NODE_ENV === 'development' || - process.env.NODE_ENV === 'docker' || - process.env.NODE_ENV === undefined - -export const IS_PROD_ENV: boolean = process.env.NODE_ENV === 'production' - -export const IS_STAGING_ENV: boolean = process.env.NODE_ENV === 'staging' - -export const IS_CLOUD_ENV: boolean = IS_PROD_ENV || IS_STAGING_ENV - -export const SQS_CONFIG: SQSConfiguration = config.get('sqs') - -export const LOG_LEVEL: string = process.env.LOG_LEVEL || 'info' - -export const SERVICE: string = process.env.SERVICE diff --git a/premium/job-generator/src/job-generator.ts b/premium/job-generator/src/job-generator.ts deleted file mode 100644 index c9009b2456..0000000000 --- a/premium/job-generator/src/job-generator.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { CronJob } from 'cron' -import jobs from './jobs' -import { createServiceLogger } from './logging' - -const log = createServiceLogger() - -for (const job of jobs) { - const cronJob = new CronJob( - job.cronTime, - async () => { - log.info(`Triggering premium job: ${job.name}!`) - try { - await job.onTrigger() - } catch (err) { - log.error(err, `Error while executing premium job: ${job.name}!`) - } - }, - null, - true, - 'Europe/Berlin', - ) - if (cronJob.running) { - log.info(`Scheduled premium job: ${job.name}!`) - } -} diff --git a/premium/job-generator/src/jobs/eagleEyeRefreshJob.ts b/premium/job-generator/src/jobs/eagleEyeRefreshJob.ts deleted file mode 100644 index 8f3daa749b..0000000000 --- a/premium/job-generator/src/jobs/eagleEyeRefreshJob.ts +++ /dev/null @@ -1,30 +0,0 @@ -import cronGenerator from 'cron-time-generator' -import { createServiceChildLogger } from '../logging' -import { sendPremiumPythonWorkerMessage } from '../premiumPythonWorkerSQS' -import { CrowdJob } from '../types' - -const log = createServiceChildLogger('Eagle-eye Refresh Job') - -const job: CrowdJob = { - name: 'Eagle-eye Refresh Job', - cronTime: cronGenerator.every(1).hours(), - onTrigger: async () => { - // HackerNews should stay first so the integration will work quickly - try { - await sendPremiumPythonWorkerMessage({ - platform: 'hacker_news', - }) - } catch (err) { - log.error(err, 'Error while emitting Hacker News Eagle-eye refresh message!') - } - try { - await sendPremiumPythonWorkerMessage({ - platform: 'devto', - }) - } catch (err) { - log.error(err, 'Error while emitting DEV Eagle-eye refresh message!') - } - }, -} - -export default job diff --git a/premium/job-generator/src/jobs/index.ts b/premium/job-generator/src/jobs/index.ts deleted file mode 100644 index 07a71d6f16..0000000000 --- a/premium/job-generator/src/jobs/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { CrowdJob } from '../types' -import eagleEyeRefreshJob from './eagleEyeRefreshJob' - -const jobs: CrowdJob[] = [eagleEyeRefreshJob] - -export default jobs diff --git a/premium/job-generator/src/logging.ts b/premium/job-generator/src/logging.ts deleted file mode 100644 index bb4fb38f2a..0000000000 --- a/premium/job-generator/src/logging.ts +++ /dev/null @@ -1,67 +0,0 @@ -import * as Bunyan from 'bunyan' -import BunyanFormat from 'bunyan-format' -import { performance } from 'perf_hooks' -import moment from 'moment' -import { LOG_LEVEL, IS_DEV_ENV, IS_TEST_ENV, SERVICE } from './config' - -export type Logger = Bunyan - -const PRETTY_FORMAT = new BunyanFormat({ outputMode: 'short', levelInString: true }) -const JSON_FORMAT = new BunyanFormat({ outputMode: 'bunyan', levelInString: true }) - -let serviceLoggerInstance: Bunyan - -export const createServiceLogger = (): Logger => { - if (serviceLoggerInstance) return serviceLoggerInstance - - const options = { - name: SERVICE || 'unknown-service', - level: LOG_LEVEL as Bunyan.LogLevel, - stream: IS_DEV_ENV || IS_TEST_ENV ? PRETTY_FORMAT : JSON_FORMAT, - } - - serviceLoggerInstance = Bunyan.createLogger(options) - return serviceLoggerInstance -} - -export const getServiceLogger = (): Logger => { - if (serviceLoggerInstance) return serviceLoggerInstance - return createServiceLogger() -} - -export const createChildLogger = ( - childName: string, - parentLogger: Logger, - logProperties?: any, -): Logger => { - const options = { - component: childName, - ...(logProperties || {}), - } - - return parentLogger.child(options, true) -} - -export const createServiceChildLogger = (childName: string, logProperties?: any): Logger => { - const options = { - component: childName, - ...(logProperties || {}), - } - - return getServiceLogger().child(options, true) -} - -export const logExecutionTime = async ( - process: () => Promise, - log: Logger, - name: string, -): Promise => { - const start = performance.now() - try { - return await process() - } finally { - const end = performance.now() - const duration = moment.duration(end - start, 'milliseconds') - log.info(`Process ${name} took ${duration.asSeconds()} seconds!`) - } -} diff --git a/premium/job-generator/src/premiumPythonWorkerSQS.ts b/premium/job-generator/src/premiumPythonWorkerSQS.ts deleted file mode 100644 index 8811b16eed..0000000000 --- a/premium/job-generator/src/premiumPythonWorkerSQS.ts +++ /dev/null @@ -1,29 +0,0 @@ -import moment from 'moment' -import { sqs } from './aws' -import { IS_TEST_ENV, SQS_CONFIG } from './config' -import { createServiceChildLogger } from './logging' - -const log = createServiceChildLogger('PremiumPythonWorkerSQS') - -export const sendPremiumPythonWorkerMessage = async ( - body: any, - groupId?: string, - deduplicationId?: string, -): Promise => { - if (IS_TEST_ENV) { - return - } - - log.info( - { queue: SQS_CONFIG.premiumPythonWorkerQueue }, - 'Sending message to premium python worker queue!', - ) - await sqs - .sendMessage({ - QueueUrl: SQS_CONFIG.premiumPythonWorkerQueue, - MessageGroupId: groupId || 'premium-python-worker', - MessageDeduplicationId: deduplicationId || `${moment().valueOf()}`, - MessageBody: JSON.stringify(body), - }) - .promise() -} diff --git a/premium/job-generator/src/types.ts b/premium/job-generator/src/types.ts deleted file mode 100644 index 7c28aba8b7..0000000000 --- a/premium/job-generator/src/types.ts +++ /dev/null @@ -1,27 +0,0 @@ -export interface CrowdJob { - name: string - cronTime: string - onTrigger: () => Promise -} - -export interface AwsCredentials { - accountId: string - accessKeyId: string - secretAccessKey: string - region: string -} - -export interface SQSConfiguration { - host?: string - port?: number - nodejsWorkerQueue: string - pythonWorkerQueue: string - premiumPythonWorkerQueue: string - aws: AwsCredentials -} - -export enum TenantMode { - SINGLE = 'single', - MULTI = 'multi', - MULTI_WITH_SUBDOMAIN = 'multi-with-subdomain', -} diff --git a/premium/job-generator/tsconfig.json b/premium/job-generator/tsconfig.json deleted file mode 100644 index 358abf8929..0000000000 --- a/premium/job-generator/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "allowSyntheticDefaultImports": true, - "resolveJsonModule": true, - "esModuleInterop": true, - "lib": ["es2017", "dom"], - "module": "commonjs", - "moduleResolution": "node", - "noUnusedLocals": false, - "noUnusedParameters": false, - "outDir": "./dist", - "sourceMap": true, - "target": "es2017", - "types": ["node"] - }, - "include": ["src"], - "exclude": ["node_modules"] -} diff --git a/scripts/builders/premium-job-generator.sh b/scripts/builders/premium-job-generator.sh deleted file mode 100644 index b6c2950079..0000000000 --- a/scripts/builders/premium-job-generator.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -DOCKERFILE="../premium/job-generator/Dockerfile" -CONTEXT="../premium/job-generator" -REPO="crowddotdev/premium-job-generator" \ No newline at end of file diff --git a/scripts/builders/premium-python-backend.sh b/scripts/builders/premium-python-backend.sh deleted file mode 100644 index 0eeb2282a4..0000000000 --- a/scripts/builders/premium-python-backend.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -DOCKERFILE="../premium/eagle-eye/Dockerfile.kube" -CONTEXT="../premium/eagle-eye" -REPO="crowddotdev/premium-python-backend" \ No newline at end of file diff --git a/scripts/cli b/scripts/cli index f9c0b1daad..cf7565d009 100755 --- a/scripts/cli +++ b/scripts/cli @@ -478,53 +478,53 @@ do exit; ;; start) - declare -a INGORED_SERVICES=("premium-api" "premium-job-generator" "premium-python-worker" "community-help-center") + declare -a INGORED_SERVICES=("community-help-center") start exit; ;; start-e2e) - declare -a INGORED_SERVICES=("premium-api" "premium-job-generator" "premium-python-worker" "community-help-center" "python-worker" "job-generator") + declare -a INGORED_SERVICES=("community-help-center" "python-worker" "job-generator") start exit; ;; start-dev) - declare -a INGORED_SERVICES=("premium-api" "premium-job-generator" "premium-python-worker" "community-help-center") + declare -a INGORED_SERVICES=("community-help-center") DEV=1 start exit; ;; clean-start) - declare -a INGORED_SERVICES=("premium-api" "premium-job-generator" "premium-python-worker" "community-help-center") + declare -a INGORED_SERVICES=("community-help-center") CLEAN_START=1 start exit; ;; clean-start-dev) - declare -a INGORED_SERVICES=("premium-api" "premium-job-generator" "premium-python-worker" "community-help-center") + declare -a INGORED_SERVICES=("community-help-center") CLEAN_START=1 DEV=1 start exit; ;; start-backend) - declare -a INGORED_SERVICES=("frontend" "premium-api" "premium-job-generator" "premium-python-worker" "community-help-center") + declare -a INGORED_SERVICES=("frontend" "community-help-center") start exit; ;; start-backend-dev) - declare -a INGORED_SERVICES=("frontend" "premium-api" "premium-job-generator" "premium-python-worker" "community-help-center") + declare -a INGORED_SERVICES=("frontend" "community-help-center") DEV=1 start exit; ;; clean-start-backend) - declare -a INGORED_SERVICES=("frontend" "premium-api" "premium-job-generator" "premium-python-worker" "community-help-center") + declare -a INGORED_SERVICES=("frontend" "community-help-center") CLEAN_START=1 start exit; ;; clean-start-backend-dev) - declare -a INGORED_SERVICES=("frontend" "premium-api" "premium-job-generator" "premium-python-worker" "community-help-center") + declare -a INGORED_SERVICES=("frontend" "community-help-center") CLEAN_START=1 DEV=1 start diff --git a/scripts/scaffold.yaml b/scripts/scaffold.yaml index 3a6a664817..b1f3ea7622 100644 --- a/scripts/scaffold.yaml +++ b/scripts/scaffold.yaml @@ -85,14 +85,6 @@ services: networks: - crowd-bridge - qdrant: - image: qdrant/qdrant:latest - restart: always - ports: - - 6333:6333 - networks: - - crowd-bridge - redis: build: context: scaffold/redis diff --git a/scripts/services/premium-api.yaml b/scripts/services/premium-api.yaml deleted file mode 100644 index fbc7f2c731..0000000000 --- a/scripts/services/premium-api.yaml +++ /dev/null @@ -1,44 +0,0 @@ -version: '3.1' - -x-env-args: &env-args - DOCKER_BUILDKIT: 1 - SERVICE_ENV: docker - SERVICE: premium-api - -services: - premium-api: - build: - context: ../premium/eagle-eye - dockerfile: Dockerfile.kube - command: ['./start-premium-api.sh'] - env_file: - - ../../backend/.env.dist.local - - ../../backend/.env.dist.composed - - ../../backend/.env.override.local - - ../../backend/.env.override.composed - environment: - <<: *env-args - restart: always - networks: - - crowd-bridge - - premium-api-dev: - build: - context: ../premium/eagle-eye - dockerfile: Dockerfile.kube - command: ['./start-premium-api.sh'] - user: '${USER_ID}:${GROUP_ID}' - env_file: - - ../../backend/.env.dist.local - - ../../backend/.env.dist.composed - - ../../backend/.env.override.local - - ../../backend/.env.override.composed - environment: - <<: *env-args - hostname: premium-api - networks: - - crowd-bridge - -networks: - crowd-bridge: - external: true diff --git a/scripts/services/premium-job-generator.yaml b/scripts/services/premium-job-generator.yaml deleted file mode 100644 index 207e016bf0..0000000000 --- a/scripts/services/premium-job-generator.yaml +++ /dev/null @@ -1,47 +0,0 @@ -version: '3.1' - -x-env-args: &env-args - DOCKER_BUILDKIT: 1 - NODE_ENV: docker - SERVICE: premium-job-generator - -services: - premium-job-generator: - build: - context: ../premium/job-generator - dockerfile: Dockerfile - command: 'npm run start' - env_file: - - ../../backend/.env.dist.local - - ../../backend/.env.dist.composed - - ../../backend/.env.override.local - - ../../backend/.env.override.composed - environment: - <<: *env-args - restart: always - networks: - - crowd-bridge - - premium-job-generator-dev: - build: - context: ../premium/job-generator - dockerfile: Dockerfile - command: 'npm run start:dev' - # user: '${USER_ID}:${GROUP_ID}' - env_file: - - ../../backend/.env.dist.local - - ../../backend/.env.dist.composed - - ../../backend/.env.override.local - - ../../backend/.env.override.composed - environment: - <<: *env-args - hostname: premium-job-generator - networks: - - crowd-bridge - volumes: - - ../../premium/job-generator:/usr/crowd/premium-job-generator - - /usr/crowd/premium-job-generator/node_modules - -networks: - crowd-bridge: - external: true diff --git a/scripts/services/premium-python-worker.yaml b/scripts/services/premium-python-worker.yaml deleted file mode 100644 index a74e3742a3..0000000000 --- a/scripts/services/premium-python-worker.yaml +++ /dev/null @@ -1,44 +0,0 @@ -version: '3.1' - -x-env-args: &env-args - DOCKER_BUILDKIT: 1 - SERVICE_ENV: docker - SERVICE: premium-python-worker - -services: - premium-python-worker: - build: - context: ../premium/eagle-eye - dockerfile: Dockerfile.kube - command: ['./start-premium-python-worker.sh'] - env_file: - - ../../backend/.env.dist.local - - ../../backend/.env.dist.composed - - ../../backend/.env.override.local - - ../../backend/.env.override.composed - environment: - <<: *env-args - restart: always - networks: - - crowd-bridge - - premium-python-worker-dev: - build: - context: ../premium/eagle-eye - dockerfile: Dockerfile.kube - command: ['./start-premium-python-worker.sh'] - user: '${USER_ID}:${GROUP_ID}' - env_file: - - ../../backend/.env.dist.local - - ../../backend/.env.dist.composed - - ../../backend/.env.override.local - - ../../backend/.env.override.composed - environment: - <<: *env-args - hostname: premium-python-worker - networks: - - crowd-bridge - -networks: - crowd-bridge: - external: true diff --git a/start.sh b/start.sh deleted file mode 100755 index 3fa2b5fe94..0000000000 --- a/start.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/bash -# Starts a slim version of crowd services. -# Usage `bash start.sh [ -l | --localVersion ]` -# Started services will use the generic .env.dist environment variable -# which doesn't have integration related client id/secrets. By default, -# script will try to get the latest released version using git tags. -# App will be availabe at https://app.localhost - -if [[ $1 == "dev" ]]; then - IS_DEV=true -else - IS_DEV=false -fi - -set -ue pipefail - -CLI_HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -CROWD_VERSION="$(cd $CLI_HOME && git describe --tags --abbrev=0)" - -if [[ "$OSTYPE" == "linux-gnu"* ]]; then - echo "Trying to install ssl tools, need to get sudo privileges" - apt install libnss3-tools -fi - -if [[ "$IS_DEV" = false ]]; then - cp $CLI_HOME/backend/.env.dist $CLI_HOME/backend/.env - cp $CLI_HOME/frontend/.env.dist $CLI_HOME/frontend/.env -fi - -sed -i -e "s|PROJECT_ROOT=.*|PROJECT_ROOT=\'$CLI_HOME\'|g" $CLI_HOME/backend/.env - -cp $CLI_HOME/docker/docker-compose.default.yaml $CLI_HOME/docker/docker-compose.yaml -cp $CLI_HOME/docker/docker-compose.dev.default.yaml $CLI_HOME/docker/docker-compose.dev.yaml - -docker pull crowddotdev/conversations:$CROWD_VERSION-dev -docker pull crowddotdev/lambda-py-packages:$CROWD_VERSION-dev -docker pull crowddotdev/backend:$CROWD_VERSION-dev -docker pull crowddotdev/frontend:$CROWD_VERSION-dev - -cd $CLI_HOME/nginx/ssl && bash init-certs.sh - -export CROWD_VERSION=$CROWD_VERSION - -echo $IS_DEV -if [[ "$IS_DEV" = false ]]; then - cd $CLI_HOME/docker && docker-compose -p crowd up --force-recreate -else - # cd $CLI_HOME && bash $CLI_HOME/backend/util/install-all.sh - cd $CLI_HOME/docker && docker-compose -f docker-compose.yaml -f docker-compose.dev.yaml -p crowd up --force-recreate -fi From 893332ccfb80222969d96bc687cb0f59978f42b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Tue, 21 Feb 2023 09:56:03 +0100 Subject: [PATCH 47/56] fix --- backend/src/bin/jobs/checkSqsQueues.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/backend/src/bin/jobs/checkSqsQueues.ts b/backend/src/bin/jobs/checkSqsQueues.ts index 9f37ba6ca5..baefc4d070 100644 --- a/backend/src/bin/jobs/checkSqsQueues.ts +++ b/backend/src/bin/jobs/checkSqsQueues.ts @@ -9,11 +9,7 @@ interface IQueueCount { increaseCount: number } -const queues = [ - SQS_CONFIG.nodejsWorkerQueue, - SQS_CONFIG.pythonWorkerQueue, - SQS_CONFIG.premiumPythonWorkerQueue, -] +const queues = [SQS_CONFIG.nodejsWorkerQueue, SQS_CONFIG.pythonWorkerQueue] const messageCounts: Map = new Map() From f62badd9cead1b44354dc487ea4622eb69d54360 Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Tue, 21 Feb 2023 10:20:22 +0000 Subject: [PATCH 48/56] Update eagle eye feature flag validation --- frontend/src/app.vue | 18 +++-- .../src/{unleash => featureFlag}/index.js | 15 +++- .../linkedin/components/linkedin-connect.vue | 2 +- .../src/modules/auth/auth-current-tenant.js | 2 +- frontend/src/modules/auth/auth-socket.js | 2 +- .../modules/automation/automation-store.js | 2 +- .../automation/pages/automation-list-page.vue | 2 +- .../components/integration-list-item.vue | 2 +- .../layout/components/paywall-modal.vue | 2 +- .../src/modules/layout/pages/paywall-page.vue | 17 +++-- .../src/modules/member/member-enrichment.js | 2 +- frontend/src/modules/tenant/store/actions.js | 4 ++ .../src/modules/tenant/store/mutations.js | 12 +++- frontend/src/modules/tenant/store/state.js | 4 ++ .../components/settings/_general.vue | 2 +- .../pages/community-help-center-page.vue | 2 +- .../src/premium/eagle-eye/eagle-eye-routes.js | 70 ------------------- .../pages/eagle-eye-onboard-page.vue | 4 +- .../pages/eagle-eye-page-wrapper.vue | 24 +++++-- .../eagle-eye/pages/eagle-eye-page.vue | 4 +- 20 files changed, 87 insertions(+), 105 deletions(-) rename frontend/src/{unleash => featureFlag}/index.js (82%) diff --git a/frontend/src/app.vue b/frontend/src/app.vue index a0f695ba8a..d9e5982340 100644 --- a/frontend/src/app.vue +++ b/frontend/src/app.vue @@ -1,5 +1,5 @@