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

You either have a bug or a lag problem. Maybe a lag problem due to programming in JavaScript. Is Bitburner interpreted or compiled? #1718

Open
seannaquah opened this issue Oct 22, 2024 · 23 comments

Comments

@seannaquah
Copy link

bitburnerSave_1729617814_BN1x1.json.gz

I think it should be this file, but I might be mistaken. Do let me know if you got the wrong file. Sorry for all the trouble. really

Anyway, I just started the game, and I've been running scripts but I got this. I never used to get this though. I used to earn money fine.

image

This is the second time this has happened. It's really weird. It never used to happen. I used to earn money from my scripts fine. My script is a very simplistic one because I couldn't be bothered to make a more complicated one, seeing as I was born and still have multiple congenital medical conditions that I have to put up with, but it's still true that Hacknets are multiplicative, so they earn more early game, so you need to put more money into the hackable servers for the scripts to hack. I used the same script, so it can't be because of a script error that I'm not earning money from my scripts. I used to earn money from them fine.

Here are some of my scripts:-

templBatchRun64.js:-

/** @param {NS} ns */
export async function main(ns) {
    ns.exec('hostnameHackNode.js','hostname',26);
}
//end template BatchRun64 Script

templHackNode.js:-

/** @param {NS} ns */
export async function main(ns) {
    const serverMaxMoney = ns.getServerMaxMoney;
    const serverMinSecurity = ns.getServerMinSecurityLevel;
    const serverWeakenUntil = serverMinSecurity + 0.2;
    const serverWeakenWhen = serverMinSecurity + 0.5;
    const hackLimit = (serverMaxMoney/3)*2;
        
    while(true){
        if(ns.getServerSecurityLevel > serverWeakenWhen){
            if(ns.getServerSecurityLevel >= serverWeakenUntil){
                await ns.weaken('hostname');
            }
        }
        else if(ns.getServerMoneyAvailable < serverMaxMoney) {
            await ns.grow('hostname');
        }
        else if(ns.getServerMoneyAvailable > hackLimit){
            await ns.hack('hostname');
        }
        //end IF

        await ns.sleep(20);
    }
    //end WHILE
}
//end template HackNode Script

templhosttargetserverBatchRun1024:-

/** @param {NS} ns */
export async function main(ns) {
    ns.exec('targetHackNode.js','hostserver',425);
}
//end hostserver HackNodetargetBatchRun1024 Script

They used to work perfectly fine.

  • Just upload and run the scripts on any servers accessible, and get the servers with no money to target omega-net server since it has the most money early game.

  • Version: Bitburner v2.6.2 (633da38)

@Hoekstraa
Copy link
Contributor

For reference, same issue initially reported at bitburner-official/typescript-template#23

@Caldwell-74
Copy link
Contributor

image
you are not calling these functions you need ('hostname') behind them

@seannaquah
Copy link
Author

seannaquah commented Oct 22, 2024

you are not calling the functions image image you need ("hostname") behind all of these functions otherwise you are just obtaining the function object and are not calling them

That's because, have you seen the name of the file? they're called templxxxxxxxxxx.js, meaning that they're template scripts. I'm not one of those programmers who retypes everything from scratch every single time they write a program or script. I do things the short and simple way. It's the reason for my high efficiency and effectiveness at work at every place I've worked at. I have templates for everything because retyping everything every single time is just dumb. Obviously in the actual script, it would have the proper hostname and everything. I'm not stupid.

@d0sboots
Copy link
Collaborator

In that case, please show us your actual code, not your "template."

@seannaquah
Copy link
Author

seannaquah commented Oct 23, 2024

image you are not calling these functions you need ('hostname') behind them

Same thing again. You people really like to make your life hard and tedious for yourselves. Why redo something over and over again when you can just copy and paste it and then save it? I'd never do something so tedious as rehashing everything every single time. It's just silly. I basically have a template for almost any simple script or program you can think up. I don't do redos. Even if it's just a simple CLI-based dice roller with modifiers for rolling DnD dice rolls. I only do things once. No more. Which is why back in the old days before named parameters existed, I would do function overloading to allow my function to do multiple different things and store them in a library that I could just #include.

Oh, OOC, Angel's Computer Graphics textbook has quite a number of mistakes and errors. The mathematics is all wrong, and you can do it using much simpler methods. Same goes for Uckan's textbook.

@d0sboots
Copy link
Collaborator

You are misunderstanding. If the code you are showing is just a "template," it is not the code you are actually running. Therefore, it is irrelevant when it comes to debugging. Show the code that is actually running.

@d0sboots
Copy link
Collaborator

I downloaded your save. Upon loading it, I found two processes running, which were two copies of omega-netHackNode.js. The code looks like this:

/** @param {NS} ns */
export async function main(ns) {
    const serverMaxMoney = ns.getServerMaxMoney;
    const serverMinSecurity = ns.getServerMinSecurityLevel;
    const serverWeakenUntil = serverMinSecurity + 0.2;
    const serverWeakenWhen = serverMinSecurity + 0.5;
    const hackLimit = (serverMaxMoney/3)*2;
        
    while(true){
        if(ns.getServerSecurityLevel > serverWeakenWhen){
            if(ns.getServerSecurityLevel >= serverWeakenUntil){
                await ns.weaken('omega-net');
            }
        }
        else if(ns.getServerMoneyAvailable < serverMaxMoney) {
            await ns.grow('omega-net');
        }
        else if(ns.getServerMoneyAvailable > hackLimit){
            await ns.hack('omega-net');
        }
        //end IF

        await ns.sleep(20);
    }
    //end WHILE
}
//end omega-net HackNode Script

looking at other similarly named scripts (CSECHackNode.js, n00dlesHackNode.js, etc.) shows the same pattern. The issue appears to be exactly what Caldwell already told you, which you claimed you changed in the actual files.

@seannaquah
Copy link
Author

seannaquah commented Oct 23, 2024

You are misunderstanding. If the code you are showing is just a "template," it is not the code you are actually running. Therefore, it is irrelevant when it comes to debugging. Show the code that is actually running.

Just insert 'omega-netHackNode' and 'omega-net', etc. What's so difficult? Has the standard of programming dropped that much while I was away? It's easy to figure out, template or actual script. I gave the template simply because it applies for all the scripts I wrote instead of bombarding you with a whole ton of scripts that wouldn't give you a complete idea of the concept of the scripting/programming. My lecturers and professors back in the day were perfectly fine with it and understood it perfectly. In fact, when my sibling tells me about new concepts, he totally goes 100% conceptual and abstract and it's like he's teaching in templates, no real proper script or programming code. He expects you to figure it out yourself. And it's easy enough to do so. If you don't, he'll just say you're not putting in enough effort, and tell you, "here's the official website URL, go look it up and learn it yourself". He won't like give you the answer or the code like on those computer programming help sites. He'll just say, "God helps those who help themselves".

@cmfrydos
Copy link
Contributor

Just to clarify, the same code is present in every non-template .js file within the save game. To move this discussion forward productively, let’s focus on identifying the root cause together. Remember, everyone makes mistakes, and this repository is here for us to collaborate on improving Bitburner by addressing bugs and enhancing features. Your expertise is valuable, and together we can make the game better for everyone.

So, do you believe the issue, that you didn't earn any money was not due to the scripts not calling the functions properly? Maybe you just changed your scripting setup, and you've overseen this error. Don't ask, how often that happened to me, especially in js. But if you're sure the error lies somewhere else, then we need some more info.

@seannaquah
Copy link
Author

Just to clarify, the same code is present in every non-template .js file within the save game. To move this discussion forward productively, let’s focus on identifying the root cause together. Remember, everyone makes mistakes, and this repository is here for us to collaborate on improving Bitburner by addressing bugs and enhancing features. Your expertise is valuable, and together we can make the game better for everyone.

So, do you believe the issue, that you didn't earn any money was not due to the scripts not calling the functions properly? Maybe you just changed your scripting setup, and you've overseen this error. Don't ask, how often that happened to me, especially in js. But if you're sure the error lies somewhere else, then we need some more info.

I've already submitted the whole thing to the Bug Reporting. It should be enough to figure things out with, I'm sure. Save game and scripts, etc. with the screenshot. I'm pretty sure the hang and jam is due to lag being mistaken for infinite loops without await ns.sleep(n);

I also barely changed a thing in my scripts so it can't be that I used to earn money and suddenly now I don't. That just doesn't make sense logically speaking. I'm not trying to put anybody down, but please don't pick on me first. I don't exactly like people doing that because I used to get bullied a lot as a kid just for being different. Don't ask me why they picked on me, but they did, and I'm very sensitive about it. Not that I want to pick on you people. I really don't have any grudges against you people.

Anyway, let's assume an example:-

/** @param {NS} ns */
export async function main(ns) {
    const serverMaxMoney = ns.getServerMaxMoney;
    const serverMinSecurity = ns.getServerMinSecurityLevel;
    const serverWeakenUntil = serverMinSecurity + 0.2;
    const serverWeakenWhen = serverMinSecurity + 0.5;
    const hackLimit = (serverMaxMoney/3)*2;
        
    while(true){
        if(ns.getServerSecurityLevel > serverWeakenWhen){
            if(ns.getServerSecurityLevel >= serverWeakenUntil){
                await ns.weaken('omega-net');
            }
        }
        else if(ns.getServerMoneyAvailable < serverMaxMoney) {
            await ns.grow('omega-net');
        }
        else if(ns.getServerMoneyAvailable > hackLimit){
            await ns.hack('omega-net');
        }
        //end IF

        await ns.sleep(20);
    }
    //end WHILE
}
//end omega-net HackNode Script

@d0sboots
Copy link
Collaborator

d0sboots commented Oct 23, 2024

Caldwell already told you the issue with that code. He used red circles to highlight the sections with missing function calls, and everything.

Edit: It's possible that the code, as written, could have worked or partially worked before. Comparing functions and numbers is perfectly legal in javascript, although the result won't be anything you would likely expect.

@cmfrydos
Copy link
Contributor

cmfrydos commented Oct 23, 2024

Like Caldwell pointed out, you forgot to actually call the function getServerMaxMoney here:

const serverMaxMoney = ns.getServerMaxMoney;

This only assigns serverMaxMoney a reference to the ns.getServerMaxMoney function. What you want is to call it:

const hostname = "omega-net";
const serverMaxMoney = ns.getServerMaxMoney(hostname);

Also, I've noticed that your last if clause should actually be one level up; otherwise, it has no effect.

Lastly, the nested if statements that check whether the security level is above a certain level are somewhat redundant, so sticking to one level is the way to go here.

Putting everything together, we get:

/** @param {NS} ns */
export async function main(ns) {
    const hostname = "omega-net";
    const serverMaxMoney = ns.getServerMaxMoney(hostname);
    const serverMinSecurity = ns.getServerMinSecurityLevel(hostname);
    const serverWeakenWhen = serverMinSecurity + 0.5;
    const hackLimit = (serverMaxMoney/3)*2;
        
    while(true){
        if(ns.getServerSecurityLevel(hostname) > serverWeakenWhen){      
            await ns.weaken(hostname);
        }
        else if(ns.getServerMoneyAvailable(hostname) > hackLimit){
            await ns.hack(hostname);
        }
        else {
            await ns.grow(hostname);
        }
        //end IF

        await ns.sleep(20);
    }
    //end WHILE
}
//end omega-net HackNode Script

I hope this helps, and fixes your issue. If you need any further explanations, don't hesitate to ask. There is also a great channel on the discord for topics like these: https://discord.com/channels/415207508303544321/909403255040266260

@seannaquah
Copy link
Author

seannaquah commented Oct 23, 2024

Like Caldwell pointed out, you forgot to actually call the function getServerMaxMoney here:

const serverMaxMoney = ns.getServerMaxMoney;

This only assigns serverMaxMoney a reference to the ns.getServerMaxMoney function. What you want is to call it:

const hostname = "omega-net";
const serverMaxMoney = ns.getServerMaxMoney(hostname);

Also, I've noticed that your last if clause should actually be one level up; otherwise, it has no effect.

Lastly, the nested if statements that check whether the security level is above a certain level are somewhat redundant, so sticking to one level is the way to go here.

Putting everything together, we get:

/** @param {NS} ns */
export async function main(ns) {
    const hostname = "omega-net";
    const serverMaxMoney = ns.getServerMaxMoney(hostname);
    const serverMinSecurity = ns.getServerMinSecurityLevel(hostname);
    const serverWeakenWhen = serverMinSecurity + 0.5;
    const hackLimit = (serverMaxMoney/3)*2;
        
    while(true){
        if(ns.getServerSecurityLevel(hostname) > serverWeakenWhen){      
            await ns.weaken(hostname);
        }
        else if(ns.getServerMoneyAvailable(hostname) > hackLimit){
            await ns.hack(hostname);
        }
        else {
            await ns.grow(hostname);
        }
        //end IF

        await ns.sleep(20);
    }
    //end WHILE
}
//end omega-net HackNode Script

I hope this helps, and fixes your issue. If you need any further explanations, don't hesitate to ask. There is also a great channel on the discord for topics like these: https://discord.com/channels/415207508303544321/909403255040266260

Well, this sure worked for me earlier:-

const serverMaxMoney = ns.getServerMaxMoney;

So I don't see what you're talking about. Ah, I see, you're talking about calling it from home. But I'm calling it from the damn server itself though? Certainly if I called from home, I'd need to specify which server I wanted it from, but if I called it directly, I don't think I need to, if I recall correctly. I mean, I'm calling the server itself directly. Why would I need to tell it its name? I don't need to tell my PC its name, when I call it directly, it already knows it. After all, I already did an scp to upload the script onto the server. After all, I'm making use of the target server's own RAM as well.

Also, I've noticed that your last if clause should actually be one level up; otherwise, it has no effect.

Actually it does. It's perfectly fine that way. It worked fine before, so why shouldn't it now? Read the code carefully. The previous IF is checking for the optimal situation to do the hack. Otherwise grow.

Redundant? Ah, I see, that should have been a WHILE loop. Sorry. My bad. It was originally like that with an await ns.sleep(20); but I changed the script and must have forgotten to get rid of the second IF statement.

However, please read code carefully before you comment. It kind of gets on my nerves when you talk about the red circles when I already explained why.

@Caldwell-74
Copy link
Contributor

Caldwell-74 commented Oct 23, 2024

So I don't see what you're talking about. Ah, I see, you're talking about calling it from home. But I'm calling it from the damn server itself though? Certainly if I called from home, I'd need to specify which server I wanted it from, but if I called it directly, I don't think I need to, if I recall correctly. I mean, I'm calling the server itself directly. Why would I need to tell it its name? I don't need to tell my PC its name, when I call it directly, it already knows it. After all, I already did an scp to upload the script onto the server. After all, I'm making use of the target server's own RAM as well.

the problem is that you are not calling the function
calling here means telling js to run the code of a function
to call a function you need () behind them

const serverMaxMoney = ns.getServerMaxMoney;
this assigns the function Object of getServerMaxMoney to the variable serverMaxMoney

const serverMaxMoney = ns.getServerMaxMoney();
this would call getServerMaxMoney without an argument

but you want
const serverMaxMoney = ns.getServerMaxMoney(<servername>);
where you replace < servername > with the right servername string

the same goes for the other functions i highlighted
here a ressource for more informations
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#calling_functions

@seannaquah
Copy link
Author

seannaquah commented Oct 23, 2024

So I don't see what you're talking about. Ah, I see, you're talking about calling it from home. But I'm calling it from the damn server itself though? Certainly if I called from home, I'd need to specify which server I wanted it from, but if I called it directly, I don't think I need to, if I recall correctly. I mean, I'm calling the server itself directly. Why would I need to tell it its name? I don't need to tell my PC its name, when I call it directly, it already knows it. After all, I already did an scp to upload the script onto the server. After all, I'm making use of the target server's own RAM as well.

the problem is that you are not calling the function calling here means telling js to run the code of a function to call a function you need () behind them

const serverMaxMoney = ns.getServerMaxMoney; this assigns the function Object of getServerMaxMoney to the variable serverMaxMoney

const serverMaxMoney = ns.getServerMaxMoney(); this would call getServerMaxMoney without an argument

but you want const serverMaxMoney = ns.getServerMaxMoney(<servername>); where you replace < servername > with the right servername string

the same goes for the other functions i highlighted here a ressource for more informations https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#calling_functions

Huh, didn't notice that. It used to have the brackets. Wonder how they disappeared. >.>

Anyway, thanks for the heads up. And don't get me wrong. It's not that I don't like feedback. I just hate having to repeat myself. Because well, my family is like, they never listen to what I say and I keep having to repeat myself, so it's become really annoying. lol

@Caldwell-74
Copy link
Contributor

Caldwell-74 commented Oct 23, 2024

I just hate having to repeat myself.

we all do.

@seannaquah
Copy link
Author

seannaquah commented Oct 23, 2024

I just hate having to repeat myself.

we all do.

True, true. You've been very patient with me. I didn't notice the missing brackets. Thanks. My eyesight is getting, well, not as good as it used to be (I'm getting old), so forgive me for not noticing it earlier. Hehe. By the way, just curious, you a guy or a girl? Me, I'm a lady.

@seannaquah
Copy link
Author

By the way, about this part,

if(ns.getServerSecurityLevel > serverWeakenWhen){
            if(ns.getServerSecurityLevel >= serverWeakenUntil){
                await ns.weaken('hostname');
            }

It's not redundant. Because earlier on I set const serverWeakenUntil to a certain level, because earlier on it was giving me problems of weakening forever and never going on to the next steps, so these 2 IF statements are actually checking for 2 very different things. 1 checks whether to start, the other checks whether it's enough and shouldn't start, but I think I'll put it together in the same IF statement, that'll make it simpler and lower the complexity of the script as well. It'll make it a lot simpler.

@Hoekstraa
Copy link
Contributor

Hoekstraa commented Oct 23, 2024

By the way, about this part,

if(ns.getServerSecurityLevel > serverWeakenWhen){
            if(ns.getServerSecurityLevel >= serverWeakenUntil){
                await ns.weaken('hostname');
            }

Just be wary of the fact that if the first statement is true, but the second isn't, your script will get stuck in a loop of doing nothing, assuming no outside-script interaction with the server (due to the if-else structure). So there'd be a second benefit to moving them together into one logical statement in one if.

@seannaquah
Copy link
Author

seannaquah commented Oct 23, 2024

By the way, about this part,

if(ns.getServerSecurityLevel > serverWeakenWhen){
            if(ns.getServerSecurityLevel >= serverWeakenUntil){
                await ns.weaken('hostname');
            }

Just be wary of the fact that if the first statement is true, but the second isn't, your script will get stuck in a loop of doing nothing, assuming no outside-script interaction with the server (due to the if-else structure). So there'd be a second benefit to moving them together into one logical statement in one if.

That's what I just did. I moved them in together. Secondly, it won't get stuck in a loop of doing nothing. Remember, it's an IF-ELSE IF clause. If the first IF fails, it'll just move on to the next IF statement. And I added some amount of value to the response from ns.getServerSecurityLevel(), so serverWeakenUntil is definitely going to be higher than the minimum security value, so it will trigger until it goes below a certain threshold. I just don't want the Security Level getting too high and making the ns.hack() take too long.

I just am not exactly used to JavaScript because it's been ages, like years, since I last used JavaScript-like languages. I mean, They're not made for larger programs, if you know what I mean. It's just that JavaScript outgrow it's own purpose. Even the creator of JavaScript says it wasn't supposed to be this large scale, because it's just too laggy. The compile time is long, and interpreted JavaScript is laggy as hell. Electron for example, takes way too long to compile stuff. This is coming from my sibling who has to deal with people who keep on deciding to use JavaScript to program their stuff when there are more modern, efficient and effective languages now. Even I am starting to shy away from using C because of how verbose it is, and how it's not object-oriented at all. I only use it for certain purposes nowadays. Even C++'s so-called object-oriented language is just plain syntactic sugar. It's not a real Object Oriented Language. And I'm kind of disappointed that they lost their motivation for functional languages. It's so useful! In certain cases, functional languages are far superior to procedural languages like Java, C#, etc. It can do things that no procedural language can do! So as I always say, it's always important to choose the right language for the right problem at hand. Why else do we learn PLCP (Programming Language Concepts and Paradigms)? Why explore so many different kinds of languages? It's to get a grasp of what's good at what. Like for example, Tower of Hanoi problem takes several lines in C++ to solve at the very least. But in Prolog, it only takes 2 lines.

@seannaquah
Copy link
Author

seannaquah commented Oct 23, 2024

Like Caldwell pointed out, you forgot to actually call the function getServerMaxMoney here:

const serverMaxMoney = ns.getServerMaxMoney;

This only assigns serverMaxMoney a reference to the ns.getServerMaxMoney function. What you want is to call it:

const hostname = "omega-net";
const serverMaxMoney = ns.getServerMaxMoney(hostname);

Also, I've noticed that your last if clause should actually be one level up; otherwise, it has no effect.

Lastly, the nested if statements that check whether the security level is above a certain level are somewhat redundant, so sticking to one level is the way to go here.

Putting everything together, we get:

/** @param {NS} ns */
export async function main(ns) {
    const hostname = "omega-net";
    const serverMaxMoney = ns.getServerMaxMoney(hostname);
    const serverMinSecurity = ns.getServerMinSecurityLevel(hostname);
    const serverWeakenWhen = serverMinSecurity + 0.5;
    const hackLimit = (serverMaxMoney/3)*2;
        
    while(true){
        if(ns.getServerSecurityLevel(hostname) > serverWeakenWhen){      
            await ns.weaken(hostname);
        }
        else if(ns.getServerMoneyAvailable(hostname) > hackLimit){
            await ns.hack(hostname);
        }
        else {
            await ns.grow(hostname);
        }
        //end IF

        await ns.sleep(20);
    }
    //end WHILE
}
//end omega-net HackNode Script

I hope this helps, and fixes your issue. If you need any further explanations, don't hesitate to ask. There is also a great channel on the discord for topics like these: https://discord.com/channels/415207508303544321/909403255040266260

I'm not saying this because I think I was wrong about everything. This is not a matter of who was right and who was wrong. But I thought it over, and I believe that you deserve this at the very least. At least, it's what I think is right. I'm very sorry for getting so upset with you earlier on. I sometimes get rather (sometimes very, very) emotional, so I believe I owe you an apology for getting angry/upset (mainly upset) with you. Have a great day and I hope we can leave the past behind us. ❤

P.S. I do however think that both you and I need to work on our communication and social skills~ Hehe~

Also, I've noticed that your last if clause should actually be one level up; otherwise, it has no effect.

P.S. I just checked. I was right. It works just fine. The effect is there.

But this is why I have been suggesting to the people developing this game to put in an in-game guide as in an in-game API reference with the examples instead of referring players to the web every single time because what the game uses is NOT actually JavaScript. It's some version of JavaScript-like scripting language that they made for the game themselves. Even my sibling who works with JavaScript and TypeScript a lot doesn't recognize it as orthodox. I mean, the APIs are all totally different from what I learned, that's for sure. And it's not like I don't know how to program or anything like that. I'm perfectly fine and at ease dealing with heirarchical graphical modeling, double or triple buffering, vectors, and all kind of other stuff, including bitwise programming, or coming up with a simpler and easier to understand method of doing things that uses classes, methods and properties, etc. But this, is just weird in my eyes. So I strongly believe that a set of in-game API references with examples would be a big plus for this game. At least that's from my designer's perspective. I know the implementation will be much more tedious as I'm also a programmer, so I am not saying it's an easy job, but I AM saying that it's a worthwhile job.

@Hoekstraa
Copy link
Contributor

Hoekstraa commented Oct 23, 2024

We'd be happy to explain the underlying concepts used in the game.
I've referred you in the past to the Discord server, we can help answer any questions you have there.

It seems to me you and your sibling are unfamiliar with dependency injection? The basics of which are already displayed in the in-game documentation. Besides that, it might be wise to take a course or read a book on Javascript (and/or Enterprise software design patterns) if you're unfamiliar and you're looking to learn. Sadly we can't go through everything there is to JS and design concepts. Due to the use of regular, modern ECMA Javascript, everything should be available online. Anything that is specific to the game sometimes is just easier to ask and answer, specific to the person at hand. It's incredibly difficult to document this in a way that is suitable to all audiences. As I'm sure you know.

@Hoekstraa
Copy link
Contributor

Also.. I've found that usually, getting people who are only just acquainted with a project to write the documentation is very helpful for these people, but also really shows where the pain points are. Someone experienced with a project can only presume what issues a newcomer runs into, with usually a skewed perspective.

So if you do really feel this is important, and something you're capable of doing, please, feel free.
You seem to be motivated enough to write out your qualms, would it perhaps be productive to use this energy to resolve the issues you're having?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants