Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Volcanic Ore Pack & fix errors with 2.4.0 osjs #5709

Merged
merged 18 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .env.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
TZ="UTC"
ROBOCHIMP_DATABASE_URL=postgresql://postgres:postgres@localhost:5436/robochimp_integration_test?connection_limit=1000
DATABASE_URL=postgresql://postgres:postgres@localhost:5435/osb_integration_test?pool_timeout=120&connection_limit=1000
PATREON_CAMPAIGN_ID=1234
PATREON_TOKEN=asdfasdfasdf
PATREON_WEBHOOK_SECRET=asdfasdfasdf
HTTP_PORT=7373
CLIENT_ID=111398433321891634
# PRISMA_CLIENT_ENGINE_TYPE=binary
6 changes: 5 additions & 1 deletion .github/workflows/integration_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@ jobs:
test:
name: Node v${{ matrix.node_version }} - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
matrix:
node_version: [18.12.0, 20]
os: [ubuntu-latest]

steps:
- name: Install System Packages
run: sudo apt-get install -y build-essential libpq-dev

- name: Checkout Project
uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node_version }}
Expand All @@ -37,6 +41,6 @@ jobs:
cp config.example.ts config.ts &&
popd
- name: Copy env
run: cp .env.example .env
run: cp .env.test .env
- name: Test
run: yarn test:integration
3 changes: 2 additions & 1 deletion .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ jobs:
test:
name: Node v${{ matrix.node_version }} - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
matrix:
node_version: [18.12.0, 20]
Expand All @@ -37,7 +38,7 @@ jobs:
cp config.example.ts config.ts &&
popd
- name: Copy env
run: cp .env.example .env
run: cp .env.test .env
- name: Generate Prisma Client
run: yarn gen
- name: Run ESLint on changed files
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ version: "3.9"
services:
osb:
image: postgres:13-alpine
command: -c 'max_connections=100'
command: -c 'max_connections=1000'
restart: always
container_name: osb_database
ports:
Expand All @@ -18,7 +18,7 @@ services:

robochimp:
image: postgres:13-alpine
command: -c 'max_connections=100'
command: -c 'max_connections=1000'
restart: always
container_name: robochimp_database
ports:
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"@fastify/sensible": "^5.2.0",
"@napi-rs/canvas": "0.1.38",
"@octokit/graphql": "^4.8.0",
"@oldschoolgg/toolkit": "^0.0.23",
"@oldschoolgg/toolkit": "^0.0.24",
"@prisma/client": "^5.10.2",
"@sapphire/stopwatch": "^1.4.0",
"@sapphire/time-utilities": "^1.6.0",
Expand All @@ -46,7 +46,7 @@
"murmurhash": "^2.0.1",
"node-cron": "^3.0.3",
"node-fetch": "^2.6.7",
"oldschooljs": "^2.3.8",
"oldschooljs": "^2.4.0",
"p-queue": "^6.6.2",
"piscina": "^4.3.2",
"random-js": "^2.1.0",
Expand All @@ -70,7 +70,7 @@
"@types/node-fetch": "^2.6.1",
"@typescript-eslint/eslint-plugin": "^5.41.0",
"@typescript-eslint/parser": "^5.41.0",
"@vitest/coverage-c8": "^0.31.0",
"@vitest/coverage-v8": "^1.3.1",
"concurrently": "^7.6.0",
"dotenv-cli": "^7.3.0",
"esbuild": "^0.19.5",
Expand All @@ -87,7 +87,7 @@
"rimraf": "^4.4.0",
"source-map-support": "^0.5.21",
"typescript": "5.0.2",
"vitest": "^0.31.0"
"vitest": "^1.3.1"
},
"engines": {
"node": ">=18.12.0"
Expand Down
5 changes: 2 additions & 3 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,6 @@ model User {
farmingPatches_flower Json? @map("farmingPatches.flower") @db.Json
farmingPatches_mushroom Json? @map("farmingPatches.mushroom") @db.Json
farmingPatches_belladonna Json? @map("farmingPatches.belladonna") @db.Json
kourend_favour Json? @map("kourend_favour") @db.Json

geListings GEListing[]
bingo_participant BingoParticipant[]
Expand Down Expand Up @@ -1013,10 +1012,10 @@ model GETransaction {

total_tax_paid BigInt

buy_listing GEListing @relation("buy_transactions", fields: [buy_listing_id], references: [id])
buy_listing GEListing @relation("buy_transactions", fields: [buy_listing_id], references: [id], onDelete: Cascade)
buy_listing_id Int

sell_listing GEListing @relation("sell_transactions", fields: [sell_listing_id], references: [id])
sell_listing GEListing @relation("sell_transactions", fields: [sell_listing_id], references: [id], onDelete: Cascade)
sell_listing_id Int

@@index([sell_listing_id])
Expand Down
12 changes: 2 additions & 10 deletions src/lib/MUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { GearSetup, UserFullGearSetup } from './gear/types';
import { handleNewCLItems } from './handleNewCLItems';
import backgroundImages from './minions/data/bankBackgrounds';
import { CombatOptionsEnum } from './minions/data/combatConstants';
import { baseUserKourendFavour, UserKourendFavour } from './minions/data/kourendFavour';
import { defaultFarmingContract } from './minions/farming';
import { FarmingContract } from './minions/farming/types';
import { AttackStyles } from './minions/functions';
Expand All @@ -35,7 +34,7 @@ import { SkillsEnum } from './skilling/types';
import { BankSortMethod } from './sorts';
import { defaultGear, Gear } from './structures/Gear';
import { ItemBank, Skills } from './types';
import { addItemToBank, assert, convertXPtoLVL, itemNameFromID, percentChance } from './util';
import { addItemToBank, convertXPtoLVL, itemNameFromID, percentChance } from './util';
import { determineRunes } from './util/determineRunes';
import { getKCByName } from './util/getKCByName';
import getOSItem, { getItem } from './util/getOSItem';
Expand Down Expand Up @@ -163,13 +162,6 @@ export class MUserClass {
});
}

get kourendFavour() {
const favour = this.user.kourend_favour as any as UserKourendFavour | null;
if (favour === null) return { ...baseUserKourendFavour };
assert(typeof favour.Arceuus === 'number', `kourendFavour should return valid data for ${this.id}`);
return favour;
}

get isBusy() {
return userIsBusy(this.id);
}
Expand Down Expand Up @@ -277,7 +269,7 @@ export class MUserClass {

async calcActualClues() {
const result: { id: number; qty: number }[] =
await prisma.$queryRawUnsafe(`SELECT (data->>'clueID')::int AS id, SUM((data->>'quantity')::int) AS qty
await prisma.$queryRawUnsafe(`SELECT (data->>'clueID')::int AS id, SUM((data->>'quantity')::int)::int AS qty
FROM activity
WHERE type = 'ClueCompletion'
AND user_id = '${this.id}'::bigint
Expand Down
5 changes: 2 additions & 3 deletions src/lib/Task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import { aerialFishingTask } from '../tasks/minions/HunterActivity/aerialFishing
import { birdHouseTask } from '../tasks/minions/HunterActivity/birdhouseActivity';
import { driftNetTask } from '../tasks/minions/HunterActivity/driftNetActivity';
import { hunterTask } from '../tasks/minions/HunterActivity/hunterActivity';
import { kourendTask } from '../tasks/minions/kourendFavourActivity';
import { mageArenaTwoTask } from '../tasks/minions/mageArena2Activity';
import { mageArenaTask } from '../tasks/minions/mageArenaActivity';
import { agilityArenaTask } from '../tasks/minions/minigames/agilityArenaActivity';
Expand Down Expand Up @@ -161,7 +160,6 @@ export const tasks: MinionTask[] = [
pickpocketTask,
questingTask,
monsterTask,
kourendTask,
vmTask,
templeTrekkingTask,
mageTrainingTask,
Expand Down Expand Up @@ -277,7 +275,8 @@ const ignored: activity_type_enum[] = [
activity_type_enum.BlastFurnace,
activity_type_enum.Easter,
activity_type_enum.HalloweenEvent,
activity_type_enum.Revenants
activity_type_enum.Revenants,
activity_type_enum.KourendFavour
];
for (const a of Object.values(activity_type_enum)) {
if (ignored.includes(a)) {
Expand Down
6 changes: 3 additions & 3 deletions src/lib/addXP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { sendToChannelID } from './util/webhook';

const skillsVals = Object.values(Skills);
const maxFilter = skillsVals.map(s => `"skills.${s.id}" >= ${LEVEL_99_XP}`).join(' AND ');
const makeQuery = (ironman: boolean) => `SELECT count(id)
const makeQuery = (ironman: boolean) => `SELECT count(id)::int
FROM users
WHERE ${maxFilter}
${ironman ? 'AND "minion.ironman" = true' : ''};`;
Expand Down Expand Up @@ -111,7 +111,7 @@ export async function addXP(user: MUser, params: AddXpParams): Promise<string> {
{
count: string;
}[]
>(`SELECT COUNT(*) FROM users WHERE "skills.${params.skillName}" >= ${LEVEL_99_XP};`);
>(`SELECT COUNT(*)::int FROM users WHERE "skills.${params.skillName}" >= ${LEVEL_99_XP};`);

let str = `${skill.emoji} **${user.badgedUsername}'s** minion, ${
user.minionName
Expand All @@ -125,7 +125,7 @@ export async function addXP(user: MUser, params: AddXpParams): Promise<string> {
count: string;
}[]
>(
`SELECT COUNT(*) FROM users WHERE "minion.ironman" = true AND "skills.${params.skillName}" >= ${LEVEL_99_XP};`
`SELECT COUNT(*)::int FROM users WHERE "minion.ironman" = true AND "skills.${params.skillName}" >= ${LEVEL_99_XP};`
);
str += ` They are the ${formatOrdinal(parseInt(ironmenWith.count) + 1)} Ironman to get 99.`;
}
Expand Down
8 changes: 4 additions & 4 deletions src/lib/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ export async function analyticsTick() {
const [numberOfMinions, totalSacrificed, numberOfIronmen, totalGP] = (
await Promise.all(
[
'SELECT COUNT(*) FROM users WHERE "minion.hasBought" = true;',
'SELECT SUM ("sacrificedValue") AS count FROM users;',
'SELECT COUNT(*) FROM users WHERE "minion.ironman" = true;',
'SELECT SUM ("GP") AS count FROM users;'
'SELECT COUNT(*)::int FROM users WHERE "minion.hasBought" = true;',
'SELECT SUM("sacrificedValue")::int AS count FROM users;',
'SELECT COUNT(*)::int FROM users WHERE "minion.ironman" = true;',
'SELECT SUM("GP") AS count FROM users;'
].map(query => prisma.$queryRawUnsafe(query))
)
).map((result: any) => parseInt(result[0].count)) as number[];
Expand Down
6 changes: 5 additions & 1 deletion src/lib/bankImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,11 @@
[i('Sanguinesti staff (uncharged)'), 'Unch.'],
[i('Scythe of vitur (uncharged)'), 'Unch.'],
[i('Holy scythe of vitur (uncharged)'), 'Unch.'],
[i('Sanguine scythe of vitur (uncharged)'), 'Unch.']
[i('Sanguine scythe of vitur (uncharged)'), 'Unch.'],

// Ore Packs
[27_019, 'GF Pack'],
[27_693, 'VM Pack']
]);

function drawTitle(ctx: SKRSContext2D, title: string, canvas: Canvas) {
Expand Down Expand Up @@ -370,7 +374,7 @@
}
}

async getItemImage(itemID: number, user?: MUser): Promise<Image> {

Check warning on line 377 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v18.12.0 - ubuntu-latest

'itemID' is already declared in the upper scope on line 22 column 8

Check warning on line 377 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v20 - ubuntu-latest

'itemID' is already declared in the upper scope on line 22 column 8
if (user && user.user.icon_pack_id !== null) {
for (const pack of ItemIconPacks) {
if (pack.id === user.user.icon_pack_id) {
Expand Down Expand Up @@ -399,7 +403,7 @@
}
}

async fetchAndCacheImage(itemID: number) {

Check warning on line 406 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v18.12.0 - ubuntu-latest

'itemID' is already declared in the upper scope on line 22 column 8

Check warning on line 406 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v20 - ubuntu-latest

'itemID' is already declared in the upper scope on line 22 column 8
const imageBuffer = await fetch(`https://chisel.weirdgloop.org/static/img/osrs-sprite/${itemID}.png`).then(
result => result.buffer()
);
Expand Down Expand Up @@ -476,7 +480,7 @@
}

getBgAndSprite(bankBgId: number = 1, user?: MUser) {
let background = this.backgroundImages.find(i => i.id === bankBgId)!;

Check warning on line 483 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v18.12.0 - ubuntu-latest

'i' is already declared in the upper scope on line 71 column 7

Check warning on line 483 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v20 - ubuntu-latest

'i' is already declared in the upper scope on line 71 column 7

const currentContract = user?.farmingContract();
const isFarmingContractReadyToHarvest = Boolean(
Expand All @@ -488,10 +492,10 @@

let backgroundImage = background.image!;
if (bankBgId === 29 && isFarmingContractReadyToHarvest) {
backgroundImage = this.alternateImages.find(i => i.bgId === 29)!.image;

Check warning on line 495 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v18.12.0 - ubuntu-latest

'i' is already declared in the upper scope on line 71 column 7

Check warning on line 495 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v20 - ubuntu-latest

'i' is already declared in the upper scope on line 71 column 7
}
if (bankBgId === 30 && isFarmingContractReadyToHarvest) {
backgroundImage = this.alternateImages.find(i => i.bgId === 30)!.image;

Check warning on line 498 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v18.12.0 - ubuntu-latest

'i' is already declared in the upper scope on line 71 column 7

Check warning on line 498 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v20 - ubuntu-latest

'i' is already declared in the upper scope on line 71 column 7
}

const hasBgSprite = Boolean(this.bgSpriteList[background.name.toLowerCase()]);
Expand Down Expand Up @@ -526,7 +530,7 @@

let xLoc = 0;
let yLoc = compact ? 5 : 0;
for (let i = 0; i < items.length; i++) {

Check warning on line 533 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v18.12.0 - ubuntu-latest

'i' is already declared in the upper scope on line 71 column 7

Check warning on line 533 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v20 - ubuntu-latest

'i' is already declared in the upper scope on line 71 column 7
if (i % itemsPerRow === 0) yLoc += floor((itemSize + spacer / 2) * (compact ? 0.9 : 1.08)) + verticalSpacer;
// For some reason, it starts drawing at -2 so we compensate that
// Adds the border width
Expand Down Expand Up @@ -573,17 +577,17 @@
bottomItemText = item.id.toString();
} else if (flags.has('names') || mahojiFlags?.includes('show_names')) {
bottomItemText = item.name;
} else if (mahojiFlags?.includes('show_weights') && weightings && weightings[item.id]) {

Check warning on line 580 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v18.12.0 - ubuntu-latest

Unexpected number value in conditional. An explicit zero/NaN check is required

Check warning on line 580 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v20 - ubuntu-latest

Unexpected number value in conditional. An explicit zero/NaN check is required
bottomItemText = weightings[item.id];
}

const forcedShortName = forcedShortNameMap.get(item.id);
if (forcedShortName && !bottomItemText) {

Check warning on line 585 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v18.12.0 - ubuntu-latest

Unexpected value in conditional. A boolean expression is required

Check warning on line 585 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v20 - ubuntu-latest

Unexpected value in conditional. A boolean expression is required
ctx.font = '10px Smallest Pixel-7';
bottomItemText = forcedShortName.toUpperCase();
}

if (bottomItemText) {

Check warning on line 590 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v18.12.0 - ubuntu-latest

Unexpected value in conditional. A boolean expression is required

Check warning on line 590 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v20 - ubuntu-latest

Unexpected value in conditional. A boolean expression is required
let text =
typeof bottomItemText === 'number' ? toKMB(bottomItemText) : bottomItemText.toString().slice(0, 8);
ctx.fillStyle = 'black';
Expand Down Expand Up @@ -617,7 +621,7 @@
// Filtering
const searchQuery = flags.get('search') as string | undefined;
const filterInput = flags.get('filter');
const filter = flags.get('search')

Check warning on line 624 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v18.12.0 - ubuntu-latest

Unexpected value in conditional. A boolean expression is required

Check warning on line 624 in src/lib/bankImage.ts

View workflow job for this annotation

GitHub Actions / Node v20 - ubuntu-latest

Unexpected value in conditional. A boolean expression is required
? filterableTypes.find(type => type.aliases.some(alias => filterInput === alias)) ?? null
: null;
if (filter || searchQuery) {
Expand Down
2 changes: 1 addition & 1 deletion src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ const globalConfigSchema = z.object({
clientID: z.string().min(15).max(25),
geAdminChannelID: z.string().default('')
});
dotenv.config({ path: path.resolve(process.cwd(), process.env.TEST ? '.env.example' : '.env') });
dotenv.config({ path: path.resolve(process.cwd(), process.env.TEST ? '.env.test' : '.env') });

export const globalConfig = globalConfigSchema.parse({
patreonToken: process.env.PATREON_TOKEN,
Expand Down
9 changes: 6 additions & 3 deletions src/lib/data/CollectionsExport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1488,7 +1488,12 @@ export const troubleBrewingCL = resolveItems([
'Red rum (trouble brewing)',
'Blue rum (trouble brewing)'
]);
export const volcanicMineCL = resolveItems(['Ash covered tome', 'Large water container', 'Volcanic mine teleport']);
export const volcanicMineCL = resolveItems([
'Ash covered tome',
'Large water container',
'Volcanic mine teleport',
'Dragon pickaxe (broken)'
]);
export const anglerOutfit = resolveItems(['Angler hat', 'Angler top', 'Angler waders', 'Angler boots']);
export const aerialFishingCL = resolveItems([
'Golden tench',
Expand Down Expand Up @@ -2265,8 +2270,6 @@ export const LMSBuyables: LMSBuyable[] = [
{ item: getOSItem('Guthixian icon'), cost: 500 },
{ item: getOSItem('Trouver parchment'), cost: 18 },
{ item: getOSItem('Wilderness crabs teleport'), cost: 1 },
{ item: getOSItem('Blighted bind sack'), quantity: 300, cost: 1 },
{ item: getOSItem('Blighted snare sack'), quantity: 150, cost: 1 },
{ item: getOSItem('Blighted entangle sack'), quantity: 70, cost: 1 },
{ item: getOSItem('Blighted teleport spell sack'), quantity: 50, cost: 1 },
{ item: getOSItem('Blighted vengeance sack'), quantity: 50, cost: 1 },
Expand Down
15 changes: 6 additions & 9 deletions src/lib/data/buyables/buyables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Bank } from 'oldschooljs';
import { QuestID } from '../../../mahoji/lib/abstracted_commands/questCommand';
import { chompyHats } from '../../constants';
import { CombatCannonItemBank } from '../../minions/data/combatConstants';
import { Favours } from '../../minions/data/kourendFavour';
import { MinigameName } from '../../settings/settings';
import { soteSkillRequirements } from '../../skilling/functions/questRequirements';
import { MUserStats } from '../../structures/MUserStats';
Expand Down Expand Up @@ -35,7 +34,6 @@ export interface Buyable {
itemCost?: Bank;
aliases?: string[];
skillsNeeded?: Skills;
requiredFavour?: Favours;
restockTime?: number;
minigameScoreReq?: [MinigameName, number];
ironmanPrice?: number;
Expand Down Expand Up @@ -203,8 +201,7 @@ const constructionBuyables: Buyable[] = [
},
{
name: 'Arceuus signet',
gpCost: 100_000,
requiredFavour: Favours.Arceuus
gpCost: 100_000
},
{
name: 'Ancient signet',
Expand Down Expand Up @@ -593,7 +590,7 @@ const questBuyables: Buyable[] = [
name: 'Berserker helm',
gpCost: 780_000,
qpRequired: 60,
ironmanPrice: 78_000
ironmanPrice: 98_000
},
{
name: 'Archer helm',
Expand Down Expand Up @@ -795,7 +792,7 @@ const Buyables: Buyable[] = [
{
name: 'Bucket',
gpCost: 30,
ironmanPrice: 5
ironmanPrice: 10
},
{
name: 'Cup of hot water',
Expand Down Expand Up @@ -891,7 +888,7 @@ const Buyables: Buyable[] = [
{
name: 'Steel pickaxe',
gpCost: 2000,
ironmanPrice: 500
ironmanPrice: 600
},
{
name: 'Mithril pickaxe',
Expand Down Expand Up @@ -961,7 +958,7 @@ const Buyables: Buyable[] = [
{
name: 'Adamant halberd',
gpCost: 100_000,
ironmanPrice: 9600,
ironmanPrice: 50_000,
qpRequired: 150,
skillsNeeded: soteSkillRequirements
},
Expand Down Expand Up @@ -1116,7 +1113,7 @@ for (const cape of allTeamCapes) {
Buyables.push({
name: cape.name,
outputItems: new Bank().add(cape.id),
gpCost: 5000
gpCost: 15_000
});
}

Expand Down
Loading
Loading