“Arquivo de assinatura inválido” ao tentar executar um arquivo .jar

450

Meu programa java é empacotado em um arquivo jar e faz uso de uma biblioteca jar externa, o castelo insuflável . Meu código compila bem, mas a execução do jar leva ao seguinte erro:

Exceção no encadeamento "main" java.lang.SecurityException: resumo do arquivo de assinatura inválido para os principais atributos do Manifest

Pesquisei por mais de uma hora pesquisando uma explicação e encontrei muito pouco valor. Se alguém já viu esse erro antes e pudesse oferecer alguma ajuda, eu seria obrigado.


fonte
1
você está tentando assinar seu próprio frasco? Se sim, como você está tentando assinar?
Cogy
Não, pelo menos eu não acho que sou. O Xcode pode estar tentando assiná-lo por conta própria, mas não parece haver nenhuma configuração para desativar isso.
não se esqueça de verificar se os frascos contendo interfaces implementadas também são assinados!
gaurav 19/03

Respostas:

47

A solução listada aqui pode fornecer um ponteiro.

Resumo do arquivo de assinatura inválido para os principais atributos do manifesto

Bottom line:

Provavelmente, é melhor manter o jar oficial como está e apenas adicioná-lo como uma dependência no arquivo de manifesto do arquivo jar do aplicativo.

Nrj
fonte
3
Como eu refletiria isso no arquivo de manifesto? Eu nunca editei um antes. Estou usando o Xcode, e a convenção comum é colocar bibliotecas jar externas no diretório myproject / lib para inclusão, que é o que estou fazendo.
@ user123003 .. como é o caso do Intelli-J
MikeM
13
Infelizmente, alguns de nós usam coisas como "plug-in sombra maven", de modo incluindo cópias fiéis do frasco original não é tão fácil nos casos ...
rogerdpack
plugue descarado para responder neste site: stackoverflow.com/a/30922181/448779
foo
e quanto ao maven-assembly-plugin?
Resolva
1083

Para aqueles que receberam esse erro ao tentar criar um uber-jar com maven-shade-plugin, a solução é excluir arquivos de assinatura de manifesto adicionando as seguintes linhas à configuração do plug-in:

<configuration>
    <filters>
        <filter>
            <artifact>*:*</artifact>
            <excludes>
                <exclude>META-INF/*.SF</exclude>
                <exclude>META-INF/*.DSA</exclude>
                <exclude>META-INF/*.RSA</exclude>
            </excludes>
        </filter>
    </filters>
    <!-- Additional configuration. -->
</configuration>
ruhsuzbaykus
fonte
9
Eu usei esse método para o meu uber-jar e funcionou muito bem. Há um exemplo completo de POM em maven.apache.org/plugins/maven-shade-plugin/examples/… que mostra esse método filtrando os arquivos incluídos.
M. Dudley
4
Fiquei tentado a iniciar um tópico totalmente novo - mas como esse é o número 1 nos resultados do Google - parecia adequado mantê-lo aqui. As linhas listadas aqui estão no arquivo POM que estou usando - e ainda estou recebendo o erro de segurança ao executar o aplicativo. Ele constrói bem - e, é claro, corre bem quando NÃO está fazendo um jar do Uber - como esperado. E, embora isso seja certamente uma opção - mantenha-os separados - não resolverá o problema se você quiser um Uber Jar.
Gavin Baumanis
7
Isso funciona para mim, mas ... por que tivemos que ignorar os arquivos de assinatura? Im certeza assinatura manifesto estão lá por uma razão ....
Jeryl Cozinhe
4
Certifique-se de fazer "mvn clean" depois de fazer acima!
precisa saber é o seguinte
4
@JerylCook Os arquivos de assinatura estão lá para indicar que o conteúdo deste jar possui esses arquivos. Ao criar um uber jar, você adiciona mais arquivos ao jar e, portanto, a assinatura não está correta. Se você realmente quisesse, poderia assinar novamente o novo frasco, mas é claro que seria com a sua assinatura, não a antiga. Como alternativa, você não pode distribuir o uber jar, mas incluir o jar assinado como um arquivo separado, mas isso acaba com o objetivo de um uber jar.
precisa saber é o seguinte
139

Para aqueles que usam gradle e tentam criar e usar um frasco de gordura, a seguinte sintaxe pode ajudar.

jar {
    doFirst {
        from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } 
    }
    exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA' 
}
Keith P
fonte
1
Isso basicamente exclui todos os arquivos com extensões .RSA, .SF ou .DSA dentro do diretório META-INF.
Keith P
9
A assinatura de um arquivo jar adiciona esses arquivos no META-INF, mas, quando incluídos, as assinaturas não concordam mais com o conteúdo do jar. Assim, removê-los evita a incompatibilidade de assinatura.
Peter N. Steinmetz 04/04
1
Há uma pergunta semelhante estritamente sobre o uso jar gordura em Gradle - stackoverflow.com/questions/4871656/...
Tomasz Sętkowski
3
Isso não funcionou para mim. Eu tive que colocar a excludeminha fatJartarefa, que tinha esse configurations.compile.collectcomando. Veja stackoverflow.com/a/31426413/103412
Torsten
1
Isso também resolve o erroError: Could not find or load main class App Caused by: java.lang.ClassNotFoundException: App
vonox7 18/11/19
57

Algumas de suas dependências provavelmente são jarfiles assinados. Quando você combina todos eles em um grande jarfile, os arquivos de assinatura correspondentes ainda estão presentes e não correspondem mais ao jarfile "grande combinado"; portanto, o tempo de execução pára de pensar que o arquivo jar foi violado (o que ... falar).

Você pode resolver o problema eliminando os arquivos de assinatura das suas dependências do jarfile. Infelizmente, não é possível fazer isso em uma única etapa no form .

No entanto, consegui fazer isso funcionar com o Ant em duas etapas, sem nomear especificamente cada dependência do jarfile, usando:

<target name="jar" depends="compile" description="Create one big jarfile.">
    <jar jarfile="${output.dir}/deps.jar">
        <zipgroupfileset dir="jars">
            <include name="**/*.jar" />
        </zipgroupfileset>
    </jar>
    <sleep seconds="1" />
    <jar jarfile="${output.dir}/myjar.jar" basedir="${classes.dir}">
        <zipfileset src="${output.dir}/deps.jar" excludes="META-INF/*.SF" />
        <manifest>
            <attribute name="Main-Class" value="com.mycompany.MyMain" />
        </manifest>
    </jar>
</target>

O elemento sleep deve evitar erros sobre arquivos com datas de modificação no futuro .

Outras variações que encontrei nos threads vinculados não funcionaram para mim.

Rich Apodaca
fonte
É possível fazer isso em uma única etapa, usando uma maneira diferente de especificar seus jars: <jar destfile = "build / myjar.jar"> <restrição> <não> <name name = "META-INF / *. SF" /> </not> <archives> <zips> <conjunto de arquivos dir = "jarfolder" inclui = " * / .jar" /> </zips> </archives> </restrict> </jar>
DieterDP
57

Por favor, use o seguinte comando

zip -d yourjar.jar 'META-INF/*.SF' 'META-INF/*.RSA' 'META-INF/*SF'
Peter2711
fonte
4
Obrigado, tive esse problema com o intellij 14 e sua solução funciona para mim!
Mohamad Kouhi Moghadam 27/10
5
Obrigado, trabalhou para mim no Windows. Apenas abri o jar com 7zip, excluí os arquivos .SF. Eu não tinha nenhum arquivo .RSA para excluir
candino
3
Uau, posso apenas dizer que esta solução foi incrível (e aprendi algo muito poderoso ao longo do caminho!) Isso precisa de mais votos.
Dylan_Larkin
Concordo com o comentário de @Dylan_Larkin, foi isso que resolveu para mim.
Felipe Valdes
26

Eu tive esse problema ao usar o IntelliJ IDEA 14.01.

Consegui corrigi-lo da seguinte maneira:

Arquivo-> Estrutura do Projeto-> Adicionar Novo (Artefatos) -> jar-> Dos Módulos com Dependências na Janela Criar Jar do Módulo:

Selecione sua classe principal

Arquivo JAR das Bibliotecas Selecione copiar para o diretório de saída e vincular através do manifesto

Travis
fonte
2
É possível colocar os frascos dependentes no frasco de destino?
Codigo.chenzhi
suas soluções funcionam bem !! Muito Obrigado!
hzitoun
19

A segurança já é um tópico difícil, mas estou desapontado ao ver que a solução mais popular é excluir as assinaturas de segurança. O JCE requer essas assinaturas . A sombra Maven explode o arquivo jar do BouncyCastle que coloca as assinaturas no META-INF, mas as assinaturas do BouncyCastle não são válidas para um novo uber-jar (apenas para o jar BC), e é isso que causa o erro de assinatura inválida neste encadeamento .

Sim, excluir ou excluir as assinaturas, conforme sugerido por @ruhsuzbaykus, faz com que o erro original desapareça, mas também pode levar a novos erros enigmáticos:

java.security.NoSuchAlgorithmException: PBEWithSHA256And256BitAES-CBC-BC SecretKeyFactory not available

Especificando explicitamente onde encontrar o algoritmo como este:

SecretKeyFactory.getInstance("PBEWithSHA256And256BitAES-CBC-BC","BC");

Consegui receber um erro diferente:

java.security.NoSuchProviderException: JCE cannot authenticate the provider BC

A JCE não pode autenticar o provedor porque excluímos as assinaturas criptográficas seguindo a sugestão em outra parte desse mesmo encadeamento .

A solução que encontrei foi o plug-in empacotador executável que usa uma abordagem jar-in-jar para preservar a assinatura BouncyCastle em um único jar executável.

ATUALIZAR :

Outra maneira de fazer isso (da maneira correta?) É usar o assinante Maven Jar . Isso permite que você continue usando o tom Maven sem obter erros de segurança. No entanto, você deve ter um certificado de assinatura de código (a Oracle sugere procurar por "Certificado de assinatura de código Java"). A configuração do POM é assim:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.1.0</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <filters>
                    <filter>
                        <artifact>org.bouncycastle:*</artifact>
                        <excludes>
                            <exclude>META-INF/*.SF</exclude>
                            <exclude>META-INF/*.DSA</exclude>
                            <exclude>META-INF/*.RSA</exclude>
                        </excludes>
                    </filter>
                </filters>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>your.class.here</mainClass>
                    </transformer>
                </transformers>
                <shadedArtifactAttached>true</shadedArtifactAttached>
            </configuration>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jarsigner-plugin</artifactId>
    <version>1.4</version>
    <executions>
        <execution>
            <id>sign</id>
            <goals>
                <goal>sign</goal>
            </goals>
        </execution>
        <execution>
            <id>verify</id>
            <goals>
                <goal>verify</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <keystore>/path/to/myKeystore</keystore>
        <alias>myfirstkey</alias>
        <storepass>111111</storepass>
        <keypass>111111</keypass>
    </configuration>
</plugin>

Não, não há como fazer com que a JCE reconheça um certificado autoassinado; portanto, se você precisar preservar os certificados BouncyCastle, precisará usar o plug-in jar-in-jar ou obter um certificado JCE.

MattW
fonte
Esta é definitivamente a maneira certa de fazer isso, mesmo que seja trabalhoso. Obrigado por apontar, em detalhes, as advertências ao usar a resposta aprovada. Você sabe se o certificado JCE precisa ser assinado pela Sun? Ou pode
WiteCastle
1
Existem terceiros que podem emitir certificados de assinatura de código. Pesquise "Certificado de assinatura de código Java" para ver as opções.
MattW
Você, senhor, fez o meu dia!
Socona 28/02
Ajudou por mim. Existem alguns arquivos nesta biblioteca que eu não uso, portanto, exceto eles, me ajudem com o arquivo do frasco de gordura
Saidolim
14

Eu enfrentei o mesmo problema, após referência em algum lugar, funcionou da seguinte forma:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.2.1</version>
    <configuration>
        <createDependencyReducedPom>false</createDependencyReducedPom>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <filters>
                    <filter>
                        <artifact>*:*</artifact>
                        <excludes>
                            <exclude>META-INF/*.SF</exclude>
                            <exclude>META-INF/*.DSA</exclude>
                            <exclude>META-INF/*.RSA</exclude>
                        </excludes>
                    </filter>
                </filters>
            </configuration>
        </execution>
    </executions>
</plugin>
m.nguyencntt
fonte
1
Isso resolveu meu problema rapidamente! Para completar, isso deve constar na maven-shade-plugintag.
Kuzeko 20/03/19
1
@Kuzeko Atualizou a resposta com sua sugestão. Graças
m.nguyencntt
8

Supondo que você construa seu arquivo jar com o ant, basta instruir o ant para deixar de fora o diretório META-INF. Esta é uma versão simplificada do meu alvo formiga:

<jar destfile="app.jar" basedir="${classes.dir}">
    <zipfileset excludes="META-INF/**/*" src="${lib.dir}/bcprov-jdk16-145.jar"></zipfileset>
    <manifest>
        <attribute name="Main-Class" value="app.Main"/>
    </manifest>
</jar>
Kim Stebel
fonte
onde devo adicionar essas linhas?
Addi.Star 21/09/19
4

Recentemente, comecei a usar o IntelliJ em meus projetos. No entanto, alguns de meus colegas ainda usam o Eclipse nos mesmos projetos. Hoje, tenho o mesmo erro depois de executar o arquivo jar criado pelo meu IntelliJ. Enquanto todas as soluções aqui falando sobre quase a mesma coisa, nenhuma delas funcionou para mim com facilidade (possivelmente porque eu não uso o ANT, o maven build me deu outros erros que me indicaram http://cwiki.apache.org/ confluência / tela / MAVEN / MojoExecutionException e também não consegui descobrir quais são os frascos assinados por mim!)

Finalmente, isso me ajudou

zip -d demoSampler.jar 'META-INF/*.SF' 'META-INF/*.RSA' 'META-INF/*SF'

Adivinha o que foi removido do meu arquivo jar ?!

deleting: META-INF/ECLIPSE_.SF 
deleting: META-INF/ECLIPSE_.RSA

Parece que o problema foi relevante para alguns arquivos relevantes para o eclipse.

mhn_namak
fonte
4

Eu tive o mesmo problema gradleao criar um Jar gordo, atualizando o build.gradlearquivo com uma linha de exclusão corrigida.

jar {
    from {
        configurations.compile.collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
    exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
    manifest {
        attributes 'Main-Class': 'com.test.Main'
    }
}
Ahmad Al-Kurdi
fonte
1
Eu estava depurando por dias, isso resolveu meu problema com o frasco de gordura.
sysuser 7/11/19
A maneira como depurei é colocar o jar gordo no diretório jmeter lib. Se você tem o frasco problemático em lib / ext, este problema não vai ser óbvio, em vez você vai obter um erro como aquele em stackoverflow.com/questions/37624187/...
SYSUSER
1
excluir 'META-INF / *. RSA', 'META-INF / *. SF', 'META-INF / *. DSA' Isso estava faltando, algum jar dependente estava causando o problema
Nirbhay Mishra
3

Caso você esteja usando o gradle, aqui está uma tarefa completa do farJar:

version = '1.0'
//create a single Jar with all dependencies
task fatJar(type: Jar) {
    manifest {
        attributes 'Implementation-Title': 'Gradle Jar File Example',  
            'Implementation-Version': version,
            'Main-Class': 'com.example.main'
    }
    baseName = project.name + '-all'
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
    exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA' 
    with jar
}
Nick De Greek
fonte
2

Compare a pasta META-INF no novo jar com o jar antigo (antes de adicionar novas bibliotecas). É possível que haja novos arquivos. Se sim, você pode removê-los. Deveria ajudar. Atenciosamente, 999michal

999michal
fonte
2

Uma estratégia consistiria em usar o ANT para simplificar a remoção da assinatura de cada arquivo Jar. Ele continuaria com as seguintes etapas:

  1. Copiando o MANIFEST.MF em um arquivo temporário
  2. Removendo as entradas Nome e SHA do arquivo temporário
  3. Criando um arquivo Jar temporário com o manifesto temporário
  4. Removendo o manifesto temporário
  5. Trocando o arquivo Jar original pelo temporário

Aqui está um macrodef ANT fazendo o trabalho:

<macrodef name="unsignjar" description="To unsign a specific Jar file">
    <attribute name="jarfile" 
        description="The jar file to unsign" />
    <sequential>
<!-- Copying to the temporary manifest file -->
        <copy toFile="@{jarFile}_MANIFEST.tmp">
            <resources>
                <zipentry zipfile="@{jarFile}" name="META-INF/MANIFEST.MF"/>
            </resources>
        </copy>
<!-- Removing the Name and SHA entries from the temporary file -->
        <replaceregexp file="@{jarFile}_MANIFEST.tmp" match="\nName:(.+?)\nSH" replace="SH" flags="gis" byline="false"/>
        <replaceregexp file="@{jarFile}_MANIFEST.tmp" match="SHA(.*)" replace="" flags="gis" byline="false"/>
<!-- Creating a temporary Jar file with the temporary manifest -->
        <jar jarfile="@{jarFile}.tmp"
            manifest="@{jarFile}_MANIFEST.tmp">
            <zipfileset src="@{jarFile}">
                <include name="**"/>
                <exclude name="META-INF/*.SF"/>
                <exclude name="META-INF/*.DSA"/>
                <exclude name="META-INF/*.RSA"/>
            </zipfileset>
        </jar>
<!-- Removing the temporary manifest -->
        <delete file="@{jarFile}_MANIFEST.tmp" />
<!-- Swapping the original Jar file with the temporary one -->
        <move file="@{jarFile}.tmp"
              tofile="@{jarFile}"
              overwrite="true" />
</sequential>

`

A definição pode ser chamada dessa maneira em uma tarefa ANT:

<target name="unsignJar">
    <unsignjar jarFile="org.test.myjartounsign.jar" />
</target>
bdulac
fonte
2

Erro: Ocorreu um erro JNI, verifique sua instalação e tente novamente Exceção no encadeamento "main" java.lang.SecurityException: Resumo do arquivo de assinatura inválido para os principais atributos do Manifest em sun.security.util.SignatureFileVerifier.processImpl (SignatureFileVerifier.java: 314) em sun.security.util.SignatureFileVerifier.process (SignatureFileVerifier.java:268) em java.util.jar.JarVerifier.processEntry (JarVerifier.java:316) em java.util.jar.JarVerifier.update (JarVerifier.java : 228) em java.util.jar.JarFile.initializeVerifier (JarFile.java:383) em java.util.jar.JarFile.getInputStream (JarFile.java:450) em sun.misc.URLClassPath $ JarLoader $ 2.getInputStream (URLClassPath .java: 977) em sun.misc.Resource.cachedInputStream (Resource.java:77) em sun.misc.Resource.getByteBuffer (Resource.java:160) em java.net.URLClassLoader.defineClass (URLClassLoader.java:454) em java.net.URLClassLoader.access $ 100 (URLClassLoader.java:73) em java.net.URLClassLoader $ 1.run (URLClassLoader.java:8) java.net.URLClassLoader $ 1.run (URLClassLoader.java:362) em java.security.AccessController.doPrivileged (método nativo) em java.net.URLClassLoader.findClass (URLClassLoader.java:361) em java.lass.ClassLoad.ClassLoader. (ClassLoader.java:424) em sun.misc.Launcher $ AppClassLoader.loadClass (Launcher.java:331) em java.lang.ClassLoader.loadClass (ClassLoader.java:357) em sun.launcher.LauncherHelper.checkAndLoadMain (Launcher.Help. java: 495)execute (URLClassLoader.java:368) em java.net.URLClassLoader $ 1.run (URLClassLoader.java:362) em java.security.AccessController.doPrivileged (método nativo) em java.net.URLClassLoader.findClass (URLClassLoader.findClass (URLClassLoader.java:368) ), em java.lang.ClassLoader.loadClass (ClassLoader.java:424) em sun.misc.Launcher $ AppClassLoader.loadClass (Launcher.java:331) em java.lang.ClassLoader.loadClass (ClassLoader.java:357) em sun .launcher.LauncherHelper.checkAndLoadMain (LauncherHelper.java:495)execute (URLClassLoader.java:368) em java.net.URLClassLoader $ 1.run (URLClassLoader.java:362) em java.security.AccessController.doPrivileged (método nativo) em java.net.URLClassLoader.findClass (URLClassLoader.findClass (URLClassLoader.java:368) ), em java.lang.ClassLoader.loadClass (ClassLoader.java:424) em sun.misc.Launcher $ AppClassLoader.loadClass (Launcher.java:331) em java.lang.ClassLoader.loadClass (ClassLoader.java:357) em sun .launcher.LauncherHelper.checkAndLoadMain (LauncherHelper.java:495)331) em java.lang.ClassLoader.loadClass (ClassLoader.java:357) e sun.launcher.LauncherHelper.checkAndLoadMain (LauncherHelper.java:495)331) em java.lang.ClassLoader.loadClass (ClassLoader.java:357) e sun.launcher.LauncherHelper.checkAndLoadMain (LauncherHelper.java:495)

O que me ajudou (IntelliJ IDEA 2016.3): Arquivo -> Estrutura do projeto -> Artefatos -> Adicionar JAR -> Selecionar classe principal -> Escolha "copiar para o diretório de saída e vincular via manifesto" -> OK -> Aplicar -> Construir - > Criar artefatos ... -> Criar

Pequena raposa
fonte
1

Se você está procurando uma solução Fat JAR sem descompactar ou adulterar as bibliotecas originais, mas com um carregador de classes JAR especial, dê uma olhada no meu projeto aqui .

Isenção de responsabilidade: não escrevi o código, apenas o empacote e publique no Maven Central e descreva no meu leia-me como usá-lo.

Eu pessoalmente o uso para criar JARs uber executáveis ​​que contêm dependências do BouncyCastle. Talvez seja útil para você também.

kriegaex
fonte
0

Para aqueles que têm problemas com a solução aceita, há outra maneira de excluir recursos do jar sombreado com o DontIncludeResourceTransformer:

https://maven.apache.org/plugins/maven-shade-plugin/examples/resource-transformers.html#DontIncludeResourceTransformer

          <transformers>
            <transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
                <resource>BC1024KE.DSA</resource>
            </transformer>
          </transformers>

Do Shade 3.0, esse transformador aceita uma lista de recursos. Antes disso, você só precisa usar vários transformadores, cada um com um recurso.

M.Liang
fonte
0

Isso aconteceu comigo no Intellij quando cliquei em "Adicionar como projeto Maven" na linha inferior quando o Intellij disse "arquivos pom não gerenciados encontrados". Enquanto isso, a pasta já foi gerada. Portanto, não obteve alterações recentes.

Excluir a pasta e executar o programa resolveu o problema para mim. A pasta de saída foi recriada.

Veja a resposta de Little Fox também. O erro que recebi foi muito semelhante ao dele.

Onat Korucu
fonte
-1

Eu tive um problema parecido. O motivo foi que eu estava compilando usando um JDK com um JRE diferente do padrão na minha caixa do Windows.

Usar o java.exe correto resolveu meu problema.

Jus12
fonte
-2

Se você estiver obtendo isso ao tentar vincular arquivos JAR para um projeto de ligações do Xamarin.Android, assim:

JARTOXML: aviso J2XA006: erro de classe ausente foi gerado ao refletir com.your.class: Resumo do arquivo de assinatura inválido para os principais atributos do manifesto

Basta abrir os arquivos JAR usando o Winzip e excluir os diretórios meta-inf. Reconstruir - trabalho concluído

Dean Wild
fonte
1
Esta é uma técnica horrível. Absolutamente Horrível. Faça as correções localmente não fazer alterações em frascos de entrada
sinisterrook