Jak uruchomić UTF-8 w aplikacjach Java?


367

Potrzebuję, aby UTF-8 działał w mojej aplikacji Java (serwlety + JSP, bez frameworka) do obsługi äöåitp. Dla zwykłego fińskiego tekstu i cyrylicy, jak ЦжФw szczególnych przypadkach.

Moja konfiguracja jest następująca:

  • Środowisko programistyczne: Windows XP
  • Środowisko produkcyjne: Debian

Użyta baza danych: MySQL 5.x

Użytkownicy korzystają głównie z przeglądarki Firefox2, ale do uzyskiwania dostępu do witryny wykorzystywane są również Opera 9.x, FF3, IE7 i Google Chrome.

Jak to osiągnąć?


Odpowiedzi:


552

Zachęcam do udzielania odpowiedzi na często zadawane pytania na tej stronie. To działa dla mnie:

Przeważnie znaki äåö nie stanowią problemu, ponieważ domyślnym zestawem znaków używanym przez przeglądarki i tomcat / java dla aplikacji internetowych jest latin1, tj. ISO-8859-1, która „rozumie” te znaki.

Aby UTF-8 działał pod Javą + Tomcat + Linux / Windows + Mysql wymaga:

Konfigurowanie serwera.xml serwera Tomcat

Konieczne jest skonfigurowanie, aby łącznik używa UTF-8 do kodowania parametrów adresu URL (żądanie GET):

<Connector port="8080" maxHttpHeaderSize="8192"
 maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
 enableLookups="false" redirectPort="8443" acceptCount="100"
 connectionTimeout="20000" disableUploadTimeout="true" 
 compression="on" 
 compressionMinSize="128" 
 noCompressionUserAgents="gozilla, traviata" 
 compressableMimeType="text/html,text/xml,text/plain,text/css,text/ javascript,application/x-javascript,application/javascript"
 URIEncoding="UTF-8"
/>

Kluczową częścią jest URIEncoding = "UTF-8" w powyższym przykładzie. To gwarantuje, że Tomcat obsługuje wszystkie przychodzące parametry GET jako kodowane w UTF-8. W rezultacie, gdy użytkownik zapisze w pasku adresu przeglądarki:

 https://localhost:8443/ID/Users?action=search&name=*ж*

znak ж jest obsługiwany jako UTF-8 i jest zakodowany (zwykle przez przeglądarkę, zanim nawet dostanie się na serwer) jako % D0% B6 .

Nie ma to wpływu na żądanie POST.

CharsetFilter

Następnie nadszedł czas, aby zmusić aplikację Java do obsługi wszystkich żądań i odpowiedzi w postaci zakodowanej w UTF-8. Wymaga to zdefiniowania filtru zestawu znaków, takiego jak:

package fi.foo.filters;

import javax.servlet.*;
import java.io.IOException;

public class CharsetFilter implements Filter {

    private String encoding;

    public void init(FilterConfig config) throws ServletException {
        encoding = config.getInitParameter("requestEncoding");
        if (encoding == null) encoding = "UTF-8";
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain next)
            throws IOException, ServletException {
        // Respect the client-specified character encoding
        // (see HTTP specification section 3.4.1)
        if (null == request.getCharacterEncoding()) {
            request.setCharacterEncoding(encoding);
        }

        // Set the default response content type and encoding
        response.setContentType("text/html; charset=UTF-8");
        response.setCharacterEncoding("UTF-8");

        next.doFilter(request, response);
    }

    public void destroy() {
    }
}

Filtr ten upewnia się, że jeśli przeglądarka nie ustawiła kodowania użytego w żądaniu, to jest ustawiona na UTF-8.

Inną czynnością wykonaną przez ten filtr jest ustawienie domyślnego kodowania odpowiedzi, tj. kodowanie, w którym zwracany html / cokolwiek jest. Alternatywą jest ustawienie kodowania odpowiedzi itp. W każdym kontrolerze aplikacji.

Ten filtr należy dodać do pliku web.xml lub deskryptora wdrażania aplikacji internetowej:

 <!--CharsetFilter start--> 

  <filter>
    <filter-name>CharsetFilter</filter-name>
    <filter-class>fi.foo.filters.CharsetFilter</filter-class>
      <init-param>
        <param-name>requestEncoding</param-name>
        <param-value>UTF-8</param-value>
      </init-param>
  </filter>

  <filter-mapping>
    <filter-name>CharsetFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

Instrukcje tworzenia tego filtra można znaleźć na wiki tomcat ( http://wiki.apache.org/tomcat/Tomcat/UTF-8 )

Kodowanie strony JSP

W pliku web.xml dodaj:

<jsp-config>
    <jsp-property-group>
        <url-pattern>*.jsp</url-pattern>
        <page-encoding>UTF-8</page-encoding>
    </jsp-property-group>
</jsp-config>

Alternatywnie, wszystkie strony JSP aplikacji internetowej musiałyby mieć na górze następujące elementy:

 <%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>

Jeśli używany jest jakiś układ z różnymi fragmentami JSP, jest to potrzebne we wszystkich z nich.

Tagi meta HTML

Kodowanie strony JSP informuje JVM, aby obsługiwał znaki na stronie JSP w prawidłowym kodowaniu. Następnie nadszedł czas, aby poinformować przeglądarkę, w którym kodowaniu jest strona HTML:

Odbywa się to w następujący sposób u góry każdej strony xhtml utworzonej przez aplikację internetową:

   <?xml version="1.0" encoding="UTF-8"?>
   <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
   <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fi">
   <head>
   <meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />
   ...

Połączenie JDBC

Podczas korzystania z bazy danych należy zdefiniować, że połączenie korzysta z kodowania UTF-8. Odbywa się to w pliku context.xml lub wszędzie tam, gdzie połączenie JDBC nie działa, w następujący sposób:

      <Resource name="jdbc/AppDB" 
        auth="Container"
        type="javax.sql.DataSource"
        maxActive="20" maxIdle="10" maxWait="10000"
        username="foo"
        password="bar"
        driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/      ID_development?useEncoding=true&amp;characterEncoding=UTF-8"
    />

Baza danych i tabele MySQL

Użyta baza danych musi używać kodowania UTF-8. Osiąga się to poprzez utworzenie bazy danych z następującymi elementami:

   CREATE DATABASE `ID_development` 
   /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_swedish_ci */;

Następnie wszystkie tabele muszą znajdować się w UTF-8:

   CREATE TABLE  `Users` (
    `id` int(10) unsigned NOT NULL auto_increment,
    `name` varchar(30) collate utf8_swedish_ci default NULL
    PRIMARY KEY  (`id`)
   ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci ROW_FORMAT=DYNAMIC;

Kluczową częścią jest CHARSET = utf8 .

Konfiguracja serwera MySQL

Serwery MySQL również muszą zostać skonfigurowane. Zazwyczaj odbywa się to w Windows modyfikując my.ini -file iw Linux przez skonfigurowanie my.cnf -file. W tych plikach należy zdefiniować, że wszyscy klienci podłączeni do serwera używają utf8 jako domyślnego zestawu znaków oraz że domyślnym zestawem znaków używanym przez serwer jest również utf8.

   [client]
   port=3306
   default-character-set=utf8

   [mysql]
   default-character-set=utf8

Procedury i funkcje MySQL

Te również muszą mieć zdefiniowany zestaw znaków. Na przykład:

   DELIMITER $$

   DROP FUNCTION IF EXISTS `pathToNode` $$
   CREATE FUNCTION `pathToNode` (ryhma_id INT) RETURNS TEXT CHARACTER SET utf8
   READS SQL DATA
   BEGIN

    DECLARE path VARCHAR(255) CHARACTER SET utf8;

   SET path = NULL;

   ...

   RETURN path;

   END $$

   DELIMITER ;

Żądania GET: latin1 i UTF-8

Jeśli i kiedy zostanie zdefiniowane w pliku server.xml tomcat, że parametry żądania GET są kodowane w UTF-8, następujące żądania GET są obsługiwane poprawnie:

   https://localhost:8443/ID/Users?action=search&name=Petteri
   https://localhost:8443/ID/Users?action=search&name=ж

Ponieważ znaki ASCII są kodowane w taki sam sposób zarówno w przypadku latin1, jak i UTF-8, ciąg „Petteri” jest obsługiwany poprawnie.

Cyrylica ж w ogóle nie jest rozumiana w języku łacińskim1. Ponieważ Tomcat jest poinstruowany, aby obsługiwać parametry żądania jako UTF-8, poprawnie koduje ten znak jako % D0% B6 .

Jeśli i kiedy przeglądarki zostaną poinstruowane, aby czytać strony w kodowaniu UTF-8 (z nagłówkami żądań i metatagiem HTML), przynajmniej Firefox 2/3 i inne przeglądarki z tego okresu same kodują znak jako % D0% B6 .

W rezultacie znaleziono wszystkich użytkowników o nazwie „Petteri”, a także wszystkich użytkowników o nazwie „ж”.

Ale co z äåö?

Specyfikacja HTTP określa, że ​​domyślnie adresy URL są kodowane jako latin1. Powoduje to, że firefox2, firefox3 itp. Kodują następujące

    https://localhost:8443/ID/Users?action=search&name=*Päivi*

w wersji zakodowanej

    https://localhost:8443/ID/Users?action=search&name=*P%E4ivi*

W Latin1 znak ä jest zakodowany jako % E4 . Mimo że strona / żądanie / wszystko jest zdefiniowane do używania UTF-8 . Wersja ä zakodowana w UTF-8 to % C3% A4

Wynikiem tego jest to, że aplikacja internetowa nie może poprawnie obsługiwać parametrów żądań z żądań GET, ponieważ niektóre znaki są kodowane w latin1, a inne w UTF-8. Uwaga: żądania POST działają, ponieważ przeglądarki kodują wszystkie parametry żądań z formularzy całkowicie w UTF-8, jeśli strona jest zdefiniowana jako UTF-8

Rzeczy do przeczytania

Bardzo dziękuję autorom następujących artykułów za udzielenie odpowiedzi na mój problem:

  • http://tagunov.tripod.com/i18n/i18n.html
  • http://wiki.apache.org/tomcat/Tomcat/UTF-8
  • http://java.sun.com/developer/technicalArticles/Intl/HTTPCharset/
  • http://dev.mysql.com/doc/refman/5.0/en/charset-syntax.html
  • http://cagan327.blogspot.com/2006/05/utf-8-encoding-fix-tomcat-jsp-etc.html
  • http://cagan327.blogspot.com/2006/05/utf-8-encoding-fix-for-mysql-tomcat.html
  • http://jeppesn.dk/utf-8.html
  • http://www.nabble.com/request-parameters-mishandle-utf-8-encoding-td18720039.html
  • http://www.utoronto.ca/webdocs/HTMLdocs/NewHTML/iso_table.html
  • http://www.utf8-chartable.de/

Ważna uwaga

obsługuje podstawową płaszczyznę wielojęzyczną przy użyciu 3-bajtowych znaków UTF-8. Jeśli musisz wyjść poza to (niektóre alfabety wymagają więcej niż 3 bajtów UTF-8), musisz użyć smaku VARBINARYtypu kolumny lub utf8mb4zestawu znaków (który wymaga MySQL 5.5.3 lub nowszego). Pamiętaj tylko, że użycie utf8zestawu znaków w MySQL nie będzie działać w 100% przypadków.

Tomcat z Apache

Jeszcze jedna rzecz Jeśli używasz łącznika Apache + Tomcat + mod_JK, musisz także wprowadzić następujące zmiany:

  1. Dodaj URIEncoding = "UTF-8" do pliku tomcat server.xml dla złącza 8009, jest on używany przez złącze mod_JK. <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>
  2. Goto Twój apache folderu tzn /etc/httpd/confi dodać AddDefaultCharset utf-8w httpd.conf file. Uwaga: Najpierw sprawdź, czy istnieje, czy nie. Jeśli istnieje, możesz zaktualizować go o tę linię. Możesz dodać tę linię również na dole.

Te kroki działają również z Struts / kafelkami i bazą danych postgres.
kosoant

17
Dwa komentarze: 1) w tagach HMTL-meta umieściłeś deklarację xml. Usuń go, spowoduje to uruchomienie przeglądarek tylko w trybie dziwactw, nie chcesz tego mieć. Ponadto metatagi HTML są już pośrednio wykonywane przez JSP pageEncoding, więc możesz je nawet pominąć. 2) w bazie danych MySQL i tabelach, których używałeś utf8_swedish_si, powinno być utf8_unicode_ci. Możesz nawet zostawić zestawienie z dala, CHARACTER SET utf8wystarczy.
BalusC,

Żaden z dokumentów, z którymi się skonsultowałem, dotyczących metatagów HTML i trybu dziwactw (np. Ericmeyeroncss.com/bonus/render-mode.html , en.wikipedia.org/wiki/Quirks_mode ) nie wskazuje, że obecność <meta http-equiv = 'Treść -Type ”ma wpływ na tryb renderowania.
Marcel Stör

Jako ciekawą notatkę dodatkową możesz również mieć świadomość, że jeśli masz detektor, który uzyskuje dostęp do parametru żądania, musisz dodać detektor, który ustawia zestaw znaków zamiast filtru, ponieważ detektory są wykonywane przed filtrami. Wykonałem wszystkie kroki i nadal nie działało z tego powodu. Pomyślałem, że przekażę te informacje, na wypadek gdyby ktoś miał podobny problem.
testowanie123

3
## Tomcat z Apache ## Jeszcze jedno Jeśli używasz łącznika Apache + Tomcat + mod_JK, musisz także wprowadzić następujące zmiany: 1. Dodaj URIEncoding = "UTF-8" do pliku tomcat server.xml dla złącza 8009, to jest używany przez złącze mod_JK. <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/> 2. Przejdź do folderu apache tj. /etc/httpd/confI dodaj AddDefaultCharset utf-8plik „httpd.conf”. Uwaga: najpierw sprawdź, czy istnieje, czy nie. Jeśli istnieje, możesz zaktualizować go o tę linię. Możesz dodać tę linię również na dole.
Vijay Shegokar

14

Myślę, że podsumowałeś to całkiem dobrze we własnej odpowiedzi.

W procesie UTF-8-ing (?) Od końca do końca możesz także chcieć upewnić się, że java używa UTF-8. Użyj parametru -Dfile.encoding = utf-8 jako parametru dla JVM (można skonfigurować w pliku catalina.bat).


Pomogło mi to, zrobiłem wszystko, co wspomniano, ale kodowanie JVM to Windows-1250, gdy tylko zmieniłem na UTF-8, działało bezbłędnie.
coding_idiot

2
Gdzie proszę to dodać w pliku Catalina.bat?
Noah

11

Aby dodać do odpowiedzi kosoant , jeśli używasz Springa, zamiast pisać własny filtr serwletu, możesz użyć org.springframework.web.filter.CharacterEncodingFilterdostarczonej przez niego klasy , konfigurując go w następujący sposób w pliku web.xml:

 <filter>
    <filter-name>encoding-filter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
       <param-name>encoding</param-name>
       <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
       <param-name>forceEncoding</param-name>
       <param-value>FALSE</param-value>
    </init-param>
 </filter>
 <filter-mapping>
    <filter-name>encoding-filter</filter-name>
    <url-pattern>/*</url-pattern>
 </filter-mapping>

1
Ten filtr musi być pierwszym filtrem w
pliku

2

Chcę również dodać stąd, że ta część rozwiązała mój problem z utf:

runtime.encoding=<encoding>

1

Dotyczy to kodowania greckiego w tabelach MySql, gdy chcemy uzyskać do nich dostęp za pomocą Java:

Użyj poniższej konfiguracji połączenia w puli połączeń JBoss (mysql-ds.xml)

<connection-url>jdbc:mysql://192.168.10.123:3308/mydatabase</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>nts</user-name>
<password>xaxaxa!</password>
<connection-property name="useUnicode">true</connection-property>
<connection-property name="characterEncoding">greek</connection-property>

Jeśli nie chcesz umieszczać tego w puli połączeń JNDI, możesz skonfigurować go jako adres URL JDBC, jak pokazano w następnym wierszu:

jdbc:mysql://192.168.10.123:3308/mydatabase?characterEncoding=greek

Dla mnie i Nicka, więc nigdy o tym nie zapominamy i tracimy czas .....


5
Nadal wolałbym UTF-8 powyżej greckiego (i przekonwertować twoje obecne greckie dane na UTF-8), aby twoja aplikacja była gotowa do dominacji nad światem.
BalusC,

1

Ładna szczegółowa odpowiedź. Chciałem tylko dodać jeszcze jedną rzecz, która na pewno pomoże innym zobaczyć kodowanie UTF-8 w adresach URL w akcji.

Wykonaj poniższe czynności, aby włączyć kodowanie UTF-8 w adresach URL w Firefoksie.

  1. wpisz „about: config” w pasku adresu.

  2. Użyj typu wejściowego filtru, aby wyszukać właściwość „network.standard-url.encode-query-utf8”.

  3. powyższa właściwość będzie domyślnie fałszywa, zmień ją na PRAWDA.
  4. uruchom ponownie przeglądarkę.

Kodowanie UTF-8 w adresach URL działa domyślnie w IE6 / 7/8 i chrome.


1

Poprzednie odpowiedzi nie działały z moim problemem. To było tylko w produkcji, z tomcat i apache mod_proxy_ajp. Ciało postu straciło znaki nie ascii przez? Ostatecznie problem dotyczył JVM defaultCharset (US-ASCII w domyślnej instalacji: Charset dfset = Charset.defaultCharset ();), więc rozwiązaniem było uruchomienie serwera tomcat z modyfikatorem do uruchomienia JVM z UTF-8 jako domyślnym zestawem znaków:

JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8" 

(dodaj ten wiersz do catalina.sh i uruchom ponownie serwis tomcat)

Być może musisz również zmienić zmienną systemową linux (edytuj ~ / .bashrc i ~ / .profile, aby zmienić na stałe, patrz https://perlgeek.de/en/article/set-up-a-clean-utf8-environment )

eksport LC_ALL = en_US.UTF-8
eksport LANG = en_US.UTF-8

eksportuj JĘZYK = en_US.UTF-8


0

Mam podobny problem, ale w nazwach plików kompresuję się przy użyciu apache commons. Rozwiązałem to za pomocą tego polecenia:

convmv --notest -f cp1252 -t utf8 * -r

działa dla mnie bardzo dobrze. Mam nadzieję, że pomoże każdemu;)


0

W moim przypadku wyświetlania znaku Unicode z pakietów wiadomości nie muszę stosować sekcji „Kodowanie strony JSP”, aby wyświetlać Unicode na mojej stronie jsp. Wszystko czego potrzebuję to sekcja „CharsetFilter”.


0

Jeszcze jeden punkt, o którym nie wspomniano, dotyczy serwletów Java współpracujących z Ajax. Mam sytuacje, w których strona internetowa pobiera tekst utf-8 od użytkownika wysyłającego go do pliku JavaScript, który zawiera go w identyfikatorze URI wysyłanym do serwletu. Serwlet wysyła zapytanie do bazy danych, przechwytuje wynik i zwraca go jako plik XML do pliku JavaScript, który go formatuje i wstawia sformatowaną odpowiedź na oryginalnej stronie internetowej.

W jednej z aplikacji internetowych postępowałem zgodnie z instrukcjami wczesnej książki Ajax, aby zakończyć JavaScript w konstruowaniu identyfikatora URI. W podanym w książce przykładzie użyto metody escape (), którą odkryłem (trudną drogą). W przypadku utf-8 musisz użyć encodeURIComponent ().

Niewiele osób wydaje się obecnie tworzyć własne Ajax, ale pomyślałem, że równie dobrze mogę to dodać.


0

O CharsetFilterwymienionych w odpowiedzi na @kosoant ....

W Filtertomcat znajduje się wbudowana wersja web.xml(zlokalizowana pod conf/web.xml). Filtr nazywa się setCharacterEncodingFilteri jest domyślnie komentowany. Możesz to odkomentować (pamiętaj, aby też odkomentować filter-mapping)

Również nie ma potrzeby ustawiania jsp-configw twoim web.xml(przetestowałem to dla Tomcat 7+)


0

Czasami możesz rozwiązać problem za pomocą kreatora administratora MySQL. W

Zmienne uruchamiania> Zaawansowane>

i ustaw Def. zestaw znaków: utf8

Być może ta konfiguracja wymaga ponownego uruchomienia MySQL.


0

Ten sam problem wystąpił na Spring MVC 5 + Tomcat 9 + JSP.
Po długich badaniach, przyszedł eleganckie rozwiązanie ( nie ma potrzebę filtrów i żadnych potrzebę zmian w Tomcat server.xml (począwszy od wersji 8.0.0-RC3))

  1. W implementacji WebMvcConfigurer ustaw domyślne kodowanie dla messageSource (do odczytu danych z plików źródłowych komunikatów w kodowaniu UTF-8.

    @Configuration
    @EnableWebMvc
    @ComponentScan("{package.with.components}")
    public class WebApplicationContextConfig implements WebMvcConfigurer {
    
        @Bean
        public MessageSource messageSource() {
            final ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    
            messageSource.setBasenames("messages");
            messageSource.setDefaultEncoding("UTF-8");
    
            return messageSource;
        }
    
        /* other beans and methods */
    
    }
  2. W implementacji DispatcherServletInitializer @ Przestaw metodę onStartup i ustaw w niej kodowanie znaków żądania i zasobów.

    public class DispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
        @Override
        public void onStartup(final ServletContext servletContext) throws ServletException {
    
            // https://wiki.apache.org/tomcat/FAQ/CharacterEncoding
            servletContext.setRequestCharacterEncoding("UTF-8");
            servletContext.setResponseCharacterEncoding("UTF-8");
    
            super.onStartup(servletContext);
        }
    
        /* servlet mappings, root and web application configs, other methods */
    
    }
  3. Zapisz wszystkie źródła wiadomości i przeglądaj pliki w kodowaniu UTF-8.

  4. Dodaj <% @ page contentType = "text / html; charset = UTF-8"%> lub <% @ page pageEncoding = "UTF-8"%> w każdym pliku * .jsp lub dodaj deskryptor jsp-config do pliku web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
     id="WebApp_ID" version="3.0">
        <display-name>AppName</display-name>
    
        <jsp-config>
            <jsp-property-group>
                <url-pattern>*.jsp</url-pattern>
                <page-encoding>UTF-8</page-encoding>
            </jsp-property-group>
        </jsp-config>
    </web-app>

-1

Jeśli podałeś w puli połączeń (mysql-ds.xml), w kodzie Java możesz otworzyć połączenie w następujący sposób:

DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Connection conn = DriverManager.getConnection(
    "jdbc:mysql://192.168.1.12:3308/mydb?characterEncoding=greek",
    "Myuser", "mypass");
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.