@ihsandeen/aya 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +39 -0
- package/LICENSE +21 -0
- package/README.md +141 -0
- package/dist/commands/adab.js +28 -0
- package/dist/commands/adhan.js +58 -0
- package/dist/commands/anatomy.js +29 -0
- package/dist/commands/blame.js +29 -0
- package/dist/commands/commit.js +44 -0
- package/dist/commands/diff.js +54 -0
- package/dist/commands/dua.js +34 -0
- package/dist/commands/fast.js +36 -0
- package/dist/commands/friday.js +21 -0
- package/dist/commands/hero.js +69 -0
- package/dist/commands/hijri.js +42 -0
- package/dist/commands/history.js +98 -0
- package/dist/commands/init.js +54 -0
- package/dist/commands/invest.js +26 -0
- package/dist/commands/journal.js +84 -0
- package/dist/commands/journey.js +24 -0
- package/dist/commands/lens.js +58 -0
- package/dist/commands/memorize.js +117 -0
- package/dist/commands/mirror.js +47 -0
- package/dist/commands/names.js +48 -0
- package/dist/commands/nature.js +28 -0
- package/dist/commands/nazm.js +100 -0
- package/dist/commands/parable.js +332 -0
- package/dist/commands/prayers.js +63 -0
- package/dist/commands/pull.js +28 -0
- package/dist/commands/push.js +156 -0
- package/dist/commands/qibla.js +118 -0
- package/dist/commands/repo.js +34 -0
- package/dist/commands/sabr.js +32 -0
- package/dist/commands/scene.js +54 -0
- package/dist/commands/seek.js +28 -0
- package/dist/commands/shukr.js +22 -0
- package/dist/commands/sleep.js +26 -0
- package/dist/commands/sound.js +35 -0
- package/dist/commands/status.js +109 -0
- package/dist/commands/sunnah.js +24 -0
- package/dist/commands/tafsir.js +89 -0
- package/dist/commands/tasbih.js +50 -0
- package/dist/commands/wudu.js +22 -0
- package/dist/commands/zakat.js +72 -0
- package/dist/data/commands-db.js +365 -0
- package/dist/data/events.js +105 -0
- package/dist/data/gems.js +160 -0
- package/dist/data/nak.js +616 -0
- package/dist/data/tafsir.js +157 -0
- package/dist/data/vocab.js +105 -0
- package/dist/index.js +86 -0
- package/dist/server.js +140 -0
- package/dist/utils/config.js +38 -0
- package/dist/utils/logger.js +104 -0
- package/dist/utils/printer.js +36 -0
- package/docs/index.html +1048 -0
- package/docs/repo.html +952 -0
- package/package.json +55 -0
- package/public/hero.html +285 -0
- package/public/index.html +1039 -0
- package/public/repo.html +904 -0
- package/src/commands/adab.ts +24 -0
- package/src/commands/adhan.ts +55 -0
- package/src/commands/anatomy.ts +25 -0
- package/src/commands/blame.ts +31 -0
- package/src/commands/commit.ts +42 -0
- package/src/commands/diff.ts +56 -0
- package/src/commands/dua.ts +34 -0
- package/src/commands/fast.ts +35 -0
- package/src/commands/friday.ts +17 -0
- package/src/commands/hero.ts +73 -0
- package/src/commands/hijri.ts +43 -0
- package/src/commands/history.ts +103 -0
- package/src/commands/init.ts +53 -0
- package/src/commands/invest.ts +22 -0
- package/src/commands/journal.ts +97 -0
- package/src/commands/journey.ts +20 -0
- package/src/commands/lens.ts +58 -0
- package/src/commands/memorize.ts +131 -0
- package/src/commands/mirror.ts +48 -0
- package/src/commands/names.ts +46 -0
- package/src/commands/nature.ts +24 -0
- package/src/commands/nazm.ts +102 -0
- package/src/commands/parable.ts +360 -0
- package/src/commands/prayers.ts +65 -0
- package/src/commands/pull.ts +28 -0
- package/src/commands/push.ts +171 -0
- package/src/commands/qibla.ts +127 -0
- package/src/commands/repo.ts +34 -0
- package/src/commands/sabr.ts +28 -0
- package/src/commands/scene.ts +56 -0
- package/src/commands/seek.ts +24 -0
- package/src/commands/shukr.ts +19 -0
- package/src/commands/sleep.ts +23 -0
- package/src/commands/sound.ts +34 -0
- package/src/commands/status.ts +132 -0
- package/src/commands/sunnah.ts +21 -0
- package/src/commands/tafsir.ts +86 -0
- package/src/commands/tasbih.ts +49 -0
- package/src/commands/wudu.ts +19 -0
- package/src/commands/zakat.ts +73 -0
- package/src/data/commands-db.ts +372 -0
- package/src/data/events.ts +113 -0
- package/src/data/gems.ts +163 -0
- package/src/data/nak.ts +805 -0
- package/src/data/tafsir.ts +165 -0
- package/src/data/vocab.ts +114 -0
- package/src/index.ts +94 -0
- package/src/server.ts +128 -0
- package/src/utils/config.ts +44 -0
- package/src/utils/logger.ts +122 -0
- package/src/utils/printer.ts +38 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.qiblaCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const axios_1 = __importDefault(require("axios"));
|
|
10
|
+
const config_1 = require("../utils/config");
|
|
11
|
+
const ora_1 = __importDefault(require("ora"));
|
|
12
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
13
|
+
const printer_1 = require("../utils/printer");
|
|
14
|
+
exports.qiblaCommand = new commander_1.Command('qibla')
|
|
15
|
+
.description('Find the direction and distance to the Kaaba')
|
|
16
|
+
.action(async () => {
|
|
17
|
+
(0, printer_1.printCommandHeader)('qibla');
|
|
18
|
+
let config = (0, config_1.getConfig)();
|
|
19
|
+
let city = config.location?.city;
|
|
20
|
+
let country = config.location?.country;
|
|
21
|
+
if (!city || !country) {
|
|
22
|
+
console.log(chalk_1.default.yellow('Location not configured.'));
|
|
23
|
+
const answers = await inquirer_1.default.prompt([
|
|
24
|
+
{ type: 'input', name: 'city', message: 'Enter your city:' },
|
|
25
|
+
{ type: 'input', name: 'country', message: 'Enter your country:' }
|
|
26
|
+
]);
|
|
27
|
+
city = answers.city;
|
|
28
|
+
country = answers.country;
|
|
29
|
+
}
|
|
30
|
+
const spinner = (0, ora_1.default)(`Locating Kaaba from ${city}, ${country}...`).start();
|
|
31
|
+
try {
|
|
32
|
+
// 1. Get coordinates for the city
|
|
33
|
+
const response = await axios_1.default.get('http://api.aladhan.com/v1/timingsByCity', {
|
|
34
|
+
params: { city, country }
|
|
35
|
+
});
|
|
36
|
+
const meta = response.data.data.meta;
|
|
37
|
+
const lat = meta.latitude;
|
|
38
|
+
const long = meta.longitude;
|
|
39
|
+
// 2. Get Qibla direction
|
|
40
|
+
const qiblaResponse = await axios_1.default.get(`http://api.aladhan.com/v1/qibla/${lat}/${long}`);
|
|
41
|
+
const direction = qiblaResponse.data.data.direction; // Degrees from North
|
|
42
|
+
spinner.stop();
|
|
43
|
+
console.clear();
|
|
44
|
+
console.log(chalk_1.default.green.bold('\n Qibla Finder'));
|
|
45
|
+
console.log(chalk_1.default.gray('----------------------------------------'));
|
|
46
|
+
console.log(chalk_1.default.white(`Location: ${chalk_1.default.bold(city)}, ${country}`));
|
|
47
|
+
console.log(chalk_1.default.white(`Coordinates: ${lat}, ${long}`));
|
|
48
|
+
console.log(chalk_1.default.cyan.bold(`Qibla Direction: ${Math.round(direction)}° from North (Clockwise)`));
|
|
49
|
+
console.log('');
|
|
50
|
+
// Calculate Distance (Haversine Formula)
|
|
51
|
+
// Kaaba coordinates: 21.4225° N, 39.8262° E
|
|
52
|
+
const kaabaLat = 21.4225;
|
|
53
|
+
const kaabaLong = 39.8262;
|
|
54
|
+
const distance = getDistanceFromLatLonInKm(lat, long, kaabaLat, kaabaLong);
|
|
55
|
+
console.log(chalk_1.default.blue(`Distance to Kaaba: ${Math.round(distance).toLocaleString()} km`));
|
|
56
|
+
console.log('');
|
|
57
|
+
// ASCII Compass Visualization
|
|
58
|
+
drawCompass(direction);
|
|
59
|
+
console.log('');
|
|
60
|
+
console.log(chalk_1.default.gray('Turn your face towards the Sacred Mosque.'));
|
|
61
|
+
console.log(chalk_1.default.italic('"So turn your face toward al-Masjid al-Haram." (2:144)'));
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
spinner.fail('Could not calculate Qibla.');
|
|
65
|
+
console.error(chalk_1.default.red('Please check your internet connection or location settings.'));
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
function drawCompass(degree) {
|
|
69
|
+
const needle = getArrow(degree);
|
|
70
|
+
const compass = `
|
|
71
|
+
N
|
|
72
|
+
|
|
|
73
|
+
W --+-- E
|
|
74
|
+
|
|
|
75
|
+
S
|
|
76
|
+
`;
|
|
77
|
+
// We can't easily rotate the whole compass in ASCII without complex logic.
|
|
78
|
+
// Instead, we show the needle direction relative to North.
|
|
79
|
+
console.log(chalk_1.default.yellow.bold(' N'));
|
|
80
|
+
console.log(chalk_1.default.yellow.bold(' |'));
|
|
81
|
+
// Show the direction arrow
|
|
82
|
+
console.log(chalk_1.default.green.bold(` ${needle} (${Math.round(degree)}°)`));
|
|
83
|
+
console.log(chalk_1.default.yellow.bold(' |'));
|
|
84
|
+
}
|
|
85
|
+
function getArrow(degree) {
|
|
86
|
+
const normalized = (degree % 360 + 360) % 360;
|
|
87
|
+
if (normalized >= 337.5 || normalized < 22.5)
|
|
88
|
+
return '^';
|
|
89
|
+
if (normalized >= 22.5 && normalized < 67.5)
|
|
90
|
+
return '/';
|
|
91
|
+
if (normalized >= 67.5 && normalized < 112.5)
|
|
92
|
+
return '>';
|
|
93
|
+
if (normalized >= 112.5 && normalized < 157.5)
|
|
94
|
+
return '\\';
|
|
95
|
+
if (normalized >= 157.5 && normalized < 202.5)
|
|
96
|
+
return 'v';
|
|
97
|
+
if (normalized >= 202.5 && normalized < 247.5)
|
|
98
|
+
return '/';
|
|
99
|
+
if (normalized >= 247.5 && normalized < 292.5)
|
|
100
|
+
return '<';
|
|
101
|
+
if (normalized >= 292.5 && normalized < 337.5)
|
|
102
|
+
return '\\';
|
|
103
|
+
return '^';
|
|
104
|
+
}
|
|
105
|
+
function getDistanceFromLatLonInKm(lat1, lon1, lat2, lon2) {
|
|
106
|
+
const R = 6371; // Radius of the earth in km
|
|
107
|
+
const dLat = deg2rad(lat2 - lat1); // deg2rad below
|
|
108
|
+
const dLon = deg2rad(lon2 - lon1);
|
|
109
|
+
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
|
110
|
+
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
|
|
111
|
+
Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
|
112
|
+
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
113
|
+
const d = R * c; // Distance in km
|
|
114
|
+
return d;
|
|
115
|
+
}
|
|
116
|
+
function deg2rad(deg) {
|
|
117
|
+
return deg * (Math.PI / 180);
|
|
118
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.repoCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const server_1 = require("../server");
|
|
9
|
+
const child_process_1 = require("child_process");
|
|
10
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
11
|
+
const ora_1 = __importDefault(require("ora"));
|
|
12
|
+
const printer_1 = require("../utils/printer");
|
|
13
|
+
exports.repoCommand = new commander_1.Command('repo')
|
|
14
|
+
.description('The Book of Deeds UI (Visualize your journey)')
|
|
15
|
+
.action(async () => {
|
|
16
|
+
(0, printer_1.printCommandHeader)('repo');
|
|
17
|
+
const spinner = (0, ora_1.default)('Opening your Book of Deeds in the browser...').start();
|
|
18
|
+
try {
|
|
19
|
+
const port = await (0, server_1.startServer)();
|
|
20
|
+
const url = `http://localhost:${port}/repo`;
|
|
21
|
+
spinner.succeed(chalk_1.default.green('Book of Deeds is open!'));
|
|
22
|
+
console.log(chalk_1.default.cyan(` ➜ ${url}`));
|
|
23
|
+
console.log(chalk_1.default.dim(' (Press Ctrl+C to close the connection)'));
|
|
24
|
+
// Open browser based on OS
|
|
25
|
+
const start = (process.platform == 'darwin' ? 'open' : process.platform == 'win32' ? 'start' : 'xdg-open');
|
|
26
|
+
(0, child_process_1.exec)(`${start} ${url}`);
|
|
27
|
+
// Keep the process alive is handled by the server.listen() inside startServer
|
|
28
|
+
// We don't need to do anything else, the node process will stay alive.
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
spinner.fail('Could not open Book of Deeds.');
|
|
32
|
+
console.error(error);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.sabrCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
10
|
+
const nak_1 = require("../data/nak");
|
|
11
|
+
const printer_1 = require("../utils/printer");
|
|
12
|
+
exports.sabrCommand = new commander_1.Command('sabr')
|
|
13
|
+
.description('The Patience Diagnostic')
|
|
14
|
+
.action(async () => {
|
|
15
|
+
(0, printer_1.printCommandHeader)('sabr');
|
|
16
|
+
const { situation } = await inquirer_1.default.prompt([{
|
|
17
|
+
type: 'list',
|
|
18
|
+
name: 'situation',
|
|
19
|
+
message: 'What are you struggling with?',
|
|
20
|
+
choices: nak_1.sabrData.map(s => ({
|
|
21
|
+
name: `${s.type} (${s.arabic})`,
|
|
22
|
+
value: s.type
|
|
23
|
+
}))
|
|
24
|
+
}]);
|
|
25
|
+
const data = nak_1.sabrData.find(s => s.type === situation);
|
|
26
|
+
if (data) {
|
|
27
|
+
console.log(chalk_1.default.blue.bold(`\n Diagnosis: ${data.type} (${data.arabic})`));
|
|
28
|
+
console.log(chalk_1.default.white(` Definition: ${data.description}`));
|
|
29
|
+
console.log(chalk_1.default.gray(` Example: ${data.example}`));
|
|
30
|
+
console.log(chalk_1.default.green('\n Prescription: "Indeed, Allah is with the patient." (2:153)\n'));
|
|
31
|
+
}
|
|
32
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.sceneCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
10
|
+
const nak_1 = require("../data/nak");
|
|
11
|
+
const printer_1 = require("../utils/printer");
|
|
12
|
+
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
13
|
+
exports.sceneCommand = new commander_1.Command('scene')
|
|
14
|
+
.description('The Cinematic Visualizer (Tadabbur in 4K)')
|
|
15
|
+
.argument('[ref]', 'The Ayah reference (e.g. 82:1)')
|
|
16
|
+
.action(async (ref) => {
|
|
17
|
+
(0, printer_1.printCommandHeader)('scene');
|
|
18
|
+
let data = ref
|
|
19
|
+
? nak_1.sceneData.find(s => s.ref.includes(ref) || s.surah.toLowerCase().includes(ref))
|
|
20
|
+
: null;
|
|
21
|
+
if (!data && ref) {
|
|
22
|
+
console.log(chalk_1.default.red('Scene not found for that reference.'));
|
|
23
|
+
}
|
|
24
|
+
if (!data) {
|
|
25
|
+
const { choice } = await inquirer_1.default.prompt([{
|
|
26
|
+
type: 'list',
|
|
27
|
+
name: 'choice',
|
|
28
|
+
message: 'Select a scene to visualize:',
|
|
29
|
+
choices: nak_1.sceneData.map(s => ({
|
|
30
|
+
name: `${s.surah} (${s.ayah}): ${s.title}`,
|
|
31
|
+
value: s
|
|
32
|
+
}))
|
|
33
|
+
}]);
|
|
34
|
+
data = choice;
|
|
35
|
+
}
|
|
36
|
+
if (!data)
|
|
37
|
+
return;
|
|
38
|
+
console.clear();
|
|
39
|
+
console.log(chalk_1.default.red.bold(`\n Aya Scene: ${data.title}`));
|
|
40
|
+
console.log(chalk_1.default.gray(`Surah ${data.surah} (${data.ayah})\n`));
|
|
41
|
+
// Display Lighting and Audio first to set the mood
|
|
42
|
+
console.log(chalk_1.default.yellow(' Lighting: ') + chalk_1.default.white(data.lighting));
|
|
43
|
+
console.log(chalk_1.default.cyan(' Audio: ') + chalk_1.default.white(data.audio));
|
|
44
|
+
console.log(chalk_1.default.gray('----------------------------------------\n'));
|
|
45
|
+
console.log(chalk_1.default.white.bold(' Shot List:'));
|
|
46
|
+
// Animate shots sequentially
|
|
47
|
+
for (let i = 0; i < data.shots.length; i++) {
|
|
48
|
+
const shot = data.shots[i];
|
|
49
|
+
await sleep(1000);
|
|
50
|
+
console.log(chalk_1.default.green(`\n[${i + 1}] ${shot.type}`));
|
|
51
|
+
console.log(chalk_1.default.white(` ${shot.description}`));
|
|
52
|
+
}
|
|
53
|
+
console.log('');
|
|
54
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.seekCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
10
|
+
const nak_1 = require("../data/nak");
|
|
11
|
+
const printer_1 = require("../utils/printer");
|
|
12
|
+
exports.seekCommand = new commander_1.Command('seek')
|
|
13
|
+
.description('Contextual Quranic Search')
|
|
14
|
+
.action(async () => {
|
|
15
|
+
(0, printer_1.printCommandHeader)('seek');
|
|
16
|
+
const { topic } = await inquirer_1.default.prompt([{
|
|
17
|
+
type: 'list',
|
|
18
|
+
name: 'topic',
|
|
19
|
+
message: 'What topic are you looking for?',
|
|
20
|
+
choices: nak_1.searchData.map(s => s.keyword)
|
|
21
|
+
}]);
|
|
22
|
+
const data = nak_1.searchData.find(s => s.keyword === topic);
|
|
23
|
+
if (data) {
|
|
24
|
+
console.log(chalk_1.default.blue.bold(`\n Topic: ${data.keyword}`));
|
|
25
|
+
console.log(chalk_1.default.green(` Ayah: ${data.ayah}`));
|
|
26
|
+
console.log(chalk_1.default.white(` Context (The "Why"): ${data.context}\n`));
|
|
27
|
+
}
|
|
28
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.shukrCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const nak_1 = require("../data/nak");
|
|
10
|
+
const printer_1 = require("../utils/printer");
|
|
11
|
+
exports.shukrCommand = new commander_1.Command('shukr')
|
|
12
|
+
.description('The Gratitude Reality Check')
|
|
13
|
+
.action(() => {
|
|
14
|
+
(0, printer_1.printCommandHeader)('shukr');
|
|
15
|
+
console.log(chalk_1.default.yellow.bold('\n The 3 Levels of Shukr (Gratitude)\n'));
|
|
16
|
+
nak_1.shukrData.forEach((level) => {
|
|
17
|
+
console.log(chalk_1.default.blue.bold(` Level: ${level.level}`));
|
|
18
|
+
console.log(chalk_1.default.white(` ${level.description}`));
|
|
19
|
+
console.log(chalk_1.default.green(` Reality: ${level.reality}\n`));
|
|
20
|
+
});
|
|
21
|
+
console.log(chalk_1.default.gray(' "If you are grateful, I will surely increase you." (14:7)'));
|
|
22
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.sleepCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const nak_1 = require("../data/nak");
|
|
10
|
+
const printer_1 = require("../utils/printer");
|
|
11
|
+
exports.sleepCommand = new commander_1.Command('sleep')
|
|
12
|
+
.description('The Minor Death (Sleep Adhkar)')
|
|
13
|
+
.action(async () => {
|
|
14
|
+
(0, printer_1.printCommandHeader)('sleep');
|
|
15
|
+
console.clear();
|
|
16
|
+
console.log(chalk_1.default.blue.bold('\n The Minor Death (An-Nawm)\n'));
|
|
17
|
+
console.log(chalk_1.default.gray(' "Allah takes the souls at the time of their death, and those that do not die [He takes] during their sleep." (39:42)\n'));
|
|
18
|
+
nak_1.sleepData.forEach(s => {
|
|
19
|
+
console.log(chalk_1.default.yellow.bold(` ${s.title}`));
|
|
20
|
+
console.log(chalk_1.default.green(` "${s.arabic}"`));
|
|
21
|
+
console.log(chalk_1.default.white(` "${s.translation}"`));
|
|
22
|
+
console.log(chalk_1.default.cyan.italic(` Reflection: ${s.reflection}\n`));
|
|
23
|
+
});
|
|
24
|
+
console.log(chalk_1.default.gray(' Good night. Reset your intentions for the resurrection (tomorrow).'));
|
|
25
|
+
console.log('\n');
|
|
26
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.soundCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const nak_1 = require("../data/nak");
|
|
10
|
+
const printer_1 = require("../utils/printer");
|
|
11
|
+
exports.soundCommand = new commander_1.Command('sound')
|
|
12
|
+
.description('Phonetic Storytelling (Tajweed as Tafsir)')
|
|
13
|
+
.argument('[ref]', 'The Ayah reference (e.g. 100:1)')
|
|
14
|
+
.action((ref) => {
|
|
15
|
+
(0, printer_1.printCommandHeader)('sound');
|
|
16
|
+
// If no ref, show available?
|
|
17
|
+
if (!ref) {
|
|
18
|
+
console.log(chalk_1.default.yellow('Please provide an Ayah reference to analyze.'));
|
|
19
|
+
console.log(chalk_1.default.gray('Available examples: 100:1, 113:1'));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const data = nak_1.soundData.find(d => d.ref === ref || `${d.surah}:${d.ayah}` === ref);
|
|
23
|
+
if (!data) {
|
|
24
|
+
console.log(chalk_1.default.red('Sound analysis not found for that Ayah.'));
|
|
25
|
+
console.log(chalk_1.default.gray('Currently available: 100:1 (Al-Adiyat), 113:1 (Al-Falaq)'));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
console.clear();
|
|
29
|
+
console.log(chalk_1.default.cyan.bold(`\n Aya Sound: ${data.surah} (${data.ayah})`));
|
|
30
|
+
console.log(chalk_1.default.white.italic(`"${data.text}"`));
|
|
31
|
+
console.log(chalk_1.default.gray('----------------------------------------\n'));
|
|
32
|
+
console.log(chalk_1.default.green.bold('Phonetic Analysis:'));
|
|
33
|
+
console.log(chalk_1.default.white(data.analysis));
|
|
34
|
+
console.log('');
|
|
35
|
+
});
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.statusCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const axios_1 = __importDefault(require("axios"));
|
|
10
|
+
const date_fns_1 = require("date-fns");
|
|
11
|
+
const config_1 = require("../utils/config");
|
|
12
|
+
const ora_1 = __importDefault(require("ora"));
|
|
13
|
+
const printer_1 = require("../utils/printer");
|
|
14
|
+
const boxen_1 = __importDefault(require("boxen"));
|
|
15
|
+
exports.statusCommand = new commander_1.Command('status')
|
|
16
|
+
.description('Check your spiritual status (prayer times)')
|
|
17
|
+
.action(async () => {
|
|
18
|
+
(0, printer_1.printCommandHeader)('status');
|
|
19
|
+
const config = (0, config_1.getConfig)();
|
|
20
|
+
const city = config.location?.city || 'Mecca';
|
|
21
|
+
const country = config.location?.country || 'Saudi Arabia';
|
|
22
|
+
const spinner = (0, ora_1.default)(`Pinging the heavens for ${city}, ${country}...`).start();
|
|
23
|
+
try {
|
|
24
|
+
const response = await axios_1.default.get('http://api.aladhan.com/v1/timingsByCity', {
|
|
25
|
+
params: {
|
|
26
|
+
city,
|
|
27
|
+
country,
|
|
28
|
+
method: 2, // ISNA
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
const timings = response.data.data.timings;
|
|
32
|
+
const hijri = response.data.data.date.hijri;
|
|
33
|
+
const prayerNames = ['Fajr', 'Dhuhr', 'Asr', 'Maghrib', 'Isha'];
|
|
34
|
+
const now = new Date();
|
|
35
|
+
let nextPrayer = null;
|
|
36
|
+
let nextPrayerTime = null;
|
|
37
|
+
let missedPrayersCount = 0;
|
|
38
|
+
// Find next prayer logic...
|
|
39
|
+
for (const name of prayerNames) {
|
|
40
|
+
const timeStr = timings[name];
|
|
41
|
+
const [hours, minutes] = timeStr.split(':').map(Number);
|
|
42
|
+
const prayerDate = new Date();
|
|
43
|
+
prayerDate.setHours(hours, minutes, 0, 0);
|
|
44
|
+
if (prayerDate > now) {
|
|
45
|
+
if (!nextPrayer) {
|
|
46
|
+
nextPrayer = name;
|
|
47
|
+
nextPrayerTime = prayerDate;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
missedPrayersCount++;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (!nextPrayer) {
|
|
55
|
+
nextPrayer = 'Fajr';
|
|
56
|
+
const timeStr = timings['Fajr'];
|
|
57
|
+
const [hours, minutes] = timeStr.split(':').map(Number);
|
|
58
|
+
const prayerDate = new Date();
|
|
59
|
+
prayerDate.setDate(prayerDate.getDate() + 1);
|
|
60
|
+
prayerDate.setHours(hours, minutes, 0, 0);
|
|
61
|
+
nextPrayerTime = prayerDate;
|
|
62
|
+
}
|
|
63
|
+
spinner.stop();
|
|
64
|
+
// NAK Style Status Output
|
|
65
|
+
console.log((0, boxen_1.default)(chalk_1.default.bold.green(` 🕌 Spiritual Status Report `) + '\n' +
|
|
66
|
+
chalk_1.default.dim(` Location: ${city}, ${country} `) + '\n' +
|
|
67
|
+
chalk_1.default.dim(` Date: ${hijri.day} ${hijri.month.en} ${hijri.year} AH `), {
|
|
68
|
+
padding: 1,
|
|
69
|
+
margin: 1,
|
|
70
|
+
borderStyle: 'round',
|
|
71
|
+
borderColor: 'green',
|
|
72
|
+
}));
|
|
73
|
+
console.log(chalk_1.default.bold.blue('📡 Connection Status:'));
|
|
74
|
+
console.log(` Your heart is currently on branch ${chalk_1.default.green("'dunya'")}.`);
|
|
75
|
+
if (missedPrayersCount > 0) {
|
|
76
|
+
console.log(chalk_1.default.yellow(` Warning: ${missedPrayersCount} prayer times missed.`));
|
|
77
|
+
console.log(chalk_1.default.cyan(` Suggestion: run 'aya wudu' to refresh session.`));
|
|
78
|
+
}
|
|
79
|
+
console.log('');
|
|
80
|
+
if (nextPrayer && nextPrayerTime) {
|
|
81
|
+
const diff = (0, date_fns_1.differenceInMinutes)(nextPrayerTime, now);
|
|
82
|
+
const hours = Math.floor(diff / 60);
|
|
83
|
+
const mins = diff % 60;
|
|
84
|
+
let timeString = '';
|
|
85
|
+
if (hours > 0)
|
|
86
|
+
timeString += `${hours}h `;
|
|
87
|
+
timeString += `${mins}m`;
|
|
88
|
+
console.log(chalk_1.default.bold.yellow('⏳ Next Obligatory Commit:'));
|
|
89
|
+
console.log(` ${chalk_1.default.cyan.bold(nextPrayer)} is due in ${chalk_1.default.yellow.bold(timeString)}`);
|
|
90
|
+
console.log(chalk_1.default.italic.gray(' "Indeed, prayer has been decreed upon the believers a decree of specified times." (4:103)'));
|
|
91
|
+
}
|
|
92
|
+
console.log('');
|
|
93
|
+
console.log(chalk_1.default.bold.white('📅 Today\'s Schedule (The Daily Sprint):'));
|
|
94
|
+
prayerNames.forEach(name => {
|
|
95
|
+
const isNext = name === nextPrayer;
|
|
96
|
+
const color = isNext ? chalk_1.default.green.bold : chalk_1.default.white;
|
|
97
|
+
const marker = isNext ? chalk_1.default.yellow(' ← UP NEXT') : '';
|
|
98
|
+
const time = timings[name];
|
|
99
|
+
// Simple formatting
|
|
100
|
+
console.log(` ${color(name.padEnd(10))} ${time} ${marker}`);
|
|
101
|
+
});
|
|
102
|
+
console.log('');
|
|
103
|
+
console.log(chalk_1.default.gray('(Run "aya init" to re-calibrate your location coordinates)'));
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
spinner.fail('Connection lost.');
|
|
107
|
+
console.error(chalk_1.default.red('Could not fetch prayer times. Please check your network connection.'));
|
|
108
|
+
}
|
|
109
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.sunnahCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const nak_1 = require("../data/nak");
|
|
10
|
+
const printer_1 = require("../utils/printer");
|
|
11
|
+
exports.sunnahCommand = new commander_1.Command('sunnah')
|
|
12
|
+
.description('Daily Micro-Ibadaat Habits')
|
|
13
|
+
.action(async () => {
|
|
14
|
+
(0, printer_1.printCommandHeader)('sunnah');
|
|
15
|
+
console.clear();
|
|
16
|
+
console.log(chalk_1.default.green.bold('\n Daily Sunnah Habits (Micro-Ibadaat)\n'));
|
|
17
|
+
nak_1.sunnahData.forEach(s => {
|
|
18
|
+
console.log(chalk_1.default.yellow.bold(` ${s.action} `) + chalk_1.default.gray(`(${s.category})`));
|
|
19
|
+
console.log(chalk_1.default.cyan(` Impact: ${s.impact}`));
|
|
20
|
+
console.log(chalk_1.default.white.italic(` ${s.description}\n`));
|
|
21
|
+
});
|
|
22
|
+
console.log(chalk_1.default.gray(' "He who revives my Sunnah has loved me..."'));
|
|
23
|
+
console.log('\n');
|
|
24
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.tafsirCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
10
|
+
const tafsir_1 = require("../data/tafsir");
|
|
11
|
+
const printer_1 = require("../utils/printer");
|
|
12
|
+
exports.tafsirCommand = new commander_1.Command('tafsir')
|
|
13
|
+
.description('Interactive linguistic deep dive (Tadabbur)')
|
|
14
|
+
.argument('[query]', 'The specific surah/ayah to study (e.g. 93:3, fatiha, ikhlas)')
|
|
15
|
+
.action(async (query) => {
|
|
16
|
+
(0, printer_1.printCommandHeader)('tafsir');
|
|
17
|
+
let selectedTafsir;
|
|
18
|
+
if (query) {
|
|
19
|
+
const q = query.toLowerCase();
|
|
20
|
+
selectedTafsir = tafsir_1.tafsirData.find(t => t.surah.toLowerCase().includes(q) ||
|
|
21
|
+
`${t.ayah}` === q ||
|
|
22
|
+
(query.includes(':') && `${t.surah}:${t.ayah}`.includes(q)) || // weak check, but okay
|
|
23
|
+
(query.includes(':') && t.ayah === parseInt(query.split(':')[1]) && t.surah.toLowerCase().includes(query.split(':')[0])) // better check? No, surah is a name in data
|
|
24
|
+
);
|
|
25
|
+
// Better matching logic
|
|
26
|
+
if (!selectedTafsir) {
|
|
27
|
+
// Try to match "93:3" style
|
|
28
|
+
if (query.includes(':')) {
|
|
29
|
+
const [s, a] = query.split(':');
|
|
30
|
+
// We don't have surah numbers in data, only names.
|
|
31
|
+
// But let's check if user typed "duha:3"
|
|
32
|
+
selectedTafsir = tafsir_1.tafsirData.find(t => t.surah.toLowerCase().includes(s) && t.ayah.toString() === a);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Hardcoded fallback for specific numbers if they were in the original code
|
|
36
|
+
// 93:3 -> Ad-Duhaa
|
|
37
|
+
if (!selectedTafsir && query === '93:3')
|
|
38
|
+
selectedTafsir = tafsir_1.tafsirData.find(t => t.surah === 'Ad-Duhaa');
|
|
39
|
+
if (!selectedTafsir && query === '1:5')
|
|
40
|
+
selectedTafsir = tafsir_1.tafsirData.find(t => t.surah === 'Al-Fatiha');
|
|
41
|
+
if (!selectedTafsir && query === '103:1')
|
|
42
|
+
selectedTafsir = tafsir_1.tafsirData.find(t => t.surah === 'Al-Asr');
|
|
43
|
+
if (!selectedTafsir && query === '112:1')
|
|
44
|
+
selectedTafsir = tafsir_1.tafsirData.find(t => t.surah === 'Al-Ikhlas');
|
|
45
|
+
if (!selectedTafsir && query === '113:1')
|
|
46
|
+
selectedTafsir = tafsir_1.tafsirData.find(t => t.surah === 'Al-Falaq');
|
|
47
|
+
if (!selectedTafsir && query === '114:1')
|
|
48
|
+
selectedTafsir = tafsir_1.tafsirData.find(t => t.surah === 'An-Nas');
|
|
49
|
+
if (!selectedTafsir) {
|
|
50
|
+
console.log(chalk_1.default.red('Tafsir not found for that Ayah.'));
|
|
51
|
+
console.log(chalk_1.default.gray('Available: Ad-Duhaa (93:3), Al-Fatiha (1:5), Al-Asr (103:1), Al-Ikhlas (112:1), Al-Falaq (113:1), An-Nas (114:1)'));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// Interactive menu if no argument provided
|
|
57
|
+
const answers = await inquirer_1.default.prompt([
|
|
58
|
+
{
|
|
59
|
+
type: 'list',
|
|
60
|
+
name: 'selectedTafsirIndex',
|
|
61
|
+
message: 'Choose a Surah/Ayah to study:',
|
|
62
|
+
choices: tafsir_1.tafsirData.map((t, index) => ({
|
|
63
|
+
name: `${t.surah} (Ayah ${t.ayah})`,
|
|
64
|
+
value: index
|
|
65
|
+
}))
|
|
66
|
+
}
|
|
67
|
+
]);
|
|
68
|
+
selectedTafsir = tafsir_1.tafsirData[answers.selectedTafsirIndex];
|
|
69
|
+
}
|
|
70
|
+
if (!selectedTafsir)
|
|
71
|
+
return;
|
|
72
|
+
console.clear();
|
|
73
|
+
console.log(chalk_1.default.green.bold(`\n Tafsir: Surah ${selectedTafsir.surah}, Ayah ${selectedTafsir.ayah}`));
|
|
74
|
+
console.log(chalk_1.default.gray('Take a deep breath. Let the words sink in.\n'));
|
|
75
|
+
for (const step of selectedTafsir.steps) {
|
|
76
|
+
await inquirer_1.default.prompt([{
|
|
77
|
+
type: 'input',
|
|
78
|
+
name: 'continue',
|
|
79
|
+
message: chalk_1.default.yellow.bold(step.word),
|
|
80
|
+
suffix: chalk_1.default.gray(' (Press Enter to reveal meaning)')
|
|
81
|
+
}]);
|
|
82
|
+
console.log(chalk_1.default.cyan(`Meaning: ${step.meaning}`));
|
|
83
|
+
console.log(chalk_1.default.white(step.explanation));
|
|
84
|
+
console.log(chalk_1.default.gray('----------------------------------------'));
|
|
85
|
+
}
|
|
86
|
+
console.log(chalk_1.default.green.bold('\n Final Reflection:'));
|
|
87
|
+
console.log(chalk_1.default.white.italic(selectedTafsir.finalThought));
|
|
88
|
+
console.log('');
|
|
89
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.tasbihCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
10
|
+
const printer_1 = require("../utils/printer");
|
|
11
|
+
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
12
|
+
exports.tasbihCommand = new commander_1.Command('tasbih')
|
|
13
|
+
.description('Digital Counter (Tasbih)')
|
|
14
|
+
.action(async () => {
|
|
15
|
+
(0, printer_1.printCommandHeader)('tasbih');
|
|
16
|
+
let count = 0;
|
|
17
|
+
console.clear();
|
|
18
|
+
console.log(chalk_1.default.cyan.bold('\n Digital Tasbih'));
|
|
19
|
+
console.log(chalk_1.default.gray('Press ENTER to count. Type "reset" to reset. Ctrl+C to exit.\n'));
|
|
20
|
+
// We need a loop to handle inputs
|
|
21
|
+
while (true) {
|
|
22
|
+
const { input } = await inquirer_1.default.prompt([{
|
|
23
|
+
type: 'input',
|
|
24
|
+
name: 'input',
|
|
25
|
+
message: `Count: ${chalk_1.default.green.bold(count)} Wait for prompt...`,
|
|
26
|
+
default: '',
|
|
27
|
+
prefix: '' // Remove prefix
|
|
28
|
+
}]);
|
|
29
|
+
if (input.toLowerCase() === 'reset') {
|
|
30
|
+
count = 0;
|
|
31
|
+
}
|
|
32
|
+
else if (input.toLowerCase() === 'exit' || input.toLowerCase() === 'q') {
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
count++;
|
|
37
|
+
}
|
|
38
|
+
console.clear();
|
|
39
|
+
console.log(chalk_1.default.cyan.bold('\n Digital Tasbih'));
|
|
40
|
+
console.log(chalk_1.default.gray('Press ENTER to count. Type "reset" to reset. Type "exit" to quit.\n'));
|
|
41
|
+
console.log(chalk_1.default.green.bold(`Current Count: ${count}`));
|
|
42
|
+
// Simple feedback
|
|
43
|
+
if (count % 33 === 0 && count > 0) {
|
|
44
|
+
console.log(chalk_1.default.yellow(' SubhanAllah / Alhamdulillah / Allahu Akbar (33 completed)'));
|
|
45
|
+
}
|
|
46
|
+
if (count % 100 === 0 && count > 0) {
|
|
47
|
+
console.log(chalk_1.default.magenta(' 100 Completed! May Allah accept it.'));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.wuduCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const nak_1 = require("../data/nak");
|
|
10
|
+
const printer_1 = require("../utils/printer");
|
|
11
|
+
exports.wuduCommand = new commander_1.Command('wudu')
|
|
12
|
+
.description('The Spiritual Detox (Washing away sins)')
|
|
13
|
+
.action(() => {
|
|
14
|
+
(0, printer_1.printCommandHeader)('wudu');
|
|
15
|
+
console.log(chalk_1.default.cyan.bold('\n Wudu: The Spiritual Detox\n'));
|
|
16
|
+
nak_1.wuduData.forEach((step, index) => {
|
|
17
|
+
console.log(chalk_1.default.blue.bold(` ${index + 1}. ${step.step}`));
|
|
18
|
+
console.log(chalk_1.default.white(` Physical: ${step.physical}`));
|
|
19
|
+
console.log(chalk_1.default.green(` Spiritual: ${step.spiritual}\n`));
|
|
20
|
+
});
|
|
21
|
+
console.log(chalk_1.default.gray(' "Oh Allah, make me of those who repent and those who purify themselves."'));
|
|
22
|
+
});
|