Proses pada Arch Linux kehabisan memori pada 7.6GB terlepas dari 16GB RAM diikuti oleh kesalahan bus


2

Saya mencoba menggunakan sebagian besar memori dalam R, dengan ukuran sekitar 7,6 GB. Sistem saya memiliki 16 GB RAM, jadi saya tidak berharap ini menjadi masalah. Namun, R mencegah hal ini, dan berusaha mengelaknya menyebabkan crash besar pada R dan berbagai aplikasi lain (browser web). Sistem melaporkan masalah bus, tetapi saya tidak memiliki pesan kesalahan yang tepat karena sistem akhirnya macet.

Pertanyaan saya adalah: Apa yang terjadi? Bagaimana saya mencegah ini dan mengalokasikan lebih banyak memori dalam R (atau aplikasi apa pun)?

Saya merasa bahwa itu mungkin terkait dengan berapa banyak memori yang dapat dialamatkan, bukan memori yang tersedia secara teoritis.

Detail

Saya mencoba menggunakan potongan memori yang lebih besar di R, sebuah matriks dengan entri 1bn, sekitar 7,6 GB. R tidak mudah memungkinkan vektor / matriks ukuran itu, meskipun tidak jelas bagi saya, mengapa. ( Error: cannot allocate vector of size 7.6 GbMenghasilkan) Namun, R memiliki perpustakaan seperti bigmemory yang konon mampu menangani vektor besar. Dari penerjemah R:

> library(bigmemory)
Loading required package: bigmemory.sri
> bx <- big.matrix(45070,45070)

 *** caught bus error ***
address 0x7ff75ffac000, cause 'non-existent physical address'

Traceback:
 1: .Call("bigmemory_CreateSharedMatrix", PACKAGE = "bigmemory",     row, col, colnames, rownames, typeLength, ini, separated)
 2: CreateSharedMatrix(as.double(nrow), as.double(ncol), as.character(colnames),     as.character(rownames), as.integer(typeVal), as.double(init),     as.logical(separated))
 3: big.matrix(45070, 45070)

Possible actions:
1: abort (with core dump, if enabled)
2: normal R exit
3: exit R without saving workspace
4: exit R saving workspace
Selection: 

Jadi R crash, tetapi dapat disimpan dengan memilih 2 dan membatalkan pintu keluar. Mungkin tidak terlalu pintar untuk mencoba hal yang sama lagi, tapi bagaimanapun, ini dia:

Selection: 2
Save workspace image? [y/n/c]: c
> bx <- big.matrix(45070,45070)
terminate called after throwing an instance of 'boost::interprocess::interprocess_exception'
  what():  No space left on device
Aborted (core dumped)

Dari jurnal jurnal, terlihat seperti ini:

Aug 23 14:49:25 system systemd-coredump[426]: Process 423 (R) of user 1000 dumped core.

                                           Stack trace of thread 423:
                                           #0  0x00007ff94bab18c0 raise (libc.so.6)
                                           #1  0x00007ff94bab2f72 abort (libc.so.6)
                                           #2  0x00007ff94774d035 _ZN9__gnu_cxx27__verbose_terminate_handlerEv (libstdc++.so.6)
                                           #3  0x00007ff94774ac46 _ZN10__cxxabiv111__terminateEPFvvE (libstdc++.so.6)
                                           #4  0x00007ff947749b49 __cxa_call_terminate (libstdc++.so.6)
                                           #5  0x00007ff94774a538 __gxx_personality_v0 (libstdc++.so.6)
                                           #6  0x00007ff9474b3ee3 _Unwind_RaiseException_Phase2 (libgcc_s.so.1)
                                           #7  0x00007ff9474b470e _Unwind_Resume (libgcc_s.so.1)
                                           #8  0x00007ff945279da6 _ZN21SharedMemoryBigMatrix7destroyEv (bigmemory.so)
                                           #9  0x00007ff9452a7762 _Z15CreateRAMMatrixI21SharedMemoryBigMatrixEP7SEXPRECS2_S2_S2_S2_S2_S2_S2_ (bigmemory.so)
                                           #10 0x00007ff94528d79c bigmemory_CreateSharedMatrix (bigmemory.so)
                                           #11 0x00007ff94c11a33a n/a (libR.so)
                                           #12 0x00007ff94c11a8c6 n/a (libR.so)
                                           #13 0x00007ff94c158fb8 Rf_eval (libR.so)
                                           #14 0x00007ff94c15ba3b n/a (libR.so)
                                           #15 0x00007ff94c158d5b Rf_eval (libR.so)
                                           #16 0x00007ff94c15adce n/a (libR.so)
                                           #17 0x00007ff94c150963 n/a (libR.so)
                                           #18 0x00007ff94c158938 Rf_eval (libR.so)
                                           #19 0x00007ff94c15adce n/a (libR.so)
                                           #20 0x00007ff94c158b02 Rf_eval (libR.so)
                                           #21 0x00007ff94c15cbc7 n/a (libR.so)
                                           #22 0x00007ff94c158d5b Rf_eval (libR.so)
                                           #23 0x00007ff94c181f92 Rf_ReplIteration (libR.so)
                                           #24 0x00007ff94c1823b1 n/a (libR.so)
                                           #25 0x00007ff94c182468 run_Rmainloop (libR.so)
                                           #26 0x000000000040074b main (R)
                                           #27 0x00007ff94ba9e4ca __libc_start_main (libc.so.6)
                                           #28 0x000000000040078a _start (R)
-- Subject: Process 423 (R) dumped core
-- Defined-By: systemd
-- Support: https://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- Documentation: man:core(5)
-- 
-- Process 423 (R) crashed and dumped core.
-- 
-- This usually indicates a programming error in the crashing program and
-- should be reported to its vendor as a bug.

Konsekuensi seluruh sistem

Pada saat ini, lingkungan desktop maupun aplikasi grafis tidak berjalan. Saya memulai manajer jendela dan browser untuk mencari tahu apa yang terjadi. Betapa terkejutnya saya, saya mendapati bahwa baik Firefox, Opera maupun Chromium tidak akan mulai. Pesan kesalahan mengatakan sesuatu tentang kesalahan bus, tapi saya tidak punya pesan kesalahan yang tepat karena sistem akhirnya macet. Perlu dicatat bahwa aplikasi lain, bahkan yang lebih besar, seperti libreoffice, dapat dimulai tanpa masalah. Mungkinkah ini ada hubungannya dengan alamat yang diperlukan untuk membangun koneksi jaringan? Mungkinkah sistem itu entah bagaimana keluar dari alamat setelah R crash? (Namun, saya tidak mengerti mengapa hal itu akan bertahan setelah proses R. meninggal.)

Dari jurnal jurnal, sepertinya ini (jejak tumpukan panjang terpotong):

Aug 23 15:16:19 system systemd-coredump[18050]: Process 18017 (firefox) of user 1000 dumped core.

                                             Stack trace of thread 18017:
                                             #0  0x00007ff72e679018 sem_init@@GLIBC_2.2.5 (libpthread.so.0)
                                    (...)

Aug 23 15:16:20 system systemd-coredump[18097]: Process 18062 (firefox) of user 1000 dumped core.

                                             Stack trace of thread 18062:
                                             #0  0x00007f2098a98018 sem_init@@GLIBC_2.2.5 (libpthread.so.0)
                                    (...)

Aug 23 15:16:21 system systemd-coredump[18144]: Process 18109 (firefox) of user 1000 dumped core.

                                             Stack trace of thread 18109:
                                             #0  0x00007f2d45410018 sem_init@@GLIBC_2.2.5 (libpthread.so.0)
                                    (...)
                                    (...)
                                    (...)

Aug 23 15:19:16 system systemd-coredump[19510]: Process 19370 (opera) of user 1000 dumped core.

                                             Stack trace of thread 19395:
                                             #0  0x0000000001c882f7 n/a (opera)
                                             #1  0x0000000001c890e9 n/a (opera)
                                    (...)

Aug 23 15:20:58 system systemd-coredump[20140]: Process 20136 (evas_image_load) of user 1000 dumped core.

                                             Stack trace of thread 20136:
                                             #0  0x00007fba4432babd __memset_avx2_erms (libc.so.6)
                                    (...)

Aug 23 15:30:11 system systemd-coredump[20990]: Process 20958 (WebKitWebProces) of user 1000 dumped core.

                                             Stack trace of thread 20958:
                                             #0  0x00007fc5dd5ed7d0 n/a (libpixman-1.so.0)
                                             #1  0x00007fc5dd5d273b n/a (libpixman-1.so.0)
                                    (...)

Aug 23 15:31:07 system systemd-coredump[22406]: Process 20936 (midori) of user 1000 dumped core.

                                             Stack trace of thread 22403:
                                             #0  0x00007f3a38d5b6df __memmove_avx_unaligned_erms (libc.so.6)
                                             #1  0x00007f3a39759e78 n/a (libwebkit2gtk-4.0.so.37)

Saya kemudian mencoba untuk me-restart dbus (yang juga bukan langkah paling cerdas dan sistem crash).

Aspek lainnya

Sebelum sistem macet, saya juga menyadari hal berikut:

[user@system ~]$ df -h
Filesystem         Size  Used Avail Use% Mounted on
dev                7.6G     0  7.6G   0% /dev
run                7.6G  788K  7.6G   1% /run
/dev/mapper/root   412G   89G  324G  22% /
tmpfs              7.6G  7.6G     0 100% /dev/shm
tmpfs              7.6G     0  7.6G   0% /sys/fs/cgroup
/dev/sda1          2.0G   52M  1.8G   3% /boot
tmpfs              7.6G     0  7.6G   0% /tmp
tmpfs              1.6G     0  1.6G   0% /run/user/1000
[user@system ~]$ free -m
              total        used        free      shared  buff/cache   available
Mem:          15469         146        7438        7735        7884        7349
Swap:         14335           0       14335
[user@system ~]$ 

Mengapa sistem file virtual (dev, run, tmpfs) semuanya berukuran 7.6GB, tepatnya apa yang tidak akan dialokasikan R?

Saya telah memverifikasi bahwa dimungkinkan untuk mengalokasikan sebanyak 6,7GB dalam R, tetapi di suatu tempat di bawah 7,6GB ada batasnya. Tidak ada memori maksimum yang diatur dalam R atau dalam sistem:

[user@system ~]$ ulimit -a
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 61833
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 99
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 61833
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

... dan dalam juru bahasa R:

> Sys.getenv("R_MAX_MEM_SIZE")
[1] ""
> Sys.getenv()
COLUMNS                 235
DBUS_SESSION_BUS_ADDRESS
                        unix:path=/run/user/1000/bus
DESKTOP                 Enlightenment
DISPLAY                 :0.0
E_BIN_DIR               /usr/bin
E_CONF_PROFILE          standard
E_DATA_DIR              /usr/share/enlightenment
E_ICON_THEME            gnome
E_IPC_SOCKET            /run/user/1000/e-user@0/633
E_LIB_DIR               /usr/lib
E_LOCALE_DIR            /usr/share/locale
E_PREFIX                /usr
E_RESTART               1
E_SCALE                 1.000
E_START                 enlightenment_start
E_START_TIME            1503499246.8
E_TAINTED               NO
EDITOR                  vi
HOME                    /home/user
LANG                    en_GB.UTF-8
LD_LIBRARY_PATH         /usr/lib64/R/lib:/usr/lib/jvm/java-7-openjdk/jre/lib/amd64/server
LINES                   58
LN_S                    ln -s
LOGNAME                 user
M2                      /opt/maven//bin
M2_HOME                 /opt/maven/
MAIL                    /var/spool/mail/user
MAKE                    make
MAVEN_OPTS              -Xmx512m
MOZ_PLUGIN_PATH         /usr/lib/mozilla/plugins
PAGER                   /usr/bin/less
PANTS                   ON
PATH                    /opt/maven//bin:/home/user/Applications/.bin:/usr/bin:/opt/maven//bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl
PWD                     /home/user
QT_QPA_PLATFORMTHEME    gtk2
QT_STYLE_OVERRIDE       gtk2
R_ARCH                  
R_BROWSER               /usr/bin/xdg-open
R_BZIPCMD               /usr/bin/bzip2
R_DOC_DIR               /usr/share/doc/R/
R_GZIPCMD               /usr/bin/gzip
R_HOME                  /usr/lib64/R
R_INCLUDE_DIR           /usr/include/R/
R_LIBS_SITE             
R_LIBS_USER             ~/R/x86_64-pc-linux-gnu-library/3.4
R_PAPERSIZE             a4
R_PDFVIEWER             /usr/bin/xdg-open
R_PLATFORM              x86_64-pc-linux-gnu
R_PRINTCMD              
R_RD4PDF                times,inconsolata,hyper
R_SESSION_TMPDIR        /tmp/RtmpXBvepb
R_SHARE_DIR             /usr/share/R/
R_SYSTEM_ABI            linux,gcc,gxx,gfortran,?
R_TEXI2DVICMD           /usr/bin/texi2dvi
R_UNZIPCMD              /usr/bin/unzip
R_ZIPCMD                /usr/bin/zip
SED                     /usr/bin/sed
SHELL                   /bin/bash
SHLVL                   3
TAR                     /usr/bin/tar
TERM                    xterm
USER                    user
WINDOWPATH              1
XAUTHORITY              /home/user/.Xauthority
XDG_CONFIG_DIRS         /usr/etc/xdg:/etc/xdg
XDG_DATA_DIRS           /usr/share/enlightenment:/usr/share:/usr/local/share:/usr/share
XDG_MENU_PREFIX         e-
XDG_RUNTIME_DIR         /run/user/1000
XDG_SEAT                seat0
E_PREFIX                /usr
E_RESTART               1
E_SCALE                 1.000
E_START                 enlightenment_start
E_START_TIME            1503499246.8
E_TAINTED               NO
EDITOR                  vi
HOME                    /home/user
LANG                    en_GB.UTF-8
LD_LIBRARY_PATH         /usr/lib64/R/lib:/usr/lib/jvm/java-7-openjdk/jre/lib/amd64/server
LINES                   58
LN_S                    ln -s
LOGNAME                 user
M2                      /opt/maven//bin
M2_HOME                 /opt/maven/
MAIL                    /var/spool/mail/user
MAKE                    make
MAVEN_OPTS              -Xmx512m
MOZ_PLUGIN_PATH         /usr/lib/mozilla/plugins
PAGER                   /usr/bin/less
PANTS                   ON
PATH                    /opt/maven//bin:/home/user/Applications/.bin:/usr/bin:/opt/maven//bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl
PWD                     /home/user
QT_QPA_PLATFORMTHEME    gtk2
QT_STYLE_OVERRIDE       gtk2
R_ARCH                  
R_BROWSER               /usr/bin/xdg-open
R_BZIPCMD               /usr/bin/bzip2
R_DOC_DIR               /usr/share/doc/R/
R_GZIPCMD               /usr/bin/gzip
R_HOME                  /usr/lib64/R
R_INCLUDE_DIR           /usr/include/R/
R_LIBS_SITE             
R_LIBS_USER             ~/R/x86_64-pc-linux-gnu-library/3.4
R_PAPERSIZE             a4
R_PDFVIEWER             /usr/bin/xdg-open
R_PLATFORM              x86_64-pc-linux-gnu
R_PRINTCMD              
R_RD4PDF                times,inconsolata,hyper
R_SESSION_TMPDIR        /tmp/RtmpXBvepb
R_SHARE_DIR             /usr/share/R/
R_SYSTEM_ABI            linux,gcc,gxx,gfortran,?
R_TEXI2DVICMD           /usr/bin/texi2dvi
R_UNZIPCMD              /usr/bin/unzip
R_ZIPCMD                /usr/bin/zip
SED                     /usr/bin/sed
SHELL                   /bin/bash
SHLVL                   3
TAR                     /usr/bin/tar
TERM                    xterm
USER                    user
WINDOWPATH              1
XAUTHORITY              /home/user/.Xauthority
XDG_CONFIG_DIRS         /usr/etc/xdg:/etc/xdg
XDG_DATA_DIRS           /usr/share/enlightenment:/usr/share:/usr/local/share:/usr/share
XDG_MENU_PREFIX         e-
XDG_RUNTIME_DIR         /run/user/1000
XDG_SEAT                seat0
XDG_SESSION_ID          c1
XDG_VTNR                1
XMODIFIERS              @im=ibus

Perangkat lunak

Versi R adalah 3.4.1; sistemnya adalah Arch Linux.

[user@system ~]$ uname -a
Linux system 4.11.9-1-ARCH #1 SMP PREEMPT Wed Jul 5 18:23:08 CEST 2017 x86_64 GNU/Linux

Jawaban:


3

Ini adalah salah satu dari sedikit kesempatan di mana saya tidak setuju dengan kegelisahan , yang jawabannya selalu mencerahkan, bagi banyak orang dan juga bagi saya.

Alasannya adalah bahwa pengisian up / dev / shm ini tidak disebabkan oleh beberapa proses lain, sehingga dapat dengan mudah dibebaskan untuk digunakan oleh R paket, tetapi hal itu disebabkan oleh big.memory modul dalam R sendiri! Jadi membebaskan / dev / shm sama saja dengan membunuh R .

Manual paket memori menyatakan, pada halaman 1:

Deskripsi : Membuat, menyimpan, mengakses, dan memanipulasi matriks besar. Matriks dialokasikan untuk memori bersama dan dapat menggunakan file yang dipetakan memori.

Ini mengklarifikasi poin penting: Anda tidak dapat mengharapkan untuk menggunakan semua memori Anda dengan menggunakan big.memory , hanya bagian yang dialokasikan ke / dev / shm , yang biasanya setengah dari total memori yang Anda miliki. Jika Anda ingin memperbesar atau memperkecil shm , ubah baris yang relevan di / etc / fstab dan reboot.

Kita bisa berasumsi bahwa pengisian up / dev / shm adalah karena R . Bahkan, pos OP jelas menyatakan bahwa tidak ada program lain yang berjalan pada saat itu,

Pada saat ini, lingkungan desktop maupun aplikasi grafis tidak berjalan.

, jadi sulit untuk membayangkan apa lagi ( yaitu , terpisah dari R ) yang mungkin menelan begitu banyak memori bersama.

Bahkan, juga mudah untuk memahami akar masalahnya. Pertama-tama, matriks Anda

bx <- big.matrix (45070.45070)

memiliki 45070 x 45070 > 2 miliar elemen. Kedua, sesuai manual R ,

R tidak memiliki tipe data presisi tunggal. Semua bilangan real disimpan dalam format presisi ganda

lalu

Semua platform R diharuskan untuk bekerja dengan nilai yang sesuai dengan standar IEC 60559 (juga dikenal sebagai IEEE 754).

....

Dalam IEEE 754-2008 / IEC60559: 2011 ini disebut format 'binary64'.

dan artikel Wikipedia tentang format binary64 dengan jelas menyatakan:

Format floating-point presisi ganda adalah format angka komputer yang menempati 8 byte (64 bit) dalam memori komputer.

Jadi, lebih dari 2 miliar elemen Anda, masing-masing menempati 8 byte, ingin menempati lebih dari 16 miliar byte memori, yang kira-kira dua kali lipat dari / dev / shm Anda (di mana big.memory ingin menyimpannya, lihat di atas ), telah tersedia. Karenanya crash, dan pesan kesalahan:

terminate dipanggil setelah melempar instance 'boost :: interprocess :: interprocess_exception' what (): Tidak ada ruang tersisa di perangkat

Pesan galat ini, dari perpustakaan Boost C ++ , berkaitan dengan kelas fungsi yang:

Proses Boost.Inter menawarkan beberapa kelas dasar untuk membuat objek memori bersama dan memetakan file dan memetakan kelas-kelas yang bisa dipetakan ke ruang alamat proses.

Adapun sistem Anda gagal setelah dump inti R , itu dijelaskan dengan baik oleh grawity , bahwa / dev / shm belum dibersihkan, dan semua proses yang menggunakan memori bersama (seperti semua yang menggunakan perpustakaan dinamis, misalnya) akan gagal karena kurangnya ruang pada perangkat: opsi termudah Anda adalah untuk reboot.

Apa pilihanmu? Pertama, mungkin Anda dapat menginstal memori 32GiB, yang akan memaksa keadaan Anda saat ini. Atau, Anda dapat melihat apakah matriks Anda benar-benar membutuhkan begitu banyak elemen: misalnya, matriks simetris hanya mengandung sedikit lebih dari setengah elemen dari matriks non-simetris, dan Anda hanya perlu memperbesar / dev / shm sedikit . Atau mungkin Anda berurusan dengan matriks jarang, yang akan lebih mudah dikompresi daripada matriks simetris.

Dengan kata lain, Anda harus melihat beberapa detail dari matriks dan menemukan solusi yang disesuaikan dengan situasi konkret Anda.


Apa itu "proses bus"?
grawity

Ah saya mengerti. Tapi ... Meskipun pustaka dibagi dalam memori, itu sama sekali tidak ada hubungannya dengan / dev / shm - kernel langsung menggunakan paging untuk itu. Folder / dev / shm murni untuk fungsi IPC POSIX "shm".
grawity

Ah saya mengerti. Tapi ... Meskipun pustaka dibagi dalam memori, itu sama sekali tidak ada hubungannya dengan / dev / shm - kernel langsung menggunakan paging untuk itu. Folder / dev / shm murni untuk fungsi IPC POSIX "shm".
grawity

3

filesystem tmpfs tumbuh sesuai permintaan, sehingga "ukuran total" yang Anda lihat hanyalah batas kapasitas - kecuali ditentukan lain pada saat mount, batas default sama dengan 50% dari memori fisik. (Ini tidak berarti tmpfs dikunci ke dalam memori fisik; itu dapat ditukar.)

Namun, perhatikan bahwa satu sistem file,, /dev/shmmelaporkan 7,6 GB yang digunakan (yaitu diisi hingga batasnya). Lokasi ini adalah tempat segmen SHM (memori bersama - fitur komunikasi antar-proses) disimpan, meskipun terkadang program membuat file lain-lain di sana secara langsung juga.

Segmen SHM gigih; jika suatu program keluar tanpa menghapusnya secara eksplisit, mereka akan tetap ada. Jadi jika menjalankan Anda sebelumnya terus mengatur SHM dan kemudian crash, itu bisa dengan mudah mengisi setengah RAM Anda dan hanya menyisakan ~ 8 GB untuk program baru.

(Dan sebaliknya, karena kapasitas default /dev/shmadalah 50% dari memori fisik, ukuran total semua segmen SHM terbatas pada 7,6 GB. Saya ragu itu relevan di sini - saya akan sangat terkejut jika suatu program secara sah membutuhkan segmen SHM yang besar.)

Untuk membersihkan / dev / shm, Anda dapat a) me-reboot, atau b) dengan hati-hati menghapus file yang ditemukan di sana menggunakan file lama rm. Tapi pertama-tama selalu gunakan lsofuntuk memastikan mereka tidak digunakan.

Atau, naikkan batas ukuran menggunakan:

mount -o remount,size=90% /dev/shm

(Sebagai catatan, Anda menjalankan kernel yang agak lama untuk Arch Linux - versi saat ini adalah 4.12.8, kecuali jika Anda menjalankan linux-lts.)


Dengan "tumbuh sesuai permintaan", maksudnya semua /runsistem file seperti yang tercantum dalam pertanyaan hanya membutuhkan memori 788 KB (+ beberapa overhead). contoh tmpfs sebagian besar datang secara gratis dalam hal apa pun, sungguh.
Daniel B

Saya percaya ini tidak sepenuhnya benar: paket bigmemory benar - benar menggunakan memori bersama untuk penanganan matriks besar dan inilah yang mengisinya hingga ke jurang, dan akhirnya menyebabkan crash. Mohon baca balasan saya di bawah ini.
MariusMatutiae
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.