mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-11-10 14:10:59 +08:00
Merge remote-tracking branch 'upstream/master' into store_custom_themes
This commit is contained in:
commit
1c63694877
43 changed files with 700 additions and 894 deletions
|
|
@ -46,6 +46,7 @@ class ApeKeysController {
|
|||
hash: saltyHash,
|
||||
createdOn: Date.now(),
|
||||
modifiedOn: Date.now(),
|
||||
lastUsedOn: -1,
|
||||
};
|
||||
|
||||
const apeKeyId = await ApeKeysDAO.addApeKey(uid, apeKey);
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ class QuotesController {
|
|||
|
||||
const data = await QuoteRatingsDAO.get(
|
||||
parseInt(quoteId as string),
|
||||
language
|
||||
language as string
|
||||
);
|
||||
|
||||
return new MonkeyResponse("Rating retrieved", data);
|
||||
|
|
@ -107,25 +107,18 @@ class QuotesController {
|
|||
throw new MonkeyError(400, "Captcha check failed.");
|
||||
}
|
||||
|
||||
const newReport = {
|
||||
const newReport: MonkeyTypes.Report = {
|
||||
id: uuidv4(),
|
||||
type: "quote",
|
||||
timestamp: new Date().getTime(),
|
||||
uid,
|
||||
details: {
|
||||
contentId: `${quoteLanguage}-${quoteId}`,
|
||||
reason,
|
||||
comment,
|
||||
},
|
||||
contentId: `${quoteLanguage}-${quoteId}`,
|
||||
reason,
|
||||
comment,
|
||||
};
|
||||
|
||||
await ReportDAO.createReport(newReport, maxReports, contentReportLimit);
|
||||
|
||||
Logger.log("report_created", {
|
||||
type: newReport.type,
|
||||
details: newReport.details,
|
||||
});
|
||||
|
||||
return new MonkeyResponse("Quote reported");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import _ from "lodash";
|
|||
import UsersDAO from "../../dao/user";
|
||||
import BotDAO from "../../dao/bot";
|
||||
import MonkeyError from "../../utils/error";
|
||||
import Logger from "../../utils/logger.js";
|
||||
import Logger from "../../utils/logger";
|
||||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
import { linkAccount } from "../../utils/discord";
|
||||
import { buildAgentLog } from "../../utils/misc";
|
||||
|
|
@ -175,7 +175,6 @@ class UserController {
|
|||
const { tagId } = req.params;
|
||||
|
||||
await UsersDAO.removeTagPb(uid, tagId);
|
||||
[];
|
||||
return new MonkeyResponse("Tag PB cleared");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { asyncHandler } from "../../middlewares/api-utils";
|
|||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
import { Application, NextFunction, Response } from "express";
|
||||
import swStats from "swagger-stats";
|
||||
import SwaggerSpec from "../../swagger.json";
|
||||
|
||||
const pathOverride = process.env.API_PATH_OVERRIDE;
|
||||
const BASE_ROUTE = pathOverride ? `/${pathOverride}` : "";
|
||||
|
|
@ -37,6 +38,7 @@ function addApiRoutes(app: Application): void {
|
|||
uriPath: "/stats",
|
||||
authentication: process.env.MODE !== "dev",
|
||||
apdexThreshold: 100,
|
||||
swaggerSpec: SwaggerSpec,
|
||||
onAuthenticate: (_req, username, password) => {
|
||||
return (
|
||||
username === process.env.STATS_USERNAME &&
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import _ from "lodash";
|
||||
|
||||
type Status = {
|
||||
code: number;
|
||||
message: string;
|
||||
|
|
@ -13,10 +15,6 @@ type Statuses = {
|
|||
GIT_GUD: Status;
|
||||
};
|
||||
|
||||
export function getCodesRangeStart(): number {
|
||||
return 460;
|
||||
}
|
||||
|
||||
const statuses: Statuses = {
|
||||
TEST_TOO_SHORT: {
|
||||
code: 460,
|
||||
|
|
@ -48,4 +46,12 @@ const statuses: Statuses = {
|
|||
},
|
||||
};
|
||||
|
||||
const CUSTOM_STATUS_CODES = new Set(
|
||||
_.map(statuses, (status: Status) => status.code)
|
||||
);
|
||||
|
||||
export function isCustomCode(code: number): boolean {
|
||||
return CUSTOM_STATUS_CODES.has(code);
|
||||
}
|
||||
|
||||
export default statuses;
|
||||
|
|
|
|||
|
|
@ -72,6 +72,16 @@ class ApeKeysDAO {
|
|||
const apeKeys = _.omit(user.apeKeys, keyId);
|
||||
await UsersDAO.setApeKeys(uid, apeKeys);
|
||||
}
|
||||
|
||||
static async updateLastUsedOn(
|
||||
user: MonkeyTypes.User,
|
||||
keyId: string
|
||||
): Promise<void> {
|
||||
checkIfKeyExists(user.apeKeys, keyId);
|
||||
|
||||
user.apeKeys[keyId].lastUsedOn = Date.now();
|
||||
await UsersDAO.setApeKeys(user.uid, user.apeKeys);
|
||||
}
|
||||
}
|
||||
|
||||
export default ApeKeysDAO;
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
import db from "../init/db";
|
||||
|
||||
class PsaDAO {
|
||||
static async get(_uid, _config) {
|
||||
return await db.collection("psa").find().toArray();
|
||||
}
|
||||
}
|
||||
|
||||
export default PsaDAO;
|
||||
9
backend/dao/psa.ts
Normal file
9
backend/dao/psa.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import db from "../init/db";
|
||||
|
||||
class PsaDAO {
|
||||
static async get(): Promise<MonkeyTypes.PSA[]> {
|
||||
return await db.collection<MonkeyTypes.PSA>("psa").find().toArray();
|
||||
}
|
||||
}
|
||||
|
||||
export default PsaDAO;
|
||||
|
|
@ -3,15 +3,17 @@ import { roundTo2 } from "../utils/misc";
|
|||
|
||||
class PublicStatsDAO {
|
||||
//needs to be rewritten, this is public stats not user stats
|
||||
static async updateStats(restartCount, time) {
|
||||
time = roundTo2(time);
|
||||
await db.collection("public").updateOne(
|
||||
static async updateStats(
|
||||
restartCount: number,
|
||||
time: number
|
||||
): Promise<boolean> {
|
||||
await db.collection<MonkeyTypes.PublicStats>("public").updateOne(
|
||||
{ type: "stats" },
|
||||
{
|
||||
$inc: {
|
||||
testsCompleted: 1,
|
||||
testsStarted: restartCount + 1,
|
||||
timeTyping: time,
|
||||
timeTyping: roundTo2(time),
|
||||
},
|
||||
},
|
||||
{ upsert: true }
|
||||
|
|
@ -1,10 +1,15 @@
|
|||
import db from "../init/db";
|
||||
|
||||
class QuoteRatingsDAO {
|
||||
static async submit(quoteId, language, rating, update) {
|
||||
static async submit(
|
||||
quoteId: number,
|
||||
language: string,
|
||||
rating: number,
|
||||
update: boolean
|
||||
): Promise<void> {
|
||||
if (update) {
|
||||
await db
|
||||
.collection("quote-rating")
|
||||
.collection<MonkeyTypes.QuoteRating>("quote-rating")
|
||||
.updateOne(
|
||||
{ quoteId, language },
|
||||
{ $inc: { totalRating: rating } },
|
||||
|
|
@ -12,28 +17,33 @@ class QuoteRatingsDAO {
|
|||
);
|
||||
} else {
|
||||
await db
|
||||
.collection("quote-rating")
|
||||
.collection<MonkeyTypes.QuoteRating>("quote-rating")
|
||||
.updateOne(
|
||||
{ quoteId, language },
|
||||
{ $inc: { ratings: 1, totalRating: rating } },
|
||||
{ upsert: true }
|
||||
);
|
||||
}
|
||||
let quoteRating = await this.get(quoteId, language);
|
||||
|
||||
let average = parseFloat(
|
||||
const quoteRating = await this.get(quoteId, language);
|
||||
const average = parseFloat(
|
||||
(
|
||||
Math.round((quoteRating.totalRating / quoteRating.ratings) * 10) / 10
|
||||
).toFixed(1)
|
||||
);
|
||||
|
||||
return await db
|
||||
.collection("quote-rating")
|
||||
await db
|
||||
.collection<MonkeyTypes.QuoteRating>("quote-rating")
|
||||
.updateOne({ quoteId, language }, { $set: { average } });
|
||||
}
|
||||
|
||||
static async get(quoteId, language) {
|
||||
return await db.collection("quote-rating").findOne({ quoteId, language });
|
||||
static async get(
|
||||
quoteId: number,
|
||||
language: string
|
||||
): Promise<MonkeyTypes.QuoteRating> {
|
||||
return await db
|
||||
.collection<MonkeyTypes.QuoteRating>("quote-rating")
|
||||
.findOne({ quoteId, language });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
import MonkeyError from "../utils/error";
|
||||
import db from "../init/db";
|
||||
class ReportDAO {
|
||||
static async createReport(report, maxReports, contentReportLimit) {
|
||||
const reports = await db.collection("reports").find().toArray();
|
||||
|
||||
if (reports.length >= maxReports) {
|
||||
throw new MonkeyError(
|
||||
503,
|
||||
"Reports are not being accepted at this time. Please try again later."
|
||||
);
|
||||
}
|
||||
|
||||
const sameReports = reports.filter((existingReport) => {
|
||||
return existingReport.details.contentId === report.details.contentId;
|
||||
});
|
||||
|
||||
if (sameReports.length >= contentReportLimit) {
|
||||
throw new MonkeyError(
|
||||
409,
|
||||
"A report limit for this content has been reached."
|
||||
);
|
||||
}
|
||||
|
||||
await db.collection("reports").insertOne(report);
|
||||
}
|
||||
}
|
||||
|
||||
export default ReportDAO;
|
||||
39
backend/dao/report.ts
Normal file
39
backend/dao/report.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import MonkeyError from "../utils/error";
|
||||
import db from "../init/db";
|
||||
|
||||
const COLLECTION_NAME = "reports";
|
||||
|
||||
class ReportDAO {
|
||||
static async createReport(
|
||||
report: MonkeyTypes.Report,
|
||||
maxReports: number,
|
||||
contentReportLimit: number
|
||||
): Promise<void> {
|
||||
const reportsCount = await db
|
||||
.collection<MonkeyTypes.Report>(COLLECTION_NAME)
|
||||
.estimatedDocumentCount();
|
||||
|
||||
if (reportsCount >= maxReports) {
|
||||
throw new MonkeyError(
|
||||
503,
|
||||
"Reports are not being accepted at this time. Please try again later."
|
||||
);
|
||||
}
|
||||
|
||||
const sameReports = await db
|
||||
.collection<MonkeyTypes.Report>(COLLECTION_NAME)
|
||||
.find({ contentId: report.contentId })
|
||||
.toArray();
|
||||
|
||||
if (sameReports.length >= contentReportLimit) {
|
||||
throw new MonkeyError(
|
||||
409,
|
||||
"A report limit for this content has been reached."
|
||||
);
|
||||
}
|
||||
|
||||
await db.collection<MonkeyTypes.Report>(COLLECTION_NAME).insertOne(report);
|
||||
}
|
||||
}
|
||||
|
||||
export default ReportDAO;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import _ from "lodash";
|
||||
import { isUsernameValid } from "../utils/validation";
|
||||
import { updateAuthEmail } from "../utils/auth";
|
||||
import { updateUserEmail } from "../utils/auth";
|
||||
import { checkAndUpdatePb } from "../utils/pb";
|
||||
import db from "../init/db";
|
||||
import MonkeyError from "../utils/error";
|
||||
|
|
@ -66,7 +66,7 @@ class UsersDAO {
|
|||
static async updateEmail(uid, email) {
|
||||
const user = await db.collection("users").findOne({ uid });
|
||||
if (!user) throw new MonkeyError(404, "User not found", "update email");
|
||||
await updateAuthEmail(uid, email);
|
||||
await updateUserEmail(uid, email);
|
||||
await db.collection("users").updateOne({ uid }, { $set: { email } });
|
||||
return true;
|
||||
}
|
||||
|
|
@ -167,19 +167,7 @@ class UsersDAO {
|
|||
}
|
||||
|
||||
static async checkIfPb(uid, user, result) {
|
||||
const {
|
||||
mode,
|
||||
mode2,
|
||||
acc,
|
||||
consistency,
|
||||
difficulty,
|
||||
lazyMode,
|
||||
language,
|
||||
punctuation,
|
||||
rawWpm,
|
||||
wpm,
|
||||
funbox,
|
||||
} = result;
|
||||
const { mode, funbox } = result;
|
||||
|
||||
if (funbox !== "none" && funbox !== "plus_one" && funbox !== "plus_two") {
|
||||
return false;
|
||||
|
|
@ -192,20 +180,7 @@ class UsersDAO {
|
|||
let lbpb = user.lbPersonalBests;
|
||||
if (!lbpb) lbpb = {};
|
||||
|
||||
let pb = checkAndUpdatePb(
|
||||
user.personalBests,
|
||||
lbpb,
|
||||
mode,
|
||||
mode2,
|
||||
acc,
|
||||
consistency,
|
||||
difficulty,
|
||||
lazyMode,
|
||||
language,
|
||||
punctuation,
|
||||
rawWpm,
|
||||
wpm
|
||||
);
|
||||
let pb = checkAndUpdatePb(user.personalBests, lbpb, result);
|
||||
|
||||
if (pb.isPb) {
|
||||
await db
|
||||
|
|
@ -227,20 +202,7 @@ class UsersDAO {
|
|||
return [];
|
||||
}
|
||||
|
||||
const {
|
||||
mode,
|
||||
mode2,
|
||||
acc,
|
||||
consistency,
|
||||
difficulty,
|
||||
lazyMode,
|
||||
language,
|
||||
punctuation,
|
||||
rawWpm,
|
||||
wpm,
|
||||
tags,
|
||||
funbox,
|
||||
} = result;
|
||||
const { mode, tags, funbox } = result;
|
||||
|
||||
if (funbox !== "none" && funbox !== "plus_one" && funbox !== "plus_two") {
|
||||
return [];
|
||||
|
|
@ -262,20 +224,7 @@ class UsersDAO {
|
|||
let ret = [];
|
||||
|
||||
tagsToCheck.forEach(async (tag) => {
|
||||
let tagpb = checkAndUpdatePb(
|
||||
tag.personalBests,
|
||||
undefined,
|
||||
mode,
|
||||
mode2,
|
||||
acc,
|
||||
consistency,
|
||||
difficulty,
|
||||
lazyMode,
|
||||
language,
|
||||
punctuation,
|
||||
rawWpm,
|
||||
wpm
|
||||
);
|
||||
let tagpb = checkAndUpdatePb(tag.personalBests, undefined, result);
|
||||
if (tagpb.isPb) {
|
||||
ret.push(tag._id);
|
||||
await db
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import db from "./db";
|
||||
import _ from "lodash";
|
||||
import Logger from "../utils/logger.js";
|
||||
import Logger from "../utils/logger";
|
||||
import { identity } from "../utils/misc";
|
||||
import BASE_CONFIGURATION from "../constants/base-configuration";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import _ from "lodash";
|
||||
import { compare } from "bcrypt";
|
||||
import UsersDAO from "../dao/user";
|
||||
import ApeKeysDAO from "../dao/ape-keys";
|
||||
import MonkeyError from "../utils/error";
|
||||
import { verifyIdToken } from "../utils/auth";
|
||||
import { base64UrlDecode } from "../utils/misc";
|
||||
|
|
@ -154,12 +155,19 @@ async function authenticateWithApeKey(
|
|||
|
||||
const keyOwner = (await UsersDAO.getUser(uid)) as MonkeyTypes.User;
|
||||
const targetApeKey = _.get(keyOwner.apeKeys, keyId);
|
||||
|
||||
if (!targetApeKey.enabled) {
|
||||
throw new MonkeyError(400, "ApeKey is disabled");
|
||||
}
|
||||
|
||||
const isKeyValid = await compare(apeKey, targetApeKey?.hash);
|
||||
|
||||
if (!isKeyValid) {
|
||||
throw new MonkeyError(400, "Invalid ApeKey");
|
||||
}
|
||||
|
||||
await ApeKeysDAO.updateLastUsedOn(keyOwner, keyId);
|
||||
|
||||
return {
|
||||
uid,
|
||||
email: keyOwner.email,
|
||||
|
|
|
|||
20
backend/package-lock.json
generated
20
backend/package-lock.json
generated
|
|
@ -36,7 +36,6 @@
|
|||
"@types/cors": "2.8.12",
|
||||
"@types/cron": "1.7.3",
|
||||
"@types/lodash": "4.14.178",
|
||||
"@types/mongodb": "4.0.7",
|
||||
"@types/node": "17.0.18",
|
||||
"@types/node-fetch": "2.6.1",
|
||||
"@types/swagger-stats": "0.95.4",
|
||||
|
|
@ -736,16 +735,6 @@
|
|||
"integrity": "sha512-kGZJY+R+WnR5Rk+RPHUMERtb2qBRViIHCBdtUrY+NmwuGb8pQdfTqQiCKPrxpdoycl8KWm2DLdkpoSdt479XoQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/mongodb": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-4.0.7.tgz",
|
||||
"integrity": "sha512-lPUYPpzA43baXqnd36cZ9xxorprybxXDzteVKCPAdp14ppHtFJHnXYvNpmBvtMUTb5fKXVv6sVbzo1LHkWhJlw==",
|
||||
"deprecated": "mongodb provides its own types. @types/mongodb is no longer needed.",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"mongodb": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "17.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.18.tgz",
|
||||
|
|
@ -5557,15 +5546,6 @@
|
|||
"integrity": "sha512-kGZJY+R+WnR5Rk+RPHUMERtb2qBRViIHCBdtUrY+NmwuGb8pQdfTqQiCKPrxpdoycl8KWm2DLdkpoSdt479XoQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/mongodb": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-4.0.7.tgz",
|
||||
"integrity": "sha512-lPUYPpzA43baXqnd36cZ9xxorprybxXDzteVKCPAdp14ppHtFJHnXYvNpmBvtMUTb5fKXVv6sVbzo1LHkWhJlw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mongodb": "*"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "17.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.18.tgz",
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@
|
|||
"@types/cors": "2.8.12",
|
||||
"@types/cron": "1.7.3",
|
||||
"@types/lodash": "4.14.178",
|
||||
"@types/mongodb": "4.0.7",
|
||||
"@types/node": "17.0.18",
|
||||
"@types/node-fetch": "2.6.1",
|
||||
"@types/swagger-stats": "0.95.4",
|
||||
|
|
|
|||
|
|
@ -1,84 +1,62 @@
|
|||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "These are the set of `internal` endpoints dedicated to the Monkeytype web client. Authentication for these endpoints requires a user account.",
|
||||
"version": "1.0.0",
|
||||
"title": "Monkeytype",
|
||||
"termsOfService": "http://monkeytype.com/terms-of-service",
|
||||
"termsOfService": "https://monkeytype.com/terms-of-service",
|
||||
"contact": {
|
||||
"name": "Developer",
|
||||
"email": "jack@monkeytype.com"
|
||||
}
|
||||
},
|
||||
"host": "api.monkeytype.com",
|
||||
"basePath": "/",
|
||||
"schemes": ["https"],
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": [
|
||||
{
|
||||
"name": "index",
|
||||
"description": ""
|
||||
"description": "Server status information"
|
||||
},
|
||||
{
|
||||
"name": "users",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "tags",
|
||||
"description": ""
|
||||
"description": "User data and related operations"
|
||||
},
|
||||
{
|
||||
"name": "psas",
|
||||
"description": ""
|
||||
"description": "Public service announcements"
|
||||
},
|
||||
{
|
||||
"name": "presets",
|
||||
"description": ""
|
||||
"description": "Preset data and related operations"
|
||||
},
|
||||
{
|
||||
"name": "configs",
|
||||
"description": ""
|
||||
"description": "User configuration data and related operations"
|
||||
},
|
||||
{
|
||||
"name": "ape-keys",
|
||||
"description": ""
|
||||
"description": "ApeKey data and related operations"
|
||||
},
|
||||
{
|
||||
"name": "leaderboards",
|
||||
"description": ""
|
||||
"description": "Leaderboard data"
|
||||
},
|
||||
{
|
||||
"name": "results",
|
||||
"description": ""
|
||||
"description": "Result data and related operations"
|
||||
},
|
||||
{
|
||||
"name": "quotes",
|
||||
"description": ""
|
||||
"description": "Quote data and related operations"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/": {
|
||||
"get": {
|
||||
"tags": ["index"],
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"uptime": {
|
||||
"type": "number"
|
||||
},
|
||||
"requestsProcessed": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": ["users"],
|
||||
"summary": "Gets the server's status data",
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "",
|
||||
|
|
@ -92,6 +70,7 @@
|
|||
"/users": {
|
||||
"get": {
|
||||
"tags": ["users"],
|
||||
"summary": "Returns a user's data",
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "",
|
||||
|
|
@ -103,6 +82,7 @@
|
|||
},
|
||||
"delete": {
|
||||
"tags": ["users"],
|
||||
"summary": "Deletes a user's account",
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "",
|
||||
|
|
@ -116,6 +96,7 @@
|
|||
"/users/name": {
|
||||
"patch": {
|
||||
"tags": ["users"],
|
||||
"summary": "Updates a user's name",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -144,6 +125,7 @@
|
|||
"/users/signup": {
|
||||
"post": {
|
||||
"tags": ["users"],
|
||||
"summary": "Creates a new user",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -178,6 +160,7 @@
|
|||
"/users/checkName/{name}": {
|
||||
"get": {
|
||||
"tags": ["users"],
|
||||
"summary": "Checks to see if a username is available",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "name",
|
||||
|
|
@ -200,6 +183,7 @@
|
|||
"/users/leaderboardMemory": {
|
||||
"patch": {
|
||||
"tags": ["users"],
|
||||
"summary": "Updates a user's cached leaderboard state",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -237,6 +221,7 @@
|
|||
"/users/discord/link": {
|
||||
"post": {
|
||||
"tags": ["users"],
|
||||
"summary": "Links a user's account with a discord account",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -271,6 +256,7 @@
|
|||
"/users/discord/unlink": {
|
||||
"post": {
|
||||
"tags": ["users"],
|
||||
"summary": "Unlinks a user's account with a discord account",
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "",
|
||||
|
|
@ -284,6 +270,7 @@
|
|||
"/users/email": {
|
||||
"patch": {
|
||||
"tags": ["users"],
|
||||
"summary": "Updates a user's email",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -315,6 +302,7 @@
|
|||
"/users/personalBests": {
|
||||
"delete": {
|
||||
"tags": ["users"],
|
||||
"summary": "Gets a user's personal bests",
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "",
|
||||
|
|
@ -327,7 +315,8 @@
|
|||
},
|
||||
"/users/tags": {
|
||||
"get": {
|
||||
"tags": ["tags"],
|
||||
"tags": ["users"],
|
||||
"summary": "Gets a user's tags",
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "",
|
||||
|
|
@ -338,7 +327,8 @@
|
|||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": ["tags"],
|
||||
"tags": ["users"],
|
||||
"summary": "Creates a new tag",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -364,7 +354,8 @@
|
|||
}
|
||||
},
|
||||
"patch": {
|
||||
"tags": ["tags"],
|
||||
"tags": ["users"],
|
||||
"summary": "Updates an existing tag",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -395,7 +386,8 @@
|
|||
},
|
||||
"/users/tags/{tagId}": {
|
||||
"delete": {
|
||||
"tags": ["tags"],
|
||||
"tags": ["users"],
|
||||
"summary": "Deletes a tag",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -416,7 +408,8 @@
|
|||
},
|
||||
"/users/tags/{tagId}/personalBest": {
|
||||
"delete": {
|
||||
"tags": ["tags"],
|
||||
"tags": ["users"],
|
||||
"summary": "Removes personal bests associated with a tag",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -438,6 +431,7 @@
|
|||
"/psas": {
|
||||
"get": {
|
||||
"tags": ["psas"],
|
||||
"summary": "Gets the latest public service announcements",
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "",
|
||||
|
|
@ -451,6 +445,7 @@
|
|||
"/presets": {
|
||||
"get": {
|
||||
"tags": ["presets"],
|
||||
"summary": "Gets saved preset configurations",
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "",
|
||||
|
|
@ -462,6 +457,7 @@
|
|||
},
|
||||
"post": {
|
||||
"tags": ["presets"],
|
||||
"summary": "Creates a preset configuration",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -491,6 +487,7 @@
|
|||
},
|
||||
"patch": {
|
||||
"tags": ["presets"],
|
||||
"summary": "Updates an existing preset configuration",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -525,6 +522,7 @@
|
|||
"/presets/{presetId}": {
|
||||
"delete": {
|
||||
"tags": ["presets"],
|
||||
"summary": "Deletes a preset configuration",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -546,6 +544,7 @@
|
|||
"/configs": {
|
||||
"get": {
|
||||
"tags": ["configs"],
|
||||
"summary": "Gets the user's current configuration",
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "",
|
||||
|
|
@ -557,6 +556,7 @@
|
|||
},
|
||||
"patch": {
|
||||
"tags": ["configs"],
|
||||
"summary": "Updates a user's configuration",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -585,6 +585,7 @@
|
|||
"/ape-keys": {
|
||||
"get": {
|
||||
"tags": ["ape-keys"],
|
||||
"summary": "Gets ApeKeys created by a user",
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "",
|
||||
|
|
@ -596,6 +597,7 @@
|
|||
},
|
||||
"post": {
|
||||
"tags": ["ape-keys"],
|
||||
"summary": "Creates an ApeKey",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -627,6 +629,7 @@
|
|||
"/ape-keys/{apeKeyId}": {
|
||||
"patch": {
|
||||
"tags": ["ape-keys"],
|
||||
"summary": "Updates an ApeKey",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -646,6 +649,7 @@
|
|||
},
|
||||
"delete": {
|
||||
"tags": ["ape-keys"],
|
||||
"summary": "Deletes an ApeKey",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -667,6 +671,7 @@
|
|||
"/leaderboards": {
|
||||
"get": {
|
||||
"tags": ["leaderboards"],
|
||||
"summary": "Gets a leaderboard",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "query",
|
||||
|
|
@ -707,6 +712,7 @@
|
|||
"/leaderboards/rank": {
|
||||
"get": {
|
||||
"tags": ["leaderboards"],
|
||||
"summary": "Gets a user's rank from a leaderboard",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "query",
|
||||
|
|
@ -737,6 +743,7 @@
|
|||
"/results": {
|
||||
"get": {
|
||||
"tags": ["results"],
|
||||
"summary": "Gets a history of a user's results",
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "",
|
||||
|
|
@ -748,6 +755,7 @@
|
|||
},
|
||||
"post": {
|
||||
"tags": ["results"],
|
||||
"summary": "Save a user's result",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -774,6 +782,7 @@
|
|||
},
|
||||
"delete": {
|
||||
"tags": ["results"],
|
||||
"summary": "Deletes all results",
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "",
|
||||
|
|
@ -787,6 +796,7 @@
|
|||
"/results/tags": {
|
||||
"patch": {
|
||||
"tags": ["results"],
|
||||
"summary": "Labels a result with the specified tags",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -821,6 +831,7 @@
|
|||
"/quotes": {
|
||||
"get": {
|
||||
"tags": ["quotes"],
|
||||
"summary": "Gets a list of quote submissions",
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "",
|
||||
|
|
@ -832,6 +843,7 @@
|
|||
},
|
||||
"post": {
|
||||
"tags": ["quotes"],
|
||||
"summary": "Creates a quote submission",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -869,6 +881,7 @@
|
|||
"/quotes/approve": {
|
||||
"post": {
|
||||
"tags": ["quotes"],
|
||||
"summary": "Approves a quote submission",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -903,6 +916,7 @@
|
|||
"/quotes/reject": {
|
||||
"post": {
|
||||
"tags": ["quotes"],
|
||||
"summary": "Rejects a quote submission",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -931,6 +945,7 @@
|
|||
"/quotes/rating": {
|
||||
"get": {
|
||||
"tags": ["quotes"],
|
||||
"summary": "Gets a rating for a quote",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -960,6 +975,7 @@
|
|||
},
|
||||
"post": {
|
||||
"tags": ["quotes"],
|
||||
"summary": "Adds a rating for a quote",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -994,6 +1010,7 @@
|
|||
"/quotes/report": {
|
||||
"post": {
|
||||
"tags": ["quotes"],
|
||||
"summary": "Reports a quote",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
|
|
@ -1035,11 +1052,8 @@
|
|||
"definitions": {
|
||||
"Response": {
|
||||
"type": "object",
|
||||
"required": ["error", "message"],
|
||||
"required": ["message", "data"],
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
|||
38
backend/types/types.d.ts
vendored
38
backend/types/types.d.ts
vendored
|
|
@ -70,6 +70,7 @@ declare namespace MonkeyTypes {
|
|||
hash: string;
|
||||
createdOn: number;
|
||||
modifiedOn: number;
|
||||
lastUsedOn: number;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
|
|
@ -78,6 +79,7 @@ declare namespace MonkeyTypes {
|
|||
type Mode2<M extends Mode> = keyof PersonalBests[M];
|
||||
|
||||
type Difficulty = "normal" | "expert" | "master";
|
||||
|
||||
interface PersonalBest {
|
||||
acc: number;
|
||||
consistency: number;
|
||||
|
|
@ -89,6 +91,7 @@ declare namespace MonkeyTypes {
|
|||
wpm: number;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
interface PersonalBests {
|
||||
time: {
|
||||
[key: number]: PersonalBest[];
|
||||
|
|
@ -169,4 +172,39 @@ declare namespace MonkeyTypes {
|
|||
delimiter: string;
|
||||
textLen?: number;
|
||||
}
|
||||
|
||||
interface PSA {
|
||||
sticky?: boolean;
|
||||
message: string;
|
||||
level?: number;
|
||||
}
|
||||
|
||||
type ReportTypes = "quote";
|
||||
|
||||
interface Report {
|
||||
id: string;
|
||||
type: ReportTypes;
|
||||
timestamp: number;
|
||||
uid: string;
|
||||
contentId: string;
|
||||
reason: string;
|
||||
comment: string;
|
||||
}
|
||||
|
||||
interface PublicStats {
|
||||
_id: string;
|
||||
testsCompleted: number;
|
||||
testsStarted: number;
|
||||
timeTyping: number;
|
||||
type: string;
|
||||
}
|
||||
|
||||
interface QuoteRating {
|
||||
_id: string;
|
||||
average: number;
|
||||
language: string;
|
||||
quoteId: number;
|
||||
ratings: number;
|
||||
totalRating: number;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
import admin from "firebase-admin";
|
||||
|
||||
export async function verifyIdToken(idToken) {
|
||||
return await admin.auth().verifyIdToken(idToken, true);
|
||||
}
|
||||
|
||||
export async function updateAuthEmail(uid, email) {
|
||||
return await admin.auth().updateUser(uid, {
|
||||
email,
|
||||
emailVerified: false,
|
||||
});
|
||||
}
|
||||
17
backend/utils/auth.ts
Normal file
17
backend/utils/auth.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import admin from "firebase-admin";
|
||||
import { UserRecord } from "firebase-admin/lib/auth/user-record";
|
||||
import { DecodedIdToken } from "firebase-admin/lib/auth/token-verifier";
|
||||
|
||||
export async function verifyIdToken(idToken: string): Promise<DecodedIdToken> {
|
||||
return await admin.auth().verifyIdToken(idToken, true);
|
||||
}
|
||||
|
||||
export async function updateUserEmail(
|
||||
uid: string,
|
||||
email: string
|
||||
): Promise<UserRecord> {
|
||||
return await admin.auth().updateUser(uid, {
|
||||
email,
|
||||
emailVerified: false,
|
||||
});
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
import fetch from "node-fetch";
|
||||
import "dotenv/config";
|
||||
|
||||
export async function verify(captcha) {
|
||||
if (process.env.MODE === "dev") return true;
|
||||
const response = await fetch(
|
||||
`https://www.google.com/recaptcha/api/siteverify`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
body: `secret=${process.env.RECAPTCHA_SECRET}&response=${captcha}`,
|
||||
}
|
||||
);
|
||||
const responseJSON = await response.json();
|
||||
return responseJSON?.success;
|
||||
}
|
||||
24
backend/utils/captcha.ts
Normal file
24
backend/utils/captcha.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import fetch from "node-fetch";
|
||||
|
||||
interface CaptchaData {
|
||||
success: boolean;
|
||||
challenge_ts?: number;
|
||||
hostname: string;
|
||||
"error-codes"?: string[];
|
||||
}
|
||||
|
||||
export async function verify(captcha: string): Promise<boolean> {
|
||||
if (process.env.MODE === "dev") {
|
||||
return true;
|
||||
}
|
||||
const response = await fetch(
|
||||
`https://www.google.com/recaptcha/api/siteverify`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
body: `secret=${process.env.RECAPTCHA_SECRET}&response=${captcha}`,
|
||||
}
|
||||
);
|
||||
const captchaData = (await response.json()) as CaptchaData;
|
||||
return captchaData.success;
|
||||
}
|
||||
|
|
@ -1,13 +1,19 @@
|
|||
import * as uuid from "uuid";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
class MonkeyError extends Error {
|
||||
status: number;
|
||||
errorId: string;
|
||||
uid: string;
|
||||
constructor(status: number, message: string, stack = null, uid = null) {
|
||||
uid?: string;
|
||||
|
||||
constructor(
|
||||
status: number,
|
||||
message: string,
|
||||
stack: string = null,
|
||||
uid: string = null
|
||||
) {
|
||||
super();
|
||||
this.status = status ?? 500;
|
||||
this.errorId = uuid.v4();
|
||||
this.errorId = uuidv4();
|
||||
this.stack = stack;
|
||||
this.uid = uid;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,15 @@
|
|||
import db from "../init/db";
|
||||
|
||||
interface Log {
|
||||
timestamp: number;
|
||||
uid: string;
|
||||
event: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export default {
|
||||
async log(event, message, uid) {
|
||||
const logsCollection = db.collection("logs");
|
||||
async log(event: string, message: any, uid?: string): Promise<void> {
|
||||
const logsCollection = db.collection<Log>("logs");
|
||||
|
||||
console.log(new Date(), "\t", event, "\t", uid, "\t", message);
|
||||
await logsCollection.insertOne({
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
import uaparser from "ua-parser-js";
|
||||
|
||||
export function roundTo2(num) {
|
||||
return Math.round((num + Number.EPSILON) * 100) / 100;
|
||||
}
|
||||
|
||||
export function escapeRegExp(str) {
|
||||
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
}
|
||||
|
||||
export function stdDev(array) {
|
||||
const n = array.length;
|
||||
const mean = array.reduce((a, b) => a + b) / n;
|
||||
return Math.sqrt(
|
||||
array.map((x) => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n
|
||||
);
|
||||
}
|
||||
|
||||
export function mean(array) {
|
||||
try {
|
||||
return (
|
||||
array.reduce((previous, current) => (current += previous)) / array.length
|
||||
);
|
||||
} catch (e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function kogasa(cov) {
|
||||
return (
|
||||
100 * (1 - Math.tanh(cov + Math.pow(cov, 3) / 3 + Math.pow(cov, 5) / 5))
|
||||
);
|
||||
}
|
||||
|
||||
export function identity(value) {
|
||||
return Object.prototype.toString
|
||||
.call(value)
|
||||
.replace(/^\[object\s+([a-z]+)\]$/i, "$1")
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
export function base64UrlEncode(string) {
|
||||
return Buffer.from(string).toString("base64url");
|
||||
}
|
||||
|
||||
export function base64UrlDecode(string) {
|
||||
return Buffer.from(string, "base64url").toString();
|
||||
}
|
||||
|
||||
export function buildAgentLog(req) {
|
||||
const agent = uaparser(req.headers["user-agent"]);
|
||||
|
||||
const agentLog = {
|
||||
ip:
|
||||
req.headers["cf-connecting-ip"] ||
|
||||
req.headers["x-forwarded-for"] ||
|
||||
req.ip ||
|
||||
"255.255.255.255",
|
||||
agent: `${agent.os.name} ${agent.os.version} ${agent.browser.name} ${agent.browser.version}`,
|
||||
};
|
||||
|
||||
const {
|
||||
device: { vendor, model, type },
|
||||
} = agent;
|
||||
if (vendor) {
|
||||
agentLog.device = `${vendor} ${model} ${type}`;
|
||||
}
|
||||
|
||||
return agentLog;
|
||||
}
|
||||
72
backend/utils/misc.ts
Normal file
72
backend/utils/misc.ts
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import _ from "lodash";
|
||||
import uaparser from "ua-parser-js";
|
||||
|
||||
export function roundTo2(num: number): number {
|
||||
return _.round(num, 2);
|
||||
}
|
||||
|
||||
export function stdDev(population: number[]): number {
|
||||
const n = population.length;
|
||||
if (n === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const populationMean = mean(population);
|
||||
const variance = _.sumBy(population, (x) => (x - populationMean) ** 2) / n;
|
||||
|
||||
return Math.sqrt(variance);
|
||||
}
|
||||
|
||||
export function mean(population: number[]): number {
|
||||
const n = population.length;
|
||||
return n > 0 ? _.sum(population) / n : 0;
|
||||
}
|
||||
|
||||
export function kogasa(cov: number): number {
|
||||
return (
|
||||
100 * (1 - Math.tanh(cov + Math.pow(cov, 3) / 3 + Math.pow(cov, 5) / 5))
|
||||
);
|
||||
}
|
||||
|
||||
export function identity(value: string): string {
|
||||
return Object.prototype.toString
|
||||
.call(value)
|
||||
.replace(/^\[object\s+([a-z]+)\]$/i, "$1")
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
export function base64UrlEncode(data: string): string {
|
||||
return Buffer.from(data).toString("base64url");
|
||||
}
|
||||
|
||||
export function base64UrlDecode(data: string): string {
|
||||
return Buffer.from(data, "base64url").toString();
|
||||
}
|
||||
|
||||
interface AgentLog {
|
||||
ip: string | string[];
|
||||
agent: string;
|
||||
device?: string;
|
||||
}
|
||||
|
||||
export function buildAgentLog(req: MonkeyTypes.Request): AgentLog {
|
||||
const agent = uaparser(req.headers["user-agent"]);
|
||||
|
||||
const agentLog: AgentLog = {
|
||||
ip:
|
||||
req.headers["cf-connecting-ip"] ||
|
||||
req.headers["x-forwarded-for"] ||
|
||||
req.ip ||
|
||||
"255.255.255.255",
|
||||
agent: `${agent.os.name} ${agent.os.version} ${agent.browser.name} ${agent.browser.version}`,
|
||||
};
|
||||
|
||||
const {
|
||||
device: { vendor, model, type },
|
||||
} = agent;
|
||||
if (vendor) {
|
||||
agentLog.device = `${vendor} ${model} ${type}`;
|
||||
}
|
||||
|
||||
return agentLog;
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
import { getCodesRangeStart } from "../constants/monkey-status-codes";
|
||||
|
||||
export class MonkeyResponse {
|
||||
constructor(message, data, status = 200) {
|
||||
this.message = message;
|
||||
this.data = data ?? null;
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
||||
export function handleMonkeyResponse(handlerData, res) {
|
||||
const isMonkeyResponse = handlerData instanceof MonkeyResponse;
|
||||
const monkeyResponse = !isMonkeyResponse
|
||||
? new MonkeyResponse("ok", handlerData)
|
||||
: handlerData;
|
||||
const { message, data, status } = monkeyResponse;
|
||||
|
||||
res.status(status);
|
||||
if (status >= getCodesRangeStart()) res.statusMessage = message;
|
||||
|
||||
res.monkeyMessage = message; // so that we can see message in swagger stats
|
||||
if ([301, 302].includes(status)) {
|
||||
return res.redirect(data);
|
||||
}
|
||||
|
||||
res.json({ message, data });
|
||||
}
|
||||
34
backend/utils/monkey-response.ts
Normal file
34
backend/utils/monkey-response.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { Response } from "express";
|
||||
import { isCustomCode } from "../constants/monkey-status-codes";
|
||||
|
||||
export class MonkeyResponse {
|
||||
message: string;
|
||||
data: any;
|
||||
status: number;
|
||||
|
||||
constructor(message?: string, data?: any, status = 200) {
|
||||
this.message = message ?? "ok";
|
||||
this.data = data ?? null;
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
||||
export function handleMonkeyResponse(
|
||||
monkeyResponse: MonkeyResponse,
|
||||
res: Response
|
||||
): void {
|
||||
const { message, data, status } = monkeyResponse;
|
||||
|
||||
res.status(status);
|
||||
if (isCustomCode(status)) {
|
||||
res.statusMessage = message;
|
||||
}
|
||||
|
||||
//@ts-ignore ignored so that we can see message in swagger stats
|
||||
res.monkeyMessage = message;
|
||||
if ([301, 302].includes(status)) {
|
||||
return res.redirect(data);
|
||||
}
|
||||
|
||||
res.json({ message, data });
|
||||
}
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
/*
|
||||
|
||||
|
||||
obj structure
|
||||
|
||||
time: {
|
||||
10: [ - this is a list because there can be
|
||||
different personal bests for different difficulties, languages and punctuation
|
||||
{
|
||||
acc,
|
||||
consistency,
|
||||
difficulty,
|
||||
language,
|
||||
punctuation,
|
||||
raw,
|
||||
timestamp,
|
||||
wpm
|
||||
}
|
||||
]
|
||||
},
|
||||
words: {
|
||||
10: [
|
||||
{}
|
||||
]
|
||||
},
|
||||
zen: {
|
||||
zen: [
|
||||
{}
|
||||
]
|
||||
},
|
||||
custom: {
|
||||
custom: {
|
||||
[]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
export function checkAndUpdatePb(
|
||||
obj,
|
||||
lbObj,
|
||||
mode,
|
||||
mode2,
|
||||
acc,
|
||||
consistency,
|
||||
difficulty,
|
||||
lazyMode = false,
|
||||
language,
|
||||
punctuation,
|
||||
raw,
|
||||
wpm
|
||||
) {
|
||||
//verify structure first
|
||||
if (obj === undefined) obj = {};
|
||||
if (obj[mode] === undefined) obj[mode] = {};
|
||||
if (obj[mode][mode2] === undefined) obj[mode][mode2] = [];
|
||||
|
||||
let isPb = false;
|
||||
let found = false;
|
||||
//find a pb
|
||||
obj[mode][mode2].forEach((pb) => {
|
||||
//check if we should compare first
|
||||
if (
|
||||
(pb.lazyMode === lazyMode ||
|
||||
(pb.lazyMode === undefined && lazyMode === false)) &&
|
||||
pb.difficulty === difficulty &&
|
||||
pb.language === language &&
|
||||
pb.punctuation === punctuation
|
||||
) {
|
||||
found = true;
|
||||
//compare
|
||||
if (pb.wpm < wpm) {
|
||||
//update
|
||||
isPb = true;
|
||||
pb.acc = acc;
|
||||
pb.consistency = consistency;
|
||||
pb.difficulty = difficulty;
|
||||
pb.language = language;
|
||||
pb.punctuation = punctuation;
|
||||
pb.lazyMode = lazyMode;
|
||||
pb.raw = raw;
|
||||
pb.wpm = wpm;
|
||||
pb.timestamp = Date.now();
|
||||
}
|
||||
}
|
||||
});
|
||||
//if not found push a new one
|
||||
if (!found) {
|
||||
isPb = true;
|
||||
obj[mode][mode2].push({
|
||||
acc,
|
||||
consistency,
|
||||
difficulty,
|
||||
lazyMode,
|
||||
language,
|
||||
punctuation,
|
||||
raw,
|
||||
wpm,
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
lbObj &&
|
||||
mode === "time" &&
|
||||
(mode2 == "15" || mode2 == "60") &&
|
||||
!lazyMode
|
||||
) {
|
||||
//updating lbpersonalbests object
|
||||
//verify structure first
|
||||
if (lbObj[mode] === undefined) lbObj[mode] = {};
|
||||
if (lbObj[mode][mode2] === undefined || Array.isArray(lbObj[mode][mode2]))
|
||||
lbObj[mode][mode2] = {};
|
||||
|
||||
let bestForEveryLanguage = {};
|
||||
if (obj?.[mode]?.[mode2]) {
|
||||
obj[mode][mode2].forEach((pb) => {
|
||||
if (!bestForEveryLanguage[pb.language]) {
|
||||
bestForEveryLanguage[pb.language] = pb;
|
||||
} else {
|
||||
if (bestForEveryLanguage[pb.language].wpm < pb.wpm) {
|
||||
bestForEveryLanguage[pb.language] = pb;
|
||||
}
|
||||
}
|
||||
});
|
||||
Object.keys(bestForEveryLanguage).forEach((key) => {
|
||||
if (lbObj[mode][mode2][key] === undefined) {
|
||||
lbObj[mode][mode2][key] = bestForEveryLanguage[key];
|
||||
} else {
|
||||
if (lbObj[mode][mode2][key].wpm < bestForEveryLanguage[key].wpm) {
|
||||
lbObj[mode][mode2][key] = bestForEveryLanguage[key];
|
||||
}
|
||||
}
|
||||
});
|
||||
bestForEveryLanguage = {};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
isPb,
|
||||
obj,
|
||||
lbObj,
|
||||
};
|
||||
}
|
||||
146
backend/utils/pb.ts
Normal file
146
backend/utils/pb.ts
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
import _ from "lodash";
|
||||
|
||||
interface CheckAndUpdatePbResult {
|
||||
isPb: boolean;
|
||||
obj: object;
|
||||
lbObj: object;
|
||||
}
|
||||
|
||||
type Result = MonkeyTypes.Result<MonkeyTypes.Mode>;
|
||||
|
||||
export function checkAndUpdatePb(
|
||||
userPersonalBests: MonkeyTypes.User["personalBests"],
|
||||
lbPersonalBests: MonkeyTypes.User["lbPersonalBests"],
|
||||
result: Result
|
||||
): CheckAndUpdatePbResult {
|
||||
const { mode, mode2 } = result;
|
||||
|
||||
const userPb = userPersonalBests ?? {};
|
||||
userPb[mode] = userPb[mode] ?? {};
|
||||
userPb[mode][mode2] = userPb[mode][mode2] ?? [];
|
||||
|
||||
const personalBestMatch: MonkeyTypes.PersonalBest = userPb[mode][mode2].find(
|
||||
(pb: MonkeyTypes.PersonalBest) => {
|
||||
return matchesPersonalBest(result, pb);
|
||||
}
|
||||
);
|
||||
|
||||
let isPb = true;
|
||||
|
||||
if (personalBestMatch) {
|
||||
const didUpdate = updatePersonalBest(personalBestMatch, result);
|
||||
isPb = didUpdate;
|
||||
} else {
|
||||
userPb[mode][mode2].push(buildPersonalBest(result));
|
||||
}
|
||||
|
||||
updateLeaderboardPersonalBests(userPb, lbPersonalBests, result);
|
||||
|
||||
return {
|
||||
isPb,
|
||||
obj: userPb,
|
||||
lbObj: lbPersonalBests,
|
||||
};
|
||||
}
|
||||
|
||||
function matchesPersonalBest(
|
||||
result: Result,
|
||||
personalBest: MonkeyTypes.PersonalBest
|
||||
): boolean {
|
||||
const sameLazyMode =
|
||||
result.lazyMode === personalBest.lazyMode ||
|
||||
(!result.lazyMode && !personalBest.lazyMode);
|
||||
const samePunctuation = result.punctuation === personalBest.punctuation;
|
||||
const sameDifficulty = result.difficulty === personalBest.difficulty;
|
||||
const sameLanguage = result.language === personalBest.language;
|
||||
|
||||
return sameLazyMode && samePunctuation && sameDifficulty && sameLanguage;
|
||||
}
|
||||
|
||||
function updatePersonalBest(
|
||||
personalBest: MonkeyTypes.PersonalBest,
|
||||
result: Result
|
||||
): boolean {
|
||||
if (personalBest.wpm > result.wpm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
personalBest.acc = result.acc;
|
||||
personalBest.consistency = result.consistency;
|
||||
personalBest.difficulty = result.difficulty;
|
||||
personalBest.language = result.language;
|
||||
personalBest.punctuation = result.punctuation;
|
||||
personalBest.lazyMode = result.lazyMode;
|
||||
personalBest.raw = result.rawWpm;
|
||||
personalBest.wpm = result.wpm;
|
||||
personalBest.timestamp = Date.now();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function buildPersonalBest(result: Result): MonkeyTypes.PersonalBest {
|
||||
return {
|
||||
acc: result.acc,
|
||||
consistency: result.consistency,
|
||||
difficulty: result.difficulty,
|
||||
lazyMode: result.lazyMode,
|
||||
language: result.language,
|
||||
punctuation: result.punctuation,
|
||||
raw: result.rawWpm,
|
||||
wpm: result.wpm,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
function updateLeaderboardPersonalBests(
|
||||
userPersonalBests: MonkeyTypes.User["personalBests"],
|
||||
lbPersonalBests: MonkeyTypes.User["lbPersonalBests"],
|
||||
result: Result
|
||||
): void {
|
||||
if (!shouldUpdateLeaderboardPersonalBests(lbPersonalBests, result)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { mode, mode2 } = result;
|
||||
|
||||
lbPersonalBests[mode] = lbPersonalBests[mode] ?? {};
|
||||
const lbMode2 = lbPersonalBests[mode][mode2];
|
||||
if (!lbMode2 || Array.isArray(lbMode2)) {
|
||||
lbPersonalBests[mode][mode2] = {};
|
||||
}
|
||||
|
||||
const bestForEveryLanguage = {};
|
||||
|
||||
userPersonalBests[mode][mode2].forEach((pb: MonkeyTypes.PersonalBest) => {
|
||||
const language = pb.language;
|
||||
if (
|
||||
!bestForEveryLanguage[language] ||
|
||||
bestForEveryLanguage[language].wpm < pb.wpm
|
||||
) {
|
||||
bestForEveryLanguage[language] = pb;
|
||||
}
|
||||
});
|
||||
|
||||
_.each(
|
||||
bestForEveryLanguage,
|
||||
(pb: MonkeyTypes.PersonalBest, language: string) => {
|
||||
const languageDoesNotExist = !lbPersonalBests[mode][mode2][language];
|
||||
|
||||
if (
|
||||
languageDoesNotExist ||
|
||||
lbPersonalBests[mode][mode2][language].wpm < pb.wpm
|
||||
) {
|
||||
lbPersonalBests[mode][mode2][language] = pb;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function shouldUpdateLeaderboardPersonalBests(
|
||||
lbPersonalBests: MonkeyTypes.User["lbPersonalBests"],
|
||||
result: Result
|
||||
): boolean {
|
||||
const isValidTimeMode =
|
||||
result.mode === "time" && (result.mode2 === "15" || result.mode2 === "60");
|
||||
return lbPersonalBests && isValidTimeMode && !result.lazyMode;
|
||||
}
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
// module.exports = {
|
||||
// check(result, userdata) {
|
||||
// let pbs = null;
|
||||
// if (result.mode == "quote") {
|
||||
// return false;
|
||||
// }
|
||||
// if (result.funbox !== "none") {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// pbs = userdata?.personalBests;
|
||||
// if(pbs === undefined){
|
||||
// //userdao set personal best
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// // try {
|
||||
// // pbs = userdata.personalBests;
|
||||
// // if (pbs === undefined) {
|
||||
// // throw new Error("pb is undefined");
|
||||
// // }
|
||||
// // } catch (e) {
|
||||
// // User.findOne({ uid: userdata.uid }, (err, user) => {
|
||||
// // user.personalBests = {
|
||||
// // [result.mode]: {
|
||||
// // [result.mode2]: [
|
||||
// // {
|
||||
// // language: result.language,
|
||||
// // difficulty: result.difficulty,
|
||||
// // punctuation: result.punctuation,
|
||||
// // wpm: result.wpm,
|
||||
// // acc: result.acc,
|
||||
// // raw: result.rawWpm,
|
||||
// // timestamp: Date.now(),
|
||||
// // consistency: result.consistency,
|
||||
// // },
|
||||
// // ],
|
||||
// // },
|
||||
// // };
|
||||
// // }).then(() => {
|
||||
// // return true;
|
||||
// // });
|
||||
// // }
|
||||
|
||||
// let toUpdate = false;
|
||||
// let found = false;
|
||||
// try {
|
||||
// if (pbs[result.mode][result.mode2] === undefined) {
|
||||
// pbs[result.mode][result.mode2] = [];
|
||||
// }
|
||||
// pbs[result.mode][result.mode2].forEach((pb) => {
|
||||
// if (
|
||||
// pb.punctuation === result.punctuation &&
|
||||
// pb.difficulty === result.difficulty &&
|
||||
// pb.language === result.language
|
||||
// ) {
|
||||
// //entry like this already exists, compare wpm
|
||||
// found = true;
|
||||
// if (pb.wpm < result.wpm) {
|
||||
// //new pb
|
||||
// pb.wpm = result.wpm;
|
||||
// pb.acc = result.acc;
|
||||
// pb.raw = result.rawWpm;
|
||||
// pb.timestamp = Date.now();
|
||||
// pb.consistency = result.consistency;
|
||||
// toUpdate = true;
|
||||
// } else {
|
||||
// //no pb
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// //checked all pbs, nothing found - meaning this is a new pb
|
||||
// if (!found) {
|
||||
// pbs[result.mode][result.mode2] = [
|
||||
// {
|
||||
// language: result.language,
|
||||
// difficulty: result.difficulty,
|
||||
// punctuation: result.punctuation,
|
||||
// wpm: result.wpm,
|
||||
// acc: result.acc,
|
||||
// raw: result.rawWpm,
|
||||
// timestamp: Date.now(),
|
||||
// consistency: result.consistency,
|
||||
// },
|
||||
// ];
|
||||
// toUpdate = true;
|
||||
// }
|
||||
// } catch (e) {
|
||||
// // console.log(e);
|
||||
// pbs[result.mode] = {};
|
||||
// pbs[result.mode][result.mode2] = [
|
||||
// {
|
||||
// language: result.language,
|
||||
// difficulty: result.difficulty,
|
||||
// punctuation: result.punctuation,
|
||||
// wpm: result.wpm,
|
||||
// acc: result.acc,
|
||||
// raw: result.rawWpm,
|
||||
// timestamp: Date.now(),
|
||||
// consistency: result.consistency,
|
||||
// },
|
||||
// ];
|
||||
// toUpdate = true;
|
||||
// }
|
||||
|
||||
// if (toUpdate) {
|
||||
// // User.findOne({ uid: userdata.uid }, (err, user) => {
|
||||
// // user.personalBests = pbs;
|
||||
// // user.save();
|
||||
// // });
|
||||
|
||||
// //userdao update the whole personalBests parameter with pbs object
|
||||
// return true;
|
||||
// } else {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
|
@ -46,7 +46,7 @@ export function isTestTooShort(result: MonkeyTypes.CompletedEvent): boolean {
|
|||
|
||||
if (mode === "words") {
|
||||
const setWordTooShort = mode2 > 0 && mode2 < 10;
|
||||
const infiniteWordTooShort = mode2 == 0 && testDuration < 15;
|
||||
const infiniteWordTooShort = mode2 === 0 && testDuration < 15;
|
||||
return setWordTooShort || infiniteWordTooShort;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -448,7 +448,7 @@ export async function signInWithGoogle() {
|
|||
}
|
||||
//create database object for the new user
|
||||
// try {
|
||||
const response = Ape.users.create(name);
|
||||
const response = await Ape.users.create(name);
|
||||
if (response.status !== 200) {
|
||||
throw response;
|
||||
}
|
||||
|
|
@ -500,6 +500,7 @@ export async function signInWithGoogle() {
|
|||
await Ape.users.delete();
|
||||
await signedInUser.user.delete();
|
||||
}
|
||||
signOut();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@
|
|||
"brew",
|
||||
"miscellaneous",
|
||||
"conspiration",
|
||||
"swazi",
|
||||
"Swazi",
|
||||
"jade",
|
||||
"threadlike",
|
||||
"retrospective",
|
||||
|
|
@ -246,7 +246,7 @@
|
|||
"prato",
|
||||
"inspissate",
|
||||
"citrine",
|
||||
"ares",
|
||||
"Ares",
|
||||
"swagman",
|
||||
"puissant",
|
||||
"wurst",
|
||||
|
|
@ -257,14 +257,12 @@
|
|||
"eraser",
|
||||
"repentant",
|
||||
"mandolin",
|
||||
"Poole",
|
||||
"tainted",
|
||||
"hierarchic",
|
||||
"cochineal",
|
||||
"insinuation",
|
||||
"Faraday",
|
||||
"ablative",
|
||||
"nime",
|
||||
"bygone",
|
||||
"scheduled",
|
||||
"streamline",
|
||||
|
|
@ -279,13 +277,12 @@
|
|||
"brainstorming",
|
||||
"diffusion",
|
||||
"upland",
|
||||
"teresina",
|
||||
"spoof",
|
||||
"grannie",
|
||||
"nene",
|
||||
"disjointed",
|
||||
"pneumatic",
|
||||
"oceanus",
|
||||
"Oceanus",
|
||||
"hopscotch",
|
||||
"kobold",
|
||||
"pyrexia",
|
||||
|
|
@ -644,7 +641,6 @@
|
|||
"suzy",
|
||||
"auditorium",
|
||||
"hyaena",
|
||||
"feck",
|
||||
"Tory",
|
||||
"maven",
|
||||
"teenage",
|
||||
|
|
@ -694,7 +690,6 @@
|
|||
"pertussis",
|
||||
"temerity",
|
||||
"chamfer",
|
||||
"Michelle",
|
||||
"gaper",
|
||||
"dens",
|
||||
"unadulterated",
|
||||
|
|
@ -1051,8 +1046,8 @@
|
|||
"erysipelas",
|
||||
"jeer",
|
||||
"asset",
|
||||
"quetzalcoatl",
|
||||
"wesleyanism",
|
||||
"Quetzalcoatl",
|
||||
"Wesleyanism",
|
||||
"neptunian",
|
||||
"flack",
|
||||
"syrup",
|
||||
|
|
@ -1072,7 +1067,6 @@
|
|||
"thrush",
|
||||
"beleaguer",
|
||||
"environs",
|
||||
"Winnipeg",
|
||||
"conventicle",
|
||||
"cephalopod",
|
||||
"stow",
|
||||
|
|
@ -1167,7 +1161,6 @@
|
|||
"cascade",
|
||||
"tantalum",
|
||||
"crippleware",
|
||||
"jackass",
|
||||
"abderites",
|
||||
"pairing",
|
||||
"flounder",
|
||||
|
|
@ -1398,7 +1391,6 @@
|
|||
"astounding",
|
||||
"aries",
|
||||
"debarkation",
|
||||
"invagination",
|
||||
"nares",
|
||||
"noxious",
|
||||
"accuser",
|
||||
|
|
@ -1937,7 +1929,6 @@
|
|||
"quebracho",
|
||||
"abstrusely",
|
||||
"scarred",
|
||||
"whorehouse",
|
||||
"archive",
|
||||
"hashish",
|
||||
"membership",
|
||||
|
|
@ -2138,7 +2129,6 @@
|
|||
"porcine",
|
||||
"yeah",
|
||||
"thrift",
|
||||
"poop",
|
||||
"patois",
|
||||
"yucca",
|
||||
"immigrate",
|
||||
|
|
@ -4032,7 +4022,6 @@
|
|||
"outdoor",
|
||||
"dictum",
|
||||
"publicize",
|
||||
"anus",
|
||||
"boardwalk",
|
||||
"bemused",
|
||||
"wooly",
|
||||
|
|
@ -4066,7 +4055,6 @@
|
|||
"verification",
|
||||
"prepositional",
|
||||
"ciconia",
|
||||
"damnable",
|
||||
"alphabetized",
|
||||
"amative",
|
||||
"salzburg",
|
||||
|
|
@ -4249,7 +4237,6 @@
|
|||
"fadge",
|
||||
"ingrained",
|
||||
"exclave",
|
||||
"damnation",
|
||||
"sunup",
|
||||
"conventual",
|
||||
"overijssel",
|
||||
|
|
@ -5083,7 +5070,6 @@
|
|||
"jollification",
|
||||
"axiom",
|
||||
"birding",
|
||||
"wank",
|
||||
"coincident",
|
||||
"barrow",
|
||||
"gleed",
|
||||
|
|
@ -6238,7 +6224,6 @@
|
|||
"stumble",
|
||||
"copal",
|
||||
"google",
|
||||
"helluva",
|
||||
"mascara",
|
||||
"limpet",
|
||||
"boathouse",
|
||||
|
|
@ -6564,7 +6549,6 @@
|
|||
"chiasmus",
|
||||
"ferret",
|
||||
"grana",
|
||||
"dumbass",
|
||||
"radiata",
|
||||
"portmanteau",
|
||||
"suitcase",
|
||||
|
|
@ -6899,7 +6883,6 @@
|
|||
"peppercorn",
|
||||
"anteater",
|
||||
"nirvana",
|
||||
"boner",
|
||||
"midway",
|
||||
"filbert",
|
||||
"jihad",
|
||||
|
|
@ -7234,7 +7217,6 @@
|
|||
"heliostat",
|
||||
"percent",
|
||||
"radiophone",
|
||||
"massimo",
|
||||
"flirt",
|
||||
"doer",
|
||||
"eructation",
|
||||
|
|
@ -7764,12 +7746,11 @@
|
|||
"scrapbook",
|
||||
"sarabande",
|
||||
"install",
|
||||
"teledildonics",
|
||||
"caterpillar",
|
||||
"datolite",
|
||||
"thriving",
|
||||
"bodkin",
|
||||
"sata",
|
||||
"SATA",
|
||||
"cony",
|
||||
"classroom",
|
||||
"ticked",
|
||||
|
|
@ -8279,7 +8260,6 @@
|
|||
"cuboid",
|
||||
"praecipe",
|
||||
"tropism",
|
||||
"whoremonger",
|
||||
"Sudan",
|
||||
"Erin",
|
||||
"turnstile",
|
||||
|
|
@ -8450,7 +8430,6 @@
|
|||
"macau",
|
||||
"benzol",
|
||||
"supposititious",
|
||||
"slut",
|
||||
"labuan",
|
||||
"meretricious",
|
||||
"syncopated",
|
||||
|
|
@ -8491,7 +8470,6 @@
|
|||
"xhosa",
|
||||
"borage",
|
||||
"safar",
|
||||
"asswage",
|
||||
"totalitarian",
|
||||
"logistics",
|
||||
"mozarabic",
|
||||
|
|
@ -9166,11 +9144,11 @@
|
|||
"nonconformist",
|
||||
"inclusive",
|
||||
"escheated",
|
||||
"wwii",
|
||||
"WWII",
|
||||
"unhoused",
|
||||
"Zimbabwe",
|
||||
"cypress",
|
||||
"uranus",
|
||||
"Uranus",
|
||||
"commute",
|
||||
"uniquely",
|
||||
"heuristics",
|
||||
|
|
@ -9280,7 +9258,6 @@
|
|||
"rune",
|
||||
"linty",
|
||||
"epilepsy",
|
||||
"shitting",
|
||||
"dragoman",
|
||||
"Barnet",
|
||||
"alimentary",
|
||||
|
|
@ -9573,7 +9550,7 @@
|
|||
"obstruent",
|
||||
"cochlea",
|
||||
"yill",
|
||||
"janus",
|
||||
"Janus",
|
||||
"nuff",
|
||||
"lifelessly",
|
||||
"narrator",
|
||||
|
|
@ -9694,7 +9671,6 @@
|
|||
"becket",
|
||||
"liquorice",
|
||||
"crackers",
|
||||
"bullshit",
|
||||
"photology",
|
||||
"omelette",
|
||||
"jaunt",
|
||||
|
|
@ -9868,7 +9844,6 @@
|
|||
"backhander",
|
||||
"vaporous",
|
||||
"Melbourne",
|
||||
"arse",
|
||||
"survival",
|
||||
"tangle",
|
||||
"abet",
|
||||
|
|
@ -9877,7 +9852,6 @@
|
|||
"sift",
|
||||
"crud",
|
||||
"surcease",
|
||||
"turd",
|
||||
"storing",
|
||||
"upsidedown",
|
||||
"caddis",
|
||||
|
|
@ -9933,7 +9907,6 @@
|
|||
"sensed",
|
||||
"subfamily",
|
||||
"assigns",
|
||||
"asshole",
|
||||
"warble",
|
||||
"typify",
|
||||
"yellowknife",
|
||||
|
|
@ -10023,7 +9996,6 @@
|
|||
"panicle",
|
||||
"passover",
|
||||
"orate",
|
||||
"Meuse",
|
||||
"crossbeam",
|
||||
"pilum",
|
||||
"structural",
|
||||
|
|
@ -10328,7 +10300,6 @@
|
|||
"uncooked",
|
||||
"esker",
|
||||
"glyph",
|
||||
"clitoris",
|
||||
"Nehemiah",
|
||||
"Inca",
|
||||
"evolve",
|
||||
|
|
@ -10374,7 +10345,6 @@
|
|||
"airlines",
|
||||
"unchallengeable",
|
||||
"altruistic",
|
||||
"fagot",
|
||||
"verifiable",
|
||||
"backsliding",
|
||||
"iaea",
|
||||
|
|
@ -10602,17 +10572,15 @@
|
|||
"insert",
|
||||
"circumfluent",
|
||||
"passer",
|
||||
"kobe",
|
||||
"fellatio",
|
||||
"wickedly",
|
||||
"Berber",
|
||||
"ghanaian",
|
||||
"Ghanaian",
|
||||
"arsenal",
|
||||
"accra",
|
||||
"tenso",
|
||||
"corkscrews",
|
||||
"empower",
|
||||
"santorini",
|
||||
"Santorini",
|
||||
"battler",
|
||||
"angelic",
|
||||
"sushi",
|
||||
|
|
@ -11595,7 +11563,6 @@
|
|||
"horoscope",
|
||||
"reproducible",
|
||||
"euphorbia",
|
||||
"tallahassee",
|
||||
"vivisection",
|
||||
"liverwort",
|
||||
"blacklist",
|
||||
|
|
@ -11628,7 +11595,7 @@
|
|||
"palaeozoic",
|
||||
"decrypt",
|
||||
"cooee",
|
||||
"abkhazia",
|
||||
"Abkhazia",
|
||||
"strangulation",
|
||||
"Burmese",
|
||||
"antelope",
|
||||
|
|
@ -11875,7 +11842,7 @@
|
|||
"pyrotechnic",
|
||||
"cinnabar",
|
||||
"livonian",
|
||||
"abbasid",
|
||||
"Abbasid",
|
||||
"evangelist",
|
||||
"indiscreet",
|
||||
"experimenting",
|
||||
|
|
@ -12112,11 +12079,9 @@
|
|||
"elasmobranchii",
|
||||
"withy",
|
||||
"calliope",
|
||||
"pube",
|
||||
"hight",
|
||||
"garnish",
|
||||
"impartiality",
|
||||
"penises",
|
||||
"retina",
|
||||
"logarithm",
|
||||
"hexapoda",
|
||||
|
|
@ -12534,7 +12499,6 @@
|
|||
"sideshow",
|
||||
"estop",
|
||||
"lank",
|
||||
"dyke",
|
||||
"Armenian",
|
||||
"octant",
|
||||
"allegro",
|
||||
|
|
@ -12551,7 +12515,6 @@
|
|||
"redhanded",
|
||||
"cuneate",
|
||||
"coupe",
|
||||
"vagina",
|
||||
"gorgon",
|
||||
"carbonade",
|
||||
"hedonic",
|
||||
|
|
@ -13387,7 +13350,6 @@
|
|||
"tocsin",
|
||||
"vibrator",
|
||||
"intermittently",
|
||||
"hellas",
|
||||
"loathing",
|
||||
"caprimulgus",
|
||||
"probation",
|
||||
|
|
@ -13554,7 +13516,7 @@
|
|||
"scaffolding",
|
||||
"pimpernel",
|
||||
"digital",
|
||||
"passamaquoddy",
|
||||
"Passamaquoddy",
|
||||
"trainer",
|
||||
"disabuse",
|
||||
"crore",
|
||||
|
|
@ -13606,7 +13568,6 @@
|
|||
"arum",
|
||||
"churchy",
|
||||
"cassiope",
|
||||
"Geraldine",
|
||||
"bypass",
|
||||
"refute",
|
||||
"flashback",
|
||||
|
|
@ -14104,7 +14065,6 @@
|
|||
"Rutland",
|
||||
"functioning",
|
||||
"polygamy",
|
||||
"pussy",
|
||||
"figuration",
|
||||
"contraception",
|
||||
"emoticon",
|
||||
|
|
@ -14521,7 +14481,6 @@
|
|||
"percolator",
|
||||
"creeper",
|
||||
"opine",
|
||||
"coon",
|
||||
"arsenic",
|
||||
"acuity",
|
||||
"insolvency",
|
||||
|
|
@ -14742,7 +14701,6 @@
|
|||
"lapidation",
|
||||
"evolutionary",
|
||||
"overwhelm",
|
||||
"simp",
|
||||
"pollution",
|
||||
"escalator",
|
||||
"coup",
|
||||
|
|
@ -14849,7 +14807,6 @@
|
|||
"keratin",
|
||||
"clavichord",
|
||||
"peterborough",
|
||||
"whore",
|
||||
"ethnicity",
|
||||
"abstinent",
|
||||
"vivacious",
|
||||
|
|
@ -15261,7 +15218,6 @@
|
|||
"contritely",
|
||||
"dispiteously",
|
||||
"swelter",
|
||||
"vaginal",
|
||||
"cactuses",
|
||||
"laud",
|
||||
"lupine",
|
||||
|
|
@ -15460,7 +15416,6 @@
|
|||
"markings",
|
||||
"hellenic",
|
||||
"magnific",
|
||||
"analyse",
|
||||
"viceregal",
|
||||
"pores",
|
||||
"jettison",
|
||||
|
|
@ -15864,7 +15819,7 @@
|
|||
"laconic",
|
||||
"prolific",
|
||||
"pans",
|
||||
"cassiopeia",
|
||||
"Cassiopeia",
|
||||
"reversion",
|
||||
"Ugandan",
|
||||
"abstracting",
|
||||
|
|
@ -16040,7 +15995,6 @@
|
|||
"unholy",
|
||||
"photo",
|
||||
"tela",
|
||||
"shite",
|
||||
"sensor",
|
||||
"heliometer",
|
||||
"camera",
|
||||
|
|
@ -16879,7 +16833,6 @@
|
|||
"venomously",
|
||||
"granary",
|
||||
"circuitry",
|
||||
"boob",
|
||||
"dentist",
|
||||
"illogical",
|
||||
"glimmers",
|
||||
|
|
@ -17075,7 +17028,6 @@
|
|||
"burkinabe",
|
||||
"Cole",
|
||||
"ravioli",
|
||||
"gook",
|
||||
"Tobago",
|
||||
"ramada",
|
||||
"endocrine",
|
||||
|
|
@ -17574,7 +17526,6 @@
|
|||
"freebooter",
|
||||
"maintainer",
|
||||
"deceptively",
|
||||
"bastard",
|
||||
"vicus",
|
||||
"stupefaction",
|
||||
"semicircle",
|
||||
|
|
@ -18179,7 +18130,6 @@
|
|||
"gamer",
|
||||
"maricopa",
|
||||
"rondo",
|
||||
"labial",
|
||||
"dwindle",
|
||||
"abstinence",
|
||||
"affray",
|
||||
|
|
@ -18257,7 +18207,6 @@
|
|||
"tussle",
|
||||
"mega",
|
||||
"travail",
|
||||
"whoreson",
|
||||
"binoculars",
|
||||
"surfeit",
|
||||
"canvasser",
|
||||
|
|
@ -18516,7 +18465,6 @@
|
|||
"technically",
|
||||
"ornate",
|
||||
"portends",
|
||||
"hellen",
|
||||
"quaternary",
|
||||
"preferment",
|
||||
"stigma",
|
||||
|
|
@ -18540,9 +18488,8 @@
|
|||
"lingam",
|
||||
"accosts",
|
||||
"inflame",
|
||||
"Abdullah",
|
||||
"rattler",
|
||||
"zoroastrianism",
|
||||
"Zoroastrianism",
|
||||
"petting",
|
||||
"suprarenal",
|
||||
"coeducation",
|
||||
|
|
@ -19098,7 +19045,6 @@
|
|||
"qualm",
|
||||
"implike",
|
||||
"ulcerous",
|
||||
"penis",
|
||||
"mort",
|
||||
"dolt",
|
||||
"woodcock",
|
||||
|
|
@ -19806,7 +19752,6 @@
|
|||
"federate",
|
||||
"atramentous",
|
||||
"etch",
|
||||
"smegma",
|
||||
"centennial",
|
||||
"grunge",
|
||||
"accelerated",
|
||||
|
|
@ -20699,7 +20644,6 @@
|
|||
"withershins",
|
||||
"pate",
|
||||
"necropolis",
|
||||
"hella",
|
||||
"benzoline",
|
||||
"seraphic",
|
||||
"potpourri",
|
||||
|
|
@ -20723,7 +20667,6 @@
|
|||
"Groningen",
|
||||
"ebullient",
|
||||
"searing",
|
||||
"cocks",
|
||||
"lens",
|
||||
"expand",
|
||||
"mimic",
|
||||
|
|
@ -20888,7 +20831,6 @@
|
|||
"weasel",
|
||||
"upstanding",
|
||||
"chef",
|
||||
"whoremaster",
|
||||
"sandarac",
|
||||
"achan",
|
||||
"styli",
|
||||
|
|
@ -21164,9 +21106,7 @@
|
|||
"centrepiece",
|
||||
"subliminal",
|
||||
"unplanned",
|
||||
"goddamn",
|
||||
"leggings",
|
||||
"shillong",
|
||||
"bedlam",
|
||||
"abstractness",
|
||||
"waymark",
|
||||
|
|
@ -21517,7 +21457,6 @@
|
|||
"ultraism",
|
||||
"gree",
|
||||
"glycogen",
|
||||
"assoyle",
|
||||
"vintner",
|
||||
"falstaff",
|
||||
"depredate",
|
||||
|
|
@ -21901,7 +21840,6 @@
|
|||
"ashame",
|
||||
"subtlety",
|
||||
"irenic",
|
||||
"piss",
|
||||
"extirpate",
|
||||
"permeable",
|
||||
"licit",
|
||||
|
|
@ -22198,7 +22136,7 @@
|
|||
"igneous",
|
||||
"castellated",
|
||||
"wreathes",
|
||||
"guadalcanal",
|
||||
"Guadalcanal",
|
||||
"predominance",
|
||||
"truncate",
|
||||
"disclaimed",
|
||||
|
|
@ -22267,7 +22205,6 @@
|
|||
"flection",
|
||||
"celadon",
|
||||
"altercate",
|
||||
"shit",
|
||||
"bowfin",
|
||||
"shucks",
|
||||
"frenchwoman",
|
||||
|
|
@ -22301,7 +22238,6 @@
|
|||
"neurology",
|
||||
"bogy",
|
||||
"frabjous",
|
||||
"muff",
|
||||
"chaffer",
|
||||
"salacious",
|
||||
"riparian",
|
||||
|
|
@ -22428,7 +22364,6 @@
|
|||
"zimbabwean",
|
||||
"postcardware",
|
||||
"pneuma",
|
||||
"spunk",
|
||||
"ensign",
|
||||
"sambar",
|
||||
"rebus",
|
||||
|
|
@ -23094,7 +23029,6 @@
|
|||
"macers",
|
||||
"mushroom",
|
||||
"trape",
|
||||
"whores",
|
||||
"litany",
|
||||
"arcana",
|
||||
"nave",
|
||||
|
|
@ -23114,7 +23048,6 @@
|
|||
"stasis",
|
||||
"vitamin",
|
||||
"sleeper",
|
||||
"labia",
|
||||
"acclimatize",
|
||||
"blower",
|
||||
"peahen",
|
||||
|
|
@ -23633,7 +23566,6 @@
|
|||
"elegantly",
|
||||
"dyestuff",
|
||||
"rime",
|
||||
"anal",
|
||||
"nutriment",
|
||||
"hyphen",
|
||||
"indemnification",
|
||||
|
|
@ -23778,7 +23710,6 @@
|
|||
"solfatara",
|
||||
"bodega",
|
||||
"acidly",
|
||||
"crap",
|
||||
"unsettling",
|
||||
"aborted",
|
||||
"dendrite",
|
||||
|
|
@ -23950,7 +23881,6 @@
|
|||
"denounce",
|
||||
"punchinello",
|
||||
"rejuvenate",
|
||||
"Hitler",
|
||||
"hyperbole",
|
||||
"argentic",
|
||||
"terrorism",
|
||||
|
|
@ -24290,7 +24220,7 @@
|
|||
"stinger",
|
||||
"blister",
|
||||
"preen",
|
||||
"turkmen",
|
||||
"Turkmen",
|
||||
"doggedly",
|
||||
"torr",
|
||||
"transfigure"
|
||||
|
|
|
|||
|
|
@ -211,12 +211,6 @@
|
|||
"source": "Convert real number to string with 2 decimal places - programming-idioms.org",
|
||||
"text": "let s = format!(\"{:.2}\", x);"
|
||||
},
|
||||
{
|
||||
"id": 35,
|
||||
"length": 13,
|
||||
"source": "Assign to string the japanese word \u30cd\u30b3 - programming-idioms.org",
|
||||
"text": "let s = \"\u30cd\u30b3\";"
|
||||
},
|
||||
{
|
||||
"id": 36,
|
||||
"length": 211,
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@
|
|||
"id": 27
|
||||
},
|
||||
{
|
||||
"text": "Pølser har altid fascineret mig. Man kan jo nærmest sige er der er noget mytologisk ved at dræbe et dyr og så håne det ved at stikke det op i dets eget tarm bag efter!",
|
||||
"text": "Pølser har altid fascineret mig. Man kan jo nærmest sige at der er noget mytologisk ved at dræbe et dyr og så håne det ved at stikke det op i dets eget tarm bag efter!",
|
||||
"source": "De Grønne Slagtere",
|
||||
"length": 167,
|
||||
"id": 28
|
||||
|
|
|
|||
|
|
@ -7394,10 +7394,10 @@
|
|||
"length": 249
|
||||
},
|
||||
{
|
||||
"text": "I became yearbook photographer because I liked the idea that I could sort of watch life without having to be part of it. But when you're yearbook photographer, you're like never in the picture.",
|
||||
"text": "I became a yearbook photographer because I liked the idea that I could sort of watch life without having to be part of it. But when you're yearbook photographer, you're like never in the picture.",
|
||||
"source": "My So-Called Life",
|
||||
"id": 1244,
|
||||
"length": 193
|
||||
"length": 195
|
||||
},
|
||||
{
|
||||
"text": "Time is a tool you can put on the wall or wear it on your wrist. The past is far behind us, the future doesn't exist. Time is a ruler to measure the day, it doesn't go backwards, only one way. Time went new and got old like history. Stuff from the past went into a mystery. It's out of my hands, I'm only a clock. Don't worry, I'm sure you'll be fine, but eventually everyone runs out of time.",
|
||||
|
|
@ -7987,12 +7987,6 @@
|
|||
"id": 1344,
|
||||
"length": 247
|
||||
},
|
||||
{
|
||||
"text": "Contrary to the feminist cant, there are many things we can learn from men's perspective about life and personal identity. To refuse to learn anything that could prove beneficial to yourself is a working definition of stupid.",
|
||||
"source": "Ten Stupid Things Women Do to Mess Up Their Lives",
|
||||
"id": 1345,
|
||||
"length": 225
|
||||
},
|
||||
{
|
||||
"text": "When I left my home and my family, I was no more than a boy in the company of strangers in the quiet of the railway station, running scared, laying low, seeking out the poorer quarters where the ragged people go. Looking for the places only they would know.",
|
||||
"source": "The Boxer",
|
||||
|
|
@ -8251,12 +8245,6 @@
|
|||
"id": 1389,
|
||||
"length": 291
|
||||
},
|
||||
{
|
||||
"text": "Ever since I was a child, folks have thought they had me pegged, because of the way I am, the way I talk. And they're always wrong.",
|
||||
"source": "Capote",
|
||||
"id": 1390,
|
||||
"length": 131
|
||||
},
|
||||
{
|
||||
"text": "Love is a command, not just a feeling. Somehow, in the romantic world of music and theater we have made love to be what it is not. We have so mixed it with beauty and charm and sensuality and contact that we have robbed it of its higher call of cherishing and nurturing.",
|
||||
"source": "I, Isaac, Take Thee, Rebekah: Moving from Romance to Lasting Love",
|
||||
|
|
@ -8402,7 +8390,7 @@
|
|||
"length": 206
|
||||
},
|
||||
{
|
||||
"text": "When you lose control, you'll reap the harvest you have sown. And as the fear grows, the bad blood slows and turns to stone. And it's too late to lose the weight you used to need to throw around. So have a good drown, as you go down, all alone... dragged down by the stone.",
|
||||
"text": "When you lose control, you'll reap the harvest you have sown. And as the fear grows, the bad blood slows and turns to stone. And it's too late to lose the weight you used to need to throw around. So have a good drown, as you go down, all alone... Dragged down by the stone.",
|
||||
"source": "Dogs",
|
||||
"id": 1415,
|
||||
"length": 273
|
||||
|
|
@ -8924,7 +8912,7 @@
|
|||
"length": 299
|
||||
},
|
||||
{
|
||||
"text": "Last night I dreamt I went to Manderely again. It seemed to me I stood by the iron gate leading to the drive, and for a while I could not enter, for the way was barred to me. There was a padlock and a chain upon the gate. I called in my dream to the lodge-keeper, and had no answer, and peering closer through the rusted spokes of the gate I saw that the lodge was uninhabited.",
|
||||
"text": "Last night I dreamt I went to Manderley again. It seemed to me I stood by the iron gate leading to the drive, and for a while I could not enter, for the way was barred to me. There was a padlock and a chain upon the gate. I called in my dream to the lodge-keeper, and had no answer, and peering closer through the rusted spokes of the gate I saw that the lodge was uninhabited.",
|
||||
"source": "Rebecca",
|
||||
"id": 1503,
|
||||
"length": 377
|
||||
|
|
@ -11738,7 +11726,7 @@
|
|||
"length": 62
|
||||
},
|
||||
{
|
||||
"text": "One Ring to rule them all, One Ring to find them, One Ring to bring them all and in the darkness bind them.",
|
||||
"text": "One ring to rule them all, one ring to find them, one ring to bring them all and in the darkness bind them.",
|
||||
"source": "The Fellowship of the Ring",
|
||||
"id": 1978,
|
||||
"length": 107
|
||||
|
|
@ -11937,7 +11925,7 @@
|
|||
},
|
||||
{
|
||||
"text": "There is no good and evil, there is only power and those too weak to seek it.",
|
||||
"source": "Harry Potter and the Philosopher's Stone",
|
||||
"source": "Harry Potter and the Sorcerer's Stone",
|
||||
"id": 2012,
|
||||
"length": 77
|
||||
},
|
||||
|
|
@ -13963,12 +13951,6 @@
|
|||
"id": 2351,
|
||||
"length": 237
|
||||
},
|
||||
{
|
||||
"text": "I think I really like it best when you can kid the pants off a girl when the opportunity arises.",
|
||||
"source": "The Catcher in the Rye",
|
||||
"id": 2352,
|
||||
"length": 96
|
||||
},
|
||||
{
|
||||
"text": "I guess this is just another lost cause, Mr. Paine. All you people don't know about lost causes. Mr. Paine does. He said once they were the only causes worth fighting for and he fought for them once. For the only reason any man ever fights for them. Because of just one plain simple rule. Love thy neighbor.",
|
||||
"source": "Mr. Smith Goes to Washington",
|
||||
|
|
@ -19843,12 +19825,6 @@
|
|||
"id": 3345,
|
||||
"length": 310
|
||||
},
|
||||
{
|
||||
"text": "We were playing checkers. I used to kid her once in a while because she wouldn't take her kings out of the back row. But I didn't kid her much though. You never wanted to kid Jane too much. I think I really like it best when you can kid the pants off a girl when the opportunity arises, but it's a funny thing. The girls I like best are ones I never feel much like kidding.",
|
||||
"source": "The Catcher in the Rye",
|
||||
"id": 3346,
|
||||
"length": 373
|
||||
},
|
||||
{
|
||||
"text": "Let's say life is this square of the sidewalk. We're born at this crack and we die at that crack. Now we find ourselves somewhere inside the square, and in the process of walking out of it, suddenly we realize our time in here is fleeting. Is our quick experience here pointless? Does anything we say or do in here really matter? Have we done anything important? Have we been happy? Have we made the most of these precious footsteps?",
|
||||
"source": "The Complete Calvin and Hobbes",
|
||||
|
|
@ -20137,12 +20113,6 @@
|
|||
"id": 3396,
|
||||
"length": 480
|
||||
},
|
||||
{
|
||||
"text": "I feel the Aryan in my blood, it's scarier than a Blood. Been looking for holy water, now I'm praying for a flood. It feel like time passing me by slower than a slug, while this feeling inside of my body seep in like a drug. Will you hug me, rub me on the back like a child?",
|
||||
"source": "AfricAryaN",
|
||||
"id": 3397,
|
||||
"length": 274
|
||||
},
|
||||
{
|
||||
"text": "Sure is mellow grazin' in the grass. What a trip just watchin' as the world goes past. There are too many groovy things to see while grazin' in the grass. Flowers with colors for takin', everything outta sight.",
|
||||
"source": "Grazing In The Grass",
|
||||
|
|
@ -21014,10 +20984,10 @@
|
|||
"length": 410
|
||||
},
|
||||
{
|
||||
"text": "You speak in abbreviations because real life conversation moves too slowly. You're the media's creation, yeah, your free will has been taken and you don't know.",
|
||||
"text": "You speak in abbreviations because real life conversation moves too slow. You're the media's creation, yeah, your free will has been taken and you don't know.",
|
||||
"source": "Culture Shock",
|
||||
"id": 3545,
|
||||
"length": 160
|
||||
"length": 158
|
||||
},
|
||||
{
|
||||
"text": "My feeling is if you're the CEO of a company and you're dumb enough to leave your login info on a Post-it note on your desk, while the people that you ripped off are physically in your office, it's not a hack. It's barely social engineering. It's more like natural selection.",
|
||||
|
|
@ -21782,10 +21752,10 @@
|
|||
"length": 124
|
||||
},
|
||||
{
|
||||
"text": "There are few people in the world who have more opportunity for getting close to the hot, interesting things of one's time than the special correspondent of a great paper. He is enabled to see \"the wheels go round;\" has the chance of getting his knowledge at first hand. In stirring times the drama of life is to him like the first night of a play. There are no preconceived opinions for him to go by; he ought not to, at least, be influenced by any prejudices; and the account of the performance is to some extent like that of the dramatic critic, inasmuch as that the verdict of the public or of history has either to confirm or reverse his own judgment.",
|
||||
"text": "There are few people in the world who have more opportunity for getting close to the hot, interesting things of one's time than the special correspondent of a great paper. He is enabled to see \"the wheels go round;\" has the chance of getting his knowledge at first hand. In stirring times the drama of life is to him like the first night of a play. There are no preconceived opinions for him to go by; he ought not to, at least, be influenced by any prejudices; and the account of the performance is to some extent like that of the dramatic critic, in as much as that the verdict of the public or of history has either to confirm or reverse his own judgment.",
|
||||
"source": "Impressions of a War Correspondent",
|
||||
"id": 3675,
|
||||
"length": 656
|
||||
"length": 658
|
||||
},
|
||||
{
|
||||
"text": "To be, or not to be: that is the question: whether 'tis nobler in the mind to suffer the slings and arrows of outrageous fortune, or to take arms against a sea of troubles, and by opposing end them?",
|
||||
|
|
@ -23011,12 +22981,6 @@
|
|||
"id": 3879,
|
||||
"length": 404
|
||||
},
|
||||
{
|
||||
"text": "The supreme question about a work of art is out of how deep a life does it spring.",
|
||||
"source": "Ulysses",
|
||||
"id": 3880,
|
||||
"length": 82
|
||||
},
|
||||
{
|
||||
"text": "Why study science? Science, more than any other discipline, provides us with tools to learn about the world. Science is not a listing of facts; science is an invitation to observe the world, ask questions, and puzzle over problems and enjoy the process of solving them. From the time children begin to perceive their environment, they are involved in science.",
|
||||
"source": "Magnets and Motors: Teacher's Guide",
|
||||
|
|
@ -24649,12 +24613,6 @@
|
|||
"id": 4154,
|
||||
"length": 358
|
||||
},
|
||||
{
|
||||
"text": "'Cause I was born a virgin covered in blood and free of sin, and that's the exact shape I wanna make when I jump off this bridge.",
|
||||
"source": "August (Part Two)",
|
||||
"id": 4155,
|
||||
"length": 129
|
||||
},
|
||||
{
|
||||
"text": "In the past, all a King had to do was look respectable in uniform and not fall off his horse. Now we must invade people's homes and ingratiate ourselves with them. This family's been reduced to those lowest, basest of all creatures. We've become actors!",
|
||||
"source": "The King's Speech",
|
||||
|
|
@ -24967,12 +24925,6 @@
|
|||
"id": 4207,
|
||||
"length": 554
|
||||
},
|
||||
{
|
||||
"text": "Hmm, looks like the chad is still hanging on that one, but I'm sure they'll count it.",
|
||||
"source": "Postal 2",
|
||||
"id": 4208,
|
||||
"length": 85
|
||||
},
|
||||
{
|
||||
"text": "Why so much grief for me? No man will hurl me down to Death, against my fate. And fate? No one alive has ever escaped it, neither brave man nor coward, I tell you - it's born with us the day that we are born.",
|
||||
"source": "The Iliad",
|
||||
|
|
@ -26173,12 +26125,6 @@
|
|||
"id": 4409,
|
||||
"length": 173
|
||||
},
|
||||
{
|
||||
"text": "Despondent, lugubrious, no future. We turned our bodies to computer. We are our own nature, abuser, no future, computer, abuser. I can tell every day I stay all the whiteness turns to grey. All the grey to Cimmeria as the black is setting in. Digital black, oh! We've sunken into our illusion, we've fashioned colossal confusion. I am the word of the last human; illusion, confusion, last human. I can see it all around the land. I can feel it with the back of my hand. I can hear a roaring silence of the murky caliginous. I've heard the dark beast has said that the world is like a brittle egg. He can crush it with only breath, and he can bring a black wave of death. Digital black.",
|
||||
"source": "Digital Black",
|
||||
"id": 4410,
|
||||
"length": 685
|
||||
},
|
||||
{
|
||||
"text": "A zealot might be, for instance, an individual with a personal motive for revenge so overpowering that it ensures complete dedication to the cause. Or, through intensive training and psychological manipulation, an elite team of fanatic followers can be trained to sacrifice even their own lives to accomplish a given mission.",
|
||||
"source": "Ninja Mind Control",
|
||||
|
|
@ -27404,10 +27350,10 @@
|
|||
"length": 437
|
||||
},
|
||||
{
|
||||
"text": "Why are we still here? Just to suffer? Every night, I can feel my leg... and my arm... even my fingers. The body I've lost... the comrades I've lost... won't stop hurting... It's like they're all still there. You feel it, too, don't you? I'm gonna make them give back our past.",
|
||||
"text": "Why are we still here? Just to suffer? Every night, I can feel my leg... and my arm... even my fingers. The body I've lost... the comrades I've lost... won't stop hurting... It's like they're all still there. You feel it too, don't you? I'm gonna make them give back our past.",
|
||||
"source": "Metal Gear Solid V: The Phantom Pain",
|
||||
"id": 4617,
|
||||
"length": 277
|
||||
"length": 276
|
||||
},
|
||||
{
|
||||
"text": "Hating the Empire, getting revenge... It's all I ever thought about. But I never did anything about it. I mean, I realized there was nothing I could do. It made me feel hollow, alone. And then... I'd miss my brother. I'd say stuff like \"I'm gonna be a sky pirate\", or some other stupid thing. Just anything to keep my mind off it. I was just... I was running away. I needed to get away from his death.",
|
||||
|
|
@ -28556,10 +28502,10 @@
|
|||
"length": 398
|
||||
},
|
||||
{
|
||||
"text": "Hi, my name is Jane. We hardly know each other, but that's about to change. You're gonna get to know a lot about me, and maybe even more than you imagine. This whole thing's kind of like a blind date - I mean here we are in your brand-new Corvette, running along the superinformation highway. Put your big muscular arm around me and whisper sweet nothings in my ear, and I promise you'll do whatever your little heart desires. BUT, only if you make the right moves. Just imagine watching me get propositioned by my sleazeball boss. BUT, if you make the wrong moves, you could turn me into a nun. Imagine that. Me? A nun? HA! I don't think so. But it's really all up to you. God knows what you'll do with that hot little mouse of yours. Point is: life's a game, and this game is full of life.",
|
||||
"text": "Hi, my name is Jane. We hardly know each other, but that's about to change. You're gonna get to know a lot about me, and maybe even more than you imagine. This whole thing's kind of like a blind date - I mean here we are in your brand-new Corvette, running along the superinformation highway. Put your big, muscular arm around me and whisper sweet nothings in my ear, and I promise you'll do whatever your little heart desires. BUT, only if you make the right moves. Just imagine watching me get propositioned by my sleazeball boss. BUT, if you make the wrong moves, you could turn me into a nun. Imagine that. Me? A nun? HA! I don't think so. But it's really all up to you. God knows what you'll do with that hot, little mouse of yours. Point is: life's a game, and this game is full of life.",
|
||||
"source": "Plumbers Don't Wear Ties",
|
||||
"id": 4811,
|
||||
"length": 791
|
||||
"length": 793
|
||||
},
|
||||
{
|
||||
"text": "New thoughts and hopes were whirling through my mind, and all the colors of my life were changing.",
|
||||
|
|
@ -29222,10 +29168,10 @@
|
|||
"length": 94
|
||||
},
|
||||
{
|
||||
"text": "Then listen up! When I joined the core, we didn't have any fancy schmancy tanks! We had sticks! Two sticks and a rock for a whole platoon. And we had to share the rock. Buck up, boy, you're one very lucky marine!",
|
||||
"text": "Then listen up! When I joined the Corps, we didn't have any fancy schmancy tanks! We had sticks! Two sticks and a rock for a whole platoon. And we had to share the rock. Buck up, boy, you're one very lucky marine!",
|
||||
"source": "Halo 2",
|
||||
"id": 4924,
|
||||
"length": 212
|
||||
"length": 213
|
||||
},
|
||||
{
|
||||
"text": "A pulse of energy wipes the galaxy clean of all its life. Vivisection of the cosmos, a dogma of the damned. The rule of ancients ceases to exist. Alone in a vast obscurity of infinite perception. Billions have vanished before my eyes. Psychopathic devastation is the rule of our demise. Sliding forward into the tale of which return is not an option, isolation, incubation of the virulent contagion.",
|
||||
|
|
@ -29257,12 +29203,6 @@
|
|||
"id": 4929,
|
||||
"length": 353
|
||||
},
|
||||
{
|
||||
"text": "I don't want to talk to you no more, you empty-headed animal food trough wiper! I fart in your general direction! Your mother was a hamster and your father smelt of elderberries!",
|
||||
"source": "Monty Python and the Holy Grail",
|
||||
"id": 4930,
|
||||
"length": 178
|
||||
},
|
||||
{
|
||||
"text": "As a child, I was aware that, at night, infrared vision would reveal monsters hiding in the bedroom closet only if they were warm-blooded. But everybody knows that your average bedroom monster is reptilian and cold-blooded.",
|
||||
"source": "Death by Black Hole: And Other Cosmic Quandaries",
|
||||
|
|
@ -30074,7 +30014,7 @@
|
|||
"length": 353
|
||||
},
|
||||
{
|
||||
"text": "NO ADMITTANCE. NOT EVEN TO AUTHORIZED PERSONNEL. YOU ARE WASTING YOUR TIME HERE. GO AWAY.",
|
||||
"text": "No admittance. Not even to authorized personnel. You are wasting your time here. Go away.",
|
||||
"source": "Mostly Harmless",
|
||||
"length": 89,
|
||||
"id": 5068
|
||||
|
|
@ -30193,12 +30133,6 @@
|
|||
"length": 60,
|
||||
"id": 5087
|
||||
},
|
||||
{
|
||||
"text": "Please remove any metallic items you're carrying, keys, loose change... Holy shit!",
|
||||
"source": "Security Personnel, The Matrix",
|
||||
"length": 82,
|
||||
"id": 5088
|
||||
},
|
||||
{
|
||||
"text": "I'm disinclined to acquiesce to your request... Means no.",
|
||||
"source": "Barbossa, Pirates of the Caribbean: The Curse of the Black Pearl",
|
||||
|
|
@ -30596,7 +30530,7 @@
|
|||
"id": 5154
|
||||
},
|
||||
{
|
||||
"text": "You know what my favorite color combination is? Yellow text on a magenta background. Oh, and don't forget the Comic Sans. That is just pure beauty right there. In fact, it's used in the first frame (well, close enough) of \"history of the entire world, i guess\", which makes me love that video even more.",
|
||||
"text": "You know what my favorite color combination is? Yellow text on a magenta background. Oh, and don't forget the Comic Sans. That is just pure beauty right there. In fact, it's used in the first frame (well, close enough) of \"history of the entire world, I guess\", which makes me love that video even more.",
|
||||
"source": "The Longest Text Ever",
|
||||
"length": 303,
|
||||
"id": 5155
|
||||
|
|
@ -30758,7 +30692,7 @@
|
|||
"id": 5181
|
||||
},
|
||||
{
|
||||
"text": "You know Mitch, now that I'm dying. I've become much more interesting to people.",
|
||||
"text": "You know Mitch, now that I'm dying, I've become much more interesting to people.",
|
||||
"source": "Mitch Albom, tuesdays with Morrie",
|
||||
"length": 80,
|
||||
"id": 5182
|
||||
|
|
@ -31051,12 +30985,6 @@
|
|||
"length": 112,
|
||||
"id": 5232
|
||||
},
|
||||
{
|
||||
"text": "Some people care too much. I think it's called love.",
|
||||
"source": "Pooh, Winnie-the-Pooh",
|
||||
"length": 52,
|
||||
"id": 5233
|
||||
},
|
||||
{
|
||||
"text": "\"Now let me see,\" he thought, as he took his last lick of the inside of the jar, \"where was I going, Ah, yes, Eeyore.\" He got up slowly. And then, suddenly, he remembered. He had eaten Eeyore's present!",
|
||||
"source": "Alan Alexander Milne, Winnie-the-Pooh",
|
||||
|
|
@ -31453,18 +31381,6 @@
|
|||
"length": 60,
|
||||
"id": 5301
|
||||
},
|
||||
{
|
||||
"text": "Jingle bells, I'm a cop.",
|
||||
"source": "Bill Wurtz - jingle bells",
|
||||
"length": 24,
|
||||
"id": 5302
|
||||
},
|
||||
{
|
||||
"text": "Open the country. Stop having it be closed.",
|
||||
"source": "Bill Wurtz - history of japan",
|
||||
"length": 43,
|
||||
"id": 5303
|
||||
},
|
||||
{
|
||||
"text": "I think I am probably a house, and you are probably a lamp... or a fax machine.",
|
||||
"source": "Bill Wurtz - a Play featuring an iphone power block and a mechanical pencil",
|
||||
|
|
@ -31507,18 +31423,6 @@
|
|||
"length": 174,
|
||||
"id": 5310
|
||||
},
|
||||
{
|
||||
"text": "Joke's over! You're dead!",
|
||||
"source": "Phoenix, Valorant",
|
||||
"length": 25,
|
||||
"id": 5311
|
||||
},
|
||||
{
|
||||
"text": "I would build a great wall, and nobody builds walls better than me, believe me, and I'll build them very inexpensively. I will build a great great wall on our southern border and I'll have Mexico pay for that wall.",
|
||||
"source": "Donald Trump",
|
||||
"length": 214,
|
||||
"id": 5312
|
||||
},
|
||||
{
|
||||
"text": "How silly, she was thinking, to use the word ready. When can you be ready for anything? Or is life, in fact, a continuum of things you must prepare for, and only with perfect preparation can you exist in the present?",
|
||||
"source": "Three Women",
|
||||
|
|
@ -31573,12 +31477,6 @@
|
|||
"length": 52,
|
||||
"id": 5321
|
||||
},
|
||||
{
|
||||
"text": "I don't sing because I'm happy; I'm happy because I sing.",
|
||||
"source": "William James",
|
||||
"length": 57,
|
||||
"id": 5322
|
||||
},
|
||||
{
|
||||
"text": "I can't understand why people are frightened of new ideas. I'm frightened of the old ones.",
|
||||
"source": "John Cage",
|
||||
|
|
@ -31705,12 +31603,6 @@
|
|||
"length": 108,
|
||||
"id": 5343
|
||||
},
|
||||
{
|
||||
"text": "Van Gogh would've sold more than one painting if he'd put tigers in them.",
|
||||
"source": "Bill Watterson",
|
||||
"length": 73,
|
||||
"id": 5344
|
||||
},
|
||||
{
|
||||
"text": "It's hard to see Heaven when you know you're Hell-bound.",
|
||||
"source": "Lukas Graham - 7 Years (Sik World Remix)",
|
||||
|
|
@ -31957,12 +31849,6 @@
|
|||
"length": 123,
|
||||
"id": 5386
|
||||
},
|
||||
{
|
||||
"text": "All we had to do, was follow the damn train, CJ!",
|
||||
"source": "GTA: San Andreas",
|
||||
"length": 48,
|
||||
"id": 5387
|
||||
},
|
||||
{
|
||||
"text": "There once was a tiger striped cat. This cat died a million deaths, revived and lived a million lives, and he was owned by various people who he didn't really care for. The cat wasn't afraid to die. Then one day the cat became a stray cat, which meant he was free. He met a white female cat, and the two of them spent their days together happily. Well, years passed, and the white cat grew weak and died of old age. The tiger striped cat cried a million times, and then he died too. Except this time, he didn't come back to life.",
|
||||
"source": "Cowboy Bebop",
|
||||
|
|
@ -32036,9 +31922,9 @@
|
|||
"id": 5399
|
||||
},
|
||||
{
|
||||
"text": "Dear Me 10 Years from now, If you still feel the need to listen to this again, then maybe something went wrong? Or did you change? Do you remember? What happened? Is life better, or worst? It's never too late to try and fix things. Right now, you're probably wondering how I felt when you wrote this. Well, right now, I guess I feel like I don't have a lot of control of my life, but it's exciting nonetheless. I'm smart and handsome, and I have goals to work toward. So.. me in 10 years from now, if you're reading this and you feel like things haven't changed, then just remember that it's never too late. The world around you must be different by now, but it doesn't mean you have to be. Stay positive, and keep doing your best.",
|
||||
"text": "Dear Me 10 Years from now, If you still feel the need to listen to this again, then maybe something went wrong? Or did you change? Do you remember? What happened? Is life better, or worst? It's never too late to try and fix things. Right now, you're probably wondering how I felt when you wrote this. Well, right now, I guess I feel like I don't have a lot of control of my life, but it's exciting nonetheless. I'm smart and handsome, and I have goals to work toward. So... me in 10 years from now, if you're reading this and you feel like things haven't changed, then just remember that it's never too late. The world around you must be different by now, but it doesn't mean you have to be. Stay positive, and keep doing your best.",
|
||||
"source": "Faye Valentine, Cowboy Bebop",
|
||||
"length": 731,
|
||||
"length": 732,
|
||||
"id": 5400
|
||||
},
|
||||
{
|
||||
|
|
@ -32047,12 +31933,6 @@
|
|||
"length": 74,
|
||||
"id": 5401
|
||||
},
|
||||
{
|
||||
"text": "If the world is ending, a woman will want to fix her hair. If the world's ending, a woman will take the time to tell a man something he's done wrong.",
|
||||
"source": "Robert Jordan, The Wheel of Time",
|
||||
"length": 149,
|
||||
"id": 5402
|
||||
},
|
||||
{
|
||||
"text": "How do I take off a mask when it stops being a mask, when it's as much a part of me as I am?",
|
||||
"source": "Mr. Robot",
|
||||
|
|
@ -32324,9 +32204,9 @@
|
|||
"id": 5447
|
||||
},
|
||||
{
|
||||
"text": "Have you ever had a dream, Neo, that you seemed so sure it was real? But if were unable to wake up from that dream, how would you tell the difference between the dream world & the real world?",
|
||||
"text": "Have you ever had a dream, Neo, that you seemed so sure it was real? But if you were unable to wake up from that dream, how would you tell the difference between the dream world & the real world?",
|
||||
"source": "The Matrix",
|
||||
"length": 191,
|
||||
"length": 195,
|
||||
"id": 5449
|
||||
},
|
||||
{
|
||||
|
|
@ -32492,9 +32372,9 @@
|
|||
"id": 5483
|
||||
},
|
||||
{
|
||||
"text": "Have you ever watched the jet cars race on the boulevard?...I sometimes think drivers don't know what grass is, or flowers, because they never see them slowly...If you showed a driver a green blur, Oh yes! He'd say, that's grass! A pink blur! That's a rose garden! White blurs are houses. Brown blurs are cows.",
|
||||
"text": "Have you ever watched the jet cars race on the boulevard?... I sometimes think drivers don't know what grass is, or flowers, because they never see them slowly... If you showed a driver a green blur, Oh yes! He'd say, that's grass! A pink blur! That's a rose garden! White blurs are houses. Brown blurs are cows.",
|
||||
"source": "Fahrenheit 451",
|
||||
"length": 310,
|
||||
"length": 312,
|
||||
"id": 5484
|
||||
},
|
||||
{
|
||||
|
|
@ -32564,15 +32444,15 @@
|
|||
"id": 5495
|
||||
},
|
||||
{
|
||||
"text": "Human beings do not survive on bread alone ... but on the nourishments of liberty. For what indeed is a man without freedom ... naught but a mechanism, trapped in the cogwheels of eternity.",
|
||||
"text": "Human beings do not survive on bread alone... but on the nourishments of liberty. For what indeed is a man without freedom... naught but a mechanism, trapped in the cogwheels of eternity.",
|
||||
"source": "Star Trek: The Original Series",
|
||||
"length": 189,
|
||||
"length": 187,
|
||||
"id": 5496
|
||||
},
|
||||
{
|
||||
"text": "Your will to survive, your love of life, your passion to know ... Everything that is truest and best in all species of beings has been revealed to you. Those are the qualities that make a civilization worthy to survive.",
|
||||
"text": "Your will to survive, your love of life, your passion to know... Everything that is truest and best in all species of beings has been revealed to you. Those are the qualities that make a civilization worthy to survive.",
|
||||
"source": "Star Trek: The Original Series",
|
||||
"length": 219,
|
||||
"length": 218,
|
||||
"id": 5497
|
||||
},
|
||||
{
|
||||
|
|
@ -32696,9 +32576,9 @@
|
|||
"id": 5517
|
||||
},
|
||||
{
|
||||
"text": "Tom, don't let anybody kid you. It's all personal, every bit of business. Every piece of shit every man has to eat every day of his life is personal. They call it business. OK. But it's personal as hell. You know where I learned that from? The Don. My old man. The Godfather. If a bolt of lightning hit a friend of his the old man would take it personal. He took my going into the Marines personal. That's what makes him great. The Great Don. He takes everything personal Like God. He knows every feather that falls from the tail of a sparrow or however the hell it goes? Right? And you know something? Accidents don't happen to people who take accidents as a personal insult.",
|
||||
"text": "Tom, don't let anybody kid you. It's all personal, every bit of business. Every piece of shit every man has to eat every day of his life is personal. They call it business. OK. But it's personal as hell. You know where I learned that from? The Don. My old man. The Godfather. If a bolt of lightning hit a friend of his the old man would take it personal. He took my going into the Marines personal. That's what makes him great. The Great Don. He takes everything personal. Like God. He knows every feather that falls from the tail of a sparrow or however the hell it goes? Right? And you know something? Accidents don't happen to people who take accidents as a personal insult.",
|
||||
"source": "The Godfather",
|
||||
"length": 676,
|
||||
"length": 677,
|
||||
"id": 5518
|
||||
},
|
||||
{
|
||||
|
|
@ -32858,9 +32738,9 @@
|
|||
"id": 5544
|
||||
},
|
||||
{
|
||||
"text": "Hi am Heavy Weapons Guy, and this is my weapon. She weighs one hundred fifty kilograms and fires two hundred dollar, custom-tooled cartridges at ten thousand rounds per minute. It costs four hundred thousand dollars to fire this weapon, for twelve seconds.",
|
||||
"text": "I am Heavy Weapons guy, and this is my weapon. She weighs one hundred fifty kilograms and fires two hundred dollar, custom-tooled cartridges at ten thousand rounds per minute. It costs four hundred thousand dollars to fire this weapon, for twelve seconds.",
|
||||
"source": "Team Fortess 2, Meet the Heavy",
|
||||
"length": 256,
|
||||
"length": 255,
|
||||
"id": 5545
|
||||
},
|
||||
{
|
||||
|
|
@ -33571,12 +33451,6 @@
|
|||
"length": 129,
|
||||
"id": 5676
|
||||
},
|
||||
{
|
||||
"text": "Music is ... A higher revelation than all Wisdom & Philosophy.",
|
||||
"source": "Ludwig van Beethoven",
|
||||
"length": 62,
|
||||
"id": 5677
|
||||
},
|
||||
{
|
||||
"text": "Simplicity, patience, compassion.\\nThese three are your greatest treasures.\\nSimple in actions and thoughts, you return to the source of being.\\nPatient with both friends and enemies,\\nyou accord with the way things are.\\nCompassionate toward yourself,\\nyou reconcile all beings in the world.",
|
||||
"source": "Tao Te Ching",
|
||||
|
|
@ -33698,9 +33572,9 @@
|
|||
"id": 5697
|
||||
},
|
||||
{
|
||||
"text": "Let's build a happy little cloud.\nLet's build some happy little trees.",
|
||||
"text": "Lets build a happy little cloud.\nLets build some happy little trees.",
|
||||
"source": "Bob Ross",
|
||||
"length": 70,
|
||||
"length": 68,
|
||||
"id": 5698
|
||||
},
|
||||
{
|
||||
|
|
@ -34028,7 +33902,7 @@
|
|||
"id": 5752
|
||||
},
|
||||
{
|
||||
"text": "Listen to me, Morty. I know that new situations can be intimidating. You're lookin' around and it's all scary and different, but y'know... meeting them head-on, charging into 'em like a bull — that's how we grow as people.",
|
||||
"text": "Listen to me, Morty. I know that new situations can be intimidating. You're lookin' around and it's all scary and different, but y'know... meeting them head-on, charging into 'em like a bull - that's how we grow as people.",
|
||||
"source": "Rick and Morty",
|
||||
"length": 222,
|
||||
"id": 5753
|
||||
|
|
@ -34046,7 +33920,7 @@
|
|||
"id": 5755
|
||||
},
|
||||
{
|
||||
"text": "What can I say — I like to talk. I'm a strong believer in the power of words. If you're not willing to communicate, then the problem just sits there. If you just keep staring at it without doing anything, eventually you'll watch every last opportunity to resolve it slip away before your eyes.",
|
||||
"text": "What can I say - I like to talk. I'm a strong believer in the power of words. If you're not willing to communicate, then the problem just sits there. If you just keep staring at it without doing anything, eventually you'll watch every last opportunity to resolve it slip away before your eyes.",
|
||||
"source": "Genshin Impact",
|
||||
"length": 293,
|
||||
"id": 5756
|
||||
|
|
@ -34160,9 +34034,9 @@
|
|||
"id": 5774
|
||||
},
|
||||
{
|
||||
"text": "Too many of us are not living our dreams because we are living our fears",
|
||||
"text": "Too many of us are not living our dreams because we are living our fears.",
|
||||
"source": "A Friend",
|
||||
"length": 72,
|
||||
"length": 73,
|
||||
"id": 5775
|
||||
},
|
||||
{
|
||||
|
|
@ -34532,7 +34406,7 @@
|
|||
"id": 5836
|
||||
},
|
||||
{
|
||||
"text": "Listen, Just because you have psychic powers, it doesn't make you any less human. It's the same as people who are fast, people who are book smart, and people with strong body odor. Psychic powers are just another characteristic. You must embrace that as a part of yourself and continue to live positively. The truth behind one's charm is kindness. Become a good person. That is all.",
|
||||
"text": "Listen. Just because you have psychic powers, it doesn't make you any less human. It's the same as people who are fast, people who are book smart, and people with strong body odor. Psychic powers are just another characteristic. You must embrace that as a part of yourself and continue to live positively. The truth behind one's charm is kindness. Become a good person. That is all.",
|
||||
"source": "Mob Psycho 100",
|
||||
"length": 382,
|
||||
"id": 5837
|
||||
|
|
@ -34622,9 +34496,9 @@
|
|||
"id": 5852
|
||||
},
|
||||
{
|
||||
"text": "\"The past is so much less terrifying than the future,\" he explained after some coaxing. \"Even the most terrifying terrible era of the past is at least knowable. It can be studied. The world survived it. But in the present, one never knows when the whole world survived it. But in the present, oe never knows when the whole world could come to a terrible, crashing end.",
|
||||
"text": "\"The past is so much less terrifying than the future,\" he explained after some coaxing. \"Even the most terrifying terrible era of the past is at least knowable. It can be studied. The world survived it. But in the present, one never knows when the whole world survived it. But in the present, one never knows when the whole world could come to a terrible, crashing end.",
|
||||
"source": "A Map of Days",
|
||||
"length": 368,
|
||||
"length": 369,
|
||||
"id": 5853
|
||||
},
|
||||
{
|
||||
|
|
@ -34825,12 +34699,6 @@
|
|||
"length": 186,
|
||||
"id": 5886
|
||||
},
|
||||
{
|
||||
"text": "We believe climate change will ultimately be solved by 'can do' capitalism; not 'don't do' governments seeking to control people's lives and tell them what to do, with interventionist regulation and taxes that just force up your cost of living and force businesses to close.",
|
||||
"source": "Scott Morrison",
|
||||
"length": 274,
|
||||
"id": 5887
|
||||
},
|
||||
{
|
||||
"text": "No one's gonna take me alive. Time has come to make things right. You and I must fight for our rights. You and I must fight to survive.",
|
||||
"source": "Knights of Cydonia",
|
||||
|
|
@ -34922,9 +34790,9 @@
|
|||
"id": 5902
|
||||
},
|
||||
{
|
||||
"text": "He took up his glass and sniffed at it. The stuff grew not less but more horrible with every mouthful he drank. But it had become the element he swam in. It was his life, is death, and his resurrection. It was gin that sank him into stupor every night, and gin that revived him every morning.",
|
||||
"text": "He took up his glass and sniffed at it. The stuff grew not less but more horrible with every mouthful he drank. But it had become the element he swam in. It was his life, his death, and his resurrection. It was gin that sank him into stupor every night, and gin that revived him every morning.",
|
||||
"source": "Nineteen Eighty-Four",
|
||||
"length": 292,
|
||||
"length": 293,
|
||||
"id": 5903
|
||||
},
|
||||
{
|
||||
|
|
@ -34964,9 +34832,9 @@
|
|||
"id": 5909
|
||||
},
|
||||
{
|
||||
"text": "so much depends upon a red wheel barrow glazed with rain water right beside the white chickens.",
|
||||
"text": "So much depends upon a red wheel barrow glazed with rain water beside the white chickens.",
|
||||
"source": "William Carlos Williams",
|
||||
"length": 95,
|
||||
"length": 89,
|
||||
"id": 5910
|
||||
},
|
||||
{
|
||||
|
|
@ -34994,9 +34862,9 @@
|
|||
"id": 5914
|
||||
},
|
||||
{
|
||||
"text": "Tim\nAngry at you\nTo: jack@monkeytype.com\nHURRY UP WITH THE maintenance ALREADY!!!!!!!",
|
||||
"source": "Tim K.",
|
||||
"length": 85,
|
||||
"text": "I'm hacking the FBI. Step one: identify the target and its flaws. There are always flaws. I learned that early in life. My first hack, the local library, a vulnerable FTP server in its AS400. A far cry from the Android zero days I'm using to own the FBI standard-issue smartphone. The library was a test to see if I could even get into the system. I've since set greater goals. For instance, step two: build malware and prepare an attack. At my fingertips, the zero day is wrapped in code like a Christmas present, then becomes an exploit, the programmatic expression of my will. Step three: a reverse shell, two-stage exploit. The ideal package. Load the malware into a femtocell delivery system - my personal cell tower that'll intercept all mobile data. Similar to my first time, when I found myself staring at late book fees, employee names, member addresses. Everything was revealed. The secret of the perfect hack? Make it infallible. Hidden within the kernel is a logic bomb, malicious code designed to execute under circumstances I've programmed. Should the FBI take an image of the femtocell, all memory will self-corrupt, or explode. Step four: Write the script. Why do it myself? Because that's how I learned, and I know exactly what, when, and how it's going to run. I didn't do anything harmful my first time. Just looked around. But I felt so powerful. 11 years old and in complete control of the Washington Township Public Library. Today is different. I hacked the world. Final step: launch the attack. Once I do, I'll own the Android phone of every FBI agent in that building. I'll own Evil Corp's network, applications, everything. Domain Admin. This, the thrill of pwning a system, this is the greatest rush. God access. The feeling never gets old.",
|
||||
"source": "Mr. Robot",
|
||||
"length": 1766,
|
||||
"id": 5915
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1502,7 +1502,7 @@
|
|||
"id": 252
|
||||
},
|
||||
{
|
||||
"text": "Bruce, du magst im Inneren noch immer der großartige Junge von früher sein, Aber was man im Inneren ist, zählt nicht. Das, was wir tun, zeigt, wer wir sind.",
|
||||
"text": "Bruce, du magst im Inneren noch immer der großartige Junge von früher sein, aber was man im Inneren ist, zählt nicht. Das, was wir tun, zeigt, wer wir sind.",
|
||||
"source": "Batman Begins",
|
||||
"length": 156,
|
||||
"id": 253
|
||||
|
|
@ -2144,7 +2144,7 @@
|
|||
"id": 359
|
||||
},
|
||||
{
|
||||
"text": "Und das musst du verstehen: in jedem Krieg gibt es Gruppierungen – die einen, die Frieden wollen, die anderen, die aus einer Myriade von Gründen weiterhin Krieg wollen und jene, deren Wünsche beides übertreffen.",
|
||||
"text": "Und das musst du verstehen: In jedem Krieg gibt es Gruppierungen – die einen, die Frieden wollen, die anderen, die aus einer Myriade von Gründen weiterhin Krieg wollen und jene, deren Wünsche beides übertreffen.",
|
||||
"source": "Die große Stille – Zerrissene Erde",
|
||||
"length": 211,
|
||||
"id": 360
|
||||
|
|
@ -2912,7 +2912,7 @@
|
|||
"id": 489
|
||||
},
|
||||
{
|
||||
"text": "Das Fernsehen, mein lieber Daniel, ist der Antichrist und ich sage Ihnen, es werden drei oder vier Generationen genügen, bis die Leute nicht einmal mehr selbstständig furzen können und der Mensch in die Höhle, in die mittelalterliche Barbarei und in einen Schwachsinn zurückfällt, den schon die Nachtschnecke im Pleistozän überwunden hat.",
|
||||
"text": "Das Fernsehen, mein lieber Daniel, ist der Antichrist und ich sage Ihnen, es werden drei oder vier Generationen genügen, bis die Leute nicht einmal mehr selbstständig furzen können und der Mensch in die Höhle, in die mittelalterliche Barbarei und in einen Schwachsinn zurückfällt, den schon die Nacktschnecke im Pleistozän überwunden hat.",
|
||||
"source": "Der Schatten des Windes",
|
||||
"length": 338,
|
||||
"id": 490
|
||||
|
|
@ -3036,6 +3036,90 @@
|
|||
"source": "Bertolt Brecht",
|
||||
"length": 122,
|
||||
"id": 510
|
||||
},
|
||||
{
|
||||
"text": "Da sprach die Fee zum Hexer: \"Solchen Rat geb ich dir: Zieh eiserne Stiefel an, nimm einen eisernen Wanderstab. Geh in den eisernen Stiefeln bis ans Ende der Welt, den Weg vor dir aber sollst du mit dem Stab ertasten und mit deinen Tränen netzen. Geh durch Feuer und Wasser, halte nicht inne, schau nicht zurück. Wenn aber die Sohlen durchgelaufen sind, wenn der eiserne Stab verschlissen ist, wenn deine Augen von Wind und Hitze so trocken geworden sind, dass keine Träne mehr hervorquillt, dann wirst du am Ende der Welt das finden, was du suchst, und das, was du liebst. Vielleicht.\" Und der Hexer ging durch Feuer und Wasser, schaute niemals zurück. Doch er nahm weder eiserne Stiefel mit noch einen Wanderstab. Nur sein Hexerschwert nahm er mit. Er hörte nicht auf die Worte der Fee. Und er tat gut daran, denn es war eine böse Fee.",
|
||||
"source": "Geralt-Saga – Feuertaufe",
|
||||
"length": 837,
|
||||
"id": 511
|
||||
},
|
||||
{
|
||||
"text": "Ich habe in meinem Leben viele Militärs kennengelernt. Ich kannte Marschälle, Generäle, Heergrafen und Hetmane, die Triumphatoren zahlreicher Feldzüge und Schlachten. Ich habe mir ihre Erzählungen und Erinnerungen angehört. Ich habe sie über Karten gebeugt gesehen, wie sie darauf verschiedenfarbige Striche zeichneten, Pläne machten, die Strategie bedachten. In diesem Krieg auf dem Papier passte alles, alles funktionierte, alles war klar und in vorbildlicher Ordnung. So muss es sein, erklärten die Militärs. Eine Armee heißt ja vor allem Ordnung und Disziplin. Umso erstaunlicher ist es, dass der wirkliche Krieg - und ein paar wirkliche Kriege habe ich gesehen – im Hinblick auf Ordnung und Disziplin einem in Flammen stehenden Bordell zum Verwechseln ähnlich sieht.",
|
||||
"source": "Geralt-Saga - Feuertaufe",
|
||||
"length": 771,
|
||||
"id": 512
|
||||
},
|
||||
{
|
||||
"text": "Ich danke dir für die anerkennenden Worte über die Dichter und die Dichtkunst. Und für die Belehrung in Sachen Bogenschießen. Eine gute Waffe ist das, der Bogen. Wisst ihr was? Ich glaube, dass sich die Kriegskunstgenau in diese Richtung entwickeln wird. In den künftigen Kriegen wird man auf Distanz kämpfen. Man wird eine Waffe mit so großer Reichweite erfinden, dass die Gegner einander umbringen können, ohne sich auch nur zu sehen.",
|
||||
"source": "Geralt-Saga - Feuertaufe",
|
||||
"length": 436,
|
||||
"id": 513
|
||||
},
|
||||
{
|
||||
"text": "Vampir, auch Wurdulak, heißet ein toter Mensch, so vom Chaos wieder zum Leben erweckt ward. Wiewohl er das erste Leben verloren hat, gewinnet er das zweite des Nachts. Er verlässt den Sarg beim Lichte des Mondes, und kann allein dahin gehen, wohin des Mondes Strahlen ihn führen; er kommet über schlafende Jungfern oder junge Bauernknechte und sauget, sonder sie zu wecken, ihr süßes Blut.",
|
||||
"source": "Geralt-Saga - Feuertaufe",
|
||||
"length": 389,
|
||||
"id": 514
|
||||
},
|
||||
{
|
||||
"text": "Wer Blut vergossen hat und Blut getrunken hat wird mit Blut bezahlen. Keine drei Tage vergehen, dann wird eins im anderen sterben, und dann stirbt etwas in jedem. Langsam werden sie sterben, Stück um Stück… Und wenn am Ende die eisernen Stiefel durchgelaufen sind und die Tränen trocken, dann stirbt das wenige, was bleibt. Es stirbt sogar das, was niemals stirbt.",
|
||||
"source": "Geralt-Saga - Feuertaufe - Weissagung",
|
||||
"length": 364,
|
||||
"id": 515
|
||||
},
|
||||
{
|
||||
"text": "Geralt löste den Geldbeutel vom Gürtel, hielt ihn bei den Riemen und wog ihn in der Hand. \"Du kannst mich nicht bestechen\", erklärte der Zerberus stolz. \"Das habe ich nicht vor.\" Der Türhüter war zu massig, als dass seine Reflexe ihm erlaubt hätten, sich gegen den raschen Schlag eines gewöhnlichen Menschen zu decken. Vor dem Schlag eines Hexers bekam er nicht einmal die Augen zu. Mit metallischem Klang donnerte ihm der Beutel an die Schläfe. Er stürzte gegen die Tür und hielt sich mit beiden Händen am Rahmen. Geralt riss ihn davon mit einem Tritt ins Knie los, stieß mit der Schulter zu und benutzte nochmals den Geldbeutel. Die Augen des Türstehers trübten sich und liefen zu einem urkomischen Schielen auseinander, die Beine klappten unter ihm wie zwei Federmesser zusammen. Der Hexer sah, dass der Koloss, obwohl schon fast bewusstlos, noch immer mit den Armen herumfuchtelte, und versetzte ihm noch einen dritten Schlag, mitten auf den Scheitel. \"Geld\", murmelte er, \"öffnet alle Türen.\"",
|
||||
"source": "Geralt-Saga - Der letzte Wunsch",
|
||||
"length": 997,
|
||||
"id": 516
|
||||
},
|
||||
{
|
||||
"text": "Von der Liebe wissen wir nicht viel. Mit der Liebe ist es wie mit einer Birne. Die Birne ist süß und hat eine Form. Versucht einmal, die Form einer Birne zu definieren.",
|
||||
"source": "Geralt-Saga - Die Zeit der Verachtung",
|
||||
"length": 168,
|
||||
"id": 517
|
||||
},
|
||||
{
|
||||
"text": "Zu sagen, ich hätte sie gekannt, wäre eine Übertreibung. Ich glaube, außer dem Hexer und der Zauberin kannte sie niemand wirklich. Als ich sie zum ersten Mal sah, machte sie überhaupt keinen großen Eindruck auf mich, selbst unter den ziemlich unheimlichen Begleitumständen. Ich habe Leute gekannt, die behaupteten, sofort, bei der ersten Begegnung den Hauch des Todes gespürt zu haben, der dieses Mädchen umgab. Mir jedoch kam sie ganz gewöhnlich vor, aber ich wusste ja, dass sie nicht gewöhnlich war – daher habe ich mich besonders bemüht, sie eingehend zu betrachten, in ihr das Ungewöhnliche zu entdecken, zu erfühlen. Doch ich beobachtete nichts und fühlte nichts. Nichts, was die späteren tragischen Ereignisse hätte signalisieren, ankündigen, ahnen lassen können. Die Ereignisse, deren Ursache sie war. Und die Ereignisse, die sie selbst herbeiführte.",
|
||||
"source": "Geralt-Saga - Die Zeit der Verachtung",
|
||||
"length": 858,
|
||||
"id": 518
|
||||
},
|
||||
{
|
||||
"text": "Wenn sich nach Einbruch der Dunkelheit noch jemand zu der Hütte mit dem eingesackten und moosbewachsenen Strohdach geschlichen hätte, wenn er hineingeschaut hätte, hätte er im Licht der Flammen und der Glut in der Feuerstelle einen graubärtigen Greis erblickt, über einen Haufen Felle gebeugt. Er hätte auch ein aschblondes Mädchen mit einer hässlichen Narbe auf der Wange erblickt, einer Narbe, die so gar nicht zu den grünen Augen passte, die groß waren wie bei einem Kind. Doch niemand konnte das sehen. Die Hütte stand mitten im Röhrich, in einem Sumpfland, in das sich niemand wagte.",
|
||||
"source": "Geralt-Saga - Der Schwalbenturm",
|
||||
"length": 588,
|
||||
"id": 519
|
||||
},
|
||||
{
|
||||
"text": "Die Welt ist voller offensichtlicher Dinge, die offensichtlich niemand sieht.",
|
||||
"source": "Sherlock Holmes – der Hund von Baskerville",
|
||||
"length": 77,
|
||||
"id": 520
|
||||
},
|
||||
{
|
||||
"text": "Sterben, das hatte ich gelernt, war kein Mannschaftssport. Es war ein einsames Unterfangen. Alle, die ich liebte, standen am trockenen Ufer, während ich allein in einem Boot saß, das sich langsam von der Küste entfernte, und niemand konnte etwas tun. Sie konnten nur dabei zusehen.",
|
||||
"source": "Full Tilt",
|
||||
"length": 281,
|
||||
"id": 521
|
||||
},
|
||||
{
|
||||
"text": "In der Sowjetunion ist jeder Arbeiter ein Staatsangestellter, und es gibt ein Sprichwort: So lange die Bosse vorgeben, uns zu bezahlen, werden wir vorgeben zu arbeiten.",
|
||||
"source": "Jagd auf Roter Oktober (frei übersetzt)",
|
||||
"length": 168,
|
||||
"id": 522
|
||||
},
|
||||
{
|
||||
"text": "Es ist keine Schande, etwas nicht zu wissen, aber es ist eine, nichts lernen zu wollen.",
|
||||
"source": "City of Fallen Magic – Mit Feuer und Zinn",
|
||||
"length": 87,
|
||||
"id": 523
|
||||
},
|
||||
{
|
||||
"text": "Birka war einst ein reiches Dorf gewesen, bezaubert und außergewöhnlich malerisch gelegen – seine gelben Stroh- und roten Ziegeldächer füllten dicht an dicht einen Talkessel mit steilen, bewaldeten Hängen, die je nach Jahreszeit ihre Farbe änderten. Vor allem im Herbst erfreute der Anblick von Birka das ästhetische Auge und das empfindsame Herz. So war es bis zu dem Zeitpunkt, da die Siedlung ihren Namen änderte.",
|
||||
"source": "Geralt-Saga - Der Schwalbenturm",
|
||||
"length": 416,
|
||||
"id": 524
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -848,9 +848,9 @@
|
|||
"id": 141
|
||||
},
|
||||
{
|
||||
"text": "Kau beri rasa yang berbeda. Mungkin ku salah mengartikannya, yang kurasa cinta",
|
||||
"text": "Kau beri rasa yang berbeda. Mungkin kusalah mengartikannya, yang kurasa cinta",
|
||||
"source": "Ariel",
|
||||
"length": 78,
|
||||
"length": 77,
|
||||
"id": 142
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -290,9 +290,9 @@
|
|||
"id": 47
|
||||
},
|
||||
{
|
||||
"text": "Nos esquecemos completamente das manias de assassinato e suicídio de Tyler enquanto assitimos a outro arquivo deslizar pela lateral do prédio e cair, as gavetas se abrirem no ar e pilhas de papéis branos serem apanhados por uma corrente de ar e se espalharem no vento.",
|
||||
"text": "Nos esquecemos completamente das manias de assassinato e suicídio de Tyler enquanto assistimos a outro arquivo deslizar pela lateral do prédio e cair, as gavetas se abrirem no ar e pilhas de papéis brancos serem apanhados por uma corrente de ar e se espalharem no vento.",
|
||||
"source": "Chuck Palahniuk, Clube da luta",
|
||||
"length": 268,
|
||||
"length": 270,
|
||||
"id": 48
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -868,8 +868,8 @@
|
|||
{
|
||||
"id": 144,
|
||||
"source": "Эндо Сюсаку - Молчание",
|
||||
"text": "Он читал молитвы, стараясь отвлечься от дум. Но молитва не приносила ему успококения. Почему Ты молчишь, Господи? Почему Ты всегда молчишь?.. - прошептал он.",
|
||||
"length": 157
|
||||
"text": "Он читал молитвы, стараясь отвлечься от дум. Но молитва не приносила ему успокоения. Почему Ты молчишь, Господи? Почему Ты всегда молчишь?.. - прошептал он.",
|
||||
"length": 156
|
||||
},
|
||||
{
|
||||
"id": 145,
|
||||
|
|
@ -3058,7 +3058,7 @@
|
|||
{
|
||||
"id": 509,
|
||||
"source": "Индридасон Арнальд - Каменный мешок",
|
||||
"text": "Нас, исландцев, жареным тýпиком не корми, дай сказать какую-нибудь гадость про ближних.",
|
||||
"text": "Нас, исландцев, жареным тyпиком не корми, дай сказать какую-нибудь гадость про ближних.",
|
||||
"length": 87
|
||||
},
|
||||
{
|
||||
|
|
@ -3178,14 +3178,14 @@
|
|||
{
|
||||
"id": 529,
|
||||
"source": "Брускин Гриша - Прошедшее время несовершенного вида",
|
||||
"text": "1957 год. Международный Фестиваль молодёжи и студентов. Говорили, что иностранцы разбросают повсюду красивые, привлекательные авторучки. Доверчивый русский прохожий поднимет приманку и тотчас взорвётся. одители увезли детей на Рижское взморье. одальше от подлых авторучек.",
|
||||
"length": 272
|
||||
"text": "1957 год. Международный Фестиваль молодёжи и студентов. Говорили, что иностранцы разбросают повсюду красивые, привлекательные авторучки. Доверчивый русский прохожий поднимет приманку и тотчас взорвётся. Родители увезли детей на Рижское взморье. Подальше от подлых авторучек.",
|
||||
"length": 274
|
||||
},
|
||||
{
|
||||
"id": 530,
|
||||
"source": "Брускин Гриша - Прошедшее время несовершенного вида",
|
||||
"text": "От моей тёщи Сафо Владимировны я узнал, чтос приятельницами пьют кофе, а с подругами - чай\".",
|
||||
"length": 92
|
||||
"text": "От моей тёщи Сафо Владимировны я узнал, чтос приятельницами пьют кофе, а с подругами - чай.",
|
||||
"length": 91
|
||||
},
|
||||
{
|
||||
"id": 531,
|
||||
|
|
@ -3826,8 +3826,8 @@
|
|||
{
|
||||
"id": 637,
|
||||
"source": "Гандлевский Сергей - Бездумное былое",
|
||||
"text": "Когда понаслышке интересуешься кем-то и думешь о нём, реальная встреча производит впечатление чего-то неправдоподобного, даже иллюзорного.",
|
||||
"length": 138
|
||||
"text": "Когда понаслышке интересуешься кем-то и ДумАешь о нём, реальная встреча производит впечатление чего-то неправдоподобного, даже иллюзорного.",
|
||||
"length": 139
|
||||
},
|
||||
{
|
||||
"id": 638,
|
||||
|
|
@ -4054,8 +4054,8 @@
|
|||
{
|
||||
"id": 675,
|
||||
"source": "Альбрехт Карл - Практический интеллект: Наука о здравом смысле",
|
||||
"text": "Иногда люди платят консультантам, что бы те напомнили им о здравом смысле.",
|
||||
"length": 74
|
||||
"text": "Иногда люди платят консультантам, чтобы те напомнили им о здравом смысле.",
|
||||
"length": 73
|
||||
},
|
||||
{
|
||||
"id": 676,
|
||||
|
|
@ -4066,8 +4066,8 @@
|
|||
{
|
||||
"id": 677,
|
||||
"source": "Торп Адам - Затаив дыхание",
|
||||
"text": "Такова жизнь богачей. Ничто не подталкиывает их к самоограничению, кроме чувства вины, а оно у них не очень назойливо.",
|
||||
"length": 118
|
||||
"text": "Такова жизнь богачей. Ничто не подталкивает их к самоограничению, кроме чувства вины, а оно у них не очень назойливо.",
|
||||
"length": 117
|
||||
},
|
||||
{
|
||||
"id": 678,
|
||||
|
|
@ -5635,12 +5635,6 @@
|
|||
"text": "Всё стремится существовать там, где оно медленнее всего стареет, и гравитационное притяжение направлено именно туда.",
|
||||
"length": 116
|
||||
},
|
||||
{
|
||||
"id": 939,
|
||||
"source": "Торн Кип - Интерстеллар: наука за кадром",
|
||||
"text": "Если взять окружность с центром, совпадающим с центром солнечной сферы, то диаметр этой окружности, помноженный на π, окажется больше, чем её длина, - в случае окружности самого Солнца разница составит примерно 100 километров.",
|
||||
"length": 226
|
||||
},
|
||||
{
|
||||
"id": 940,
|
||||
"source": "Ба Габриэль - Академия Амбрелла: Даллас",
|
||||
|
|
|
|||
|
|
@ -362,7 +362,7 @@
|
|||
"id": 59
|
||||
},
|
||||
{
|
||||
"text": "Phải, người họa sĩ già vừa nói chuyện, tay vừa bất giác hí hoáy vào cuốn sổ tì lên đầu gối. Hơn bao nhiêu người khác, ông biết rất rõ sự bất lực của nghệ thuật, của hội họa trong cuộc hành trình vĩ đại là cuộc đời. Ông thấy ngòi bút của ông bất lực trên từng chặng đường đi nhỏ của ông, nhưng nó như là một quả tim nữa của ông, hay chính là quả tim cũ được \"đề cao\" lên, do đó mà ông khao khát, mà ông yêu thêm cuộc sống. Thế nhưng, đối với chính nhà họa sĩ, vẽ bao giờ cũng là một việc khó, nặng nhọc, gian nan. Làm một bức chân dung, phác họa như ông làm đây, hay rồi vẽ dầu, làm thế nào làm hiện lên được mẫu người ấy? Cho người xem hiểu được anh ta, mà không phải hiểu như một ngôi sao xa? Và làm thế nào đặt được chính tấm lòng của nhà họa sĩ vào giữa bức tranh đó? Chao ôi, bắt gặp một con người như anh ta là một cơ hội hãn hữu cho sáng tác, nhưng hoàn thành được sáng tác còn là một chặng đường dài. Mặc dù vậy, ông đã chấp nhận sự thử thách.",
|
||||
"text": "Phải, người họa sĩ già vừa nói chuyện, tay vừa bất giác hí hoáy vào cuốn sổ tì lên đầu gối. Hơn bao nhiêu người khác, ông biết rất rõ sự bất lực của nghệ thuật, của hội họa trong cuộc hành trình vĩ đại là cuộc đời. Ông thấy ngòi bút của ông bất lực trên từng chặng đường đi nhỏ của ông, nhưng nó như là một quả tim nữa của ông, hay chính là quả tim cũ được \"đề cao\" lên, do đó mà ông khao khát, mà ông yêu thêm cuộc sống. Thế nhưng, đối với chính nhà họa sĩ, vẽ bao giờ cũng là một việc khó, nặng nhọc, gian nan. Làm một bức chân dung, phác họa như ông làm đây, hay rồi vẽ dầu, làm thế nào làm hiện lên được mẫu người ấy? Cho người xem hiểu được anh ta, mà không phải hiểu như một ngôi sao xa? Và làm thế nào đặt được chính tấm lòng của nhà họa sĩ vào giữa bức tranh đó? Chao ôi, bắt gặp một con người như anh ta là một cơ hội hạn hữu cho sáng tác, nhưng hoàn thành được sáng tác còn là một chặng đường dài. Mặc dù vậy, ông đã chấp nhận sự thử thách.",
|
||||
"source": "Lặng lẽ Sapa, Nguyễn Thành Long",
|
||||
"length": 950,
|
||||
"id": 60
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue