SQLite cache

This commit is contained in:
Mr. Stallion 2019-07-07 16:44:32 -05:00
parent f3f949569a
commit b983f388e1
21 changed files with 989 additions and 174 deletions

View File

@ -595,48 +595,54 @@
.message.message-score { .message {
padding-left: 5px; &.message-event {
border-bottom: 1px solid rgba(255, 255, 255, 0.1); font-size: 85%;
background-color: rgba(255, 255, 255, 0.1);
&.match {
border-left: 12px solid #027b02;
background-color: rgba(1, 76, 1, 0.45);
} }
&.weak-match { &.message-score {
border-left: 12px solid #015a01; padding-left: 5px;
background-color: rgba(0, 58, 0, 0.35); border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
&.weak-mismatch { &.match {
background-color: rgba(208, 188, 0, 0.0); border-left: 12px solid #027b02;
border-left: 12px solid rgb(138, 123, 0); background-color: rgba(1, 76, 1, 0.45);
.bbcode {
filter: grayscale(0.7);
} }
.bbcode, &.weak-match {
.user-view, border-left: 12px solid #015a01;
.message-time { background-color: rgba(0, 58, 0, 0.35);
opacity: 0.4;
}
}
&.mismatch {
border-left: 12px solid #841a1a;
.bbcode {
filter: grayscale(0.8);
} }
.bbcode, &.weak-mismatch {
.user-view, background-color: rgba(208, 188, 0, 0.0);
.message-time { border-left: 12px solid rgb(138, 123, 0);
opacity: 0.3;
.bbcode {
filter: grayscale(0.7);
}
.bbcode,
.user-view,
.message-time {
opacity: 0.4;
}
}
&.mismatch {
border-left: 12px solid #841a1a;
.bbcode {
filter: grayscale(0.8);
}
.bbcode,
.user-view,
.message-time {
opacity: 0.3;
}
} }
} }
} }
</style> </style>

View File

@ -94,7 +94,7 @@ export class Message implements Conversation.ChatMessage {
readonly id = ++messageId; readonly id = ++messageId;
isHighlight = false; isHighlight = false;
score?: number; score = 0;
constructor(readonly type: Conversation.Message.Type, readonly sender: Character, readonly text: string, constructor(readonly type: Conversation.Message.Type, readonly sender: Character, readonly text: string,
readonly time: Date = new Date()) { readonly time: Date = new Date()) {
@ -106,6 +106,8 @@ export class EventMessage implements Conversation.EventMessage {
readonly id = ++messageId; readonly id = ++messageId;
readonly type = Conversation.Message.Type.Event; readonly type = Conversation.Message.Type.Event;
readonly score = 0;
constructor(readonly text: string, readonly time: Date = new Date()) { constructor(readonly text: string, readonly time: Date = new Date()) {
} }
} }

View File

@ -14,7 +14,7 @@ export namespace Conversation {
readonly text: string readonly text: string
readonly time: Date readonly time: Date
score?: number; score: number;
} }
export interface EventMessage extends BaseMessage { export interface EventMessage extends BaseMessage {

View File

@ -1,7 +1,7 @@
import { Component, Prop, Watch } from '@f-list/vue-ts'; import { Component, Hook, Prop } from '@f-list/vue-ts';
import {CreateElement, default as Vue, VNode, VNodeChildrenArrayContents} from 'vue'; import {CreateElement, default as Vue, VNode, VNodeChildrenArrayContents} from 'vue';
import {Channel} from '../fchat'; import {Channel} from '../fchat';
import { Score, Scoring } from '../site/character_page/matcher'; import { Score, Scoring } from '../learn/matcher';
import {BBCodeView} from './bbcode'; import {BBCodeView} from './bbcode';
import {formatTime} from './common'; import {formatTime} from './common';
import core from './core'; import core from './core';
@ -16,6 +16,15 @@ const userPostfix: {[key: number]: string | undefined} = {
@Component({ @Component({
render(this: MessageView, createElement: CreateElement): VNode { render(this: MessageView, createElement: CreateElement): VNode {
const message = this.message; const message = this.message;
// setTimeout(
// () => {
// console.log('Now scoring high!', message.text.substr(0, 64));
// message.score = Scoring.MATCH;
// },
// 5000
// );
const children: VNodeChildrenArrayContents = const children: VNodeChildrenArrayContents =
[createElement('span', {staticClass: 'message-time'}, `[${formatTime(message.time)}] `)]; [createElement('span', {staticClass: 'message-time'}, `[${formatTime(message.time)}] `)];
const separators = core.connection.isOpen ? core.state.settings.messageSeparators : false; const separators = core.connection.isOpen ? core.state.settings.messageSeparators : false;
@ -59,22 +68,47 @@ export default class MessageView extends Vue {
scoreClasses = this.getMessageScoreClasses(this.message); scoreClasses = this.getMessageScoreClasses(this.message);
@Watch('message.score') scoreWatcher: (() => void) | null = ((this.message.type === Conversation.Message.Type.Ad) && (this.message.score === 0))
? this.$watch('message.score', () => this.scoreUpdate())
: null;
@Hook('beforeDestroy')
onBeforeDestroy(): void {
console.log('onbeforedestroy');
if (this.scoreWatcher) {
console.log('onbeforedestroy killed');
this.scoreWatcher(); // stop watching
this.scoreWatcher = null;
}
}
// @Watch('message.score')
scoreUpdate(): void { scoreUpdate(): void {
console.log('Message score update', this.message.score, this.message.text); const oldClasses = this.scoreClasses;
this.scoreClasses = this.getMessageScoreClasses(this.message); this.scoreClasses = this.getMessageScoreClasses(this.message);
this.$forceUpdate(); if (this.scoreClasses !== oldClasses) {
this.$forceUpdate();
}
if (this.scoreWatcher) {
console.log('watch killed');
this.scoreWatcher(); // stop watching
this.scoreWatcher = null;
}
} }
getMessageScoreClasses(message: Conversation.Message): string { getMessageScoreClasses(message: Conversation.Message): string {
if ((!('score' in message)) || (message.score === undefined) || (message.score === 0)) { if (message.score === 0) {
return ''; return '';
} }
console.log('Score was', message.score); // console.log('Score was', message.score);
return `message-score ${Score.getClasses(message.score as Scoring)}`; return `message-score ${Score.getClasses(message.score as Scoring)}`;

View File

@ -84,6 +84,7 @@
@Hook('mounted') @Hook('mounted')
mounted(): void { mounted(): void {
// top bar devtools
// browserWindow.webContents.openDevTools(); // browserWindow.webContents.openDevTools();
this.addTab(); this.addTab();
@ -196,7 +197,8 @@
tray.on('click', (_) => this.trayClicked(tab)); tray.on('click', (_) => this.trayClicked(tab));
const view = new electron.remote.BrowserView(); const view = new electron.remote.BrowserView();
// view.webContents.openDevTools(); // tab devtools
view.webContents.openDevTools();
view.setAutoResize({width: true, height: true}); view.setAutoResize({width: true, height: true});
electron.ipcRenderer.send('tab-added', view.webContents.id); electron.ipcRenderer.send('tab-added', view.webContents.id);

View File

@ -2,7 +2,7 @@ import * as electron from 'electron';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
export const defaultHost = 'wss://chat.f-list.net:9799'; export const defaultHost = 'wss://chat.f-list.net/chat2';
export class GeneralSettings { export class GeneralSettings {
account = ''; account = '';

View File

@ -3,6 +3,7 @@ const path = require('path');
const pkg = require(path.join(__dirname, 'package.json')); const pkg = require(path.join(__dirname, 'package.json'));
const fs = require('fs'); const fs = require('fs');
const child_process = require('child_process'); const child_process = require('child_process');
const _ = require('lodash');
function mkdir(dir) { function mkdir(dir) {
try { try {
@ -30,12 +31,33 @@ function mkdir(dir) {
const distDir = path.join(__dirname, 'dist'); const distDir = path.join(__dirname, 'dist');
const isBeta = pkg.version.indexOf('beta') !== -1; const isBeta = pkg.version.indexOf('beta') !== -1;
const spellcheckerPath = 'spellchecker/build/Release/spellchecker.node', keytarPath = 'keytar/build/Release/keytar.node';
const modules = path.join(__dirname, 'app', 'node_modules'); const modules = path.join(__dirname, 'app', 'node_modules');
mkdir(path.dirname(path.join(modules, spellcheckerPath)));
mkdir(path.dirname(path.join(modules, keytarPath))); // const spellcheckerPath = 'spellchecker/build/Release/spellchecker.node',
fs.copyFileSync(require.resolve(spellcheckerPath), path.join(modules, spellcheckerPath)); // keytarPath = 'keytar/build/Release/keytar.node',
fs.copyFileSync(require.resolve(keytarPath), path.join(modules, keytarPath)); // integerPath = 'integer/build/Release/integer.node',
// betterSqlite3 = 'better-sqlite3/build/Release/better_sqlite3.node';
//
// mkdir(path.dirname(path.join(modules, spellcheckerPath)));
// mkdir(path.dirname(path.join(modules, keytarPath)));
// fs.copyFileSync(require.resolve(spellcheckerPath), path.join(modules, spellcheckerPath));
// fs.copyFileSync(require.resolve(keytarPath), path.join(modules, keytarPath));
const includedPaths = [
'spellchecker/build/Release/spellchecker.node',
'keytar/build/Release/keytar.node',
'integer/build/Release/integer.node',
'better-sqlite3/build/Release/better_sqlite3.node'
];
_.each(
includedPaths,
(p) => {
mkdir(path.dirname(path.join(modules, p)));
fs.copyFileSync(require.resolve(p), path.join(modules, p));
}
);
require('electron-packager')({ require('electron-packager')({

View File

@ -1,6 +1,6 @@
{ {
"name": "fchat", "name": "fchat",
"version": "3.0.10-horse", "version": "3.0.10-ascending-v1",
"author": "The F-List Team", "author": "The F-List Team",
"description": "F-List.net Chat Client", "description": "F-List.net Chat Client",
"main": "main.js", "main": "main.js",

View File

@ -4,11 +4,12 @@ import { ChannelAdEvent, ChannelMessageEvent, CharacterDataEvent, EventBus } fro
import { Conversation } from '../chat/interfaces'; import { Conversation } from '../chat/interfaces';
import { methods } from '../site/character_page/data_store'; import { methods } from '../site/character_page/data_store';
import { Character } from '../site/character_page/interfaces'; import { Character } from '../site/character_page/interfaces';
import { Gender } from '../site/character_page/matcher'; import { Gender } from './matcher';
import { AdCache } from './ad-cache'; import { AdCache } from './ad-cache';
import { ChannelConversationCache } from './channel-conversation-cache'; import { ChannelConversationCache } from './channel-conversation-cache';
import { CharacterProfiler } from './character-profiler'; import { CharacterProfiler } from './character-profiler';
import { ProfileCache } from './profile-cache'; import { ProfileCache } from './profile-cache';
import { SqliteStore } from './sqlite-store';
import Timer = NodeJS.Timer; import Timer = NodeJS.Timer;
import ChannelConversation = Conversation.ChannelConversation; import ChannelConversation = Conversation.ChannelConversation;
import Message = Conversation.Message; import Message = Conversation.Message;
@ -23,7 +24,7 @@ export interface ProfileCacheQueueEntry {
export class CacheManager { export class CacheManager {
static readonly PROFILE_QUERY_DELAY = 3000; //1 * 1000; static readonly PROFILE_QUERY_DELAY = 1 * 1000; //1 * 1000;
adCache: AdCache = new AdCache(); adCache: AdCache = new AdCache();
profileCache: ProfileCache = new ProfileCache(); profileCache: ProfileCache = new ProfileCache();
@ -34,13 +35,15 @@ export class CacheManager {
protected profileTimer: Timer | null = null; protected profileTimer: Timer | null = null;
protected characterProfiler: CharacterProfiler | undefined; protected characterProfiler: CharacterProfiler | undefined;
protected profileStore = new SqliteStore();
queueForFetching(name: string): void { queueForFetching(name: string): void {
const key = ProfileCache.nameKey(name); if (this.profileCache.get(name))
if (this.profileCache.has(key))
return; return;
const key = ProfileCache.nameKey(name);
if (!!_.find(this.queue, (q: ProfileCacheQueueEntry) => (q.key === key))) if (!!_.find(this.queue, (q: ProfileCacheQueueEntry) => (q.key === key)))
return; return;
@ -132,6 +135,9 @@ export class CacheManager {
start(): void { start(): void {
this.stop(); this.stop();
this.profileStore.start();
this.profileCache.setStore(this.profileStore);
EventBus.$on( EventBus.$on(
'character-data', 'character-data',
(data: CharacterDataEvent) => { (data: CharacterDataEvent) => {
@ -189,8 +195,14 @@ export class CacheManager {
const next = this.consumeNextInQueue(); const next = this.consumeNextInQueue();
if (next) { if (next) {
// console.log('Learn fetch', next.name, next.score); try {
await this.fetchProfile(next.name); // console.log('Learn fetch', next.name, next.score);
await this.fetchProfile(next.name);
} catch (err) {
console.error('Profile queue error', err);
this.queue.push(next); // return to queue
}
} }
scheduleNextFetch(); scheduleNextFetch();
@ -208,6 +220,8 @@ export class CacheManager {
this.profileTimer = null; this.profileTimer = null;
} }
this.profileStore.stop();
// should do some $off here // should do some $off here
} }

View File

@ -1,7 +1,7 @@
import core from '../chat/core'; import core from '../chat/core';
import { Character as CharacterFChatInf } from '../fchat'; import { Character as CharacterFChatInf } from '../fchat';
import { Character } from '../site/character_page/interfaces'; import { Character as ComplexCharacter } from '../site/character_page/interfaces';
import { Matcher } from '../site/character_page/matcher'; import { Matcher, TagId } from './matcher';
import { AdCache } from './ad-cache'; import { AdCache } from './ad-cache';
import { ProfileCacheQueueEntry } from './cache-manager'; import { ProfileCacheQueueEntry } from './cache-manager';
@ -11,9 +11,9 @@ export class CharacterProfiler {
static readonly ADVERTISEMENT_POTENTIAL_RAGE = 50 * 60 * 1000; static readonly ADVERTISEMENT_POTENTIAL_RAGE = 50 * 60 * 1000;
protected adCache: AdCache; protected adCache: AdCache;
protected me: Character; protected me: ComplexCharacter;
constructor(me: Character, adCache: AdCache) { constructor(me: ComplexCharacter, adCache: AdCache) {
this.me = me; this.me = me;
this.adCache = adCache; this.adCache = adCache;
} }
@ -48,14 +48,16 @@ export class CharacterProfiler {
} }
getInterestScoreForGender(me: Character, c: CharacterFChatInf.Character): number { getInterestScoreForGender(me: ComplexCharacter, c: CharacterFChatInf.Character): number {
const g = Matcher.strToGender(c.gender); const g = Matcher.strToGender(c.gender);
if (g === null) { if (g === null) {
return 0; return 0;
} }
const score = Matcher.scoreOrientationByGender(me.character, g); const myGender = Matcher.getTagValueList(TagId.Gender, me.character);
const myOrientation = Matcher.getTagValueList(TagId.Orientation, me.character);
const score = Matcher.scoreOrientationByGender(myGender, myOrientation, g);
return score.score; return score.score;
} }

View File

@ -1,5 +1,5 @@
import * as _ from 'lodash'; import * as _ from 'lodash';
import { Character, CharacterInfotag } from '../../interfaces'; import { Character, CharacterInfotag } from '../interfaces';
/* eslint-disable no-null-keyword */ /* eslint-disable no-null-keyword */
@ -79,13 +79,12 @@ enum Kink {
Mammals = 224 Mammals = 224
} }
enum FurryPreference { export enum FurryPreference {
FurriesOnly = 39, FurriesOnly = 39,
FursAndHumans = 40, FursAndHumans = 40,
HumansOnly = 41, HumansOnly = 41,
HumansPreferredFurriesOk = 150, HumansPreferredFurriesOk = 150,
FurriesPreferredHumansOk = 149 FurriesPreferredHumansOk = 149
} }
interface GenderKinkIdMap { interface GenderKinkIdMap {
@ -105,7 +104,7 @@ const genderKinkMapping: GenderKinkIdMap = {
// if no species and 'no furry chareacters', === human // if no species and 'no furry chareacters', === human
// if no species and dislike 'antho characters' === human // if no species and dislike 'antho characters' === human
enum Species { export enum Species {
Human = 609, Human = 609,
Equine = 236, Equine = 236,
Feline = 212, Feline = 212,
@ -230,7 +229,10 @@ export interface MatchResult {
them: Character, them: Character,
scores: MatchResultScores; scores: MatchResultScores;
info: MatchResultCharacterInfo; info: MatchResultCharacterInfo;
total: number total: number;
yourAnalysis: CharacterAnalysis;
theirAnalysis: CharacterAnalysis;
} }
export enum Scoring { export enum Scoring {
@ -274,6 +276,39 @@ export class Score {
} }
} }
export class CharacterAnalysis {
readonly character: Character;
readonly gender: Gender | null;
readonly orientation: Orientation | null;
readonly species: Species | null;
readonly furryPreference: FurryPreference | null;
readonly age: number | null;
readonly isAnthro: boolean | null;
readonly isHuman: boolean | null;
readonly isMammal: boolean | null;
constructor(c: Character) {
this.character = c;
this.gender = Matcher.getTagValueList(TagId.Gender, c);
this.orientation = Matcher.getTagValueList(TagId.Orientation, c);
this.species = Matcher.species(c);
this.furryPreference = Matcher.getTagValueList(TagId.FurryPreference, c);
const ageTag = Matcher.getTagValue(TagId.Age, c);
this.age = ((ageTag) && (ageTag.string)) ? parseInt(ageTag.string, 10) : null;
this.isAnthro = Matcher.isAnthro(c);
this.isHuman = Matcher.isHuman(c);
this.isMammal = Matcher.isMammal(c);
}
}
/** /**
* Answers the question: What YOU think about THEM * Answers the question: What YOU think about THEM
* Never what THEY think about YOU * Never what THEY think about YOU
@ -282,17 +317,27 @@ export class Score {
* to get the full picture * to get the full picture
*/ */
export class Matcher { export class Matcher {
you: Character; readonly you: Character;
them: Character; readonly them: Character;
constructor(you: Character, them: Character) { readonly yourAnalysis: CharacterAnalysis;
readonly theirAnalysis: CharacterAnalysis;
constructor(you: Character, them: Character, yourAnalysis?: CharacterAnalysis, theirAnalysis?: CharacterAnalysis) {
this.you = you; this.you = you;
this.them = them; this.them = them;
this.yourAnalysis = yourAnalysis || new CharacterAnalysis(you);
this.theirAnalysis = theirAnalysis || new CharacterAnalysis(them);
} }
static generateReport(you: Character, them: Character): MatchReport { static generateReport(you: Character, them: Character): MatchReport {
const youThem = new Matcher(you, them); const yourAnalysis = new CharacterAnalysis(you);
const themYou = new Matcher(them, you); const theirAnalysis = new CharacterAnalysis(them);
const youThem = new Matcher(you, them, yourAnalysis, theirAnalysis);
const themYou = new Matcher(them, you, theirAnalysis, yourAnalysis);
return { return {
you: youThem.match(), you: youThem.match(),
@ -300,11 +345,14 @@ export class Matcher {
}; };
} }
match(): MatchResult { match(): MatchResult {
const data = { const data: MatchResult = {
you: this.you, you: this.you,
them: this.them, them: this.them,
yourAnalysis: this.yourAnalysis,
theirAnalysis: this.theirAnalysis,
total: 0, total: 0,
scores: { scores: {
@ -332,29 +380,19 @@ export class Matcher {
} }
private resolveOrientationScore(): Score { private resolveOrientationScore(): Score {
const you = this.you;
const them = this.them;
const yourGender = Matcher.getTagValueList(TagId.Gender, you);
const theirGender = Matcher.getTagValueList(TagId.Gender, them);
const yourOrientation = Matcher.getTagValueList(TagId.Orientation, you);
if ((yourGender === null) || (theirGender === null) || (yourOrientation === null))
return new Score(Scoring.NEUTRAL);
// Question: If someone identifies themselves as 'straight cuntboy', how should they be matched? like a straight female? // Question: If someone identifies themselves as 'straight cuntboy', how should they be matched? like a straight female?
return Matcher.scoreOrientationByGender(you, theirGender); return Matcher.scoreOrientationByGender(this.yourAnalysis.gender, this.yourAnalysis.orientation, this.theirAnalysis.gender);
} }
static scoreOrientationByGender(you: Character, theirGender: Gender): Score { static scoreOrientationByGender(yourGender: Gender | null, yourOrientation: Orientation | null, theirGender: Gender | null): Score {
const yourGender = Matcher.getTagValueList(TagId.Gender, you); if ((yourGender === null) || (theirGender === null) || (yourOrientation === null))
const yourOrientation = Matcher.getTagValueList(TagId.Orientation, you); return new Score(Scoring.NEUTRAL);
// CIS // CIS
// tslint:disable-next-line curly // tslint:disable-next-line curly
if ((yourGender !== null) && (Matcher.isCisGender(yourGender))) { if (Matcher.isCisGender(yourGender)) {
if (yourGender === theirGender) { if (yourGender === theirGender) {
// same sex CIS // same sex CIS
if (yourOrientation === Orientation.Straight) if (yourOrientation === Orientation.Straight)
@ -420,8 +458,8 @@ export class Matcher {
private resolveSpeciesScore(): Score { private resolveSpeciesScore(): Score {
const you = this.you; const you = this.you;
const them = this.them; const theirAnalysis = this.theirAnalysis;
const theirSpecies = Matcher.species(them); const theirSpecies = theirAnalysis.species;
if (theirSpecies === null) if (theirSpecies === null)
return new Score(Scoring.NEUTRAL); return new Score(Scoring.NEUTRAL);
@ -434,14 +472,14 @@ export class Matcher {
return Matcher.formatKinkScore(speciesScore, speciesName); return Matcher.formatKinkScore(speciesScore, speciesName);
} }
if (Matcher.isAnthro(them)) { if (theirAnalysis.isAnthro) {
const anthroScore = Matcher.getKinkPreference(you, Kink.AnthroCharacters); const anthroScore = Matcher.getKinkPreference(you, Kink.AnthroCharacters);
if (anthroScore !== null) if (anthroScore !== null)
return Matcher.formatKinkScore(anthroScore, 'anthros'); return Matcher.formatKinkScore(anthroScore, 'anthros');
} }
if (Matcher.isMammal(them)) { if (theirAnalysis.isMammal) {
const mammalScore = Matcher.getKinkPreference(you, Kink.Mammals); const mammalScore = Matcher.getKinkPreference(you, Kink.Mammals);
if (mammalScore !== null) if (mammalScore !== null)
@ -451,6 +489,7 @@ export class Matcher {
return new Score(Scoring.NEUTRAL); return new Score(Scoring.NEUTRAL);
} }
formatScoring(score: Scoring, description: string): Score { formatScoring(score: Scoring, description: string): Score {
let type = ''; let type = '';
@ -477,10 +516,8 @@ export class Matcher {
private resolveFurryPairingsScore(): Score { private resolveFurryPairingsScore(): Score {
const you = this.you; const you = this.you;
const them = this.them; const theyAreAnthro = this.theirAnalysis.isAnthro;
const theyAreHuman = this.theirAnalysis.isHuman;
const theyAreAnthro = Matcher.isAnthro(them);
const theyAreHuman = Matcher.isHuman(them);
const score = theyAreAnthro const score = theyAreAnthro
? Matcher.furryLikeabilityScore(you) ? Matcher.furryLikeabilityScore(you)
@ -537,19 +574,11 @@ export class Matcher {
private resolveAgeScore(): Score { private resolveAgeScore(): Score {
const you = this.you; const you = this.you;
const them = this.them; const theirAge = this.theirAnalysis.age;
const yourAgeTag = Matcher.getTagValue(TagId.Age, you); if (theirAge === null)
const theirAgeTag = Matcher.getTagValue(TagId.Age, them);
if (!theirAgeTag)
return new Score(Scoring.NEUTRAL); return new Score(Scoring.NEUTRAL);
if (!theirAgeTag.string)
return new Score(Scoring.NEUTRAL);
const theirAge = parseInt(theirAgeTag.string, 10);
const ageplayScore = Matcher.getKinkPreference(you, Kink.Ageplay); const ageplayScore = Matcher.getKinkPreference(you, Kink.Ageplay);
const underageScore = Matcher.getKinkPreference(you, Kink.UnderageCharacters); const underageScore = Matcher.getKinkPreference(you, Kink.UnderageCharacters);
@ -562,12 +591,12 @@ export class Matcher {
if ((theirAge < 18) && (underageScore !== null)) if ((theirAge < 18) && (underageScore !== null))
return Matcher.formatKinkScore(underageScore, `ages of ${theirAge}`); return Matcher.formatKinkScore(underageScore, `ages of ${theirAge}`);
if ((yourAgeTag) && (yourAgeTag.string)) { const yourAge = this.yourAnalysis.age;
if (yourAge !== null) {
const olderCharactersScore = Matcher.getKinkPreference(you, Kink.OlderCharacters); const olderCharactersScore = Matcher.getKinkPreference(you, Kink.OlderCharacters);
const youngerCharactersScore = Matcher.getKinkPreference(you, Kink.YoungerCharacters); const youngerCharactersScore = Matcher.getKinkPreference(you, Kink.YoungerCharacters);
const yourAge = parseInt(yourAgeTag.string, 10);
if ((yourAge < theirAge) && (olderCharactersScore !== null)) if ((yourAge < theirAge) && (olderCharactersScore !== null))
return Matcher.formatKinkScore(olderCharactersScore, 'older characters'); return Matcher.formatKinkScore(olderCharactersScore, 'older characters');
@ -580,9 +609,8 @@ export class Matcher {
private resolveGenderScore(): Score { private resolveGenderScore(): Score {
const you = this.you; const you = this.you;
const them = this.them;
const theirGender = Matcher.getTagValueList(TagId.Gender, them); const theirGender = this.theirAnalysis.gender;
if (theirGender === null) if (theirGender === null)
return new Score(Scoring.NEUTRAL); return new Score(Scoring.NEUTRAL);
@ -609,7 +637,7 @@ export class Matcher {
return t.list; return t.list;
} }
static isCisGender(...genders: Gender[]): boolean { static isCisGender(...genders: Gender[] | null[]): boolean {
return _.every(genders, (g: Gender) => ((g === Gender.Female) || (g === Gender.Male))); return _.every(genders, (g: Gender) => ((g === Gender.Female) || (g === Gender.Male)));
} }

View File

@ -2,8 +2,9 @@ import * as _ from 'lodash';
import core from '../chat/core'; import core from '../chat/core';
import { Character } from '../site/character_page/interfaces'; import { Character } from '../site/character_page/interfaces';
import { Matcher, Score, Scoring } from '../site/character_page/matcher'; import { Matcher, Score, Scoring } from './matcher';
import { Cache } from './cache'; import { Cache } from './cache';
import { SqliteStore } from './sqlite-store';
export interface CharacterCacheRecord { export interface CharacterCacheRecord {
character: Character; character: Character;
@ -13,10 +14,39 @@ export interface CharacterCacheRecord {
} }
export class ProfileCache extends Cache<CharacterCacheRecord> { export class ProfileCache extends Cache<CharacterCacheRecord> {
register(c: Character): CharacterCacheRecord { protected store?: SqliteStore;
setStore(store: SqliteStore): void {
this.store = store;
}
get(name: string, skipStore: boolean = false): CharacterCacheRecord | null {
const v = super.get(name);
if ((v !== null) || (!this.store) || (skipStore)) {
return v;
}
const pd = this.store.getProfile(name);
if (!pd) {
return null;
}
return this.register(pd.profileData, true);
}
register(c: Character, skipStore: boolean = false): CharacterCacheRecord {
const k = Cache.nameKey(c.character.name); const k = Cache.nameKey(c.character.name);
const score = ProfileCache.score(c); const score = ProfileCache.score(c);
if ((this.store) && (!skipStore)) {
this.store.storeProfile(c);
}
if (k in this.cache) { if (k in this.cache) {
const rExisting = this.cache[k]; const rExisting = this.cache[k];

187
learn/sqlite-store.ts Normal file
View File

@ -0,0 +1,187 @@
// import * as Sqlite from 'better-sqlite3';
// tslint:disable-next-line:no-duplicate-imports
import * as path from 'path';
import { Database, Statement } from 'better-sqlite3';
import core from '../chat/core';
// tslint:disable-next-line: no-require-imports
// const Sqlite = require('better-sqlite3');
import { nativeRequire } from '../electron/common';
// tslint:disable-next-line: no-any
const Sqlite = nativeRequire<any>('better-sqlite3');
import { Orientation, Gender, FurryPreference, Species, CharacterAnalysis } from './matcher';
import { Character as ComplexCharacter } from '../site/character_page/interfaces';
export interface ProfileRecord {
id: string;
name: string;
profileData: ComplexCharacter;
firstSeen: number;
lastFetched: number;
gender: Gender | null;
orientation: Orientation | null;
furryPreference: FurryPreference | null;
species: Species | null;
age: number | null;
domSubRole: number | null;
position: number | null;
lastCounted: number | null;
guestbookCount: number | null;
friendCount: number | null;
groupCount: number | null;
}
// export type Statement = any;
// export type Database = any;
export class SqliteStore {
protected stmtGetProfile: Statement;
protected stmtStoreProfile: Statement;
protected stmtUpdateCounts: Statement;
protected db: Database;
protected checkpointTimer: NodeJS.Timer | null = null;
constructor() {
const dbFile = path.join(core.state.generalSettings!.logDirectory, 'fchat-ascending.sqlite');
// tslint:disable-next-line: no-unsafe-any
this.db = new Sqlite(dbFile, {});
this.init();
this.migrateDatabase();
this.stmtGetProfile = this.db.prepare('SELECT * FROM profiles WHERE id = ?');
this.stmtStoreProfile = this.db.prepare(
`INSERT INTO profiles
(id, name, profileData, firstSeen, lastFetched, gender, orientation, furryPreference,
species, age, domSubRole, position)
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(id) DO UPDATE SET
profileData=excluded.profileData,
lastFetched=excluded.lastFetched,
gender=excluded.gender,
orientation=excluded.orientation,
furryPreference=excluded.furryPreference,
species=excluded.species,
age=excluded.age,
domSubRole=excluded.domSubRole,
position=excluded.position
`);
this.stmtUpdateCounts = this.db.prepare(
'UPDATE profiles SET lastCounted = ?, guestbookCount = ?, friendCount = ?, groupCount = ? WHERE id = ? LIMIT 1'
);
}
// tslint:disable-next-line: prefer-function-over-method
protected toProfileId(name: string): string {
return name.toLowerCase();
}
getProfile(name: string): ProfileRecord | undefined {
const data = this.stmtGetProfile.get(this.toProfileId(name));
if (!data) {
return;
}
// tslint:disable-next-line: no-unsafe-any
data.profileData = JSON.parse(data.profileData) as ComplexCharacter;
return data as ProfileRecord;
}
storeProfile(c: ComplexCharacter): void {
const ca = new CharacterAnalysis(c.character);
const data = [
this.toProfileId(c.character.name),
c.character.name,
JSON.stringify(c),
Math.round(Date.now() / 1000),
Math.round(Date.now() / 1000),
ca.gender,
ca.orientation,
ca.furryPreference,
ca.species,
ca.age,
null, // domSubRole
null // position
];
this.stmtStoreProfile.run(data);
}
updateProfileCounts(name: string, guestbookCount: number | null, friendCount: number | null, groupCount: number | null): void {
this.stmtUpdateCounts.run(Math.round(Date.now() / 1000), guestbookCount, friendCount, groupCount, this.toProfileId(name));
}
protected init(): void {
this.db.pragma('journal_mode = WAL');
}
protected migrateDatabase(): void {
this.db.exec(
`CREATE TABLE IF NOT EXISTS "migration" (
"version" INTEGER NOT NULL
, UNIQUE("version")
);
CREATE TABLE IF NOT EXISTS "profiles" (
"id" TEXT NOT NULL PRIMARY KEY
, "name" TEXT NOT NULL
, "profileData" TEXT NOT NULL
, "firstSeen" INTEGER NOT NULL
, "lastFetched" INTEGER NOT NULL
, "lastCounted" INTEGER
, "gender" INTEGER
, "orientation" INTEGER
, "furryPreference" INTEGER
, "species" INTEGER
, "age" INTEGER
, "domSubRole" INTEGER
, "position" INTEGER
, "guestbookCount" INTEGER
, "friendCount" INTEGER
, "groupCount" INTEGER
, UNIQUE("id")
);
INSERT OR IGNORE INTO migration(version) VALUES(1);
`);
}
start(): void {
this.stop();
this.checkpointTimer = setInterval(
() => this.db.checkpoint(),
10 * 60 * 1000
);
}
stop(): void {
if (this.checkpointTimer) {
clearInterval(this.checkpointTimer);
this.checkpointTimer = null;
}
}
}

580
package-lock.json generated
View File

@ -35,6 +35,21 @@
"integrity": "sha512-0afQfB+HBeJHlXPzcF2Jjh78SbwPSkDjba/O7pZFzAW3WGKNzd4s4AqrZo7oIlMWGnfoyDo8+QeosK0+DTDrTg==", "integrity": "sha512-0afQfB+HBeJHlXPzcF2Jjh78SbwPSkDjba/O7pZFzAW3WGKNzd4s4AqrZo7oIlMWGnfoyDo8+QeosK0+DTDrTg==",
"dev": true "dev": true
}, },
"@types/better-sqlite3": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-5.4.0.tgz",
"integrity": "sha512-nzm7lJ7l3jBmGUbtkL8cdOMhPkN6Pw2IM+b0V7iIKba+YKiLrjkIy7vVLsBIVnd7+lgzBzrHsXZxCaFTcmw5Ow==",
"dev": true,
"requires": {
"@types/integer": "*"
}
},
"@types/integer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/integer/-/integer-1.0.0.tgz",
"integrity": "sha512-3viiRKLoSP2Qr78nMoQjkDc0fan4BgmpOyV1+1gKjE8wWXo3QQ78WItO6f9WuBf3qe3ymDYhM65oqHTOZ0rFxw==",
"dev": true
},
"@types/lodash": { "@types/lodash": {
"version": "4.14.119", "version": "4.14.119",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.119.tgz", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.119.tgz",
@ -873,6 +888,31 @@
"callsite": "1.0.0" "callsite": "1.0.0"
} }
}, },
"better-sqlite3": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-5.4.0.tgz",
"integrity": "sha512-Uj1ZYOcq1GtFyFgJgqMVDoDLTy1B1pM9+bULnlX8szRX4cPjE/7JbKxCzQGhYlZlLkHQvtXXhCZ3skqsQ2byMA==",
"requires": {
"integer": "^2.1.0",
"tar": "^4.4.6"
},
"dependencies": {
"tar": {
"version": "4.4.10",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.10.tgz",
"integrity": "sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==",
"requires": {
"chownr": "^1.1.1",
"fs-minipass": "^1.2.5",
"minipass": "^2.3.5",
"minizlib": "^1.2.1",
"mkdirp": "^0.5.0",
"safe-buffer": "^5.1.2",
"yallist": "^3.0.3"
}
}
}
},
"big.js": { "big.js": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
@ -1409,9 +1449,9 @@
} }
}, },
"cli-spinners": { "cli-spinners": {
"version": "1.3.1", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-1.3.1.tgz", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.2.0.tgz",
"integrity": "sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg==", "integrity": "sha512-tgU3fKwzYjiLEQgPMD9Jt+JjHVL9kW93FiIMX/l7rivvOD4/LL0Mf7gda3+4U2KJBloybwgj5KEoQgGRioMiKQ==",
"dev": true "dev": true
}, },
"cliui": { "cliui": {
@ -1425,6 +1465,12 @@
"wrap-ansi": "^2.0.0" "wrap-ansi": "^2.0.0"
} }
}, },
"clone": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
"integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
"dev": true
},
"clone-deep": { "clone-deep": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz",
@ -2091,6 +2137,15 @@
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
}, },
"defaults": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
"integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=",
"dev": true,
"requires": {
"clone": "^1.0.2"
}
},
"define-properties": { "define-properties": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
@ -2509,42 +2564,332 @@
} }
}, },
"electron-rebuild": { "electron-rebuild": {
"version": "1.8.2", "version": "1.8.5",
"resolved": "https://registry.npmjs.org/electron-rebuild/-/electron-rebuild-1.8.2.tgz", "resolved": "https://registry.npmjs.org/electron-rebuild/-/electron-rebuild-1.8.5.tgz",
"integrity": "sha512-EeR4dgb6NN7ybxduUWMeeLhU/EuF+FzwFZJfMJXD0bx96K+ttAieCXOn9lTO5nA9Qn3hiS7pEpk8pZ9StpGgSg==", "integrity": "sha512-gDwRA3utfiPnFwBZ1z8M4SEMwsdsy6Bg4VGO2ohelMOIO0vxiCrDQ/FVdLk3h2g7fLb06QFUsQU+86jiTSmZxw==",
"dev": true, "dev": true,
"requires": { "requires": {
"colors": "^1.2.0", "colors": "^1.3.3",
"debug": "^2.6.3", "debug": "^4.1.1",
"detect-libc": "^1.0.3", "detect-libc": "^1.0.3",
"fs-extra": "^3.0.1", "fs-extra": "^7.0.1",
"node-abi": "^2.0.0", "node-abi": "^2.8.0",
"node-gyp": "^3.6.0", "node-gyp": "^4.0.0",
"ora": "^1.2.0", "ora": "^3.4.0",
"rimraf": "^2.6.1", "spawn-rx": "^3.0.0",
"spawn-rx": "^2.0.10", "yargs": "^13.2.2"
"yargs": "^7.0.2"
}, },
"dependencies": { "dependencies": {
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true
},
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true
},
"cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
"dev": true,
"requires": {
"string-width": "^3.1.0",
"strip-ansi": "^5.2.0",
"wrap-ansi": "^5.1.0"
}
},
"cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"dev": true,
"requires": {
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
},
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
},
"execa": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
"integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
"dev": true,
"requires": {
"cross-spawn": "^6.0.0",
"get-stream": "^4.0.0",
"is-stream": "^1.1.0",
"npm-run-path": "^2.0.0",
"p-finally": "^1.0.0",
"signal-exit": "^3.0.0",
"strip-eof": "^1.0.0"
}
},
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true,
"requires": {
"locate-path": "^3.0.0"
}
},
"fs-extra": { "fs-extra": {
"version": "3.0.1", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
"integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
"dev": true, "dev": true,
"requires": { "requires": {
"graceful-fs": "^4.1.2", "graceful-fs": "^4.1.2",
"jsonfile": "^3.0.0", "jsonfile": "^4.0.0",
"universalify": "^0.1.0" "universalify": "^0.1.0"
} }
}, },
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true
},
"invert-kv": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
"dev": true
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
"dev": true
},
"jsonfile": { "jsonfile": {
"version": "3.0.1", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
"dev": true, "dev": true,
"requires": { "requires": {
"graceful-fs": "^4.1.6" "graceful-fs": "^4.1.6"
} }
},
"lcid": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
"integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
"dev": true,
"requires": {
"invert-kv": "^2.0.0"
}
},
"locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"dev": true,
"requires": {
"p-locate": "^3.0.0",
"path-exists": "^3.0.0"
}
},
"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-abi": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.9.0.tgz",
"integrity": "sha512-jmEOvv0eanWjhX8dX1pmjb7oJl1U1oR4FOh0b2GnvALwSYoOdU7sj+kLDSAyjo4pfC9aj/IxkloxdLJQhSSQBA==",
"dev": true,
"requires": {
"semver": "^5.4.1"
}
},
"node-gyp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-4.0.0.tgz",
"integrity": "sha512-2XiryJ8sICNo6ej8d0idXDEMKfVfFK7kekGCtJAuelGsYHQxhj13KTf95swTCN2dZ/4lTfZ84Fu31jqJEEgjWA==",
"dev": true,
"requires": {
"glob": "^7.0.3",
"graceful-fs": "^4.1.2",
"mkdirp": "^0.5.0",
"nopt": "2 || 3",
"npmlog": "0 || 1 || 2 || 3 || 4",
"osenv": "0",
"request": "^2.87.0",
"rimraf": "2",
"semver": "~5.3.0",
"tar": "^4.4.8",
"which": "1"
},
"dependencies": {
"semver": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
"dev": true
}
}
},
"npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
"integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
"dev": true,
"requires": {
"path-key": "^2.0.0"
}
},
"os-locale": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
"integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
"dev": true,
"requires": {
"execa": "^1.0.0",
"lcid": "^2.0.0",
"mem": "^4.0.0"
}
},
"p-limit": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz",
"integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==",
"dev": true,
"requires": {
"p-try": "^2.0.0"
}
},
"p-locate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
"dev": true,
"requires": {
"p-limit": "^2.0.0"
}
},
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true
},
"path-key": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
"dev": 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==",
"dev": true
},
"string-width": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"dev": true,
"requires": {
"emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^5.1.0"
}
},
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"dev": true,
"requires": {
"ansi-regex": "^4.1.0"
}
},
"tar": {
"version": "4.4.10",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.10.tgz",
"integrity": "sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==",
"dev": true,
"requires": {
"chownr": "^1.1.1",
"fs-minipass": "^1.2.5",
"minipass": "^2.3.5",
"minizlib": "^1.2.1",
"mkdirp": "^0.5.0",
"safe-buffer": "^5.1.2",
"yallist": "^3.0.3"
}
},
"which-module": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
"dev": true
},
"wrap-ansi": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.0",
"string-width": "^3.0.0",
"strip-ansi": "^5.0.0"
}
},
"y18n": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
"dev": true
},
"yargs": {
"version": "13.2.4",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz",
"integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==",
"dev": true,
"requires": {
"cliui": "^5.0.0",
"find-up": "^3.0.0",
"get-caller-file": "^2.0.1",
"os-locale": "^3.1.0",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^3.0.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^13.1.0"
}
},
"yargs-parser": {
"version": "13.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
"integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
"dev": true,
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
} }
} }
}, },
@ -2604,6 +2949,12 @@
"minimalistic-crypto-utils": "^1.0.0" "minimalistic-crypto-utils": "^1.0.0"
} }
}, },
"emoji-regex": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
"dev": true
},
"emojis-list": { "emojis-list": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
@ -3334,6 +3685,14 @@
} }
} }
}, },
"fs-minipass": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.6.tgz",
"integrity": "sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==",
"requires": {
"minipass": "^2.2.1"
}
},
"fs-temp": { "fs-temp": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/fs-temp/-/fs-temp-1.1.2.tgz", "resolved": "https://registry.npmjs.org/fs-temp/-/fs-temp-1.1.2.tgz",
@ -4097,6 +4456,27 @@
"integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
"dev": true "dev": true
}, },
"get-stream": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
"integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
"dev": true,
"requires": {
"pump": "^3.0.0"
},
"dependencies": {
"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"
}
}
}
},
"get-value": { "get-value": {
"version": "2.0.6", "version": "2.0.6",
"resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
@ -4488,6 +4868,11 @@
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
}, },
"integer": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/integer/-/integer-2.1.0.tgz",
"integrity": "sha512-vBtiSgrEiNocWvvZX1RVfeOKa2mCHLZQ2p9nkQkQZ/BvEiY+6CcUz0eyjvIiewjJoeNidzg2I+tpPJvpyspL1w=="
},
"invert-kv": { "invert-kv": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
@ -4749,8 +5134,7 @@
"is-stream": { "is-stream": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
"optional": true
}, },
"is-svg": { "is-svg": {
"version": "3.0.0", "version": "3.0.0",
@ -5132,6 +5516,15 @@
} }
} }
}, },
"map-age-cleaner": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
"integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
"dev": true,
"requires": {
"p-defer": "^1.0.0"
}
},
"map-cache": { "map-cache": {
"version": "0.2.2", "version": "0.2.2",
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
@ -5176,6 +5569,25 @@
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
"dev": true "dev": true
}, },
"mem": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz",
"integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
"dev": true,
"requires": {
"map-age-cleaner": "^0.1.1",
"mimic-fn": "^2.0.0",
"p-is-promise": "^2.0.0"
},
"dependencies": {
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"dev": true
}
}
},
"memory-fs": { "memory-fs": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
@ -5311,6 +5723,23 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
}, },
"minipass": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
}
},
"minizlib": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
"integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
"requires": {
"minipass": "^2.2.1"
}
},
"mississippi": { "mississippi": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
@ -5504,6 +5933,12 @@
"inherits": "~2.0.1" "inherits": "~2.0.1"
} }
}, },
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
"node-abi": { "node-abi": {
"version": "2.5.0", "version": "2.5.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.5.0.tgz", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.5.0.tgz",
@ -5853,15 +6288,45 @@
} }
}, },
"ora": { "ora": {
"version": "1.4.0", "version": "3.4.0",
"resolved": "https://registry.npmjs.org/ora/-/ora-1.4.0.tgz", "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz",
"integrity": "sha512-iMK1DOQxzzh2MBlVsU42G80mnrvUhqsMh74phHtDlrcTZPK0pH6o7l7DRshK+0YsxDyEuaOkziVdvM3T0QTzpw==", "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==",
"dev": true, "dev": true,
"requires": { "requires": {
"chalk": "^2.1.0", "chalk": "^2.4.2",
"cli-cursor": "^2.1.0", "cli-cursor": "^2.1.0",
"cli-spinners": "^1.0.1", "cli-spinners": "^2.0.0",
"log-symbols": "^2.1.0" "log-symbols": "^2.2.0",
"strip-ansi": "^5.2.0",
"wcwidth": "^1.0.1"
},
"dependencies": {
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true
},
"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"
}
},
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"dev": true,
"requires": {
"ansi-regex": "^4.1.0"
}
}
} }
}, },
"os-browserify": { "os-browserify": {
@ -5899,6 +6364,24 @@
"os-tmpdir": "^1.0.0" "os-tmpdir": "^1.0.0"
} }
}, },
"p-defer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
"integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=",
"dev": true
},
"p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
"dev": true
},
"p-is-promise": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
"integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==",
"dev": true
},
"p-limit": { "p-limit": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
@ -7095,12 +7578,12 @@
} }
}, },
"rxjs": { "rxjs": {
"version": "5.5.12", "version": "6.5.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz",
"integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==",
"dev": true, "dev": true,
"requires": { "requires": {
"symbol-observable": "1.0.1" "tslib": "^1.9.0"
} }
}, },
"safe-buffer": { "safe-buffer": {
@ -7644,14 +8127,14 @@
"dev": true "dev": true
}, },
"spawn-rx": { "spawn-rx": {
"version": "2.0.12", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/spawn-rx/-/spawn-rx-2.0.12.tgz", "resolved": "https://registry.npmjs.org/spawn-rx/-/spawn-rx-3.0.0.tgz",
"integrity": "sha512-gOPXiQQFQ9lTOLuys0iMn3jfxxv9c7zzwhbYLOEbQGvEShHVJ5sSR1oD3Daj88os7jKArDYT7rbOKdvNhe7iEg==", "integrity": "sha512-dw4Ryg/KMNfkKa5ezAR5aZe9wNwPdKlnHEXtHOjVnyEDSPQyOpIPPRtcIiu7127SmtHhaCjw21yC43HliW0iIg==",
"dev": true, "dev": true,
"requires": { "requires": {
"debug": "^2.5.1", "debug": "^2.5.1",
"lodash.assign": "^4.2.0", "lodash.assign": "^4.2.0",
"rxjs": "^5.1.1" "rxjs": "^6.3.1"
} }
}, },
"spdx-correct": { "spdx-correct": {
@ -7866,8 +8349,7 @@
"strip-eof": { "strip-eof": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
"optional": true
}, },
"strip-indent": { "strip-indent": {
"version": "1.0.1", "version": "1.0.1",
@ -7944,12 +8426,6 @@
"util.promisify": "~1.0.0" "util.promisify": "~1.0.0"
} }
}, },
"symbol-observable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz",
"integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=",
"dev": true
},
"tapable": { "tapable": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.1.tgz", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.1.tgz",
@ -8622,6 +9098,15 @@
"neo-async": "^2.5.0" "neo-async": "^2.5.0"
} }
}, },
"wcwidth": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
"integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=",
"dev": true,
"requires": {
"defaults": "^1.0.3"
}
},
"webpack": { "webpack": {
"version": "4.27.1", "version": "4.27.1",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.27.1.tgz", "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.27.1.tgz",
@ -8768,8 +9253,7 @@
"yallist": { "yallist": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A=="
"dev": true
}, },
"yargs": { "yargs": {
"version": "7.1.0", "version": "7.1.0",

View File

@ -10,6 +10,7 @@
"@fortawesome/fontawesome-free": "^5.6.1", "@fortawesome/fontawesome-free": "^5.6.1",
"@types/lodash": "^4.14.119", "@types/lodash": "^4.14.119",
"@types/sortablejs": "^1.7.0", "@types/sortablejs": "^1.7.0",
"@types/better-sqlite3": "^5.4.0",
"@vue/devtools": "^5.1.0", "@vue/devtools": "^5.1.0",
"axios": "^0.18.0", "axios": "^0.18.0",
"bootstrap": "^4.1.3", "bootstrap": "^4.1.3",
@ -18,7 +19,7 @@
"electron": "3.0.13", "electron": "3.0.13",
"electron-log": "^2.2.17", "electron-log": "^2.2.17",
"electron-packager": "^13.0.1", "electron-packager": "^13.0.1",
"electron-rebuild": "^1.8.2", "electron-rebuild": "^1.8.5",
"extract-loader": "^3.1.0", "extract-loader": "^3.1.0",
"file-loader": "^2.0.0", "file-loader": "^2.0.0",
"lodash": "^4.17.11", "lodash": "^4.17.11",
@ -39,6 +40,7 @@
"webpack": "^4.27.1" "webpack": "^4.27.1"
}, },
"dependencies": { "dependencies": {
"better-sqlite3": "^5.4.0",
"keytar": "^4.3.0", "keytar": "^4.3.0",
"spellchecker": "^3.5.0" "spellchecker": "^3.5.0"
}, },
@ -48,6 +50,6 @@
"electron-winstaller": "^2.7.0" "electron-winstaller": "^2.7.0"
}, },
"scripts": { "scripts": {
"postinstall": "electron-rebuild -o spellchecker,keytar" "postinstall": "electron-rebuild -o spellchecker,keytar,better-sqlite3,integer"
} }
} }

View File

@ -1,4 +1,4 @@
# F-Chat Rising # F-Chat Ascending
This repository contains a modified version of the mainline F-Chat 3.0 client. This repository contains a modified version of the mainline F-Chat 3.0 client.
@ -9,6 +9,8 @@ This repository contains a modified version of the mainline F-Chat 3.0 client.
* Manage channel's ad settings via "Tab Settings" * Manage channel's ad settings via "Tab Settings"
* Automatically re-post ads every 11-18 minutes (randomized) for up to 180 minutes * Automatically re-post ads every 11-18 minutes (randomized) for up to 180 minutes
* Rotate multiple ads on a single channel * Rotate multiple ads on a single channel
* Ad Rating
* LFP ads are automatically rated and matched against your profile
* Link previews * Link previews
* Hover cursor over any `[url]` to see a preview of it * Hover cursor over any `[url]` to see a preview of it
* Middle click any `[url]` to turn the preview into a sticky / interactive mode * Middle click any `[url]` to turn the preview into a sticky / interactive mode

View File

@ -86,7 +86,7 @@
import CharacterKinksView from './kinks.vue'; import CharacterKinksView from './kinks.vue';
import Sidebar from './sidebar.vue'; import Sidebar from './sidebar.vue';
import core from '../../chat/core'; import core from '../../chat/core';
import { Matcher, MatchReport } from './matcher'; import { Matcher, MatchReport } from '../../learn/matcher';
import MatchReportView from './match-report.vue'; import MatchReportView from './match-report.vue';

View File

@ -13,7 +13,7 @@
import { DisplayInfotag } from './interfaces'; import { DisplayInfotag } from './interfaces';
// import { Character as CharacterInfo } from '../../interfaces'; // import { Character as CharacterInfo } from '../../interfaces';
import {Store} from './data_store'; import {Store} from './data_store';
import { MatchReport, TagId } from './matcher'; import { MatchReport, TagId } from '../../learn/matcher';
import { CssClassMap } from './match-report.vue'; import { CssClassMap } from './match-report.vue';

View File

@ -16,7 +16,7 @@
import {Character, CONTACT_GROUP_ID, DisplayInfotag} from './interfaces'; import {Character, CONTACT_GROUP_ID, DisplayInfotag} from './interfaces';
import InfotagView from './infotag.vue'; import InfotagView from './infotag.vue';
import { MatchReport } from './matcher'; import { MatchReport } from '../../learn/matcher';
interface DisplayInfotagGroup { interface DisplayInfotagGroup {
id: number id: number

View File

@ -35,7 +35,7 @@
import * as _ from 'lodash'; import * as _ from 'lodash';
import Vue from 'vue'; import Vue from 'vue';
import * as Utils from '../utils'; import * as Utils from '../utils';
import { MatchReport, MatchResult, Score, Scoring } from './matcher'; import { MatchReport, MatchResult, Score, Scoring } from '../../learn/matcher';
export interface CssClassMap { export interface CssClassMap {
[key: string]: boolean; [key: string]: boolean;

View File

@ -101,7 +101,7 @@
import FriendDialog from './friend_dialog.vue'; import FriendDialog from './friend_dialog.vue';
import InfotagView from './infotag.vue'; import InfotagView from './infotag.vue';
import {Character, CONTACT_GROUP_ID, SharedStore} from './interfaces'; import {Character, CONTACT_GROUP_ID, SharedStore} from './interfaces';
import { MatchReport } from './matcher'; import { MatchReport } from '../../learn/matcher';
import MemoDialog from './memo_dialog.vue'; import MemoDialog from './memo_dialog.vue';
import ReportDialog from './report_dialog.vue'; import ReportDialog from './report_dialog.vue';