MySQL JDBC Driver 5.1.33 - Problem ze strefą czasową


359

Niektóre tło:

Mam webapp Java 1.6 działający na Tomcat 7. Baza danych to MySQL 5.5. Wcześniej korzystałem ze sterownika JDBC Mysql 5.1.23, aby połączyć się z bazą danych. Wszystko działało Niedawno zaktualizowałem sterownik Mysql JDBC 5.1.33. Po aktualizacji Tomcat zgłasza ten błąd podczas uruchamiania aplikacji.

WARNING: Unexpected exception resolving reference
java.sql.SQLException: The server timezone value 'UTC' is unrecognized or represents more than one timezone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc timezone value if you want to utilize timezone support.

Dlaczego to się dzieje?


1
Jak wygląda twój adres URL JDBC?
David Levesque

Sprawdź moją odpowiedź stackoverflow.com/a/44720416/4592448 . Myślę, że to najlepsza odpowiedź)
Fortran

Odpowiedzi:


673

Najwyraźniej, aby uzyskać wersję 5.1.33 sterownika MySQL JDBC do pracy ze strefą czasową UTC, należy wyraźnie to określić serverTimezonew ciągu połączenia.

jdbc:mysql://localhost/db?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC

4
Według dokumentów useJDBCCompliantTimezoneShift nie ma żadnego efektu przy użyciu useLegacyDatetimeCode = false. Dlatego nie jest tam potrzebny ...
matof

24
To rozwiązuje mój błąd. Dodatkowa uwaga, ucieczka przed & with & amp; w pliku persistence.xml: <nazwa właściwości = "javax.persistence.jdbc.url" wartość = "jdbc: mysql: // localhost / test? useUnicode = true & amp; useJDBCCompliantTimezoneShift = true & amp; useLegacyDatetimeCode = false & amp; serverTimezone> UTC
pdem 18.04.16

5
To nie jest poprawne Punkt useLegacyDatetimeCode = false nie musi określać serverTimezone, więc klient koryguje różnice stref czasowych. To błąd w tej wersji klienta MySQL.
antgar9

2
To rozwiązanie niszczy strefę czasową z wyjątkiem GMT. Myślę, że właściwe rozwiązanie jest niedoceniane poniżej
DuncanSungWKim,

1
rozwiązanie działa z 8.0.17. Zdarzyło się ze świeżą instalacją MySQL. Nie mogę uwierzyć, że ten błąd nie został naprawiony po tylu latach.
Tilman Hausherr

101

Rozwiązałem ten problem, konfigurując MySQL.

SET GLOBAL time_zone = '+3:00';


6
jeśli używasz MSK czasową to +3, następnie można użyć jako adres folowing db: jdbc:mysql://localhost/db?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Europe/Moscow. Wygląda na to, że mysql-connector nie rozumie krótkich nazw stref czasowych.
babay

2
Co robisz, gdy czas letni zmienia czas?
isapir

3
W mysql 8.0 możesz wywołać „set persist time_zone = '+00: 00';” aby ustawić go na UTC w sposób ciągły, bez potrzeby edytowania pliku my.cnf lub restartowania serwera. Zobacz mysqlserverteam.com/…
ccleve

Jeśli ustawiasz to za pomocą unikalnego ręcznego zapytania SQL, to ustawienie powróciłoby do pierwotnej wartości po ponownym uruchomieniu bazy danych.
CBA110,

działa - pamiętaj o zmodyfikowaniu lokalnego ciągu strefy czasowej zamiast +3 USTAWIENIE GLOBALNE time_zone = '+3: 00';
Pravin

61

Po przeczytaniu kilku postów na ten temat, przetestowaniu różnych konfiguracji i na podstawie pewnych spostrzeżeń z tego wątku błędu mysql zrozumiałem:

  • strefa czasowa serwera jest ważna w szczególności do konwertowania dat przechowywanych w bazie danych na strefę czasową serwera aplikacji. istnieją inne implikacje, ale jest to najbardziej zauważalna
  • Systemy stref czasowych GMT x UTC. GMT został opracowany pod koniec XIX wieku i można go przełączać między czasem standardowym a czasem letnim. ta właściwość może doprowadzić do sytuacji, w której serwer bazy danych przesunie się na czas letni, a aplikacja go nie zauważy (być może istnieją inne komplikacje, ale nie badałem dalej). UTC nie zmienia się w czasie (zawsze znajduje się w odległości około 1 sekundy od średniego czasu słonecznego na długości 0 °).
  • Definicja serverTimeZone została wprowadzona w wersjach 5.1 wtyczek mysql jdbc. do wersji 8 można go było zignorować useLegacyDatetimeCode=true, co w połączeniu z useJDBCCompliantTimezoneShift=trueaplikacją spowodowałoby, że aplikacja otrzymywałaby strefę czasową bazy danych dla każdego połączenia. W tym trybie strefy czasowe GMT, takie jak „British Summer Time”, zostałyby przekonwertowane na wewnętrzny format Java / JDBC. Nowe strefy czasowe można zdefiniować w pliku .properties, takim jak ten
  • Począwszy od wersji sterownika jdbc 8, automatyczne dopasowywanie czasu ( useJDBCCompliantTimezoneShift) i starszy format czasu ( useLegacyDatetimeCode) zostały usunięte ( patrz dziennik zmian złącza mysql złącza jdbc ). dlatego ustawienie tych 2 parametrów nie ma wpływu, ponieważ są one całkowicie ignorowane (nowa wartość domyślna to useLegacyDateTimeCode=false)
  • W ten sposób ustawienie serverTimezonestało się obowiązkowe, jeśli którakolwiek ze stref czasowych (serwery aplikacji / baz danych) nie ma formatu „UTC + xx” lub „GMT + xx”
  • Ustawienie czasu serwera jako UTC nie ma wpływu (na przykład jdbc:mysql://localhost:3306/myschema?serverTimezone=UTC, nawet jeśli serwery aplikacji / bazy danych nie znajdują się w tej strefie czasowej. Ważne jest, aby parametry połączenia aplikacji + baza danych były synchronizowane z tą samą strefą czasową. Innymi słowy , po prostu ustawienie serverTimezone = UTC z inną strefą czasową na serwerze bazy danych spowoduje przesunięcie dowolnych dat wyodrębnionych z bazy danych
  • Domyślną strefę czasową MySQL można ustawić na UTC + 0 za pomocą plików my.ini lub my.cnf (odpowiednio Windows / Linux), dodając wiersz default-time-zone='+00:00'(szczegóły w tym poście StackOverflow )
  • Bazy danych skonfigurowane w AWS (serwisy Amazon) automatycznie otrzymują domyślny czas UTC + 0 ( patrz strona pomocy AWS tutaj )

1
Dobra odpowiedź, dzięki. Różne pociski są przydatne. Poszedłem z sugestią, aby umieścić plik default-time-zone = '+00:00'w /usr/local/etc/my.cnfpliku homebrew . Wydaje się, że spacje wokół =są ważne, więc możesz edytować ten punkt , aby je uwzględnić.
Mark Edington

51

Jeśli używasz Maven, możesz po prostu ustawić inną wersję konektora MySQL (miałem ten sam błąd, więc zmieniłem z 6.0.2 na 5.1.39) w pom.xml:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.39</version>
</dependency>

Jak podano w innych odpowiedziach, ten problem został rozwiązany w wersji 6.0.3 lub nowszej, dzięki czemu można użyć zaktualizowanej wersji:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>6.0.3</version>
</dependency>

Maven automatycznie odbuduje projekt po zapisaniu pom.xmlpliku.


2
Dla tych, którzy pobrali mysql-connector-java / 6 -> wystarczy pobrać np. Mysql-connector-java / 5.1.20 i powinno działać. Dzięki!
Połącz

6
należy unikać obniżenia oceny. Ponadto nie jest to naprawione przy pomocy 6.0.6Still. lepiej skorzystać z powyższego rozwiązania
phil294

dostaję ten sam błąd, nawet z najnowszym plikiem jar [mysql-connector-java-6.0.5.jar: 6.0.5]
user2478236

18
Mam to nawet w 8.0.12
Robert Niestroj

13
8.0.13 daje ten sam błąd. 5.1.47 działa jednak dla mnie.
localhost

36

Parametry połączenia powinny być ustawione w następujący sposób:

jdbc:mysql://localhost/db?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC

Jeśli definiujesz połączenia w xmlpliku (takie jak persistence.xml, standalone-full.xmlitd ..), zamiast &należy użyć &amp;lub użyć CDATAbloku.


1
To nie jest poprawne Punkt useLegacyDatetimeCode = false nie musi określać serverTimezone, więc klient koryguje różnice stref czasowych.
antgar9,

To zadziałało w przypadku łączenia się z MySQL 5.7 z phpStorm 2019.1.4.
moult86

29

Jest to błąd w mysql-connector-java od wersji 5.1.33 do 5.1.37. Zgłosiłem to tutaj: http://bugs.mysql.com/bug.php?id=79343

Edytowano: poprawiono to w mysql-connector-java 5.1.39

Była to literówka w klasie TimeUtil w metodzie loadTimeZoneMappings, która podnosi plik lokalizujący /com/mysql/jdbc/TimeZoneMapping.properties NPE. Jeśli spojrzysz na kod, plik powinien znajdować się w module ładującym klasy TimeUtil, a nie TimeZone:

TimeUtil.class.getResourceAsStream(TIME_ZONE_MAPPINGS_RESOURCE);

Parametr useLegacyDatetimeCode pozwala automatycznie korygować różnicę między strefami czasowymi klienta i serwera podczas korzystania z dat. Pomaga to precyzyjnie nie określać stref czasowych w każdej części. Chociaż użycie parametru serverTimeZone jest obejściem problemu, a tymczasem łatka zostaje wydana, możesz spróbować poprawić kod samodzielnie, tak jak ja.

  • Jeśli jest to samodzielna aplikacja, możesz po prostu dodać poprawioną klasę com / mysql / jdbc / TimeUtil do swojego kodu i uważaj na kolejność ładowania słoika. Może to pomóc: https://owenou.com/2010/07/20/patching-with-class-shadowing-and-maven.html

  • Jeśli jest to aplikacja internetowa, łatwiejszym rozwiązaniem jest utworzenie własnego mysql-connector-java-5.1.37-patched.jar, podstawiając klasę .class bezpośrednio do oryginalnego słoika.


Kochanie, dziękuję za zgłoszenie tego. Cieszę się, że ktoś był w stanie zidentyfikować błąd. Czy wiesz, kiedy poprawka zostanie wydana?
bluecollarcoder,

Rozwiązanie, które sugerujesz, jest świetne, ale myślę, że modyfikowanie źródła sterownika i zarządzanie zależnością Maven jest prawdopodobnie zbyt denerwujące dla większości ludzi.
bluecollarcoder

4
@Gili Nie zostało to naprawione od wersji 6.0.6
Imme22009

6
Błąd jest nadal obecny w 8.0.11
John Little

3
@JohnLittle Mam ten problem również w wersji 8.0.15, ale nie jest to już spowodowane błędem. Strefy czasowe są ładowane poprawnie, ale CET i CEST (te strefy czasowe powodują dla mnie problemy) nie są uwzględnione ani w TimeZone.getAvailableIDs()ani w, TimeZoneMapping.propertieswięc to rozwiązanie nie pomoże tutaj. Rozwiązaniem byłoby prawdopodobnie ustawienie jakserverTimezone=Europe/Berlin
JPT

29

Rozwiązałem wstawianie poniżej ciągu połączenia w adresie URL

jdbc:mysql://localhost:3306/db?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC

1
To nie jest poprawne Punkt useLegacyDatetimeCode = false nie musi określać serverTimezone, więc klient koryguje różnice stref czasowych.
antgar9

25

Działa to dla mnie tylko przez dodanie serverTimeZone = UTC w application.properties.
spring.datasource.url=jdbc:mysql://localhost/db?serverTimezone=UTC


22
  1. Dodałem w pliku konfiguracyjnym mysql w sekcji [mysqld]

    default_time_zone='+03:00'
  2. I zrestartuj serwer mysql:

    sudo service mysql restart

Gdzie +03: 00 moja strefa czasowa UTC.

Ścieżka do pliku konfiguracyjnego w moim systemie operacyjnym Ubuntu 16.04:

/etc/mysql/mysql.conf.d/mysqld.cnf

OSTRZEŻENIE: JEŻELI W SWOJEJ STREFIE CZASU JEST CZAS LETNI I ZIMOWY MUSISZ ZMIENIĆ UTC W KONFIGURACJI JEŻELI ZMIANA CZASU. Dwa razy w roku (zwykle) lub ustaw CRONTAB w SUDO.

Moje połączenie jdbc z url:

"jdbc:mysql://localhost/java"

1
Ponowne uruchomienie Mysql jest w zasadzie niestabilne w prawie wszystkich przypadkach zastosowań produkcyjnych. Staje się to jeszcze większym problemem, gdy w grę wchodzą replikacje.
bluecollarcoder

@bluecollarcoder Wymagaj dodawania tylko w sekcji [mysqld]. Lub dodaj sekcję [mysqld], jeśli jej nie ma. Przykład mojej konfiguracji pastebin.com/j4F7t2KS
Fortran

1
Zaktualizowałem / etc / localtime mojego serwera Linux z / usr / share / zoneinfo / US / Pacific do / usr / share / zoneinfo / America / Los_Angeles, a następnie ponownie uruchomiłem usługę mysql i to naprawiło problem.
vinnyjames

W moim przypadku dotyczącym podanej składni wystąpił błąd podczas ponownego uruchamiania, a poprawna składnia to: default-time-zone='+03:00'zamiast tego, zgodnie z tą odpowiedzią . Pochodzi również z DBeaver.
wscourge

nie s odpowiednie, jeśli trzeba powiedzieć każdemu programistów w firmie, aby zmienić ich MySQL config :)
pheromix

16

Mam ten sam problem i rozwiązałem go, dodając tylko „? ServerTimezone = UTC” do mojego połączenia łańcuchowego.

#

sinossi mój problem:

java.sql.SQLException: Wartość strefy czasowej serwera „CEST” jest nierozpoznana lub reprezentuje więcej niż jedną strefę czasową. Musisz skonfigurować serwer lub sterownik JDBC (za pośrednictwem właściwości konfiguracyjnej serverTimezone), aby używał bardziej szczegółowej wartości strefy czasowej, jeśli chcesz korzystać z obsługi strefy czasowej.

my dbDriver = com.mysql.jdbc.Driver

my jar = mysql-connector-java-8.0.12.jar

my java = 1.8

my tomcat = Apache Tomcat Version 8.5.32

my MySql server = MySql ver.8.0.12 

14

Powyższy program wygeneruje błąd strefy czasowej.

Po nazwie bazy danych trzeba dodać to: ?useTimezone=true&serverTimezone=UTC. Po zakończeniu kod będzie działał poprawnie.

Powodzenia :)



13

Wszystko, czego potrzebujemy, aby rozwiązać problem serverTimezone:

String url = "jdbc:mysql://localhost:3306/db?serverTimezone=" + TimeZone.getDefault().getID()

Zdarzyło mi się to także w najnowszej wersji 5.4.15. Ale naprawiono to: dodanie „? ServerTimezone =” + TimeZone.getDefault (). GetID () ”tuż obok bazy danych ur rozwiązuje problemy.
Tes

10

Możesz użyć łącznika MySQL w zależności Maven,

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.14</version>
</dependency>

Następnie potrzebujesz ustawić odpowiednie parametry w application.propertiespliku,

spring.datasource.url=jdbc:mysql://localhost:3306/UserReward?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
spring.datasource.username=testuser
spring.datasource.password=testpassword
# MySQL driver
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect

9

Używam mysql-connector-java-8.0.13 i miałem ten sam problem. Utworzyłem moją bazę danych w konsoli wiersza poleceń i rozwiązałem ten problem, używając rozwiązania @Dimitry Rud w wierszu polecenia:

SET GLOBAL time_zone = '-6:00';

Nie musiałem niczego ponownie uruchamiać, ustawiać czasu i natychmiast uruchamiać mój kod w zaćmieniu, co wiązało się bez żadnych problemów.

Błąd powinien zostać naprawiony w starszej wersji, ale myślę, że dostałem ten błąd, ponieważ po utworzeniu bazy danych w konsoli nie ustawiłem tego. Nie używam środowiska roboczego ani innej aplikacji do zarządzania tym, a nie konsoli.


6

Z mysql workbench uruchom następujące instrukcje SQL:

  1. SET @@ global.time_zone = '+00: 00';
  2. SET @@ session.time_zone = '+00: 00';

za pomocą następujących instrukcji SQL sprawdź, czy wartości zostały ustawione:

WYBIERZ @@ global.time_zone, @@ session.time_zone;


2
To działało dla mnie, gdy błąd pojawił się podczas próby nawiązania połączenia z IntelliJ IDEA.
Faheem Hassan Zunjani

6

To zadziałało dla mnie.

w DBeaver 6.0: Wybierz Ustawienia połączenia> Właściwości sterownika> Strefa czasowa serwera> Ustaw UTC.

Ponadto w konfiguracji rozruchu wiosennego musiałem ustawić poniżej właściwości.

jdbc: mysql: // localhost: /? serverTimezone = UTC


5

Najwyraźniej, aby uzyskać wersję 5.1.33 sterownika MySQL JDBC do pracy ze strefą czasową UTC, należy wyraźnie określić parametr serverTimezone w ciągu połączenia.

spring.datasource.url = jdbc:mysql://localhost:3306/quartz_demo?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC

3

Miałem również ten sam problem w bazie LibreOffice. Więc właśnie podałem „ciąg czasu letniego” w ciągu połączenia.
** wprowadź opis zdjęcia tutaj **

Próbowałem bez „& serverTimezone = MST”, ale to też się nie udało.

Próbowałem też „& serverTimezone = MDT” i to się nie udało, więc z jakiegoś powodu nie lubi czasu letniego!


3

Miałem ten sam problem, gdy próbowałem pracować z projektem wiosennego rozruchu w systemie Windows.

Adres URL źródła danych powinien być:

spring.datasource.url=jdbc:mysql://localhost/database?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC


3

Uruchom poniżej zapytania do mysql DB, aby rozwiązać błąd

MariaDB [xxx> SET @@global.time_zone = '+00:00';
Query OK, 0 rows affected (0.062 sec)

MariaDB [xxx]> SET @@session.time_zone = '+00:00';
Query OK, 0 rows affected (0.000 sec)

MariaDB [xxx]> SELECT @@global.time_zone, @@session.time_zone;

3

Mam błąd podobny do twojego, ale mój Wartość strefy czasowej serwera to „Afr. centrale Ouest ”, więc wykonałem następujące kroki:

MyError (w IntelliJ IDEA Community Edition):

    InvalidConnectionAttributeException: The server time zone value 'Afr. centrale Ouest' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the 'serverTimezone' configuration property) to use a more specifc time zone value if you want to u....

Napotkałem ten problem, kiedy uaktualniłem mój serwer mysql do SQL Server 8.0 (MYSQL80).

Najprostszym rozwiązaniem tego problemu jest napisanie poniższego polecenia w MYSQL Workbench -

  SET GLOBAL time_zone = '+1:00'

Wartość po strefie czasowej będzie równa GMT +/- Różnica w strefie czasowej. Powyższy przykład dotyczy Afryki Północnej (GMT + 1: 00) / lub Indii (GMT + 5: 30). To rozwiąże problem.

Wprowadź następujący kod w swoim Mysql Workbench i wykonaj zapytanie

[link źródłowy do pytania / problemu]

[link źródłowy do odpowiedzi]

[Rozwiązanie ScreenShot]


2
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/resultout? useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC","root",""))

To jest właściwie rozwiązanie tego problemu, ale nie kopiuj go i wklej w swoim programie. Jeśli po prostu przeczytasz wiersz, znajdziesz „wynik”, to jest nazwa mojej bazy danych i musisz napisać swoją.

Istnieją trzy komponenty łańcuchowe, pierwszy to url, drugi to nazwa użytkownika, a trzeci to hasło. W powyższym akapicie wyczyściliśmy adres URL. Drugi i trzeci komponent String, jak powiedział twoja nazwa użytkownika i hasło, musisz odpowiednio zmienić.

Dzięki


1

Rozwiązałem ten problem bez żadnej zmiany kodu. właśnie ustawiłem czas systemowy i ustawiłem strefę czasową. W moim przypadku domyślną strefą czasową była UTC, którą zmieniłem na lokalną strefę czasową. Po ponownym uruchomieniu wszystkich usług wszystko działało dla mnie.


1

Jestem spóźniony, ale jeśli walczysz z następującym błędem i używasz źródła danych (javax.sql.DataSource):

The server time zone value 'CEST' is unrecognized or represents more than one time zone.

Ustaw następujący wiersz, aby pozbyć się błędu:

MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setServerTimezone("UTC");

1

W moim przypadku było to środowisko testowe i musiałem sprawić, aby istniejąca aplikacja działała bez żadnych zmian konfiguracji, a jeśli to możliwe, bez żadnych zmian konfiguracji MySQL. Byłem w stanie rozwiązać ten problem, postępując zgodnie z sugestią @vinnyjames i zmieniając strefę czasową serwera na UTC :

ln -sf /usr/share/zoneinfo/UTC /etc/localtime
service mysqld restart

Wystarczyło mi to, aby rozwiązać problem.


1

Dodałem następujący wiersz do mojego /etc/mysql/my.cnfpliku:

default_time_zone='+00:00'

Zrestartował serwer MySQL:

systemctl restart mysql

I działa jak urok.


0

Zgadzam się z odpowiedzią @bluecollarcoder, ale lepiej jest użyć TimeZone.getDefault().getID();na końcu ciągu połączenia:

"jdbc:mysql://localhost/db?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=" + TimeZone.getDefault().getID();  

W takim przypadku Timezoneparametr jest aktualizowany automatycznie w zależności od strefy czasowej lokalnego komputera.


To nie jest poprawne Punkt useLegacyDatetimeCode = false nie musi określać serverTimezone, więc klient koryguje różnice stref czasowych.
antgar9

0

Wystarczy zmodyfikować ciąg połączenia za pomocą następującego kodu w pliku application.properties.


spring.datasource.url=jdbc:mysql://localhost:3301/Db?
   useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=
   false&serverTimezone=UTC

0

Nie ma wpływu na ustawienie czasu serwera jako UTC (na przykład z jdbc:mysql://localhost:3306/myschema?serverTimezone=UTC , nawet jeśli serwery aplikacji / bazy danych nie znajdują się w tej strefie czasowej. Ważne jest, aby parametry połączenia aplikacji + baza danych były synchronizowane z tą samą strefą czasową.

Innymi słowy, po prostu ustawienie serverTimezone=UTCinnej strefy czasowej na serwerze bazy danych spowoduje przesunięcie dat wyodrębnionych z bazy danych

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.