#development

1 messages · Page 225 of 1

lyric mountain
#

Apis only need to be flexible enough so that the implementor can do some minimal filtering to alleviate payload size

sharp geyser
#

Fair enough

lyric mountain
#

Anything more will be done by them

sharp geyser
#

because in reality I am the only one working on it

#

null helps where she can

wheat mesa
#

Keep in mind that your API is not meant to be public

sharp geyser
#

and I appreciate it

#

but shes busy as well most of hte time

#

😭

wheat mesa
#

So a super efficient design might not be necessary

lyric mountain
wheat mesa
#

You can optimize as you need

#

Benchmark for what you expect the use cases to be, if it doesn’t meet your expectations, then you can redesign

sharp geyser
#

My biggest problem is I am overthinking the auth system.

#

I don't know how to actually implement an auth system

wheat mesa
#

Just use google oauth

#

Honestly

sharp geyser
#

I've done small ones for public apis to make sure people aren't spamming it

sharp geyser
wheat mesa
#

Sure you can

sharp geyser
#

How so?

wheat mesa
#

Look for .edu emails

#

I’m sure there’s a scope to access their email address

sharp geyser
#

do colleges use gmail?

wheat mesa
lyric mountain
#

Mostly Microsoft

#

For ofice365

wheat mesa
#

Obviously just checking for a .edu isn’t foolproof, but it’s a good start

wheat mesa
sharp geyser
#

Does microsoft have oauth2 capabilities?

wheat mesa
#

Yes absolutely

sharp geyser
#

Wasn't sure because I honestly dont remember sites using microsoft as oauth2

#

well then I can just use microsoft oauth2

#

It's a higher chance that colleges will use microsoft than google tbh

#

since office365 is a thing (as haku pointed out)

wheat mesa
#

And remember if u need me to test it for you I got you

sharp geyser
#

Im just wondering is rust the appropriate language to write the backend in?

lyric mountain
#

Or just implement both, it's an option too

sharp geyser
#

Or is that in itself overkill

wheat mesa
#

I actually have two .edu addresses you can test with

lyric mountain
#

You just need to bind their email to a token

sharp geyser
#

but micorosoft first

lyric mountain
#

Aight

sharp geyser
#

since its the most likely

#

Once one is implemented the other is easier

lyric mountain
#

Oauth2 is a standard, so you'd just flip some addresses

sharp geyser
#

or is it overkill

#

rust's web frameworks are kind of spread out and all offer different things

#

using something like C# that has a fleshed out web framework (ASP.NET) is likely the smarter/safer option right?

wheat mesa
#

Languages are merely a tool

sharp geyser
#

Indeed

wheat mesa
#

If you wish to use a different tool because you feel the current one doesn’t fit, then feel free

#

But if you keep switching tools you’ll have to learn how to use new tools

sharp geyser
#

yea

#

I don't know val_WaaGone

#

Rust is a good option imo, but the frameworks themselves are kind of meh

#

I want to pick something that is right for the job and will be smoother sailing

lyric mountain
#

Well, java?

sharp geyser
#

💀

#

I really don't want to learn java

lyric mountain
#

I mean, u already know c#, they're the same really

sharp geyser
#

know is a strong word

#

I know enough to get around

lyric mountain
#

But anything with REST capability will suffice

sharp geyser
#

I honestly just dislike the lack the OOP nature of rust when it comes to a backend api

#

it has offered many challenges imo

#

largely due to me not being very familiar with it entirely

wheat mesa
sharp geyser
#

using it for a backend api tho?

wheat mesa
#

There’s like a grand total of 4 “advanced” things in Java and they’re not important to know for building a rest api

sharp geyser
#

Idk how to do that

wheat mesa
sharp geyser
#

im sure its capable to do it

wheat mesa
#

It’s very good at writing REST APIs and backend server applications

sharp geyser
#

I just dont know how

lyric mountain
#

Guides will tell u to use springboot, but I digress, do not

#

Javalin and vertx are pretty much better in every way possible if u just want a REST framework

#

Spring comes too bloated and too obscured

#

Vertx is much more low level, but it's faster

#

Javalin is more friendly

#

Both have similar configuration and usage, so u can hop from one another without much fuzz

sharp geyser
#

at this point im down to try anything

#

because as it stands now i haven't worked on CC in like weeks

lyric mountain
#

Vertx iirc scored 3rd or 4th among all rest frameworks regarding throughput

sharp geyser
#

if I use java tho I really will be working on it alone

#

Idk how much java null knows

lyric mountain
#

Null? Null just published a java library no?

sharp geyser
#

oh right she is isn't she

#

Also

#

Maven or Gradle

#

When I used java I preferred maven

#

but idk

lyric mountain
#

Maven for libraries, gradle for projects

#

But u can use whichever u prefer

#

They don't matter much, they're just developer preference

#

For jvm you'll use graalvm, so you can build a native image for the api

sharp geyser
#

graalvm?

lyric mountain
#

Openjdk, openj9, oraclevm, graalvm, etc

#

They're jvm implementations

sharp geyser
#

ic

#

how do I install this graalvm

lyric mountain
#

Depends, how do you usually install java?

#

If u use intellij it'll be one of the options in the dropdown menu, if u use sdkmann u can choose it too

sharp geyser
#

I installed java through homebrew

lyric mountain
sharp geyser
#

thanks

#

ima try and get this working real quick

#

get a quick api test

lyric mountain
sharp geyser
#

ty

sharp geyser
#

I was thinking of using javalin first seeing how it feels

lyric mountain
#

I used both, javalin is easier

#

Vertx uses a weird pipe-like method of passing requests donwstream, not anything too bad but still a bit odd

sharp geyser
#

Do I need to do anything here

#

?

lyric mountain
#

Personally I prefer groovy for dsl

#

But that's just cuz I'm used to it

#

Just click next

sharp geyser
lyric mountain
#

Yes

#

Oh wait

#

Yeah go back to jdk 21

#

It's the lts

sharp geyser
#

bro wtf

lyric mountain
#

Lmao what

#

Install it through intellij

#

Since u have it already

#

Click on the dropdown, then "add version"

sharp geyser
lyric mountain
#

Tho idk why the brew came damaged

#

Yes

sharp geyser
#

ok

#

its doing its thing

#

macbook sounds like a leaf blower

lyric mountain
#

First run to build the indexes lul

sharp geyser
#
plugins {
    id("java")
}

group = "org.example"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    testImplementation(platform("org.junit:junit-bom:5.10.0"))
    testImplementation("org.junit.jupiter:junit-jupiter")
}

tasks.test {
    useJUnitPlatform()
}
#

right do i need to do anything here?

lyric mountain
#

You'll add the dependency line to the block at the bottom

#

Those junit things u can remove tbh, unless u plan on doing unit tests later

#

If u do remove, then also remove the tasks.test block

sharp geyser
#

gotcha

#

should i change group at all?

lyric mountain
#

Yes

#

That'd should be ur domain, reversed

sharp geyser
#

icic

lyric mountain
#

Or anything u feel like putting, it matters mostly if you publish a lib

sharp geyser
#

right so I added that javalin dep

#

so ima rebuild it

lyric mountain
#

Click the floating elephant

#

To fetch the deps

sharp geyser
#

Should I del test ?

lyric mountain
#

Yes

#

If u did delete junit

sharp geyser
#

what is resources

lyric mountain
#

Resources is anything that's not java code

#

Assets, sql files, keystores, locale, etc

#

Anything that you feel that should be packed together with the output jar

sharp geyser
#

icic

#

that's neat

lyric mountain
#

Oh btw, remember never to put code right inside java folder

#

Always put inside a package with the same name u put in group

#

com.misty for example

#

If u put code as direct children to the root it'll be in unnamed package

sharp geyser
#
package io.collegecrafts;

public class Main {
    public static void Main(String[] args)
    {
        System.out.println("Hello, World");
    }
}

is his not a valid java class

#

I guess lowercase main

#

yea

#

intellij recognizes the entrypoint now

#
12:46:02 AM: Executing ':Main.main()'...

> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes

> Task :Main.main()
Hello, World

Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.

You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.

For more on this, please refer to https://docs.gradle.org/8.5/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.

BUILD SUCCESSFUL in 8s
2 actionable tasks: 2 executed
12:46:11 AM: Execution finished ':Main.main()'.

Should I be worried about that deprecated thing?

lyric mountain
#

Classes PascalCase, methods/variables camelCase yeah

lyric mountain
sharp geyser
#

So its not something I can fix rn?

lyric mountain
#

Java libs usually give u a warning looooong before they make a breaking change so u can prepare

#

The don't just break on a minor release

lyric mountain
#

If you pass --warning-mode all arg to it it'll show u what's the issue

#

Usually verbose

sharp geyser
#

oh all I did was use the runner in the thing

#

idk how to run the project without it

lyric mountain
#

U can edit the args for it

#

Click the 3 dots next to the green button middle top of the ide

#

But don't bother with it for now, it'll be fine till they release gradle 9

sharp geyser
#

ok

#

Well

#

time to try and make a test api

#

also the docs for javalin look better than 90% of the docs I saw for java libs

lyric mountain
#

Oh btw, I don't remember if it comes by default

#

But you might need to force intellij to pull javadocs

#
idea {
    module {
        downloadJavadoc = true
        downloadSources = true
    }
}
#

Put at the end of the build.gradle file

#

Then add id('idea') at the top inside plugins block

sharp geyser
#
SLF4J(W): No SLF4J providers were found.
SLF4J(W): Defaulting to no-operation (NOP) logger implementation
SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details.

#########################################################################
Javalin: It looks like you don't have a logger in your project.
The easiest way to fix this is to add 'slf4j-simple':

pom.xml:
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>2.0.10</version>
</dependency>

build.gradle or build.gradle.kts:
implementation("org.slf4j:slf4j-simple:2.0.10")
#

this is helpful

lyric mountain
#

That's cuz u don't have any logger implementation

sharp geyser
#

its erroring out

lyric mountain
#

U can add the suggestion at the bottom to dependencies

sharp geyser
#

I was saying the error was helpful

lyric mountain
sharp geyser
#

Cannot access 'downloadJavadoc': it is private in 'IdeaModule'

lyric mountain
#

Hm, are u using kotlin dsl?

sharp geyser
#

yes

#

you told me to just hit next

lyric mountain
#

Then it's different

#

Add parentheses to it

#

I think

sharp geyser
#

add parentheses to what exactly

lyric mountain
#

DownloadJavadocs

#

And the one below

#

Idk how it is with kotlin

sharp geyser
#

should I just swap to groovy

lyric mountain
#

Just delete that block and see if ctrl + space has descriptions for autocomplete

#

If it does then u don't need it

#

It's cuz sometimes intellij doesn't pull javadocs, so u end up with empty documentation

#

That block is to force it

sharp geyser
#

idk what im looking at

#

I pressed ctrl space and a menu came up with a bunch of options

lyric mountain
#

Well, let's not confuse u unnecessarily, delete that block and the plugin at the top

#

If u ever find yourself missing the description of methods it's cuz it didn't fetch the docs

#

Then we can act on it

#

It doesn't happen always

mighty scroll
#

I just don't understand discord...it's almost 3th day when we get timeout because of CF and still nothing clear when we will get access.

lyric mountain
#

Did u keep trying?

mighty scroll
#

No...i just turned everything off since yesterday

lyric mountain
#

How do u know u don't have access?

mighty scroll
#

cause when i try to return something i get "error code: 1015"

lyric mountain
#

What's the error body?

sharp geyser
#

It works :)

lyric mountain
#

If it's a ban then it should contain the time left till the restriction is lifted

lyric mountain
mighty scroll
lyric mountain
#

Lemme check what's that status

#

Yeah ratelimit

#

Are u truly sure there's no error body?

#

When I was ratelimited they did supply the info regarding expiry

mighty scroll
#

Ratelimit it's different, but i have this project for over 6 years

#

Never got ratelimited, never got CF ban

lyric mountain
#

Ratelimite from cloudflare

mighty scroll
lyric mountain
#

It's what u call cf ban

lyric mountain
mighty scroll
#

It's not a rate limit, cause if you move to another IP you can continue to make request

lyric mountain
#

It's an IP ratelimit

#

It's bound to ur ip, not account

#

As it's coming from cf not discord

sharp geyser
#

I guess its time to google what CRUD is

lyric mountain
#

Create read update delete

pearl trail
#

i did a little trolling (iykyk) and got cf banned KEK

#

only few hours

lyric mountain
#

Aka regular rest operations

mighty scroll
lyric mountain
sharp geyser
lyric mountain
#

I'm asking because I'm 100% sure they do send the expiration, it'll tell u how long u need to wait

#

If anything do a simple me request, it's GET so guaranteed to have a body of some sort

lyric mountain
#

Rest + websockets + auth + anything else

#

Welp, gtg now, too late already

#

Cya in 8 hours, gn

sharp geyser
#

gn

#

ty

#

Ima try and figure this out now

#

ty for the help

sharp geyser
compact pier
#

what is faster?

number+""

or

number.toString()
harsh nova
#

Probably .toString() but the difference is probably too small to matter all that much

frosty gale
frosty gale
#

.toString seems to be 40% faster but my benchmark might be wrong

civic scroll
#

2 instructions less

#

tip: do not rely on implicit cast (what if future runtimes throws an error on mismatched types?)

#

and if you want to join multiple strings together, if space allows, use template literals

`... And here the number ${number}`;
lyric mountain
#

Depends

#

For my api I use raw sql requests through jdbc

#

But with hikari as the connection pooler

#

Java has jpa too, but depending on your usecase it might be too much overhead for little advantage

#

It's an orm

sharp geyser
lyric mountain
#

jdbc by default is single connection

sharp geyser
#

ic

lyric mountain
#

I mean, not even by default, it must be

sharp geyser
#

I will have to check out pooling at a later date, for now its fine

lyric mountain
#

as jdbc is a direct driver, nothing in-between

sharp geyser
#

ic

#

So if I wanted pooling I would have to do that myself or use another library?

lyric mountain
#

you can do either, I prefer to let a lib handle that as there's too many little details that matter

sharp geyser
#

I know pooling is something I will need at a later date

lyric mountain
#

luckily for u java has standards, so as long as u have a connector class, you dont need to change anything outside of it

sharp geyser
#

but idk if its worth swapping to another lib now or waiting

lyric mountain
#

all connection poolers are required to give your a Connection instance

#

which is what u use already

sharp geyser
#

icic

#

so its hardly any change for me

#

I think for now to avoid any confusion Ima just stick with it how it is now mmLol

#
package io.collegecrafts;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class DatabaseConfig {
    private static final Properties properties = new Properties();

    static {
        try (InputStream input = DatabaseConfig.class.getClassLoader().getResourceAsStream("db.properties")){
            if (input == null)
            {
                System.out.println("Sorry, unable to find db.properties");
                System.exit(1);
            }

            properties.load(input);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static String getDbUrl() {
        return properties.getProperty("db.url");
    }

    public static String getDbUsername() {
        return properties.getProperty("db.username");
    }

    public static String getDbPassword() {
        return properties.getProperty("db.password");
    }
}
#

idk if this is appropriate tho

#

its something some tutorial told me to do

lyric mountain
#

fuck, discord hates intellij indent

sharp geyser
lyric mountain
#

sec, I'll format it

#
package com.kuuhaku.controller;

import com.kuuhaku.Main;
import com.zaxxer.hikari.HikariDataSource;

import java.sql.Connection;
import java.sql.SQLException;

public abstract class Manager {
    private static final String SERVER_IP = System.getenv("SERVER_IP");
    private static final String DB_NAME = System.getenv("DB_NAME");
    private static final String DB_LOGIN = System.getenv("DB_LOGIN");
    private static final String DB_PASS = System.getenv("DB_PASS");

    private static final HikariDataSource ds = new HikariDataSource();

    static {
        ds.setDriverClassName("org.postgresql.Driver");
        ds.setJdbcUrl("jdbc:postgresql://%s/%s?currentSchema=shiro&sslmode=require&useEncoding=true&characterEncoding=UTF-8".formatted(
            SERVER_IP, DB_NAME
        ));
        ds.setUsername(DB_LOGIN);
        ds.setPassword(DB_PASS);
        ds.setMaximumPoolSize(20);

        String db = DAO.queryNative(String.class, "SELECT current_database()");
        String schema = DAO.queryNative(String.class, "SELECT current_schema()");
        Main.LOGGER.info("Connected to database {}, schema {} successfully", db, schema);
    }

    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    public static long ping() {
        long curr = System.currentTimeMillis();

        DAO.queryUnmapped("SELECT 1");

        return System.currentTimeMillis() - curr;
    }
}
#

removed the license header so I can send it as a message

#

basically all I do to get a connection instance is call Manager.getConnection()

#

if I ever wanted to change pooling lib, it'd be a change only on that class

#

the rest of the code will still use whatever connection I return there

sharp geyser
#

iara_nod thats smart

lyric mountain
#

dont worry abt the long af string, that's just me passing query params to the connection

#

tho I do recommend using them too, it's mostly to make sure all goes well

#

especially the encoding ones

sharp geyser
#

you set the url twice?

lyric mountain
#

oh

#

must've cloned it during paste

#

also nevermind the DAO calls, that's my data access class, I've abstracted much of the sql handling

#

I bring that class with me on whatever project I work on if it uses a database

sharp geyser
#

lol

#

well I appreciate the information!

#

Ima head back to bed tho im tired

lyric mountain
#

just remember to ALWAYS use the connection like this ```java
try (var conn = Manager.getConnection()) {
...use it here
}

#

this ensures whatever happens it'll close the connection

sharp geyser
#

ok :)

lyric mountain
quartz kindle
quartz kindle
quartz kindle
#

but i think they fixed that already

#
function a(n) { return n.toString(); } a(1);
   25 S> 0000037EC4D18190 @    0 : 2f 03 00 00       GetNamedProperty a0, [0], [0]
         0000037EC4D18194 @    4 : c9                Star0
   25 E> 0000037EC4D18195 @    5 : 60 f9 03 02       CallProperty0 r0, a0, [2]
   36 S> 0000037EC4D18199 @    9 : ae                Return

function a(n) { return n+''; } a(1);
   16 S> 00000185EB598190 @    0 : 13 00             LdaConstant [0]
   24 E> 00000185EB598192 @    2 : 3b 03 00          Add a0, [0]
   28 S> 00000185EB598195 @    5 : ae                Return

function a(n) { return ''+n; } a(1);
   16 S> 0000015A25718190 @    0 : 13 00             LdaConstant [0]
         0000015A25718192 @    2 : c9                Star0
         0000015A25718193 @    3 : 0b 03             Ldar a0
   25 E> 0000015A25718195 @    5 : 3b f9 00          Add r0, [0]
   28 S> 0000015A25718198 @    8 : ae                Return

function a(n) { return `${n}`; } a(1);
   16 S> 00000257F63D8178 @    0 : 0b 03             Ldar a0
         00000257F63D817A @    2 : 7b                ToString
   30 S> 00000257F63D817B @    3 : ae                Return

function a(n) { return String(n); } a(1);
   16 S> 0000019055E98190 @    0 : 21 00 00          LdaGlobal [0], [0]
         0000019055E98193 @    3 : c9                Star0
   23 E> 0000019055E98194 @    4 : 65 f9 03 02       CallUndefinedReceiver1 r0, a0, [2]
   33 S> 0000019055E98198 @    8 : ae                Return
``` @frosty gale@civic scroll@compact pier
civic scroll
#

thanks

civic scroll
quartz kindle
#

tbh we dont know the performance characteristics of these instructions so its not guaranteed that less instructions = faster

civic scroll
#

if you can expand it more

#

if only i'm not lazy to go through v8 code

quartz kindle
#

i wouldnt understand v8 code if i went through it

#

:^)

civic scroll
#

:^)

real rose
#

:^)

sharp geyser
#

yea uhm dont do it yourself

#

unless you want to

#

which you can totally do

#

I just don't like doing oauth without help in rust

#

if you want something quick and easy use that

#

if not 100% do it yourself, its just a slightly more challenging thing to do

#

depending on the lib you use ofc for the web framework

frosty gale
lyric mountain
#

very carefully

quartz kindle
#

there is also --print-code which is much more detailed but has no filter function, so it dumps the entire node runtime

frosty gale
#

would be cool if you could write js bytecode by hand and then run it

#

you basically got yourself java but the light version

lyric mountain
#

wait till u find out about java native images

civic scroll
#

abstraction exists for a reason

#

you are defeating it

lyric mountain
#

sayu sayu, good thing ur here

#

I need your css witchcraft, how should I approach on making a pure html/css carousel?

#

I'm used to making animated things, but never did something interactable

quartz kindle
#

also js bytecode is not standarized, its v8 specific internals and they change instruction names and shit between versions

quartz kindle
#

an acquaintance of mine wants to get a new laptop, she's interested in a used 2021 macbook pro for 600 bucks she saw in a shop

#

she wants me to remote access it and download pirated adobe software on it, while she is in their shop, to make sure it works before she buys it

#

lmao

lyric mountain
#

minecraft modders: "we can mixin"

sharp saddle
lyric mountain
#

that's fairly easy, you just need to use topgg webhook

quartz kindle
#

do like the example shows

#

for node.js / javascript:

earnest phoenix
#

ما هاذا

#

يسطا اقولو انا ؟ @earnest phoenix

deft wolf
#

You need to make it

earnest phoenix
deft wolf
earnest phoenix
#

Also He want when someone make a vote to the bot the bot give him money such as froz

#

@deft wolf

#

يسطا ادية السكربت وقولو يعملة لينا

quartz kindle
earnest phoenix
#

@earnest phoenix يسطا فية Webhooks في الاختيارات عندك شوف

#

خد ليهم سكرين

quartz kindle
#

authorization = you invent one, like a password, you create

#

webhook url = your bot hosting ip and port

earnest phoenix
#

Which is the important form them

#

@quartz kindle

neon leaf
#

lol

deft wolf
quartz kindle
#

webhook url = bot hosting ip address and port number

#

where is your bot hosted?

#

like server, vps

earnest phoenix
quartz kindle
#

hosting name?

earnest phoenix
#

bot-hosting

#

i can't write it as link

quartz kindle
#

.net?

earnest phoenix
#

How he can get the port and a ip address

#

and Auth

solemn latch
#

You make up the auth

#

dj-9awdnasipdnai[0qjwnamipdna

#

could be your auth

lyric mountain
#

just make it something not too predictable, as this is the only thing you can use to check if the request is indeed coming from topgg

quartz kindle
#

yes

earnest phoenix
#

Now how can he connect the script with the top.gg web

quartz kindle
#

webhook url = de1.bot-hosting.net:20677/webhook
(port number correct?)

earnest phoenix
#

احم

#

انا غلطان اني بساعد Cry

quartz kindle
#

yes

#

auth = abc
Webhook("abc")

neon leaf
#

wtf

#

i just noticed there are no line breaks in discord code blocks anymore (or whatever its called)

solemn latch
#

Its anything you want, just like coming up with a password for an account. You decide what it should be

quartz kindle
#

any

#

example: hahahamyauth123

solemn latch
#

Looks like you're just putting your URL as your auth. Which isn't secure.

quartz kindle
#
.post(
   "/webhook",
   ...
#

no ...

#

was only example

#

yes its ok

deft wolf
#

what about port 3000?

quartz kindle
#

this authorization yes?

quartz kindle
quartz kindle
#

mb

#

u right

#

yes

#

no

#

webhook url = de1.bot-hosting.net:20677/webhook

#

example:
Authorization = hahaha123

new Topgg.Webhook("hahaha123");
#

yes

#

bot index.js?

#

click save, then click send test

#

see bot logs/console

#

clicked send test?

#

console.log(vote)

#

restart bot

#

send test

#

yes

lyric mountain
#

Authorization doesn't need to be an url

#

But you must not show it like that, as anyone with it can send fake requests to your endpoint

#

Meaning people can get infinite votes by just sending simple requests

#

So change it, and don't show anyone

quartz kindle
#

see logs again

#

i make test vote

#

good

#

work

#

click topgg send test again

#

topgg broken

#

haha

#

click save, reload page, click send test again

lyric mountain
#

Is it really expect or except?

solemn latch
#

Its possible it has to do with the auth. Its uncommon but I've seen a special character break things.

quartz kindle
#

show topgg auth

quartz kindle
lyric mountain
#

Send tests works for me

#

I did write the request handler myself tho

#

Eh, passing the error as a param makes it look like ur expecting that value (the error msg)

#

No I'm not, don't want to get tetanus tyvm

quartz kindle
#

hmmm, is ok

#

try change authorization

solemn latch
quartz kindle
#

is it failing on topgg's side?

#

my test work

#

but topgg test not work

solemn latch
quartz kindle
#

topgg broken

#

:^)

#

its ok, try real vote, not test

#

ah one more thing

#

try add http://

#

http://de1.bot-hosting.net:20667/webhook

#

test

quartz kindle
lyric mountain
#

Nope

#

Taking lunch

#

I meant they work for my bot

quartz kindle
#

who is sending him tim321 then lmao

lyric mountain
#

Woo manifest yourself

solemn latch
#

I'm not sending request 😄

quartz kindle
#

lmao

#

then i dont know, topgg bad

#

try reload topgg and send test again

#

maybe test in different browser

#

i dont know

#

try with real vote

#

send your bot page, i can try vote

#

console log?

solemn latch
#

Show code again?

quartz kindle
solemn latch
quartz kindle
#

rip

solemn latch
#

Privacy and security :/

#

We hate security topggAngry

quartz kindle
#

the only thing i can think of is that his topgg settings are either wrong or not saved correctly

#

show topgg settings again

solemn latch
#

I could add the settings to my test bot page and send a test vote.

quartz kindle
#

sure

solemn latch
#

Any chance domain they're using is reverse proxied?

#

IE its https

#

No derp

solemn latch
#

Log worked?

quartz kindle
#

on that domain

solemn latch
#

show?

quartz kindle
#

show log

solemn latch
#

So, my test vote didnt work

quartz kindle
#

woo will make a test

solemn latch
quartz kindle
#

it worked

#

show your topgg webhook settings

#

ah

solemn latch
#

Figured it out? 👀

quartz kindle
#

yes

#

20677

solemn latch
#

lol

#

Well, good stuff tim

quartz kindle
#

actually it was my fault, i scrolled back up and it was my typo and he copied that

#

good

#

it works now

solemn latch
#

😄

quartz kindle
#

hahaha

#

example for DM

client.users.cache.get(vote.user).send("you got 100 coins")
#

for coins, what database you use?

#

then maybe database[vote.user].coins += 100 ?

#

show your code

#

index.js

#

yes

#

pastebin

#

ok

solemn latch
#

Got a minute @quartz kindle ?

I'm still not sure how I want to handle a queue/ratelimit system for Discord webhooks.

I cant really use Bull or other queue systems because their queues an overall queue. I'd have to make a bull queue for each webhook ID.

a set for each webhook request

redisClient.sadd(`queued_webhooks:${webhookId}`, `webhookRequest:webhookv1:${entity.entity_id}:${user.user_id}`);

Then the ratelimit data like this

redisClient.hset(`rate_limit_data:${id}`, {
    limit,
    remaining,
    reset,
  });

I'm not sure if any of that makes sense 👀
The actual webhook data is in its own hash(webhookRequest:webhookv1:${entity.entity_id}:${user.user_id})

quartz kindle
#

put webhook code in the end of index.js

#
client.once('ready', () => {
    console.log('Bot is ready!');
});

app.post(
   "/webhook",
  webhook.listener(async (vote) => {
    const userId = vote.user;
    const user = client.users.cache.get(userId);
    const reward = 100;

    if(!balances.has(userId)) {
      balances.set(userId, 0);
    }
    balances.set(userId, balances.get(userId) + reward);
    saveBalances();
    
    // send message
    await user.send("you got 100 coins");
  })
);

app.listen(20677);
quartz kindle
#

you add requests into a redis queue right?

#

then somewhere you consume them while checking rate limits

#

the id for the rate limit should be webhookid+webhooktoken+bucketid

#

since if any of those 3 components change, the ratelimits are different

#

as far as i understand

solemn latch
quartz kindle
#

redis has a lot of things, including pub sub event messages and stuff

solemn latch
quartz kindle
#

im a teapot best http message

#

the dm message? no

#

you can make ```js
.send(you got ${reward} coins);

#

is automatic yes

#

balance code

sharp geyser
#

@lyric mountain where and what should I put my db creds in? A guide told me a .properties file but idk KEKW

#

I also assume the resources folder

quartz kindle
#

what work? make test vote and see balance

lyric mountain
#

but u can put on .properties too, tbh anything will do, that file shouldn't be uploaded with ur project anyway

sharp geyser
#

icic

#

and where should I put it?

#

resources?

#

or outside of the src

lyric mountain
#

wherever you'll start your api

#

like, I like to use a bash script to execute the code

sharp geyser
#

arent I building a native image?

lyric mountain
#
export SOME_VAR='value'

./gradlew run
sharp geyser
#

so dont I need it to be bundled with it?

lyric mountain
#

then i can System.getenv("SOME_VAR")

lyric mountain
#

that file should only exist on your machine

#

in a way that, even if someone got your project sources, they cant get the values

#

like .env

sharp geyser
#

what exactly do you mean by native image with graalvm?

#

like a .exe or a unix executable?

lyric mountain
#

graalvm can compile a jar down to a literal executable

#

yes

sharp geyser
#

right

lyric mountain
#

it can AOT compile

sharp geyser
#

so if I use a .env or .properties file

#

how does it still know what values to use?

#

ig the easiest thing to use would be .env

lyric mountain
#

if u use System.getenv(), it'll get from the environment variables

sharp geyser
#

as idk how it'd find the .properties file

lyric mountain
#

if you use anything else, u can grab a file from within runtime normally like any other lang

#

./.properties for example

#

would get a file named .properties on the same folder

sharp geyser
#

ic

lyric mountain
#

only put inside resources what you want to bundle with the jar

#

u dont want to bundle ur credentials

sharp geyser
#

So what if I don't want want to use a shell script to run my project

#

I want to just use a .env file

#

will it be able to find those values or do I have to load them somehow

#

kind of like what dotenv does in nodejs / rust

#

if it didn't work show errors you got or something

#

saying "not work" doesn't help the person helping you

#

why are you pinging them repeatedly

lyric mountain
#

u can get a file with new File("./path/to/file")

sharp geyser
lyric mountain
#

./ prefix means same folder as the jar/binary

sharp geyser
#

ye

lyric mountain
#

just make sure to check if the file exists, in case u forgor

quartz kindle
#

logs? errors? show code

lyric mountain
#
var file = new File("./path/to/file");
if (!file.exists() || file.isDirectory()) {
  System.out.println("File doesn't exist or is a folder");
  System.exit(1);
}
#

also refrain from using system.out

#

use the logger instead

sharp geyser
#

right

#

but how does this help with a .env file

lyric mountain
#

yes, u can Files.readAllLines(file)

sharp geyser
#

doesnt this defeat the purpose of a .env file

#

I thought the entire point was to load it to the env and get it with System.getenv

lyric mountain
#

the purpose of it is to have your credentials outside your code

lyric mountain
#

not from a .env file

sharp geyser
#

.env is supposed to be for your env variables though no?

lyric mountain
#

only in node

sharp geyser
#

thats dumb

lyric mountain
#

in java we use the actual environment variables

#

tho u can ofc use it too, java can parse properties files (which is the format .env uses)

#
var env = new Properties();
try (var stream = Files.newInputStream(Path.of("./path/to/file"))) {
  env.load(stream);
}
#

then u can env.getProperty("key")

#

put the try so u dont leave the stream open

sharp geyser
# lyric mountain put the try so u dont leave the stream open
package io.collegecrafts;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class DatabaseConfig {
    private static final Properties properties = new Properties();
    private static final Logger log = LoggerFactory.getLogger(DatabaseConfig.class);

    static {
        try (InputStream input = DatabaseConfig.class.getClassLoader().getResourceAsStream("db.properties")){
            if (input == null)
            {
                log.error("Could not find properties file");
                System.exit(1);
            }

            properties.load(input);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static String getDbIp() {
        return properties.getProperty("db.ip");
    }

    public static String getDbUsername() {
        return properties.getProperty("db.username");
    }

    public static String getDbPassword() {
        return properties.getProperty("db.password");
    }
}
```?
eternal osprey
#

hey guys, i have around 8tb worth of html data of various different sites. Does anyone know any type of anaylsis i can perform on it? I am not that creative

sharp geyser
#

Uhm

#

dont?

lyric mountain
eternal osprey
#

it's for a project, i have to

lyric mountain
#

and you cant put your credentials inside it

sharp geyser
lyric mountain
#

I mean, u can, but then if anyone sees your project they'll have the credentials

#

just replace that with Files.newInputStream(Path.of("the path here"))

sharp geyser
#

icic

#

and if I do ./db.properties then it'd look in the root dir? because thats where the image eventually gets built too right or at least I can put it there after its built

lyric mountain
#

it'll look at where the executable is

#
folder
  L executable
  L db.properties
sharp geyser
#

icic ty

#

idk how ima test this rn tho

#

because its not going to exist in that path if I run it through intelliJ

#

its going to look in the dir where DatabaseConfig class is right?

sharp geyser
#

and when I go to build the image I can just change it

lyric mountain
#

you can use relative paths during testing, the "this folder" will be project root

sharp geyser
#

how so?

lyric mountain
#

new File("build.gradle") for example would get you the buildscript if running from gradlew

#

because it's in project root

sharp geyser
#

ic

#

so if I use gradlew I can get anything from the root dir?

lyric mountain
#

no, I think ur misunderstanding things

sharp geyser
#

I most certainly am

lyric mountain
#

when you run the project through gradlew, your execution path will be the gradlew script itself

sharp geyser
#

right

lyric mountain
#

when you execute the jar, the execution path will be the jar

#

as in, the file jar

sharp geyser
#

yes

#

so I did understand

#

if I execute it with gradlew then where gradlew is becomes the CWD

lyric mountain
#

yes

#

filepaths in java are relative to where u entered

sharp geyser
#

yea

lyric mountain
#

except if you use a leading prefix

#

/home for example would give u the home folder, not a folder named home

#

no prefix or ./ prefix = relative path
/ prefix = absolute path

#

just like regular paths

#

actually I think this is the same for every lang

sharp geyser
#

yea

#

lol

neon leaf
sharp geyser
#

haha you ran into those already

#

nice

#

Right so a lifetime is basically something that tells the compiler how long something will live

#
struct Wrapper<'a> {
  reference: &'a String,
}

fn thing<'a>(input: &'a String) -> Wrapper<'a> {
  Wrapper { reference: input }
}
#

Take this for example

#

What you are telling the compiler is that input will live as long as Wrapper does is that

#

and since Wrapper is a return from a function, it will live as long as whatever is calling it

#

So if you call thing inside your main function, it will live as long as the scope of the main function

#

np

#

The reasns lifetimes exist is becaus the compiler doesn't always know how long something will survive for

sharp geyser
#

rust

neon leaf
#

do discord webhooks automatically get crossposted if sent into an announcements channel

deft wolf
#

I think you need to publish them

#

At least that's how it works on the Discord Developers server for example

neon leaf
#

ugh

#

why isnt there an option to auto crosspost smh

deft wolf
#

It would be a nice option, that's for sure

surreal sage
#

hi code bears

#

i currently have a button

#

and a popup/tooltip, which the button toggles

#

i'm currently struggling with properly determining when it should close

#

useOnClickOutside from usehooks

callback runs whenever anything but the tooltip was clicked (so if the button gets clicked, this gets called)

#

and the button onclick

#

now the issue is, if I want to close by pressing the button, useOnClickOutside gets activated and says nty, im undoing it

#

i could use useDebounceCallback but this adds a delay that I prefer to not have

surreal sage
#

atom one dark (thanks for helping ❤️)

#

9/10 theme, very distinct colors and everything's obvious
background colors bit bright though 💔

#

@id:akamud.vscode-theme-onedark

sharp geyser
#

@lyric mountain

package io.collegecrafts;

import com.zaxxer.hikari.HikariDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.SQLException;

public class Database {
    private static final String DB_IP = DatabaseConfig.getDbIp();
    private static final String DB_USER = DatabaseConfig.getDbUsername();
    private static final String DB_PASS = DatabaseConfig.getDbPassword();

    private static final HikariDataSource ds = new HikariDataSource();
    private static final Logger log = LoggerFactory.getLogger(Database.class);

    static {
        ds.setDriverClassName("org.postgresql.Driver");
        ds.setJdbcUrl("jdbc:postgres://%s/collegecrafts".formatted(DB_IP));
        ds.setUsername(DB_USER);
        ds.setPassword(DB_PASS);
        ds.setMaximumPoolSize(20);
        log.info("Connected to collegecrafts successfully.");
    }

    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }
}

So I kind of went along with what you did, but correct me if im wrong, that static won't run unless I call on a method of the class right or am I wrong?

#

Also, is it okay to do private static final Logger log = ...

#

or should i have 1 central logger

lyric mountain
#

static initializer will run the moment you first reference the class

#

like importing it

sharp geyser
#

so that could be importing it into my main file

lyric mountain
lyric mountain
#

a global constructor basically

sharp geyser
#

icic

#

interesting

#

now how exactly do you use gradlew

#

is it just ./gradlew?

#

or do you need to pass args

eternal osprey
sharp geyser
#

its not a pre-defined task is it?

lyric mountain
#

if you have plugin('application') you can run it

#

basically u make the project runnable through gradle

#

in fact u can check what u can do on the right panel

eternal osprey
#

Okay guys i think i finally got an idea. What would you guys think, is it complex enough?
So, on the 8tb of html data i want to filter it by crypto related content. Then i want to do a word occurence type of thing where i set apart documents per cryptocoin that are about scam related news.
Next off, from those batches i have created, i want to hash each cryptocoin to the same k-bit vector space to eventually reduce the amount of similarity functions i need to compute.
Once that's done, i will go over the reduced batches and simply compute the cosine similiarity.
Now i have successfully 1. found the cryptocoins that are most error prone, and found which things frequently go wrong (by the similarity matching i performed).

#

Parallelism will be hella hard but i think that i can use spark for that

sharp geyser
#

Is this normal?

#

it shows 75% executing

#

I also don't see anything about my database

#

For some reason it doesn't seem to want to connect to the db

sharp geyser
quartz kindle
eternal osprey
#

has anyone ever worked with googleapis for google documents?

#

I can successfully create the documents but it ffs always returns me this when i go to view it:
ain't there a way to make it publicily availabe

#

or is that not possible

sharp geyser
#

You shouldn't store access tokens in cookies

#

use a session system to store the access token with the session in db

#
  1. User logs in with oauth2 provider
  2. You get an access token & refresh token.
  3. Store a session id in a cookie (this id will be tied to a session in the database)
  4. Store this session ID in the database along with that access token & refresh token
#

Any subsequent requests you will fetch the session table to see if they have a session with that session id in the cookie

#

If so grab the access token and use it

#

Also note, store an expired bool alongside sessions. When your access token expires and you have to refresh it, generate a new session with updated creds, and set the expired field on the old session to true

#

That way you can keep track of any bad actors trying to spam your api with old session ids ( as its in a cookie people can steal them )

quartz kindle
#

logs, code...

#

more information please

sharp geyser
#

iara_lul_haha poor tim

#

isnt this the same guy for the past 2 days?

#

yea

#

sqlx is nice :)

#

right so I am looking at this microsoft oauth2 shit and I am wondering, wtf am I doing with my life rn 😭

#

the docs are all over the place

lyric mountain
#

but also no

#

like, if you're using jdbc then yes, it'll only connect if you get a connection

#

if you're using a pool then it'll just take one from the pool, favoring idle connections over creating a new one

sharp geyser
#

yea

#

Im just trying to figure out the best way to initalize the connection

#

should I just wait until an endpoint that needs it is visited

#

or should I do it as soon as the app starts?

#
public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);

    public static void main(String[] args) throws SQLException {
        Database.getConnection();

        var app = Javalin.create()
                .get("/auth/login", new Login())
                .start(7070);
    }
}
#

this is what im doing rn

#

but this seems wrong somehow

lyric mountain
#

always use it like this ```java
try (var conn = Database.getConnection()) {
...use conn
}

sharp geyser
#

Well then how do I start it off so that way it actually connects because as it stands now it won't unless I do something.

I guess I should just call getConnection when I need it

lyric mountain
#

yes

#

getConnection will return u a connection

#

u dont need to "start" the database first

sharp geyser
#

Also, do you advise I make DAO classes?

lyric mountain
#

well, I only ever make 1 DAO class, which is very generic and not really a technical DAO

sharp geyser
#

Well I likely would for what im building

#

At least I think anyways

#

It would save me a lot of headache

lyric mountain
#

for APIs it aint worth making models or DAOs for every single thing

#

as they'll likely be very simple queries

#

and mostly read

sharp geyser
#

not even for an e-commerce/marketplace api?

lyric mountain
#

I mean, u can if u want make models for each entity like products

#

or stuff that might need a lot of processing

sharp geyser
#

processing as in?

lyric mountain
#

input checking for example

#

tho even then it all depends

#

sometimes u can achieve it easily with raw sql

sharp geyser
#

I see

#

Alrighty :)

#

btw should I use oauth2 libraries at all

#

or just handle it all myself

lyric mountain
#

I handle it myself, for discord at least

#

but u can use one

sharp geyser
#

microsoft wants PCKE stuff and idrk how to do that myself KEKW

lyric mountain
#

doesn't javalin have it built-in already?

sharp geyser
#

maybe

#

doesn't look like it

#

unless im missing it

#

my biggest thing is

#

idrk how to handle code challenges

lyric mountain
#

well

sharp geyser
#

I understand I have to generate some random thing and then hash it based on the method specified e.g sha256 in this case

lyric mountain
#

u a lib then in this case KEKW

sharp geyser
#

but from there no idea

#

What libs are there?

#

the biggest one i see is Springboot Security Oauth2

#

but idk if I should use anything springboot with this KEKW

lyric mountain
#

springboot would conflict with javalin

sharp geyser
#

yuh

lyric mountain
#

pac4j has a javalin module iirc

sharp geyser
#

oh it does!

#

sweet

#

Ty :)

sharp geyser
#

oh well

#

ill have to use the generic clients

#

Unless Windows Live is the one I need thonk

#

but I thought they discontinued windows live

#

oh wait im looking at hte wrong thing

#

microsoft uses oidc

#

right so i'd use transactions btw

#
let mut transaction = YourConnectionVariable.begin().await.unwrap() // handle the result accordingly

let _ = query!("ALTER TABLE table DROP COLUMN email")
.execute(&mut *transaction)
.await
.unwrap() // Once again handle it however you want

transaction.commit().await.unwrap() // Again handle it however you want
#

Any time you are inserting, updating, deleting or altering a table use transactions

#

that way if something happens before the commit is called no changes are made

#

well no

#

transactions are just a way to handle things in case errors occur during it

#

Its not directly tied to migrations

#

if you aren't using transactions yes it will hard fail

#

and sometimes it might do stuff but fail at a certain point

#

depends on the query(ies) you are running

#

think of transactions like git

#

its version control in a way

#

If you are changing a table e.g deleting a record, inserting one or altering the columns you want to preserve that version until there are no errors right?

#

nah

#

you can do it all in one transaction

#

basically

#

Begin Transaction

Create table

Edit Table

Insert

Delete (fails)

Commit Transaction

#

Since the delete failed before commit was called

#

everything fails and nothing gets pushed to the db

#

preserving its state

#

It will only commit if there are no errors

#

no problem

#

Also

#

If you ever get bored of doing raw sql all the time there is an orm you can use (for future reference)

#

It's called diesel

#

yup

#

idk how it works tbh

#

because it doesn't need you to pass the connection along your functions at all

#

it's able to reuse the connection

lyric mountain
#

so, using only css, is it possible to make something rotate from 360deg to 0deg without doing a whole rotation?

sharp geyser
#

wdym a whole rotation?

#

Going from 360 to 0 would be a whole rotatio no?

surreal sage
#

chat what distro should i install on my laptop chat

lyric mountain
#

as in, rotate to nearest, not a literal 360 rotation

#

no, cant use js

sharp geyser
#

My brain is not computing on how to go to 0 without doing a rotation to 0

lyric mountain
#

if counter() worked with calc I could just add degrees, instead of setting angle

#

but it doesn't

lyric mountain
sharp geyser
#

I just realized I can't test my oauth2 impl

lyric mountain
#

why?

sharp geyser
#

I don't have an organization account

#

😭

#

Gotta wait for waffle to come online

#

I theoretically have it implemented

lyric mountain
#

did u do it with pac4j 🐗?

sharp geyser
#

yes

lyric mountain
#

how was it?

sharp geyser
#

whats the boar emote for

#

you calling me a pig

lyric mountain
#

javali is boar in portuguese

sharp geyser
#

okay wait

#

no im wrong

#

I didn't implement this correctly at all

#

😭

#

I forgot im not using the client

#

Right so I have the client but wtf do they want me to do with it

lyric mountain
#

you do whatever you'd do with the token

sharp geyser
#

yea but how the heck do I get this token

lyric mountain
#

at that point the auth2 transaction is complete

lyric mountain
#

getProfileCreator() is your token

sharp geyser
lyric mountain
#

I think

sharp geyser
#

see

#

i have no way of testing

#

😭

#

How does it know to redirect the user to the microsoft ad login page

lyric mountain
#

cant u create a testing account on microsoft?

sharp geyser
#

not an organization one

#

i'd need to pay for that

lyric mountain
#

like, how else would devs implement oauth2 then?

#

they need a testing account

sharp geyser
#

Well thats the thing

#

microsoft wont let me choose personal accounts for oauth2

#

or else I can do that

#

it has to be an organization account

#

I guess they assume you to be part of an organization

lyric mountain
#

well

#

you can implement google meanwhile, until you get some account to be able to test with

#

should be the same thing for both

sharp geyser
#

yea

#

How am I going to handle multiple oauth on my backend tho?

#

would it be like
example.com/auth/login/google & example.com/auth/callback/google
and same for azure?

lyric mountain
#

I think so, oauth2 is a standard

#

they all have to use the same procedures

sharp geyser
#

yea but I mean

#

on my backend is that how I should differentiate

#

because I will have to use separate clients

proven lantern
#

I am responding to a MODAL_SUBMIT with a DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE and then posting a following up message, but i get a 400 error. this is my first time setting up a response to a modal submit so i dont know what i'm doing.

#

anything special you need to do to follow up a modal submit?

#

it gets the DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE response and waits

#

oh wait

#

it needs to be an array

surreal sage
#

fuck java!!! atwood's law 4 life!!! ❤️❤️ 🤩

#

sea going hard

#

javascript jit? soon to be aot!!

sharp geyser
#

As in is there special endpoints to use for edu accounts or whatever

lyric mountain
#

I believe so

#

oauth2 is oauth2

sharp geyser
#

well yea I meant I didn't know if google did weird shit shrug

#

Bro even setting up oauth2 with google is annoying

sharp geyser
#

anything thats unique enough

#

At the end of the day it doesn't matter what the session id is

#

just has to be unique

#

ngl

#

pac4j can suck my nuts

#

This shit is so confusing

#

the docs for it are TERRIBLE

#

I am having to read source code to figure out what to use

#

not to mention the examples are kinda shite as well

#

yknow what why don't I just use the dedicated libraries for this

lyric mountain
#

ok I'm stuck at trying to find a formula

#

lets say you have current_index and many elements with a property index (constant for each item)

#

I need the value to be 1 if both values are equal, 0 otherwise

#

index can be bigger than current_index, and vice-versa

lyric mountain
#

f(x,y) = (x - y) / (x - y) could work, if not for the zero division

#

Actually, I can use max for the division

#

Nvm, i can't

sharp geyser
#

Anything dealing with 0 is going to be a hard one to solve tbh

lyric mountain
#

Oh wait, found an answer, pretty stupid tbh

f(x,y) = min((x - y) * (x - y), 1)

#

Multiplication is to make the value unsigned

#

If it's 0, then it'll return zero, else it'll return 1

sharp geyser
#

Nice!

#

Also, haku, ngl thinking of not using java KEKW this stuff blows with oauth2

#

I would have to do it myself, which is fine, but java is also the langauge I know the least and im not comfortable with it at all