Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE
Maven seems to waste a stunning amount of time doing nothing in particular. Kicking off each step in the chain incurs massive wait time as the plugin launches - for example it takes like 1:30 when it it launches maven-surefire-plugin with skipped tests. All in all I'm looking at a 9-minute build for a 7MB WAR file, almost all of which is precompiled libraries, on an i7-4770k. This happens under both Netbeans and Eclipse. Is there anything I can do to fix my build times here?

Adbot
ADBOT LOVES YOU

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

fletcher posted:

Are you running anti-virus? I've never had a problem with it but some coworkers were complaining of slow build times and we fixed it by whitelisting the directories that have source code and the maven repo. Build times substantially improved after that.

Yes, it's antivirus. I spun up a Lubuntu VM on the same machine, it did a "clean package" in 7 seconds flat. My Tomcat deploy times went from 61 seconds to 6 seconds. Come to think of it, Selenium performed a lot better on a server VM that didn't include the standard AV. At the time I blamed that one on not being able to get it to load a clean browser profile properly, with Tomcat I just didn't have a frame of reference. But in hindsight I think all three of those apps are probably tripping the read/write scanning agent. I never put the pieces together, but Sophos just doesn't play nice with Java.

We run Sophos+Bit9 and some other anti-malware. This combo gave me hell installing Netbeans, it would just silently kill the installer. Today I tried Gradle, and I realized it was doing the same silent kill thing to the gradle daemon, and the pieces fell into place for me. :negative:

Paul MaudDib fucked around with this message at 01:10 on Feb 6, 2015

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE
I'm working with Eclipse, RunJettyRun, and the 1.7 JDK. I have some getters which wrap some logic and don't represent an actual member on the class. For some reason JSTL occasionally refuses to admit the existence of these methods until I create an actual private member and run it once. After that I can delete the member and it runs just fine.

What's the deal?

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE
No questions, just wanted to share something that popped up on HN: http://java.metagno.me/

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE
Quick question: I am trying to set up Spring Security mappings so that if an authenticated user goes to "/" then they see "/main" but a non-authenticated user would see "/login". I'm using the automatic form-login functionality.

I set up a simple controller which does this, but "redirect:/login" as a destination doesn't work, presumably because that's not a real HTML page that exists in the project (it's in the Spring Security JARfile presumably). This seems like pretty basic functionality, there's got to be a way to do this.

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

Gravity Pike posted:

Do you have a compelling reason to use bare sockets instead of a higher-level abstraction? If you can imagine your client POST-ing a JSON-formatted request to a webserver, and then getting a JSON response back, it might be simpler to leverage Jersey or Spring to set up a server that handles HTTP requests.

Yeah, I don't understand why you'd be re-writing a web server here. Even servlets can be used to send back JSON, just send "text/json" as the content-type and dump a stringified JsonObject into the response body.

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE
Is there some framework that might let us tie together rules-based validation on both a web frontend and the backend into a single place? Stuff like "if fieldX = true then fieldY = false", as a simple example - we'd like to write the rule once and have it enforced via Javascript checking but also not just blindly trust user input on the backend either. Ideally this would warn the user as soon as they did something illegal rather than waiting for them to submit, but also not fire off an AJAX request on every field like a JSF validation.

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE
I'm using a Spring project with Hibernate. I have the SessionFactory in a bean because I'm using Spring to define some beans as @Transactional and injecting the Hibernate session.

I'd like to have a generic "application config" properties file that will contain the database parameters rather than building them into the application. However since I am using an XML-based configuration I can't also do programmatic configuration (AFAIK).

I'm thinking something like extending the LocalSessionFactoryBean class and overriding the setHibernateProperties method to add some additional parameters that I pull from a static class? Or is there a better way?

[insert grayscale As Seen On TV gif here]

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE
OK, more Spring questions.

Let's say that I want to have the ability to configure either a SQLite or a Postgres DB at runtime (or test-time). Do I just include both the SQLite and Postgres drivers, and then set up a properties-placeholder file that injects the appropriate class-name into the datasource/hibernate beans?

What if I didn't want to package both the JARs in it? Is there a way to declare a folder that will get injected at runtime? Or is that something that would have to be done through the JVM settings?

Now that I've got a handle on it Spring seems super nice and is a super easy way to inject stuff for testing. It's annoying how many "magic" words there are ("oh, you didn't declare a MultiPartResolver bean? no uploads for you") but once you're used to just having components just magically appear then composition becomes real easy.

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

PierreTheMime posted:

Is there a decent way to compute how much memory an application should consume and how to improve efficiency? I've been writing some tools to convert plaintext to objects via an API and while it works great for a small-moderate number of conversions it appears to draw enough memory on 240 passes in a single run to crash and throw a NoClassDefFoundException. I didn't even think this would be a possibility since the text in question is like 20k tops and I assumed garbage collection would clear out old objects after they went out of use.

How much memory are we talking? The JVM has some super low limits by default (like 256 MB per VM) but it's also possible that you are doing something that results in exponential memory consumption (strings are terrible about this unless you're aware). Be sure that you aren't going too nuts with string appending, use StringBuilder if you aren't already. Also be sure that you are dropping all references to an object after you are done using it - if it's still hanging around in a list somewhere or something else that is in-scope, it cannot be garbage collected. Keep variables local to a function as much as possible and it becomes automatic.

If you are totally stuck, you can just use something like SaxParser or Jackson, if you can convert your data into XML or JSON objects. Or if you have CSV there is an Apache CSV library out there.

Paul MaudDib fucked around with this message at 02:44 on Sep 7, 2016

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

CPColin posted:

Or StringBuilder, so you don't waste processing time on unnecessary thread safely.

Whoops, fixed.

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

CPColin posted:

I think basically everybody at my work is pretty tired of our home-built controller/layout/template/rendering engine and I wouldn't mind seeing if something like Thymeleaf could rescue us. Has anybody used it? (Is this a better question for the webdev thread?)

Thymeleaf is probably the go-to default for views at this point.

JSPs honestly aren't so bad if you stick to tags/EL and treat them like Thymeleaf templates, at that point it's just another dialect for doing the same thing. But it doesn't prohibit you from doing bad things either, like scriptlets, and then down the rabbit hole you go.

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE
For the sake of curiosity, let's say I have a list of tasks that should be handled by one of several task handlers that implements an interface, and I want to have them be pluggable at runtime, so hypothetically I could toss some JAR in the directory to add new task types. Is there some way to implement this that isn't like, reflection?

It's just a toy app where I can hardcode my handlers in there, just wondering.

ToxicSlurpee posted:

JSPs have some security issues and haven't aged all that well. Thymeleaf is made of magic and dreams.

What security issues? Just XSS or something new?

Thymeleaf is nice but I prefer the JSTL style syntax where control flow is its own elements. I haven't worked with it a ton so maybe it's just lack of experience, but I ran into some issues where control flow with that syntax could be ugly.

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

pigdog posted:

That's one of the lovely parts with JSPs, really -- they are compiled by the application server into concrete Java classes that output the HTML with println()'s and whatnot. That makes them complex to instantiate and test in isolation.

Well, Thymeleaf is a valid XML document all on it own if you just open it in a browser, but if you want to test hooking it up to your actual entities and stuff then you will still have to run it through the template engine...

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE
When I'm writing hashCode() methods normally I have something along the lines of this:

code:
public int hashCode()  {
int ret = 293;  //initial val, different for every class

ret = 31 * ret + someVal.hashCode(); //repeat for all values on object

return ret;
}
What is the proper way to handle when an object reference is null? Should the line be:

code:
ret =  31 * ret + (someVal != null ? someVal.hashCode() : 0);
Also, what if the object composition graph is not acyclic? If you have object A that calls B.hashCode(), and B calls A.hashCode() you would get infinite recursion. Should one or the other just use the object's rowId or some other surrogate key instead of business equality?

You can get some situations like collections on object A, and element B is the element collection type where an object-reference to A is actually an important business-equality key. Or again, just have B use A.id.hashCode() as the business equality key?

code:
class A {
	@Id Integer id;
	@OneToMany Collection<B> myCollection;
}

class B {
	@Id Integer id;
	@ManyToOne @JoinColumn A target;
	@Column String value;
}

Paul MaudDib fucked around with this message at 14:49 on Sep 26, 2016

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE
AMD definitely has hardware virtualization and that CPU supports it. The BIOS question is definitely a relevant one - it's disabled by default on many many systems including Intel.

This is not a definitive statement by any means but I've had some difficulties with AMD and virtualization in the past. I tried to install HyperV Server 2012 on a 5350 and could not get it to run right - something was obviously wrong, it was taking like multiple minutes to respond to user inputs and I couldn't get it to update or anything. I had virtualization turned on and everything. I eventually gave up after a couple evenings fiddling with it.

But, instruction-level emulation is going to be slow, that's pretty much just the nature of the beast. It's been a while since I played around with Android Studio on my work PC but I remember it taking a couple seconds even on an i7 4770.

Paul MaudDib fucked around with this message at 23:00 on Sep 26, 2016

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

Ornithology posted:

Can anyone recommend a guide for a beginner to learn the Spring framework?

My teacher has been showing us how to build very basic Java Web applications using NetBeans and now we have an assignment to make a Spring MVC application. I'm really getting overwhelmed. I tried using the NetBeans template for Spring MVC but it seems they use deprecated classes which their guide acknowledges but provides no recourse.

I tried looking at some examples from the book Spring in Action 4th edition but it seems like they use a completely different build structure which I can't even open in NetBeans, and starting a NetBeans Spring project and then following the textbook ends up with all kinds of import errors.

Overall I'm very confused as it seems to be totally different than the bare bones servlets we have made in class so far. I haven't even got a hello world example to run properly yet...

https://github.com/kolorobot/spring-mvc-quickstart-archetype

There's instructions there, first you will need to install the archetype and then create an instance of it.

I'm wondering if "different build structure" means Maven and if so you're going to have to handle it sooner or later. It's essentially an IDE-agnostic build system with dependency management and from your import errors it sounds like you tried shoehorning the project code into a Netbeans project and so it's not doing any of the dependency management that it's supposed to. There should be a "import Maven POM project" option or something similar that you use.

Also, IntelliJ is by far the best IDE in the Java world and you get a free copy as a student so you should do that too.

Paul MaudDib fucked around with this message at 23:35 on Oct 7, 2016

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

Data Graham posted:

Such as not using java?

I actually don't mean that to sound snarky. I'm really wondering: what are the benefits of using Java for web dev, when there are plenty of other stacks available that don't require you to muck around with IDEs or roll your own DAOs? Is the performance benefit that significant? Or is it all about scale, for maintainability of large codebases?

Java's main selling point is its ecosystem. It's historically been way ahead of the curve in terms of things like library availability, dependency management, build/test/deployment tooling, frameworks, etc. It's relatively easy to plug a few parts together and end up with something that will be easily maintainable and can be built or deployed in pretty much any software environment, without excessive bugs from the switch.

The days of poor performance from JRE 5 and 6 are long gone at this point. JRE 7 and 8 are really fast, typically among the fastest web stacks out there, especially if you use a thin web server like Jetty instead of something like Tomcat that is doing the whole Java EE stack.

It has a reputation for being excessively verbose. Frankly I think a lot of the blame here should fall on checked exceptions. High-level programming isn't bad at all, but any time you touch anything that deals with low-level I/O (f.ex network connections, SQL connections, files, streams, etc) you can pretty much guarantee that you will be swimming in exception handling. And I cannot for the life of me actually remember how you turn a stream into a string or that kind of thing, there's about five different objects involved in a simple conversion like that.

The thing is that those exceptions do represent things that can go wrong. If you are writing a network application it's important to consider "what if I can't talk to that API, or my connection disconnects, or my DB goes offline". That was the thought process behind explicitly declaring run-time failure modes in Java code. There's nothing stopping you from having every single function declare "throws Exception" and just having your application crash when something goes wrong like unhandled errors do in any language. Some APIs don't let you do that but you can always just catch Exception and return a generic "something went poorly" error page.

Another part of the blame comes down to checked exceptions that should be unchecked. The general rule of thumb nowadays is that if it's an error that happens inside the system (like the programmer asked for an illegal operation) the exception should be unchecked. That's your problem. A lot of Java stuff does not obey this rule, there are a lot of Factory classes that will throw ConfigurationException and that shouldn't happen. But in general Java has been an evolutionary thing. Java gets used in a lot of places and had a lot of weird applications in things like smart/SIM cards and microcontrollers. They made a lot of mistakes and would probably do things differently in hindsight, but they're locked into it by 20 years of legacy code. For example, the Cloneable interface is widely acknowledged to be a mistake because it doesn't do its purpose well and can open up big problems with serialization (including some security issues). But now it's there and can't be undone. I think they should be more bold on such things but it's not the Java Way (tm).

Anyway, going forward, the nice thing about Java is that you don't have to work at the bottom of the stack. Apache has put out a standard suite of tools which handle most of the boring plumbing work. IOUtils, StringUtils, StreamUtils, EntityUtils, etc are all way easier than doing things in low-level Java, and throw sensible exceptions. So really Oracle doesn't have to fix their mistakes.

rt4 posted:

I'd like to give Java web development a try. I didn't see any guides in the OP.

Anyone care to recommend some books or articles about choosing tools and writing a minimal web application?

This is the real downside to Java, there is a bunch of boring configuration bullshit. It's designed to be infinitely configurable to all kinds of tasks, but this also means that you have to make a whole bunch of decisions up front, whereas most other frameworks try to have sensible default options. It's not bad once you're used to it and have some config files you can crib from, but just getting to a Hello World web page in your desired stack is a major pain in the rear end if you don't know what you're doing. If you're totally new to webdev please forgive me for the pain I am about to lead you into. Some of this is Java-specific but a lot is generic webdev framework BS.

First, you want Maven. This is your build tool, it specifies what needs to go into the project and handles downloading the libraries for you and building. (don't actually go out and download this, your IDE will have an embedded instance, just accept it's there. And again, let Maven download the rest of this stuff for you.).

Then, you want Spring. This handles the overall application configuration, creating and attaching various parts of the application ("beans") to each other - for example, it can create/configure a connection pool (SessionFactory) as a bean object and then use a setter to put that object into a DAO class that holds specific queries you need for your application. It's really nice for testing because you can easily send in stub objects instead of the real thing. But you don't need to use it if it doesn't make sense, there's nothing wrong with passing a session around or something like that.

Then you want Spring MVC (emphasis on the controller here). This basically handles the web requests - taking a specific URL, running queries on the DB and attaching the result to the request, and then passing the request to a specific view to generate HTML.

Hibernate is the most common ORM layer. This handles translating between Java objects and database tables. The big decision you need to make here is XML mapping files or annotations. Annotations are newer and easier but XML does a better job of keeping the configuration confined to configuration files. Annotations can get really messy or entirely incompatible if (for example) you have Jackson annotations that tell Java how to map the object to a JSON format and also Hibernate annotations that tell Java how to store it in the database. You can mix and match on a per-class basis if you need.

Finally, your view is Thymeleaf. There are alternatives but this is the best practice nowadays. You have an XML skeleton, some of which may contain logical/flow-control operators (eg only display this element IF ____, write one of these elements for each item in a list, etc). Then you take objects attached to the request attribute store and the session attribute store and use them to fill in values. Thymeleaf is extra nice because a valid thymeleaf document is also valid HTML and can be displayed directly in a browser without a web server.

You also probably want Spring Security which handles stuff like logins/credentials/permissions/etc. This handles questions like "should a user with permissions X,Y,Z be allowed to load the URL '/admin'?"

You'll want to store passwords hashed in the database using a secure hash. BouncyCastle provides standard implementations of these. You want something that salts the password (adds a string to make brute forcing harder) and runs the result through a PBKDF2 derivation function. There is also a standard implementation in Java 8, see: "PBKDF2WithHmacSHA256". You actually want this to be slow, i.e. like a quarter second or so, so that it takes longer to brute force. Ideally you also want it to be resistant to GPU cracking, i.e. a hash like BCrypt. Best practice is to store metadata about how the hash was generated so that you can increase the password strength later (more PBKDF2 rounds, different hash, etc) later if you need to but also allow people to log in once and change their password to the new format.

Now, start downloading. For an IDE you want either IntelliJ Ultimate or Netbeans. I highly highly recommend IntelliJ Ultimate, especially for getting started. Use the trial, you don't have to keep using it past that, but IntelliJ is a superb piece of software and you will have a much easier time getting started.

To make a long story short: download this git repository and point your IDE to it ("open Maven POM project" or "import Maven POM" or whatever). Then do a "build project", or create a custom action for Maven with the command line "clean install". This will build and install the template. https://github.com/kolorobot/spring-mvc-quickstart-archetype

Then create an instance of the template. New Project, Maven, From Archetype, spring-mvc-quickstart-archetype.

Then you can "run" the project (custom Maven action: "run") and it will start an embedded webserver and launch the application. Start playing around from there.

Debugging a web app can be tricky. The embedded server is the easiest way - launch in debug mode and it will just work since it's running inside the IDE's JVM. You can also have a standalone web server like Jetty or Tomcat that runs the application in a separate JVM from your IDE, and you connect to it on a debug port. Tomcat doesn't open this by default, you may need the launch parameter: "-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n" added to the Java launch options.

carry on then posted:

I imagine part 2 of this will involve modifying the input in some way before writing it to output. But yeah.

For the record, in the real world you would do this with sed. :shrug:

Paul MaudDib fucked around with this message at 01:44 on Nov 9, 2016

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

carry on then posted:

Absolutely not in my experience.

Well, "modifying a stream as it's copied from source to destination" is exactly the wheelhouse of `sed`. Maybe your coworkers just suck at their jobs?

I guess reinventing the wheel in a programming language that is wildly inappropriate for the task is nothing new though.

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

baka kaba posted:

You could still use a lambda though. If you have use for a utility function then great, if it's an occasional thing then the range / forEach style isn't much longer than calling the custom function. I probably wouldn't do it, but it's not that bad

Counterpoint: both are bad and if you want to do that you should use Python.

Honestly that goes for C#'s LINQ too, it's a nice idea in theory but in practice it's a great way to kill your performance.

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE
The nice thing about Maven is it is declarative though - which makes it trivial to use as an IDE-agnostic project file. Literally any IDE can look at a POM file and spit out a working project, so you can just go ahead and git-ignore all IDE-specific project files from the repo forever and never worry about project files getting out of date or that one idiot who just can't help but check them in every single time clobbering your project config updates.

If you still want to have your "libs" dir that can build the whole app without any dependency downloads, you can still do that by installing everything into a local repository and naming it in your POM file. Ideally you will give the path relative to ${project.basedir} for portability. You pretty much need to do this for some stuff anyway, like the Oracle OJDBC drivers or some of the Java EE JARs that aren't in Maven-Central due to licensing concerns. This applies to Gradle too of course.

Also, as much as Maven has its bugs, at least it's not so slow that it needs to live as a resident daemon :lol:

Paul MaudDib fucked around with this message at 01:24 on Dec 6, 2016

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

Zaphod42 posted:

I find doing that is a huge pain in the butt compared to just dropping libs in a "libs" dir though.

What I'd really prefer to Maven would be a system where you have a libs dir and then Maven just automatically downloads and places libs into the libs dir based on dependencies. Any files that were not part of the Maven POM file would be ignored in the libs dir, so you could have your own libraries that Maven doesn't know about, but Maven would also pull things for you automatically and replace the old versions, more like a package manager. Then you'd have a totally portable folder that can compile without Maven. Make it more of a setup tool. My problem is that Maven itself ends up becoming a dependency that anybody who wants to deal with your project has to deal with. I really love being able to just rip a lib from an FTP site and compile right away without having to edit POM files.

From Maven's perspective, the problem is that it doesn't go around including a bunch of JARs "just because". If that repository was, say, Maven-Central, then including everything could be tens of thousands of JARs, probably a whole bunch of which are incompatible. From Maven's perspective, a local repository is simply one that it happens to access over file:// instead of http://. There is no other difference. Note that that this is different from your Maven cache, which is usually in the C:\Users\{username}\.m2 directory and is not shared between people..

Even if you just had a limited dir that you wanted it to include - it has no idea what is actually in that directory and what scope they should be included in (build, test, provided, etc). The point of running "mvn install:install-file" is that you give it the metadata of "what this JAR is" so it can write it into the repository directory you give, so that when it goes to grab dependencies it knows that this one is what it should include for "ojdbc-12.0.2.15". It would be super great if this were standardized but Java is the Land Of 1000 standards and walking thousands of jars would not be efficient anyway.

Other than that, "be a package manager" is exactly what Maven does. The point is that you can clone a Git repo, click "build", and it will automagically pull whatever it needs to build and assuming the build worked for the other guy then everything should succeed. You can put a local repository inside the repository for anything that cannot be pulled via Maven-Central, and then address it like - "${project.basedir}/../lib/". Then once again we're back to "git clone and build". Or if you have sub-projects you can set up a multimodule project, although in my opinion this isn't handled the most gracefully.

Gradle does that too of course, but it's imperative rather than declarative. And imperative is harder for other programs to handle, so most IDEs won't pick it up automatically. It's the equivalent of a makefile, it's its own little programming language, whereas Maven is literally "here is the things you should include to build this project" which also happens to be what the IDE needs to include.

quote:

That's great for the big heavyweight stuff with lots of dependencies and versions, but for some small lightweight libs its super overkill and takes too long to get going.

The problem in Java is traditionally that even simple projects swell to encompass a whole bunch of stuff via transitive dependencies. You may only use one lib, but if it starts including a bunch of other stuff then that has to be on the classpath too.

Logging frameworks are sort of a great example of this. Pretty much any project that relies on external libraries for anything will eventually swell to encompass Java.Util.Logging, Jakarta Commons Logging, Log4J, SLF4J, etc. Then at the final application, you use a "bridge" which routes all the different logging APIs to a single logging implementation.

It's really best to just stick to Apache-Commons libraries to try and minimize the amount of dependency bloat. They have pretty much anything you will ever need. SLF4J is pretty much the One Logging Framework To Rule Them All, too.

quote:

I don't know why they don't just build that as a feature into Maven, even. "Maven copy dependencies" would build a libs dir or something to that effect. But I guess its kinda anathema to Maven's mentality, so it'd have to be some other software to offer that kinda approach.
That option actually exists - you can have Maven build a "fat JAR" with dependencies right into it using maven-assembly-plugin. Or you should be able to just build a libs dir too somehow - I don't know how off the top of my head, but I 100% guarantee someone has done that.

edit: here you go

Paul MaudDib fucked around with this message at 02:51 on Dec 6, 2016

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

poemdexter posted:

A lot of configs use the word "password" for fields. I think you might need to lower your security settings on that one because it's not like you can go and change the external libraries to start using a different word.

I guess you could walk the fields of the properties object and build another properties object using the rot13 values of the field names, then feed that to the factory or whatever builds the connection pool.

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

Gravity Pike posted:

My team uses JOOQ, and we love it. It's like writing postgresql, but with type-safety.

Can you explain the draw of a heavy-weight ORM to me? I've never had a good experience with one; it's only been another layer that I have to fight against when I want to do anything complicated. It's been my experience that ORMs like Hibernate are trying to solve the problem "database access isn't Object-Oriented enough," which is the wrong solution to something that isn't really a problem.

That's great buddy but I can't get my boss to pay $150/year for IntelliJ, how in the world am I going to get him to pay $450 per developer seat per year for a freaking ORM?

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

pigdog posted:

Ask him why he's paying $2k - $25k per core for SQL Server or Oracle, then. For open-source databases like Postgres or MySQL it's free.

Actually we don't pay a dime for Oracle. It's our client's database, they pay for it, we are considered "developer" seats and those are free on their license. Oracle charges by the production-server core, JOOQ charges by developer seat, totally different model.

As for the client - yeah it's stupid but (a) they want someone they can call up when poo poo breaks, and (b) switching would require them admitting they're throwing away money.

Our DBA was telling me that one of the enterprise-grade Postgres derivatives has a wrapper that basically makes Postgres look like Oracle and we might be able to move forward like that.

Really they aren't doing anything that actually needs Oracle (which is probably a common story - CTO gets talked into fancy enterprise poo poo they don't need). We have maybe 50 million table rows in total, spread across ~25 tables. Our DBA spends so much time tuning queries and poo poo, and I think Postgres would probably just do it automatically just fine. Between a few poorly-designed tables that slow everything way down and the fact that Oracle's query planner is terrible and needs constant hand-tuning they think they need the big fancy enterprise products though.

I don't know how you get a join to a primary key column to take 300 seconds, but that's a thing I've experienced thanks to Oracle.

Paul MaudDib fucked around with this message at 02:10 on Dec 19, 2016

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

JewKiller 3000 posted:

In my experience, you get it by believing things like this:

No I mean I went into a database client and types in SELECT * FROM TABLE_X JOIN TABLE_Y ON TABLE_X.FKEY = TABLE_Y.PRIMARYKEY LIMIT 50 and it took 300 seconds to come back. Dafuq.

It obviously had to be attempting some kind of full table scan but that still shouldn't take 300 seconds with like 1M records in each table.

Paul MaudDib fucked around with this message at 02:48 on Dec 20, 2016

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

smackfu posted:

So Employee has both department_id (always present) and department (null until accessed) fields? I guess that's what is tripping me up.

There's two ways you can do it. The first is you can have both department and department_id fields, yes. The problem is that Hibernate can only have one set of getter/setter functions actually mapped through to any particular database column. If you have both department and department_id fields then one of them needs to have insert="false" update="false" attributes in its .hbm.xml file or the equivalent annotations. And then you need to make sure that you are not trying to do inserts/updates on the field that's been set as read-only, and be sure that they don't get out of sync.

The solution I've arrived at in the past is to have the property (the ID) be the "master" and have the entity ("department") be the read-only one, since when you call setDepartment it definitely has the appropriate Department object already and you can get the Id from that, whereas if you call setDepartmentId then it doesn't have the Department and you would have to call the database. But I don't know if this is actually the right way, it's entirely possible Hibernate is smart enough to mark the entity for lazy-loading if you change the underlying foreign, key.

The other way you can do it is to just have the entity ("department"). You know how Hibernate can lazy-load fields? It also knows when you call a getter to get the primary key on an entity to which you have a foreign-key. So if you call "getDepartment().getId()" it will just return the "department_id" foreign key instead of making a database call. If you're writing from scratch, I really think this is the better way.

The key takeaway here, by the way, is that Hibernate is hooking your getters/setters and what they actually do is totally different from how the raw code looks. I wouldn't advise putting a bunch of logic in getters/setters unless you setup some tests first to be sure they behave how you want. You should also probably default to using the getters/setters rather than touching the underlying values for anything except the getters/setters to be sure Hibernate has its chance to hook things appropriately (it may be OK to deviate from this, but again, test).

I typically have very anemic data classes, I generally try to follow the MVC pattern even for non-web applications. The model will just be data holders that closely mirror the database structure. Then I have some "controller" that does works with them, and presents a "view" of some kind (perhaps a HTTP response for an API-like application). Teachers don't like it, but I think that's much more sane than true "object oriented" programming where everything has to know how to interact with everything else and you end up with an exponential blowout of the amount of code you need to maintain. The benefits/limitations here tilt pretty heavily towards the "anemic" model for most modern applications. After all, if your code is small then who cares, and if you are large then scalability becomes important. Apart from architectural purism, why would you care about whether the main business logic lives in a controller or right in the class file, if it works and is maintainable?

quote:

Benefits

Clear separation between logic and data[3] (procedural programming).
Works well for simple applications.
Results in stateless logic, which facilitates scaling out.
Avoids the need for a complex OO-Database mapping layer.

Liabilities

Logic cannot be implemented in a truly object-oriented way.
Violation of the encapsulation and information hiding principles.
Needs a separate business layer to contain the logic otherwise located in a domain model. It also means that domain model's objects cannot guarantee their correctness at any moment, because their validation and mutation logic is placed somewhere outside (most likely in multiple places).
Needs a service layer when sharing domain logic across differing consumers of an object model.
Makes a model less expressive.
https://en.wikipedia.org/wiki/Anemic_domain_model

Paul MaudDib fucked around with this message at 03:45 on Jan 11, 2017

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE
Somehow I think I may be the only person who prefers XML configuration over annotations for Hibernate? Has nobody else tried to map the same entity to two different formats before, say one is JSON that you take in over the wire and the other is Hibernate that you store in your database?

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

geeves posted:

Having a problem with Maven. My code builds correctly on my main machine. But same codebase on other machines, I get a compilation error with HttpServletResponse. My company is JUST NOW getting to dependency management :sigh:

The code works as it is now for our application. It's just failing on build for my 2nd machine and for others.

There is an older version of javax.servlet:javax.servlet-api (we use 3.1, the dependency uses 2.3) that is used by another jar and I have tried adding it as an exclusion in the offending dependency, but that does not work

We're passing in:

method(HttpServletResponse res, ...)

and it fails on first line of the method: "res.setCharacterEncoding("UTF-8");"

Any thoughts? I've been stuck on this for over a day and really haven't been able to find an answer on Stackoverflow etc. (the exclusion one was promising, but ultimately didn't work)

geeves posted:

It's weird. I commented out the dependency on a whim and ran mvn install. Build Successful. :v:

Uncommented the dependency and built. Build Successful. :v: It's some weird circular dependency.

The library causing the issue is some very old RSS lib (yarfraw) that's from 2008. I checked out the code to perhaps fix things, but everything fails to build. I've tried several tags and the main trunk. I don't know who thought using this was a good idea (it was our CTO). So I'm going to replace since it's only used in two small places. One place for parsing date time which java 8 can now do natively. The other is just basic reading.

Usually this is exactly the problem and fix for me. You ran "mvn install" locally. Now you have a different version of the lib installed in your local Maven repository. Boom, compiles for you but nobody else. Or otherwise - somehow you have a different version of this lib in your Maven cache from everyone else, that's what it comes down to.

Dumb idea: you can set up a Maven reactor project. You have parent project A which compiles modules B and C and D. C depends on B, so the reactor will compile B and then sub it into C. Problem though - this means you are compiling everything every time, and if B's tests aren't insignificant that can potentially be a huge build time. Also, if D depends on C (B -> C -> D) then you have no way to build just C in isolation - your only unit you can build successfully by itself is "A" so compiling A will compile B and C and D too. This can also be a problem if D is huge.

Partial fix of this problem - you set up a local artifact repository inside the repo, and have Maven install to that repository when it does its thing. This is also how you replicate the traditional "libs" folder via Maven. Since it needs to know what each jar file actually is - so that it can manage your dependencies. There is no difference between Maven Central and something you install into a repo with "mvn install:install-file -DlocalRepositoryPath". One is accessible over http: //, one is accessible over file: //, that's the only distinction that Maven's abstraction will draw. https://maven.apache.org/guides/mini/guide-3rd-party-jars-local.html

Now you get an additional problem, because Maven will "helpfully" set up a cache inside your homedir ("~/.m2" on Linux, "/Users/geeves/.m2/" on Windows). Somebody else pushes a new version of your custom-built dependency jarfile and some code changes. But Maven won't check the repositories until the cache expires - not even the local repositories. gently caress you Maven, this is a terrible coding decision. To fix it, delete your ".m2" folder and you will redownload everything.

Better fix of this problem - you really need to set up an artifact repository like Nexus or Artifactory. This is basically your own version of MavenCentral that holds your private jars and stuff. You can even have it cache stuff from MavenCentral so you don't have to redownload everything slowly from the internet every single time. https://www.sonatype.com/nexus-repository-sonatype https://www.jfrog.com/open-source/

Now we hit an additional additional problem. The "contract" of Maven dependencies is the groupId, artifactId, and version of the package matching if and only if the jar is exactly the same. As far as Maven is concerned, if those things match then the jars are interchangeable. Which is why Maven is deciding to cache poo poo in the first place. So now, every time some idiot compiles the jar with something that breaks the main code then it breaks for everyone who uses the artifact repository server.

Fix: if you are compiling every time then what you actually have is a "SNAPSHOT" build. For example, instead of building version target "2.0.0" you should use "2.0.0-SNAPSHOT". Also, set these config files to force them to always be rebuilt. http://stackoverflow.com/questions/2358965/maven-automatic-snapshot-update

Further tip: don't ever set your project up to compile configuration (DB server target, etc) into your jar files. You always always do something like JNDI instead of that. Otherwise, what happens when someone installs the jar and your production server suddenly boots up with test-server configuration?

I'm not going to say that I'm totally guilt-less here, but if you're going to do it, don't ever compile to the same jar-file target filename. Different filenames for different builds, it doesn't help the Maven problem but it will help your sanity. Deploying "myapp-prod.war" to Tomcat will only ever deploy to "webapps/myapp-prod/" unless you get frisky with the web.xml. And you always always do a "mvn clean package" or "mvn clean war:war" or something, you never never never do a "mvn clean install" on something that might produce a different output based on profiles/configuration/git branch/etc. Otherwise I guarantee you will get hosed by this down the road. It may be tomorrow, it may be 2 years, but your clock is ticking buddy. If your new guy does it then you get to have a long and productive explanation of the Maven lifecycle and how you will respect it.

Paul MaudDib fucked around with this message at 00:54 on Feb 9, 2017

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

Boz0r posted:

I have some code that doesn't compile in IntelliJ, but our ant script works fine. I don't get it.

code:
public double someFunction(List<Pair<Long, Double>> parameter) { ... }

public BigDecimal someFunction(List<Pair<Integer, BigDecimal>> parameter) { ... }
As far as I can tell, it shouldn't compile. Why does it compile in ant?

Your IntelliJ classpath isn't the same as your Ant classpath somehow. Unlike Maven, Ant build files are not a declarative "project" file, they are like a makefile and you need to keep your IDE's project file in sync with them. When you run "build" it's actually IntelliJ compiling it via its own build script - not running the Ant script.

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE
Anyone used Lanterna before? Or any AWT/Swing stuff?

I'm just trying to dip my toes into Lanterna for a personal project, but the documentation is poo poo. I'm doing OK except I can't figure out how to make the font size change. Everything is super big (1/4 of my 1440p screen, so like 720p). What I'm trying is this:


code:

    public static void main( String[] args )
            throws Exception
    {
        Font font = new Font("DejaVu Sans Mono",Font.PLAIN, 4);
        TerminalSize size = new TerminalSize(80,20);
        Terminal terminal = new DefaultTerminalFactory()
                .setInitialTerminalSize(size)
                .setTerminalEmulatorFontConfiguration(AWTTerminalFontConfiguration.newInstance(font))
                .createTerminal();
        Screen screen = new TerminalScreen(terminal);
        screen.startScreen();

        Panel panel = new Panel();
        panel.setLayoutManager(new GridLayout(1));
        final CheckBoxList checkBoxList = new CheckBoxList();
        panel.addComponent(checkBoxList);

        for(int i = 0; i < 10; i++)
        {
            checkBoxList.addItem(Integer.toString(i));
        }


        final BasicWindow window = new BasicWindow();
        window.setHints(Arrays.asList(Window.Hint.EXPANDED));
        window.setComponent(panel);
        window.setTitle("title");

        panel.addComponent(new Button("Done", new Runnable() {
            public void run() {
                window.close();
            }
        }));

        MultiWindowTextGUI gui = new MultiWindowTextGUI(screen, new DefaultWindowManager(), new EmptySpace(TextColor.ANSI.BLUE));
        gui.addWindowAndWait(window);
        terminal.close();
        for(int i = 0; i < 10; i++)
        {
            if(checkBoxList.isChecked(i))
            {
                String txt = (String) checkBoxList.getItemAt(i);
                System.out.println("item " + Integer.toString(i) + ": checked");
            }
        }
    }
TerminalSize works... but it doesn't change the font size at all. Font doesn't seem to work at all. I've never worked directly with AWT before and I suspect that I may just be loving up the Font calls in some really obvious way.

Paul MaudDib fucked around with this message at 06:06 on Feb 21, 2017

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE
In unrelated news, at work I'm working on converting a legacy app that pre-generated database IDs at object creation, so basically Hibernate doesn't know what the gently caress because it sees everything as detached. saveOrUpdate is broken, persist is broken, one-to-many collections are broken, and we're piling more and more dirty hacks on top of the legacy dirty hacks because "what we had worked before!" and the tech lead doesn't want to touch anything because we have a big mass of spaghetti code and no tests.

I'm pushing hard for high-level integration testing using a container instance of the DB schema that we can set up and knock down almost instantly, and running tests by passing request parameters into the Struts actions and then parsing the output with something like TagSoup for targeted outputs. Like a form of Selenium testing that doesn't take hours to run. Then we can start delving down into the core code and cleaning it up into something testable.

Also, since it's Oracle-based, there's tons of DB quirks. Otherwise I'd propose SQLite.

The tech lead thinks it'll all just somehow work out with some bailing wire and lots of tester time. But I know we're gonna break everything all the time unless we get automated tests. Right now you have no idea what you'll be passed, every action is passing in a totally different mix of object states- transient, persistent, detached, illegal combinations thereof (detached objects that don't exist in the database!), or something that Hibernate shouldn't touch, and there's like 50 actions and several hundred views.

Paul MaudDib fucked around with this message at 06:20 on Feb 21, 2017

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

smackfu posted:

Apparently if you have a one-to-one Hibernate relationship, and you define it as lazy, it doesn't actually make it lazy. Because there is no way to give you a pointer that might need to be null if the other side of the relationship doesn't exist. (I think that's the reason.) So every time you fetch the parent, it fetches the child in a separate query.

I feel like that deserves a warning or something. And there's no easy fix to it either.

What about defining it as many-to-one with "insert=false update=false" and the key column also being the ID column?

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

geeves posted:

I don't agree with this at all. There are some libraries that are hosted in Maven Central that have, for lack of better term, "add-on" libraries that are not in Maven Central that you have to download individually (Why IBM? Why?) or you might have a very old library that still has a need in your application and you can't find a suitable replacement or just can't do a refactor at the moment.

So instead, use Artifactory and upload it to your own Maven repository.

Yup. Pretty much any artifact that is under one of Sun's packages, or javax.*, and is NOT an API-only jar, is not going to be available in the Maven-Central repo. Sun/Oracle's license is pretty horrendous and so they get shut out of OSS repositories. Same problem that afflicts Oracle JDK in the official distributions.

The place where this usually bites you is stuff like the Oracle OJDBC driver, or some of the javax artifacts like jdbc-stdext. For the most part, web stuff will be bundled and/or injected with your web server so at least that's not a real problem - you just need to note it as "provided" in your pom.xml.

In theory you should be able to point Maven at a "local repository" across file:// too - however I haven't been able to make this work reliably. It works for my local PC (probably gets installed into my .m2) but not on other computers. Also, Maven's caching rules are a cast-iron bitch for trying to debug this and I haven't figured out a viable way around them short of deleting the whole .m2 folder and letting it re-resolve everything.

Gradle, on the other hand, works perfectly in this use-case. It understands the concept of a Maven repository on disk, or you can just give it a "libs" directory full of jars to include like you would with an Ant build. As such I think that probably makes it an easier sell for teams converting from legacy Ant build scripts and/or working offline.

This is kind of unfortunate since in theory I like the idea of a Maven build much better. The declarative model is very easy for IDEs to handle for setting up classpath, and unlike Gradle you don't need a "build daemon" hanging around to get decent performance. But apart from the "imperative" style format and the daemon - I think they really get you to pretty much the same place. And gradle gives you a better mix for transitioning legacy code - you can write pretty much the same stuff as you would in Ant, but you benefit from the dependency resolution and modern conventions of Maven.

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

smackfu posted:

Your legal department probably doesn't want you to use that weird Sun junk anyways.

I personally stay the hell away from it, if for no other reason than because since it's not in the main repos it doesn't get automatic updates.

Still though, you might be surprised. The ToS from Oracle are a known quantity, and lots of project managers prefer the devil you know over "software from some guy on the internet" and "regular security updates" and similar forms of heresy.

Again, given that the client is using Oracle DB anyway, we're kind of in for a penny anyway, but at least that's mostly on them, they made that deal with the devil themselves.

Personally I'd go with Postgres over literally anything else any day, unless my workload literally couldn't be serviced by a decked-out 8-socket Xeon server. So far it doesn't have good support for horizontal scaling/distributed transactions - but anything short of that it works fine.

Honestly OJDBC has been one parade of bugs after another. Today, Hibernate decided to revert to the default sequence for no actual reason that we can determine - but only on the "sequence" generator type, the deprecated "sequence-identity" generator type works fine.

Paul MaudDib fucked around with this message at 03:47 on Mar 15, 2017

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

Good Will Hrunting posted:

I'm using a few libraries which depend on different versions of Guava. A few use an older version of Guava and when I try to do something with the jar I'm building (Spark-submit it) it's giving me a NoSuchMethod error. That method is missing in Guava before 15. I assume that the class loader is loading an older version for some reason, even though Gradle's dependency tree shows everything being forced to the latest version.

Is there a way for me to handle this? I did something similar with shading but I can't see to figure this out.

This is not gradle-specific, and it's pretty much always one of two problems. You either have an API jar and no implementation, or you have two copies of this hanging out somewhere in your dependencies. Look again.

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

Good Will Hrunting posted:

What do you mean by this? The problematic Guava version is being provided somewhere other than dependency resolution?

Maybe not that version, but you have two versions coming from somewhere. Maybe try building a jar-with-dependencies and see if there's two copies in there? Maybe there's another copy in a far-jar that is outside dependency resolution?

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE
One of my co-workers spent three weeks debugging a problem that was essentially traced back to a difference in floating-point addition between 1.4 and 1.8. Apparently you get numbers that are sliiiiiiightly different - at about 5 sigfigs. He thought he updated the jar he was comparing against 1.8 but I guess he forgot.

I also have not been allowed to touch the terrible junior-design-project (literally) level code in that library for weeks now until he could figure it out. Today I razzed him through the debugging process - so are the inputs the same at function Y? But they're different at the returns? OK, well, that's just a static function, so we should be able to write tests for the results. You're really really sure the inputs are the same and the outputs are different? OK well then it literally must be a platform problem, I can't imagine any other difference. I was about halfway through writing the test when the sheepish email came through.

So what exactly is different in FP math between 1.4 and 1.8, if anyone has a reference? I guess a difference at 5 sigfigs isn't too alarming after a couple cumulative operations (let's call it 6?), given that floating-point only has about 7 decimal points of significance - but still, that's a little weird in my book.

Paul MaudDib fucked around with this message at 20:48 on Apr 6, 2017

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

a witch posted:

e: Oops, my original post was replying to someone elses question about FP.


Welcome to hell.


Basically, Java is allowed to use extended precision, especially as an intermediate value during calculations involving floating point numbers.

I'm sorry I don't know exactly when a change may have occurred, but if you weren't using FP-strict expressions, then results aren't portable between different Java versions or platforms.

This is me. Yes, that sounds like a pretty good explanation of what happened. Nailed it. :hfive:

I know that Java isn't as platform independent as it pretends. That said, that's still pretty ugly. No, we certainly didn't have strictfp enabled.

Super fun thought: we are also running this on UltraSPARC in production. If it varies like this, I can't imagine that it's the same across x86 and SPARC. Super fun to be working out classifier bugs with this bullshit.

Thank gently caress for our serverdad who buys older hardware for a decent test environment. I owe that guy a beer, production heart-attack averted :sigh:

Paul MaudDib fucked around with this message at 22:37 on Apr 6, 2017

Adbot
ADBOT LOVES YOU

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

FateFree posted:

Ok time for some friendly architecture discussion. I'm interested in knowing how you gents would model a list of objects that should all be displayed on a UI in a row, but each one having different properties.

For instance HTML form fields would be a perfect analogy - some things are input fields with a name and value, other inputs are dropdowns that have their own collection of items to display, a text field may have a max length etc.

So from an inheritance perspective it probably makes sense to have a parent class with common attributes like name and value and child classes for the rest, but how would you model your DB tables? Different tables for each subclass and an ugly query to pull your list of objects? (I'm using Hibernate/JPA with Spring Boot btw.) Or what about a single 'Inputs' table with a JSON column for all the variable data (like the dropdown options). That would make the db very simple and I'll never need to query any of the JSON stuff anyway. But then you might have to do some manual casting to your child classes after you retrieve everything. Any model a similar structure before?

If the subclasses are predictable, you can have table-per-subclass (which is my favored strategy with inheritance). This is easy to do with Hibernate, it'll handle it automatically

If you have no idea what will be coming in - or there are an unreasonable amount of different tables - then you go with the JSON columns. Modern DBs can index JSON so that's not entirely terrible. But you can still map a bunch of the important/shared poo poo to actual relational columns and that does help performance a lot.

The problem comes in you start talking about validation, because the next stop on that crazytrain is defining your own validation language, and then a format that lets you map validation to fields, maybe add a generic format that lets you automatically build views from these forms, and then congratulations, your inner platform is designed, you just designed a template language and a validation schema, pat yourself on the back :golfclap:

We've gone down that path with electronic message parsing and poo poo is loving bullshit. We also have the "totally abstract schema where every record is a billion key-value pairs" too. Our performance is garbage specifically because of those tables and next release I get to make the case for why the PHD who designed it (still on the team somehow) is a retard. I guess he's been off playing with MongoDB in the meantime trying to sell the bosses on that (not joking).

If there is fundamentally a lot of configuration that needs to be done - there is no substitute here, regardless of whether you specify the abstractions in terms of code or in your own made-up validation scheme.

Personally I prefer the code anyway since it can be tested/validated.

Paul MaudDib fucked around with this message at 07:54 on Apr 12, 2017

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply