What is the Rust equivalent to Java’s PrintWriter?

In Rust, the equivalent of Java’s PrintWriter is the std::io::Write trait, which is implemented by a number of types that can be used to write data to an output stream, such as a file or a network socket.

To use Write to write text to an output stream, you can use the write_all method, which takes a byte slice as an argument and writes it to the output stream.

You can convert a string to a byte slice using the as_bytes method.

Here is an example of how you might use Write to write text to a file:

use std::fs::File;
use std::io::Write;

fn main() -> std::io::Result<()> {
    let mut file = File::create("output.txt")?;
    file.write_all(b"Hello, world!")?;
    Ok(())
}

If you want to use a buffered writer, similar to PrintWriter, you can use the BufWriter type from the std::io::BufWriter module.

This type wraps a Write implementation and buffers the output, improving performance by reducing the number of calls to the underlying write operation.

Here is an example of how you might use BufWriter to write text to a file:

use std::fs::File;
use std::io::{BufWriter, Write};

fn main() -> std::io::Result<()> {
    let file = File::create("output.txt")?;
    let mut writer = BufWriter::new(file);
    writer.write_all(b"Hello, world!")?;
    writer.flush()?;
    Ok(())
}

You can also use the writeln! macro from the std::fmt module to write a line of text to an output stream.

This macro takes a Write implementation and a format string as arguments, and writes the formatted string to the output stream followed by a newline character.

Here is an example of how you might use writeln! to write a line of text to a file:

use std::fs::File;
use std::io::Write;

fn main() -> std::io::Result<()> {
    let mut file = File::create("output.txt")?;
    writeln!(file, "Hello, world!")?;
    Ok(())
}

Solving “Received fatal alert: handshake_failure” error when performing HTTPS connections on a custom made JRE with jlink

TL; Tell me already what to do:
Add the jdk.crypto.cryptoki module to the list of --add-modules parameter to your jlink command invocation


If you’re reading this you’re one of the few developers out there that wanted to distribute a java 9+ app (using either jdk 9, jdk 10, jdk 11 or jdk 12, as of this writing) with a smaller version of the jdk, to build your custom jre, you used the jlink tool.

When you run your app using the full JRE that comes with the OpenJDK, your app is working fine when it comes to making https requests, but when you run your app using your custom jre you get the following error when opening https connections

[pastacode lang=”bash” manual=”Received%20fatal%20alert%3A%20handshake_failure” message=”” highlight=”” provider=”manual”/]

This issue occurs because your JRE is missing lots of Cipher Suites that come with the full JDK.

With your JDK, you can try to check the list of supported ciphers with this one liner using the jrunscript tool:

[pastacode lang=”bash” manual=”jrunscript%20-e%20%22print(java.util.Arrays.toString(javax.net.ssl.SSLServerSocketFactory.getDefault().getSupportedCipherSuites()))%22%0A” message=”” highlight=”” provider=”manual”/]

however that might not work for your custom JRE if you haven’t included the scripting module, so here’s a Java program I made that prints all the available Ciphers of your JRE

[pastacode lang=”java” manual=”public%20class%20PrintCiphers%20%7B%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%09var%20sslSocketFactory%20%3D%20javax.net.ssl.SSLServerSocketFactory.getDefault()%3B%0A%09System.out.println(%22SSLServerSocketFactory%20-%3E%20%22%20%2B%20sslSocketFactory.getClass().getName())%3B%0A%09try%20%7B%0A%20%20%09%20%20%20%20var%20getSupportedCipherSuitesMethod%20%3D%20sslSocketFactory.getClass().getMethod(%22getSupportedCipherSuites%22)%3B%0A%09%20%20%20%20String%5B%5D%20ciphers%20%3D%20(String%5B%5D)%20getSupportedCipherSuitesMethod.invoke(sslSocketFactory)%3B%0A%09%20%20%20%20int%20i%3D1%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20(String%20c%20%3A%20ciphers)%20%7B%0A%09%09System.out.println(i%2B%2B%20%2B%20%22%20%22%20%2B%20c)%3B%0A%09%20%20%20%20%7D%0A%09%7D%20catch(Throwable%20t)%20%7B%0A%09%20%20%20%20t.printStackTrace()%3B%0A%09%7D%0A%20%20%20%20%7D%0A%7D%0A” message=”” highlight=”” provider=”manual”/]

If you run PrintCiphers on your OpenJDK’s full JRE, you will see almost 50 Cipher Suites available:

[pastacode lang=”bash” manual=”%24%20java%20PrintCiphers%3B%0A1%20TLS_AES_128_GCM_SHA256%0A2%20TLS_AES_256_GCM_SHA384%0A3%20TLS_CHACHA20_POLY1305_SHA256%0A4%20TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384%0A5%20TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256%0A6%20TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256%0A7%20TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384%0A8%20TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256%0A9%20TLS_RSA_WITH_AES_256_GCM_SHA384%0A10%20TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384%0A11%20TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384%0A12%20TLS_DHE_RSA_WITH_AES_256_GCM_SHA384%0A13%20TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256%0A14%20TLS_DHE_DSS_WITH_AES_256_GCM_SHA384%0A15%20TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256%0A16%20TLS_RSA_WITH_AES_128_GCM_SHA256%0A17%20TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256%0A18%20TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256%0A19%20TLS_DHE_RSA_WITH_AES_128_GCM_SHA256%0A20%20TLS_DHE_DSS_WITH_AES_128_GCM_SHA256%0A21%20TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384%0A22%20TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384%0A23%20TLS_RSA_WITH_AES_256_CBC_SHA256%0A24%20TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384%0A25%20TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384%0A26%20TLS_DHE_RSA_WITH_AES_256_CBC_SHA256%0A27%20TLS_DHE_DSS_WITH_AES_256_CBC_SHA256%0A28%20TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA%0A29%20TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA%0A30%20TLS_RSA_WITH_AES_256_CBC_SHA%0A31%20TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA%0A32%20TLS_ECDH_RSA_WITH_AES_256_CBC_SHA%0A33%20TLS_DHE_RSA_WITH_AES_256_CBC_SHA%0A34%20TLS_DHE_DSS_WITH_AES_256_CBC_SHA%0A35%20TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256%0A36%20TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256%0A37%20TLS_RSA_WITH_AES_128_CBC_SHA256%0A38%20TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256%0A39%20TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256%0A40%20TLS_DHE_RSA_WITH_AES_128_CBC_SHA256%0A41%20TLS_DHE_DSS_WITH_AES_128_CBC_SHA256%0A42%20TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA%0A43%20TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA%0A44%20TLS_RSA_WITH_AES_128_CBC_SHA%0A45%20TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA%0A46%20TLS_ECDH_RSA_WITH_AES_128_CBC_SHA%0A47%20TLS_DHE_RSA_WITH_AES_128_CBC_SHA%0A48%20TLS_DHE_DSS_WITH_AES_128_CBC_SHA%0A49%20TLS_EMPTY_RENEGOTIATION_INFO_SCSV%0A” message=”” highlight=”” provider=”manual”/]

but if you use your custom JRE to run PrintCiphers you will see only 23 Cipher Suites available:

[pastacode lang=”bash” manual=”%24%20jre%2Fbin%2Fjava%20PrintCiphers%0A1%20TLS_AES_128_GCM_SHA256%0A2%20TLS_AES_256_GCM_SHA384%0A3%20TLS_CHACHA20_POLY1305_SHA256%0A4%20TLS_RSA_WITH_AES_256_GCM_SHA384%0A5%20TLS_DHE_RSA_WITH_AES_256_GCM_SHA384%0A6%20TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256%0A7%20TLS_DHE_DSS_WITH_AES_256_GCM_SHA384%0A8%20TLS_RSA_WITH_AES_128_GCM_SHA256%0A9%20TLS_DHE_RSA_WITH_AES_128_GCM_SHA256%0A10%20TLS_DHE_DSS_WITH_AES_128_GCM_SHA256%0A11%20TLS_RSA_WITH_AES_256_CBC_SHA256%0A12%20TLS_DHE_RSA_WITH_AES_256_CBC_SHA256%0A13%20TLS_DHE_DSS_WITH_AES_256_CBC_SHA256%0A14%20TLS_RSA_WITH_AES_256_CBC_SHA%0A15%20TLS_DHE_RSA_WITH_AES_256_CBC_SHA%0A16%20TLS_DHE_DSS_WITH_AES_256_CBC_SHA%0A17%20TLS_RSA_WITH_AES_128_CBC_SHA256%0A18%20TLS_DHE_RSA_WITH_AES_128_CBC_SHA256%0A19%20TLS_DHE_DSS_WITH_AES_128_CBC_SHA256%0A20%20TLS_RSA_WITH_AES_128_CBC_SHA%0A21%20TLS_DHE_RSA_WITH_AES_128_CBC_SHA%0A22%20TLS_DHE_DSS_WITH_AES_128_CBC_SHA%0A23%20TLS_EMPTY_RENEGOTIATION_INFO_SCSV%0A” message=”” highlight=”” provider=”manual”/]

To solve the problem you must add the jdk.crypto.cryptoki module to the list of --add-modules parameter to your jlink command invocation, next time your run PrintCiphers you should see the full list of Cipher Suites and your SSL handshake issues should be gone.

How to run your Kotlin gradle built app from the command line

So you build your Kotlin app, you went through the trouble of creating a build.gradle script that you build with

gradle assemble

this outputs a a “build/libs/kotlin.jar” .jar file, but you have no clue how to run your Kotlin code from the command line.

Doing it by hand with “java -cp ” is too much work, and there is a way to do

gradle run

or even

gradle -b /home/myuser/mykotlinapp/build.gradle run

in case you need to run your Kotlin script from a cronjob.

Make sure you have the following inside your build.gradle script in order to make the “run” task available


apply plugin: 'application'

// DO notice the "Kt" suffix on the class name below, if you don't use the Kt generated class you will get errors
mainClassName = 'com.myapp.MyKotlinAppKt'

// optional: add one string per argument you want as the default JVM args
applicationDefaultJvmArgs = ["-Xms512m", "-Xmx1g"]

What if I don’t want to use gradle, and just java

ok… ok…
java -cp $KOTLIN_LIB/kotlin-runtime.jar:build/libs/kotlin.jar: com.myapp.MyKotlinAppKt

[CODE/JAVA] Scanner – read a full line

I was solving problems at HackerRank to teach a friend how to code in Java and to process the input data it’s convenient to use Java’s built in Scanner class.

However, in one of the problems we wanted to read a whole line at once and we noticed that the Scanner’s API is geared towards reading the next token, and it doesn’t have a method that reads the entire line. It has one method that skips a line and reads from the last point which is very weird to use, so we created a static method to just read the next entire line, keeping it simple.

public static String readLine(Scanner scanner) {
            Pattern oldDelimiter = scanner.delimiter();
            scanner.useDelimiter("\\r\\n|[\\n\\x0B\\x0C\\r\\u0085\\u2028\\u2029]");
            String r = scanner.next();
            scanner.useDelimiter(oldDelimiter);
            return r;
    }

The Scanner uses as its default token delimiter a whitespace pattern, so what we do in this method is to temporarily replace the token delimiter for a newline delimiter. Once set to newline all we need to do is to read the next token, which will be the entirety of the line, and then we put the previous delimiter set back in place.

In Java 8 there’s a new Linebreak matcher expression \R, however, if we want our method to be backwards compatible (as we don’t know on which JRE it could be running) we set the equivalent delimiter manually in our function

\R  Any Unicode linebreak sequence, is equivalent to \u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]

If you don’t like the static function approach you can always repurpose this code and extend Scanner into a custom MyScanner class , and add a method nextLine that does the same thing

[CODE/JAVA] ARGB_8888 Pixel Abstraction

This is one of the ways you can decode Pixel colors out of the integers you get from Android Pixels.

ARGB_8888, stands for Alpha, Reg, Green, Blue. The 8’s stand for the number of bits per channel.

In Android, signed int‘s are used to represent pixel’s alpha/color information.
Since Android’s language of choice is java, these ints are 32-bit integers, each int takes 4 bytes.

4 bytes = 32 bits = 8bits + 8bits + 8bits + 8bits.

If you had an int like 0xFFAABBCC, each pair of letters on that hexadecimal would mean the following from left to right

{alpha=0xFF}{red=0xAA){green=0xBB}{blue=0xCC}

If you’ve done web programming and played with rgb colors and you didn’t know about this, now it all should click on how your web browser represents colors, except in HTML you don’t deal with the alpha value in the front. On Android’s XML you do.

In bits (binary), the 0xFFAABBCC value would look like this:

alpha red green blue
0xFF 0xAA 0xBB 0xCC
255 170 187 204
{0b11111111}{0b10101010}{0b10111011}{0b11001100}

If you wanted to look at the entire number in binary/bits, it’d be something like this (leaving spaces for visual help):

0b11111111 10101010 10111011 11001100 == 0xFFAABBCC == 4289379276

So if you wanted to get the red channel (0xAA = 170 = 0b10101010) , you’d have to move the whole thing towards the right 16 places, and then compare it with only the rightmost 8 bits.

So, we shift 16 places to the right, we’d get rid of the 2 bytes on the right side and end up only with the left half

0b11111111 10101010

Since we only care about those 8 bits on the right, we do an “&” (bitwise “and”) against 0xFF=255=0b111111111 (all 8 rightmost bits set to 1)

0b11111111 10101010 &
0b00000000 11111111
====================
0b00000000 10101010

So with simple right bit shifting and “& 0xff” of the shifted value we can extract the values per channel.

This class also features a “multiplyByFloat()” function, which I was using to multiply to each channel as I was operating with convolution kernels while playing with image filters.

[pastacode lang=”java” manual=”%2F**%20ARGB_8888%20Pixel%20abstraction%20*%2F%0Apublic%20static%20class%20PixelARGB_8888%20%7B%0A%20public%20final%20byte%20a%3B%0A%20public%20final%20byte%20r%3B%0A%20public%20final%20byte%20g%3B%0A%20public%20final%20byte%20b%3B%0A%20public%20final%20int%20intVal%3B%0A%0A%20public%20PixelARGB_8888(final%20int%20argb32bitInt)%20%7B%0A%20%20a%20%3D%20(byte)((argb32bitInt%20%3E%3E%2024)%20%26%200xff)%3B%0A%20%20r%20%3D%20(byte)((argb32bitInt%20%3E%3E%2016)%20%26%200xff)%3B%0A%20%20g%20%3D%20(byte)((argb32bitInt%20%3E%3E%208)%20%26%200xff)%3B%0A%20%20b%20%3D%20(byte)(argb32bitInt%20%26%200xff)%3B%0A%20%20intVal%20%3D%20argb32bitInt%3B%0A%20%7D%0A%0A%20public%20PixelARGB_8888(byte%20a%2C%20byte%20r%2C%20byte%20g%2C%20byte%20b)%20%7B%0A%20%20this.a%20%3D%20a%3B%0A%20%20this.r%20%3D%20r%3B%0A%20%20this.g%20%3D%20g%3B%0A%20%20this.b%20%3D%20b%3B%0A%20%20intVal%20%3D%20(a%20%3C%3C%2024)%20%2B%20(r%20%3C%3C%2016)%20%2B%20(g%20%3C%3C%208)%20%2B%20b%3B%0A%20%7D%0A%0A%20public%20static%20int%20multiplyByFloat(float%20factor%2C%20int%20arg32bitInt)%20%7B%0A%20%20return%20multiplyByFloat(factor%2C%20arg32bitInt%2C%20false)%3B%0A%20%7D%0A%0A%20public%20static%20int%20multiplyByFloat(float%20factor%2C%20int%20argb32bitInt%2C%20boolean%20multiplyAlphaChannel)%20%7B%0A%20%20PixelARGB_8888%20original%20%3D%20new%20PixelARGB_8888(argb32bitInt)%3B%0A%20%20byte%20alpha%20%3D%20original.a%3B%0A%20%20if%20(multiplyAlphaChannel)%20%7B%0A%20%20%20alpha%20%3D%20(byte)(original.a%20*%20factor)%3B%0A%20%20%7D%0A%20%20PixelARGB_8888%20multiplied%20%3D%20new%20PixelARGB_8888(alpha%2C%20(byte)(factor%20*%20original.r)%2C%20(byte)(factor%20*%20original.g)%2C%20(byte)(factor%20*%20original.b))%3B%0A%20%20return%20multiplied.intVal%3B%0A%20%7D%0A%7D” message=”” highlight=”” provider=”manual”/]

IntelliJ / Adroid Studio / CLion / GoLand / PyCharm / PHPStorm keymap shortcuts I can’t live without

Download settings.jar (Import with `File -> Import Settings`)

I got to IntelliJ after years of using Emacs and Eclipse. Here’s how my keymap looks now that I work with Jetbrains tools, these are the keyboard shortcuts I can’t live without as a programmer.

 

Legend (Mac keyboard)
⌘ Command
⇧ Shift

⌘1 Show Intent Actions (Things like assign to local variable)
⌘- Decrease font size
⌘= Increase font size
⌘0 Reset font size
⌘↓ Scroll to botom
⌘↑ Scroll to top
⌘f Find in text
⌘. Find next highlighted error
^⇧F Find in path (searches in all files, like a grep)
⌘⇧G Find Usages (Find all Occurrences of selected symbol [variable, method, class, identifier])
⌘I Show current function/method parameter info
F3 Jump to source (go inside function’s code)
⌘E Show list of recent files
⌘B Build
⌘L Jump to line number
⌘[ Back
⌘] Forward
⌘T Show implementations of an interface.
⌘⇧F Format (selected) code
⌘⇧O Organize/Optimize imports
⌘⌥R Rename current symbol
^K Kill line
⌘D Duplicate line
Ctrl+G on selected token – repeats selection and enables multiple cursors
Alt+Up | Alt+Down – Move the current line up or down

Debugger shortcuts
F5 Step Into
F6 Step Over
F7 Step Out
F9 Resume Program

^K Cut up to Line End. (Deletes everything to the right of where the text cursor or caret is)

2 Java debugging tricks

1. Embed state in your thread names.

Some times when you see a crash log with a thread dump, you see the stack of all the threads at the moment of the snapshot, but there’s no way to see what the state of the variables and objects at play in the thread were like.

You can use Thread.currentThread.setName(...) and embed variable states on the thread name for a more useful thread dump output.

2. Set a Default uncaught exception handler and log the error to the thread.

 

GRADLE: How to specify resources from different folders on your sourceSet

Sometimes you need to have resources in your sourceset and these may come from different locations on disk, the official documentation is lacking in real world examples, or at least I just didn’t understand it very well, but from reading forums I finally got it to work.

In the example I specify what files to include/exclude from two different folders.
When the final .jar is created, they’ll keep the package path structure that lives inside the given srcDir folders.

If you just want to add these files (for some reason to the root of your resulting jar, you should make srcDir the full path to where the files live)

[pastacode lang=”java” manual=”sourceSets%20%7B%0Amain%20%7B%0Ajava%20%7B%0A%2F%2Fyour%20java%20source%20paths%20and%20exclusions%20go%20here%E2%80%A6%0A%7D%0A%0Aresources%20%7B%0AsrcDir%20%E2%80%98components%2Fresources%2Fsrc%2Fmain%2Fresources%E2%80%99%0Ainclude%20%E2%80%98**%2F*.properties%E2%80%99%0Ainclude%20%E2%80%98**%2F*.png%E2%80%99%0Ainclude%20%E2%80%98**%2F*.gif%E2%80%99%0Ainclude%20%E2%80%98**%2F*.jpg%E2%80%99%0Ainclude%20%E2%80%98**%2F*.html%E2%80%99%0Ainclude%20%E2%80%98**%2F*.js%E2%80%99%0Ainclude%20%E2%80%98**%2F*.sh%E2%80%99%0Ainclude%20%E2%80%98**%2F*.dat%E2%80%99%0Ainclude%20%E2%80%98**%2F*.icc%E2%80%99%0Aexclude%20%E2%80%98**%2F*.DS_Store%E2%80%99%0A%0AsrcDir%20%E2%80%98common%2Fvuze%2Fazureus2%2Fsrc%E2%80%99%0Ainclude%20%E2%80%98**%2FMessages*.properties%E2%80%99%0Aexclude%20%E2%80%98**%2F*.class%E2%80%99%0Aexclude%20%E2%80%98**%2F*.java%E2%80%99%0A%7D%0A%7D%0A%7D” message=”” highlight=”” provider=”manual”/]

GRADLE: How to copy files from another .jar into your resulting output .jar

In our project we like to deliver a single jar as the final product, if you need to copy files that live on an existing jar into the Gradle’s output jar, this example shows you how to do that (and more)

[pastacode lang=”java” manual=”jar%20%7B%0A%2F%2Fthis%20is%20how%20you%20change%20the%20name%20of%20the%20output%20jar%0AarchiveName%3D%E2%80%99frostwire.jar%E2%80%99%0A%0A%2F%2Fsome%20exclusion%20rules%20to%20keep%20your%20.jar%20clean%0Aexclude(%E2%80%98META-INF%2F*.SF%E2%80%99%2C%20%E2%80%98META-INF%2F*.DSA%E2%80%99%2C%20%E2%80%98META-INF%2F*.RSA%E2%80%99%2C%20%E2%80%98META-INF%2F*.MF%E2%80%99)%0A%0A%2F%2Fhere%20we%20grab%20all%20the%20.class%20files%20inside%20messages.jar%20and%20we%20put%20them%20in%20our%20resulting%20jar%0Afrom%20(zipTree(%E2%80%98lib%2Fjars%2Fmessages.jar%E2%80%99))%20%7B%0Ainclude%20%E2%80%98**%2F*.class%E2%80%99%0A%7D%0A%0A%2F%2Fhow%20to%20manipulate%20the%20jar%E2%80%99s%20manifest%0Amanifest%20%7B%0Aattributes%20%E2%80%98Main-Class%E2%80%99%3A%20%E2%80%98com.limegroup.gnutella.gui.Main%E2%80%99%0A%7D%0A%7D” message=”” highlight=”” provider=”manual”/]

GRADLE: How to add a list of local .jar files to the build classpath

Sometimes you don’t want/cant use maven repos, all you have is a bunch of local jars on disk that you want to use as part of your compilation classpath, and the freaking gradle documentation is too vague.

Here is an example:

[pastacode lang=”java” manual=”dependencies%20%7B%0Acompile%20files(%E2%80%98lib%2Fjars%2Fgettext-commons.jar%E2%80%99%2C%0A%E2%80%98lib%2Fjars%2Flucene-3.5.0.jar%E2%80%99%2C%0A%E2%80%98lib%2Fjaudiotagger.jar%E2%80%99%2C%0A%E2%80%98lib%2Fjars%2Fh2-1.3.164.jar%E2%80%99%2C%0A%E2%80%98lib%2Fjars%2Fmessages.jar%E2%80%99%2C%0A%E2%80%98lib%2Fjars%2Fslf4j-api-1.7.5.jar%E2%80%99%2C%0A%E2%80%98lib%2Fjars%2Fjaudiotagger.jar%E2%80%99%2C%0A%E2%80%98lib%2Fjars%2Fmetadata-extractor-2.6.2.jar%E2%80%99%0A)%0A%7D” message=”” highlight=”” provider=”manual”/]