Add prefix command and some small fixes!

This commit is contained in:
Wessel Damian Tip
2019-02-10 16:15:49 +01:00
parent 057e0fd851
commit 0a5554efc9
13 changed files with 214 additions and 48 deletions

View File

@@ -51,6 +51,7 @@ discord :
commands : commands :
# Category : CORE # Category : CORE
locale : true locale : true
prefix : true
# Category : UTILITY # Category : UTILITY
ping : true ping : true
math : true math : true

View File

@@ -3,6 +3,7 @@ cooldown: 0x7289DA # Blurple
core : core :
locale: 0x7289DA # Blurple locale: 0x7289DA # Blurple
prefix: 0x7289DA # Blurple
util : util :
ping : ping :

View File

@@ -5,7 +5,7 @@ guild_only: <:exclamation:542368036255039509> # Only guilds
core : core :
locale: locale:
0 : <:wumpus_blob:541629681120837648> # Dupe locale (user) 0 : <:wumpus_blob:541629681120837648> # Dupe locale (user)
1 : <:wumpus_blob:541629681120837648> # Dupe locale (guild) 1 : <:wumpking:544167185329815589> # Dupe locale (guild)
2 : <:wumpus_love:506200781549076482> # Current locale (user) 2 : <:wumpus_love:506200781549076482> # Current locale (user)
3 : <:wumpus_love:506200781549076482> # Current locale (guild) 3 : <:wumpus_love:506200781549076482> # Current locale (guild)
4 : <:wumpus_flag:495525134220787713> # Locale list 4 : <:wumpus_flag:495525134220787713> # Locale list
@@ -13,6 +13,15 @@ core :
6 : <:ok_hand:497396122416054287> # Updated (user) 6 : <:ok_hand:497396122416054287> # Updated (user)
7 : <:sad:500719642403405824> # Invalid locale 7 : <:sad:500719642403405824> # Invalid locale
8 : <:sad:500719642403405824> # Missing permissions (guild) 8 : <:sad:500719642403405824> # Missing permissions (guild)
prefix:
0 : <:wumpus_blob:541629681120837648> # Dupe prefix (user)
1 : <:wumpus_blob:541629681120837648> # Dupe prefix (guild)
2 : <:wumpking:544167185329815589> # Current prefix (user)
3 : <:wumpus_love:506200781549076482> # Current prefix (guild)
4 : <:wumpus_flag:495525134220787713> # prefix limitations
5 : <:ok_hand:497396122416054287> # Updated (guild)
6 : <:ok_hand:497396122416054287> # Updated (user)
7 : <:sad:500719642403405824> # Missing permissions (guild)
logs : logs :
ready : '<:spacewump:542723940997529641>' ready : '<:spacewump:542723940997529641>'

View File

@@ -21,9 +21,29 @@ error :
cooldown: '$[emoji#0] $[author:mention] **>** This command is on cooldown for **$[cooldown:left]**' cooldown: '$[emoji#0] $[author:mention] **>** This command is on cooldown for **$[cooldown:left]**'
core : core :
prefix :
gchanged: '$[emoji#5] Successfully updated the guild''s prefix to `$[guild:prefix]`'
changed : '$[emoji#6] Successfully updated your prefix to `$[user:prefix]`'
gperms : '$[emoji#8] You''re missing permissions in order to execute this command (`MANAGE_GUILD`)'
gdupe : '$[emoji#1] The guild''s prefix is already set to `$[guild:prefix]`'
dupe : '$[emoji#0] Your prefix is already set to `$[user:prefix]`'
info :
- '$[emoji#2] **>** Your current prefix is `$[user:prefix]`'
- '$[emoji#3] **>** The guild''s prefix is `$[guild:prefix]`'
- ''
- '$[emoji#4] **Prefix limitations**:'
- '`1.` The maximum length of a prefix is `32`'
- '`1.` All characters are transformed to **lowercase** characters'
- ''
- 'Type `$[prefix:changeCmd]` to update your/the guild''s prefix'
locale : locale :
dupe : '$[emoji#0] Your locale is already set to `$[uLocale:code]`' gchanged: '$[emoji#5] Successfully updated the guild''s locale to `$[gLocale:code]`'
changed : '$[emoji#6] Successfully updated your locale to `$[uLocale:code]`'
invalid : '$[emoji#7] The locale you provided isn''t a valid locale'
gperms : '$[emoji#8] You''re missing permissions in order to execute this command (`MANAGE_GUILD`)'
gdupe : '$[emoji#1] The guild''s locale is already set to `$[gLocale:code]`' gdupe : '$[emoji#1] The guild''s locale is already set to `$[gLocale:code]`'
dupe : '$[emoji#0] Your locale is already set to `$[uLocale:code]`'
list : list :
- '$[emoji#2] **>** Your current locale is `$[uLocale:code]`' - '$[emoji#2] **>** Your current locale is `$[uLocale:code]`'
- '$[emoji#3] **>** The guild''s locale is `$[gLocale:code]`' - '$[emoji#3] **>** The guild''s locale is `$[gLocale:code]`'
@@ -33,10 +53,6 @@ core :
- '' - ''
- 'Type `$[locale:changeCmd]` to update your/the guild''s locale' - 'Type `$[locale:changeCmd]` to update your/the guild''s locale'
- 'If you want to help translate wump, you can join my [Discord](https://discord.gg/SV7DAE9) and create a pull request on my [GitHub](https://github.com/PassTheWessel/wump/compare)' - 'If you want to help translate wump, you can join my [Discord](https://discord.gg/SV7DAE9) and create a pull request on my [GitHub](https://github.com/PassTheWessel/wump/compare)'
gchanged: '$[emoji#5] The guild''s locale changed to `$[gLocale:code]`'
changed : '$[emoji#6] Your locale has changed to `$[uLocale:code]`'
invalid : '$[emoji#7] The locale you provided isn''t a valid locale'
gperms : '$[emoji#8] You''re missing permissions in order to execute this command (`MANAGE_GUILD`)'
util : util :
ping : ping :

View File

@@ -21,9 +21,29 @@ error :
cooldown: '$[emoji#0] $[author:mention] **>** Dit commando is op cooldown voor **$[cooldown:left]**' cooldown: '$[emoji#0] $[author:mention] **>** Dit commando is op cooldown voor **$[cooldown:left]**'
core : core :
prefix :
gchanged: '$[emoji#5] Het voorvoegsel van de gilde is bijgewerkt naar `$[guild:prefix]`'
changed : '$[emoji#6] Uw voorvoegsel is bijgewerkt naar `$[user:prefix]`'
gperms : '$[emoji#8] U heeft onvoldoende rechten om dit commando uit te voeren (`MANAGE_GUILD`)'
gdupe : '$[emoji#1] Het voorvoegsel van de gilde is al ingesteld op `$[guild:prefix]`'
dupe : '$[emoji#0] Uw voorvoegsel is al ingesteld op `$[user:prefix]`'
info :
- '$[emoji#2] **>** Uw huidige voorvoegsel is `$[user:prefix]`'
- '$[emoji#3] **>** Het voorvoegsel van de gilde is `$[guild:prefix]`'
- ''
- '$[emoji#4] **Voorvoegsel beperkingen**:'
- '`1.` De maximale lengte van een voorvoegsel is `32`'
- '`1.` Alle tekens worden omgezet in **kleine** letters'
- ''
- 'Typ `$[prefix:changeCmd]` Om het voorvoegsel van u/de gilde bij te werken'
locale : locale :
dupe : '$[emoji#0] Uw landinstelling is al ingesteld op `$[uLocale:code]`' gchanged: '$[emoji#6] De landinstelling van de gilde is bijgewerkt naar `$[gLocale:code]`'
changed : '$[emoji#5] Uw landinstelling is bijgewerkt naar `$[uLocale:code]`'
invalid : '$[emoji#7] De landinstelling dat u heeft aangegeven is geen geldige landinstelling'
gperms : '$[emoji#8] U heeft onvoldoende rechten om dit commando uit te voeren (`MANAGE_GUILD`)'
gdupe : '$[emoji#1] De landinstelling van de gilde is al ingesteld op `$[gLocale:code]`' gdupe : '$[emoji#1] De landinstelling van de gilde is al ingesteld op `$[gLocale:code]`'
dupe : '$[emoji#0] Uw landinstelling is al ingesteld op `$[uLocale:code]`'
list : list :
- '$[emoji#2] **>** Uw huidige landinstelling is `$[uLocale:code]`' - '$[emoji#2] **>** Uw huidige landinstelling is `$[uLocale:code]`'
- '$[emoji#3] **>** De landinstelling van de gilde is `$[gLocale:code]`' - '$[emoji#3] **>** De landinstelling van de gilde is `$[gLocale:code]`'
@@ -31,12 +51,9 @@ core :
- '$[emoji#4] **Beschikbare talen**:' - '$[emoji#4] **Beschikbare talen**:'
- '$[locale:map]' - '$[locale:map]'
- '' - ''
- 'Typ `$[locale:changeCmd]` om uw/de gilde zijn landinstelling bij te werken' - 'Typ `$[locale:changeCmd]` om de landinstelling van u/de gilde bij te werken'
- 'Als u wilt helpen met het vertalen van wump, kunt u zij aansluiten bij mijn [Discord](https://discord.gg/SV7DAE9) en een pull request op [GitHub](https://github.com/PassTheWessel/wump/compare) te maken' - 'Als u wilt helpen met het vertalen van Wump, kunt u zij aansluiten bij mijn [Discord](https://discord.gg/SV7DAE9) en een pull request op [GitHub](https://github.com/PassTheWessel/wump/compare) te maken'
changed : '$[emoji#5] Uw landinstelling is veranderd naar `$[uLocale:code]`'
gchanged: '$[emoji#6] De landinstelling van de gilde is veranderd naar `$[gLocale:code]`'
invalid : '$[emoji#7] De landinstelling dat u heeft aangegeven is geen geldige landinstelling'
gperms : '$[emoji#8] U heeft onvoldoende rechten om dit commando uit te voeren (`MANAGE_GUILD`)'
util : util :
ping : ping :
busy : '$[emoji#0] Pingen...' busy : '$[emoji#0] Pingen...'
@@ -100,15 +117,15 @@ info :
- '$[emoji#9] Robots **⤏** $[guild:users#bot]' - '$[emoji#9] Robots **⤏** $[guild:users#bot]'
- '$[emoji#10] Leden **⤏** $[guild:users#total]' - '$[emoji#10] Leden **⤏** $[guild:users#total]'
- '**_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\__**' - '**_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\__**'
- '$[emoji#12] Online **⤏** `$[guild:users#online]`' - '$[emoji#11] Online **⤏** `$[guild:users#online]`'
- '$[emoji#14] Idle **⤏** `$[guild:users#idle]`' - '$[emoji#12] Idle **⤏** `$[guild:users#idle]`'
- '$[emoji#13] DnD **⤏** `$[guild:users#dnd]`' - '$[emoji#13] DnD **⤏** `$[guild:users#dnd]`'
- '$[emoji#11] Offline **⤏** `$[guild:users#offline]`' - '$[emoji#14] Offline **⤏** `$[guild:users#offline]`'
invalid: '$[emoji#15] Geen gilde gevonden met uw zoekopdracht' invalid: '$[emoji#15] Geen gilde gevonden met uw zoekopdracht'
image: image:
fetching : '$[emoji#0] Een willekeurig plaatje aan het ophalen, dit kan enige tijd duren...' fetching : '$[emoji#0] Een willekeurig plaatje aan het ophalen, dit kan enige tijd duren...'
failed_cache: 'Kliek hier als het plaatje niet is geladen' failed_cache: 'Klik hier als het plaatje niet is geladen'
developer: developer:
echo : '$[emoji#0] Ongeldig bericht om te echoën' echo : '$[emoji#0] Ongeldig bericht om te echoën'

View File

@@ -0,0 +1,115 @@
const { DiscordCommand } = require('../../../core');
const larg = require('larg');
module.exports = class Prefix extends DiscordCommand {
constructor(bot) {
super(bot, {
name : 'prefix',
syntax : 'prefix <..prefix:string> <-u|-g>',
aliases : [],
argument : [ '<...prefix:string>', '-<u|g>' ],
description: 'Change your prefix',
hidden : false,
enabled : true,
cooldown : 1000,
category : 'Core',
ownerOnly : false,
guildOnly : false,
permissions: [ 'embedLinks' ]
});
}
async execute(msg, args, user, guild) {
if (!user || user === null) user = await this.bot.m.connection.collection('dUsers').findOne({ userId: msg.author.id });
if (!guild || guild === null) guild = await this.bot.m.connection.collection('dGuilds').findOne({ guildId: msg.channel.guild.id });
// Delete all empty elements in `args`
args = args.filter((v) => {
return v.length >= 1;
});
// Avoid an `undefined` prefix
if (!user || !user.prefix) {
user.prefix = this.bot.conf.discord.prefix;
}
if (!user || !guild.prefix) {
guild.prefix = this.bot.conf.discord.prefix;
}
if (args.join(' ').endsWith('-u') || args.join(' ').endsWith('--user')) {
/* User prefix */
let prefix = args.splice(0, 1).join(' ').slice(0, 32).toLowerCase();
// Checks
if (prefix.length <= 0) prefix = this.bot.conf.discord.prefix;
if (user.prefix === prefix) {
return msg.channel.createMessage(this.localize(msg.author.locale['core']['prefix']['dupe'], { uPrefix: user.prefix }));
}
// Update document
this.bot.m.connection.collection('dUsers').findOneAndUpdate({ 'userId': user.userId }, { $set: { prefix: prefix } }, (err) => {
if (err) throw err;
});
// Update user's entry in cache
const entry = this.bot.cache.get('users').filter((v) => v.userId = msg.author.id)[0];
if (entry) {
entry.prefix = prefix;
}
msg.channel.createMessage(this.localize(msg.author.locale['core']['prefix']['changed'], { uPrefix: prefix }));
} else if (args.join(' ').includes('-g') || args.join(' ').includes('--guild')) {
/* Guild prefix */
let prefix = args.splice(0, 1).join(' ').slice(0, 32).toLowerCase();
const uPerm = msg.channel.permissionsOf(msg.author.id);
// Checks
if (prefix.length <= 0) prefix = this.bot.conf.discord.prefix;
if (!uPerm.has('manageGuild')) {
return msg.channel.createMessage(this.localize(msg.author.locale['core']['prefix']['gperms']));
}
if (guild.prefix === prefix) {
return msg.channel.createMessage(this.localize(msg.author.locale['core']['prefix']['gdupe'], { gPrefix: guild.prefix }));
}
// Update document
this.bot.m.connection.collection('dGuilds').findOneAndUpdate({ 'guildId': guild.guildId }, { $set: { prefix: prefix } }, (err) => {
if (err) throw err;
});
// Update guild's entry in cache
const entry = this.bot.cache.get('guilds').filter((v) => v.guildId = msg.channel.guild.id)[0];
if (entry) {
entry.prefix = prefix;
}
msg.channel.createMessage(this.localize(msg.author.locale['core']['prefix']['gchanged'], { gPrefix: prefix }));
} else {
return msg.channel.createMessage({
embed: {
color : this.bot.col['core']['prefix'],
description: this.localize(msg.author.locale['core']['prefix']['info'].join('\n'), { uPrefix: user.prefix || this.bot.conf.discord.prefix, gPrefix: guild.prefix || this.bot.conf.discord.prefix })
}
});
}
}
localize(msg, extData) {
if (!msg) return '';
// Optional replacements
if (extData) {
if (extData.uPrefix) {
msg = msg.replace(/\$\[user:prefix]/g, extData.uPrefix);
}
if (extData.gPrefix) {
msg = msg.replace(/\$\[guild:prefix]/g, extData.gPrefix);
}
}
return msg
.replace(/\$\[prefix:changeCmd]/g, this.extData.syntax)
.replace(/\$\[emoji#0]/g, this.bot.emote('core', 'prefix', '0'))
.replace(/\$\[emoji#1]/g, this.bot.emote('core', 'prefix', '1'))
.replace(/\$\[emoji#2]/g, this.bot.emote('core', 'prefix', '2'))
.replace(/\$\[emoji#3]/g, this.bot.emote('core', 'prefix', '3'))
.replace(/\$\[emoji#4]/g, this.bot.emote('core', 'prefix', '4'))
.replace(/\$\[emoji#5]/g, this.bot.emote('core', 'prefix', '5'))
.replace(/\$\[emoji#6]/g, this.bot.emote('core', 'prefix', '6'))
.replace(/\$\[emoji#7]/g, this.bot.emote('core', 'prefix', '7'));
}
};

View File

@@ -22,7 +22,7 @@ module.exports = class Eval extends DiscordCommand {
}); });
} }
async execute(msg, args) { async execute(msg, args, user, guild) {
let result; let result;
let silent = args.join(' ').trim().endsWith('--silent') || args.join(' ').trim().endsWith('-s') ? args.pop() : false; let silent = args.join(' ').trim().endsWith('--silent') || args.join(' ').trim().endsWith('-s') ? args.pop() : false;
let asynchr = args.join(' ').trim().includes('return') || args.join(' ').trim().includes('await'); let asynchr = args.join(' ').trim().includes('return') || args.join(' ').trim().includes('await');
@@ -49,12 +49,16 @@ module.exports = class Eval extends DiscordCommand {
} }
sanitize(msg) { sanitize(msg) {
// Empty // Return nothing if empty
if (!msg) return undefined; if (!msg) return msg;
// API tokens // API tokens
for(let _ in this.bot.conf['api']) { for (let _ in this.bot.conf['api']) {
msg = msg.replace(new RegExp(this.bot.conf['api'][_], 'gi'), '<--snip-->'); msg = msg.replace(new RegExp(this.bot.conf['api'][_], 'gi'), '<--snip-->');
} }
// Webhook information
for (let _ in this.bot.conf.discord.webhook) {
msg = msg.replace(new RegExp(this.bot.conf.discord.webhook[_], 'gi'), '<--snip-->');
}
// Bot tokens // Bot tokens
return msg return msg
.replace(new RegExp(this.bot.token, 'gi'), '<--snip-->') .replace(new RegExp(this.bot.token, 'gi'), '<--snip-->')

View File

@@ -8,7 +8,7 @@ const LocaleRegistry = require('../registry/Discord/Locales');
const CommandRegistry = require('../registry/Discord/Commands'); const CommandRegistry = require('../registry/Discord/Commands');
// Utilities // Utilities
const Util = require('../../util/Util'); const Util = require('../../util/Util');
const Schema = require('../internal/Discord/Schemas'); const Schema = require('../internal/Discord/schema');
const { cyan } = require('../../util/colors'); const { cyan } = require('../../util/colors');
const Collection = require('../../util/Collection'); const Collection = require('../../util/Collection');
const PermissionUtil = require('../internal/Discord/Utils/PermissionUtil'); const PermissionUtil = require('../internal/Discord/Utils/PermissionUtil');

View File

@@ -1,21 +0,0 @@
const mongoose = require('mongoose');
const { safeLoad } = require('js-yaml');
const { readFileSync } = require('fs');
const conf = safeLoad(readFileSync('application.yml', { encoding: 'utf8' }));
const guild = new mongoose.Schema({
guildId: { type: String, default: undefined },
prefix : { type: String, default: conf['discord']['prefix'] },
locale: { type: String, default: conf['discord']['locale'] }
});
const user = new mongoose.Schema({
userId: { type: String, default: undefined },
locale: { type: String, default: conf['discord']['locale'] }
});
module.exports = {
user : mongoose.model('dUsers', user, 'dUsers'),
guild: mongoose.model('dGuilds', guild, 'dGuilds')
};

View File

@@ -0,0 +1,23 @@
const { Schema, model } = require('mongoose');
const { safeLoad } = require('js-yaml');
const { readFileSync } = require('fs');
const conf = safeLoad(readFileSync('application.yml', { encoding: 'utf8' }));
const guild = new Schema({
guildId: { type: String, default: undefined },
prefix : { type: String, default: conf.discord.prefix },
locale : { type: String, default: conf.discord.locale }
});
const user = new Schema({
userId: { type: String, default: undefined },
prefix: { type: String, default: conf.discord.prefix },
locale: { type: String, default: conf.discord.locale }
});
module.exports = {
user : model('dUsers', user, 'dUsers'),
guild: model('dGuilds', guild, 'dGuilds')
};

View File

@@ -91,7 +91,7 @@ module.exports = class CommandRegistry {
uCache.push({ 'userId': msg.author.id, locale: user.locale ? user.locale : this.bot.conf['discord']['locale'], 'prefix': user.prefix, 'entryAge': Date.now() }); uCache.push({ 'userId': msg.author.id, locale: user.locale ? user.locale : this.bot.conf['discord']['locale'], 'prefix': user.prefix, 'entryAge': Date.now() });
} else { } else {
user = await this.bot.m.connection.collection('dUsers').findOne({ userId: msg.author.id }); user = await this.bot.m.connection.collection('dUsers').findOne({ userId: msg.author.id });
uCache.push({ 'userId': msg.author.id, locale: user.locale ? user.locale : this.bot.conf['discord']['locale'], 'entryAge': Date.now() }); uCache.push({ 'userId': msg.author.id, locale: user.locale ? user.locale : this.bot.conf['discord']['locale'], 'prefix': user.prefix, 'entryAge': Date.now() });
} }
}); });
} else user = uCache.filter((v) => v['userId'] === msg.author.id )[0]; } else user = uCache.filter((v) => v['userId'] === msg.author.id )[0];
@@ -99,7 +99,8 @@ module.exports = class CommandRegistry {
prefix = new RegExp([ prefix = new RegExp([
`^<@!?${this.bot.user.id}> `, `^<@!?${this.bot.user.id}> `,
`^${this.bot.conf['discord']['prefix'].replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')}`, `^${this.bot.conf['discord']['prefix'].replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')}`,
`^${guild && guild['prefix'] ? guild['prefix'].replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&') : this.bot.conf['discord']['prefix'].replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')}` `^${guild && guild['prefix'] ? guild['prefix'].replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&') : this.bot.conf['discord']['prefix'].replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')}`,
`^${user && user['prefix'] ? user['prefix'].replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&') : this.bot.conf['discord']['prefix'].replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')}`
].join('|')).exec(msg.content.toLowerCase()); ].join('|')).exec(msg.content.toLowerCase());
} else { } else {
guild = undefined; guild = undefined;

View File

@@ -75,8 +75,8 @@ if (conf['discord']['enabled']) {
print(2, `${cyan('Discord')} >> Creating client...`); print(2, `${cyan('Discord')} >> Creating client...`);
Discord = new DiscordClient(conf['discord']['token'], { Discord = new DiscordClient(conf['discord']['token'], {
webhook :{ webhook :{
token : conf['discord']['webhook']['token'] || undefined, token : conf['discord']['webhook'] ? conf['discord']['webhook']['token'] : undefined,
channel: conf['discord']['webhook']['channel'] || undefined channel: conf['discord']['webhook'] ? conf['discord']['webhook']['channel'] : undefined
}, },
clientOptions : { clientOptions : {

View File

@@ -10,7 +10,7 @@ module.exports = class WumpUtil {
const log = `tmp\\log\\${moment(new Date).format('DD[-]MM[-]YYYY')}.log`; const log = `tmp\\log\\${moment(new Date).format('DD[-]MM[-]YYYY')}.log`;
fs.mkdir('tmp', 777, (err) => { if (err && err.code !== 'EEXIST') throw err; }); fs.mkdir('tmp', 777, (err) => { if (err && err.code !== 'EEXIST') throw err; });
fs.mkdir('tmp\\log', 777, (err) => { if (err && err.code !== 'EEXIST') throw err; }); fs.mkdir('tmp/log', 777, (err) => { if (err && err.code !== 'EEXIST') throw err; });
switch (lvl) { switch (lvl) {
case 1 && conf['debug'] && conf['debug'] >= 1: case 1 && conf['debug'] && conf['debug'] >= 1: