ที่เก็บ SVN หนึ่งหรือหลาย ๆ


106

หากคุณมีหลายโปรเจ็กต์ที่ไม่เกี่ยวข้องกันคุณควรวางโปรเจ็กต์เหล่านั้นไว้ในที่เก็บเดียวกันหรือไม่

myRepo/projectA/trunk
myRepo/projectA/tags
myRepo/projectA/branches
myRepo/projectB/trunk
myRepo/projectB/tags
myRepo/projectB/branches

หรือคุณจะสร้างที่เก็บใหม่สำหรับแต่ละที่?

myRepoA/trunk
myRepoA/tags
myRepoA/branches
myRepoB/trunk
myRepoB/tags
myRepoB/branches

ข้อดีข้อเสียของแต่ละข้อคืออะไร? สิ่งที่ฉันคิดได้ในตอนนี้คือคุณได้รับหมายเลขการแก้ไขแบบผสม (แล้วไงล่ะ) และคุณไม่สามารถใช้งานได้svn:externalsเว้นแต่ที่เก็บจะเป็นภายนอกจริงๆ (ฉันคิด?)

เหตุผลที่ฉันถามคือเพราะฉันกำลังพิจารณาที่จะรวมหลาย repos ของฉันไว้ในที่เดียวเนื่องจากโฮสต์ SVN ของฉันเริ่มเรียกเก็บเงินต่อ repo


3
ฉันเคยถามคำถามเดียวกันเมื่อก่อนดังนั้นหากคุณต้องการความช่วยเหลืออีกต่อไปอาจมีบางส่วนที่นี่: stackoverflow.com/questions/130447/…
Nathan W

1
โอ้ dammit - ขอโทษสำหรับคนหลอกลวงแล้ว ฉันพยายามค้นหาฉันสาบาน!
nickf

ไม่มีคำสั่ง :) ฉันไม่กังวลเพียงแค่พูดถึงมันดังนั้นหากคุณไม่ได้รับความช่วยเหลือที่ต้องการที่นี่อาจมีความช่วยเหลือเพิ่มเติมใน Q
Nathan W

1
nickf, svn: ภายนอกใช้งานได้ดีกับที่เก็บขนาดใหญ่เพียงแห่งเดียว คุณเพียงชี้ไปที่ไดเรกทอรีย่อยใน repo ด้วยรหัสที่คุณสนใจ
Ben Gartner

แน่นอนว่าในสภาพแวดล้อมทางการค้าปกติคุณจะมีหลาย repos (เห็นได้ชัดว่าคุณสามารถเป็นลูกค้า / กลุ่มที่แตกต่างกันสามารถเห็นโครงการที่แตกต่างกันของตนเองเท่านั้น) ลองนึกภาพหนึ่งในไซต์การโค่นล้มฟรีขนาดใหญ่ที่คุณสามารถใช้ repo ที่โค่นล้มได้ .... ลองคิดดูสิว่ามันจะโง่แค่ไหนถ้า พวกเขามี repo ขนาดใหญ่เพียงหนึ่งชิ้นแทนที่จะเป็นหนึ่งรายการสำหรับเราแต่ละคน !!
Fattie

คำตอบ:


77

ปัญหาเดียวกับหลายประเด็นขึ้นอยู่กับความชอบส่วนบุคคลหรือองค์กร

การจัดการหลาย ๆ ตัวเทียบกับแบบเดี่ยวส่วนใหญ่มาจากการควบคุมการเข้าถึงและการบำรุงรักษา

การควบคุมการเข้าถึงสำหรับที่เก็บเดียวสามารถอยู่ในไฟล์เดียว หลายที่เก็บอาจต้องใช้หลายไฟล์ การบำรุงรักษามีปัญหาที่คล้ายกัน - การสำรองข้อมูลขนาดใหญ่หนึ่งรายการหรือการสำรองข้อมูลเล็กน้อยจำนวนมาก

ฉันจัดการของฉันเอง มีที่เก็บเดียวหลายโครงการแต่ละโครงการมีแท็กลำต้นและกิ่งก้านของตัวเอง หากมีขนาดใหญ่เกินไปหรือฉันต้องการแยกรหัสของลูกค้าเพื่อความสะดวกสบายฉันสามารถสร้างที่เก็บใหม่ได้อย่างรวดเร็วและง่ายดาย

ฉันเพิ่งปรึกษากับ บริษัท ที่ค่อนข้างใหญ่เกี่ยวกับการย้ายระบบควบคุมซอร์สโค้ดหลายระบบไปยัง Subversion พวกเขามีโครงการประมาณ 50 โครงการตั้งแต่ขนาดเล็กไปจนถึงแอปพลิเคชันระดับองค์กรและเว็บไซต์ขององค์กร แผนของพวกเขา? เริ่มต้นด้วยที่เก็บเดียวโยกย้ายไปยังหลาย ๆ หากจำเป็น การย้ายข้อมูลเกือบจะเสร็จสมบูรณ์และยังคงอยู่ในที่เก็บเดียวไม่มีรายงานการร้องเรียนหรือปัญหาใด ๆ เนื่องจากเป็นที่เก็บเดียว

นี่ไม่ใช่ปัญหาไบนารีขาวดำ

ทำสิ่งที่เหมาะกับคุณ - ถ้าฉันอยู่ในตำแหน่งของคุณฉันจะรวมโปรเจ็กต์ไว้ในที่เก็บเดียวให้เร็วที่สุดเท่าที่ฉันจะพิมพ์คำสั่งได้เพราะค่าใช้จ่ายจะเป็นข้อพิจารณาที่สำคัญใน บริษัท ของฉัน (เล็กมาก)

JFTR:

ตัวเลขการแก้ไขใน Subversion ไม่มีความหมายนอกที่เก็บ หากคุณต้องการชื่อที่มีความหมายสำหรับการแก้ไขให้สร้าง TAG

ข้อความคอมมิตจะถูกกรองอย่างง่ายดายตามเส้นทางในที่เก็บดังนั้นการอ่านเฉพาะข้อความที่เกี่ยวข้องกับโปรเจ็กต์หนึ่ง ๆ จึงเป็นแบบฝึกหัดที่ไม่สำคัญ


แก้ไข: ดูการตอบสนองของBladeสำหรับรายละเอียดเกี่ยวกับการใช้การกำหนดค่าการอนุญาต / การพิสูจน์ตัวตนเดียวสำหรับ SVN


1
"การควบคุมการเข้าถึงสำหรับ [... ] ที่เก็บหลายแห่งจะต้องใช้หลายไฟล์" ที่เก็บข้อมูลจำนวนมากสามารถชี้ไปที่ไฟล์ จำกัด การเข้าถึงเดียวกัน ดูคำตอบของฉันด้านล่าง
Frederic Morin

สวัสดีเคนคุณอยากจะแสดงความคิดเห็นเพิ่มเติมเกี่ยวกับขั้นตอนการตรวจสอบและแยกสาขาในการตั้งค่าที่เก็บเดียวหลายโครงการหรือไม่ ตอนนี้ฉันกำลังทำงานกับ บริษัท ที่มีหลายโปรเจ็กต์ในที่เก็บเดียวแต่ละแห่งมีระบบโฟลเดอร์ / project / <trunk> <branch> <tags> ของตัวเอง แต่วิศวกรได้ตรวจสอบโครงการทั้งหมดพร้อมกันจากไดเร็กทอรีราก: กราฟการแยกและการแก้ไขไม่ทำงานอีกต่อไป :(
bboyle1234

25

สำหรับกรณีเฉพาะของคุณที่เก็บหนึ่ง (1) สมบูรณ์แบบ คุณจะประหยัดเงินได้มาก ฉันมักจะแนะนำให้ผู้คนใช้ที่เก็บเดียว เนื่องจากมันคล้ายกับระบบไฟล์เดียวจึงง่ายกว่า

  • คุณจะมีที่เดียวที่คุณมองหารหัส
  • คุณจะมีสิทธิ์เพียงครั้งเดียว
  • คุณจะมีหมายเลขคอมมิตเดียว (เคยพยายามสร้างโปรเจ็กต์ที่กระจายไป 3 repos หรือไม่)
  • คุณสามารถนำไลบรารีทั่วไปมาใช้ซ้ำได้ดีขึ้นและติดตามความคืบหน้าของคุณใน libs เหล่านี้ (svn: externals คือ PITA และจะไม่แก้ปัญหาทั้งหมด)
  • โครงการที่วางแผนไว้เป็นรายการที่แตกต่างกันโดยสิ้นเชิงสามารถเติบโตไปด้วยกันและแบ่งปันฟังก์ชันและอินเทอร์เฟซ นี่จะเป็นเรื่องยากมากที่จะบรรลุในหลาย repos

มีจุดเดียวสำหรับหลายที่เก็บ: การบริหารที่เก็บข้อมูลขนาดใหญ่ไม่สะดวก การถ่ายโอนข้อมูล / การโหลด repos ขนาดใหญ่ต้องใช้เวลามาก แต่เนื่องจากคุณไม่ได้ทำการบริหารใด ๆ ฉันคิดว่ามันคงไม่ใช่เรื่องน่ากังวลของคุณ;)

SVN ปรับขนาดได้ดีมากกับที่เก็บที่ใหญ่กว่าไม่มีการชะลอตัวแม้ในที่เก็บขนาดใหญ่ (> 100GB)

ดังนั้นคุณจะไม่ยุ่งยากกับที่เก็บเดียว แต่คุณควรคิดถึงเค้าโครง repo จริงๆ!


2
หลาย repos! = การอนุญาตหลายรายการ หากคุณใช้ svn + ssh และ private-key-authentication การทำ repos หลาย ๆ ครั้งบนโฮสต์เดียวกันจะไม่เจ็บปวด
Matthew Schinckel

1
ฉันบอกว่า "repos เดียว == การให้สิทธิ์ครั้งเดียว" แน่นอนว่าการปฏิเสธไม่ใช่ "หลาย repos == การให้สิทธิ์หลายรายการ" ตามที่คุณแนะนำ
Peter Parker

1
ในทางเทคนิคการพูดว่า "Multiple repos! = multiple authorization" ไม่ได้หมายความว่าคุณหมายความว่าอย่างนั้นเสมอไป เขาสามารถชี้แจงเพื่อประโยชน์ของผู้ใช้รายอื่น
Casebash

มีปัญหาอะไรบ้างที่ svn: externals ไม่สามารถแก้ไขได้?
Clint Pachl

1
@Gusdor คุณพูดถูก แต่ผู้ใช้ส่วนใหญ่ไม่ทราบถึงข้อเท็จจริงนี้และกล่าวโทษ SVN ว่ากำลังทำเวอร์ชันผิด (ในขณะที่คุณระบุว่ากำลังพัฒนาผิดพลาด) และใช่คุณพูดถูกคุณทำได้และต้องใช้ peg revs แต่จริงๆแล้ว: มีกี่คนใน SVN-Team ที่เข้าใจการแก้ไข PEG?
Peter Parker

7

ฉันจะใช้หลายที่เก็บ นอกจากปัญหาการเข้าถึงของผู้ใช้แล้วยังทำให้การสำรองข้อมูลและกู้คืนทำได้ง่ายขึ้น และหากคุณพบว่าตัวเองอยู่ในสถานะที่มีใครบางคนต้องการจ่ายเงินให้คุณสำหรับรหัสของคุณ (และประวัติของรหัสนั้น) มันจะง่ายกว่าที่จะให้พวกเขาเป็นเพียงการถ่ายโอนข้อมูลที่เก็บ

ฉันขอแนะนำว่าการรวมที่เก็บเพียงเพราะนโยบายการเรียกเก็บเงินของผู้ให้บริการโฮสติ้งของคุณไม่ใช่เหตุผลที่ดีนัก


ใช่หลายหลายหลาย!
cfeduke

3
คุณสามารถ dumpfilter ดัมพ์ที่เก็บของคุณเพื่อเข้า / ไม่รวมพา ธ ใด ๆ และแยกข้อมูลตามพา ธ ใด ๆ ดังนั้นนี่ไม่ใช่ปัญหาจริงๆ
Peter Parker

คุณยังสามารถตั้งค่าการเข้าถึงแผนผังย่อยของที่เก็บเมื่อมีคนต้องการจ่ายเงินให้คุณสำหรับรหัส
Sander Rijken

7

เราใช้ที่เก็บเดียว ข้อกังวลเดียวของฉันคือขนาด แต่หลังจากเห็นที่เก็บของ ASF (การแก้ไขและการนับ 700,000 ครั้ง) ฉันค่อนข้างเชื่อว่าประสิทธิภาพจะไม่เป็นปัญหา

โครงการของเราล้วนเกี่ยวข้องกับโมดูลการเชื่อมต่อที่แตกต่างกันซึ่งเป็นชุดของการอ้างอิงสำหรับแอปที่กำหนด ด้วยเหตุนี้ที่เก็บเดียวจึงเหมาะอย่างยิ่ง คุณอาจต้องการแยก trunk / branch / tags สำหรับแต่ละโปรเจ็กต์ แต่คุณยังคงสามารถทำการเปลี่ยนแปลงใน codebase ทั้งหมดของคุณได้ภายในการแก้ไขครั้งเดียว นี่ยอดเยี่ยมมากสำหรับการปรับโครงสร้างใหม่


7

โปรดทราบว่าในการตัดสินใจของคุณrepos SVN จำนวนมากสามารถแชร์ไฟล์ config เดียวกันได้

ตัวอย่าง (นำมาจากลิงค์ด้านบน):

ในเปลือก:

$ svn-admin create /var/svn/repos1
$ svn-admin create /var/svn/repos2
$ svn-admin create /var/svn/repos3

ไฟล์: /var/svn/repos1/conf/svnserve.conf

[general]
anon-access = none # or read or write
auth-access = write
password-db = /var/svn/conf/passwd
authz-db = /var/svn/conf/authz
realm = Repos1 SVN Repository

ไฟล์: / var / svn / conf / authz

[groups]
group_repos1_read = user1, user2
group_repos1_write = user3, user4
group_repos2_read = user1, user4

### Global Right for all repositories ###
[/]
### Could be a superadmin or something else ###
user5 = rw

### Global Rights for one repository (e.g. repos1) ###
[repos1:/]
@group_repos1_read = r
@group_repos1_write = rw

### Repository folder specific rights (e.g. the trunk folder) ###
[repos1:/trunk]
user1 = rw

### And soon for the other repositories ###
[repos2:/]
@group_repos2_read = r
user3 = rw

แม้ว่าคุณจะถูกต้องที่อาจใช้ไฟล์การอนุญาต / การพิสูจน์ตัวตนชุดเดียวสำหรับหลายที่เก็บ แต่การทำเช่นนั้นเป็นเรื่องของการตั้งค่า ฉันจะอัปเดตโพสต์ของฉันเพื่อแสดงคำตอบของคุณ ฉันพบว่า "ผิด" อักเสบเล็กน้อย
Ken Gentle

1
เมื่อก่อนตอนนี้ไม่รู้จะทำยังไง ขอบคุณ.
Harvey

5

ฉันจะสร้างที่เก็บแยกต่างหาก ... ทำไม? ตัวเลขการแก้ไขและข้อความคอมมิตจะไม่สมเหตุสมผลหากคุณมีโปรเจ็กต์ที่ไม่เกี่ยวข้องจำนวนมากในที่เก็บเพียงแห่งเดียวมันจะเป็นปัญหาใหญ่ในระยะสั้นแน่นอน ....


5
ไม่มีปัญหาถ้าคุณดูในโฟลเดอร์โครงการที่เหมาะสมคุณจะได้รับเฉพาะข้อความที่มุ่งมั่นกับโครงการนี้
Peter Parker

ใช่คุณทำได้ แต่โดยส่วนตัวแล้วฉันคิดว่าการดูแลพื้นที่เก็บข้อมูลขนาดใหญ่นั้นยากกว่าการจัดการสิทธิ์ของผู้ใช้การสำรองข้อมูลการแก้ไขหมายเลข ฯลฯ ขึ้นอยู่กับความต้องการของทีมของคุณ SVN จะปรับขนาดได้ดีมากหากคุณเลือกใช้ที่เก็บข้อมูลขนาดใหญ่ ...
CMS

3
การสำรองที่เก็บข้อมูลเดียวดูเหมือนจะง่ายกว่าการสำรองข้อมูล 20 ให้ฉัน ในฐานะที่เป็นบันทึกด้านข้างวิธีที่เรียบร้อยในการสำรองที่เก็บคือการรักษาสำเนาแบบอ่านอย่างเดียวโดยใช้ svnsync
Sander Rijken

5

เราเป็น บริษัท ซอฟต์แวร์ขนาดเล็กและเราใช้ repo เดียวสำหรับการพัฒนาทั้งหมดของเรา ต้นไม้มีลักษณะดังนี้:

/client/<clientname>/<project>/<trunk, branches, tags>

แนวคิดก็คือเราจะมีลูกค้าและงานภายในใน repo เดียวกัน แต่สุดท้ายเราก็มี บริษัท ของเราเป็น "ลูกค้า" ของตัวเอง

สิ่งนี้ได้ผลดีสำหรับเรามากและเราใช้ Trac เพื่อเชื่อมต่อกับมัน ตัวเลขการแก้ไขอยู่ใน repo ทั้งหมดและไม่ได้เจาะจงไปที่โปรเจ็กต์เดียว แต่นั่นไม่ได้เป็นการรบกวนเรา


4

โดยส่วนตัวฉันจะสร้างที่เก็บใหม่สำหรับแต่ละที่ ช่วยให้กระบวนการเช็คเอาต์ง่ายขึ้นมากและทำให้การดูแลระบบโดยรวมง่ายขึ้นอย่างน้อยก็เกี่ยวกับการเข้าถึงและการสำรองข้อมูลของผู้ใช้ นอกจากนี้ยังหลีกเลี่ยงปัญหาหมายเลขเวอร์ชันสากลดังนั้นหมายเลขเวอร์ชันจึงมีความหมายสำหรับทุกโครงการ

จริงๆแล้วคุณควรใช้ git;)


4

สิ่งหนึ่งที่ควรพิจารณาเพิ่มเติมคือการใช้ที่เก็บข้อมูลหลายที่ทำให้คุณสูญเสียความสามารถในการบันทึกแบบรวม (คำสั่ง svn log) เพียงอย่างเดียวจะเป็นเหตุผลที่ดีในการเลือกที่เก็บเดียว

ฉันใช้ TortuiseSvn และพบว่าตัวเลือก "แสดงบันทึก" เป็นเครื่องมือบังคับ แม้ว่าโปรเจ็กต์ของคุณจะไม่เกี่ยวข้องกัน แต่ฉันมั่นใจว่าคุณจะพบว่าการมีข้อมูลข้ามโปรเจ็กต์ส่วนกลางที่รวมศูนย์ (เส้นทางรหัสข้อบกพร่องข้อความและอื่น ๆ .... ) มีประโยชน์เสมอ


2

หากคุณวางแผนที่จะหรือใช้เครื่องมือเช่น trac ซึ่งรวมเข้ากับ SVN จะเหมาะสมกว่าที่จะใช้หนึ่ง repo ต่อโครงการ


2

เช่นเดียวกับคำแนะนำของ Blade เกี่ยวกับการแชร์ไฟล์นี่เป็นวิธีแก้ปัญหาที่ง่ายกว่าเล็กน้อย แต่มีความยืดหยุ่นน้อยกว่า ฉันตั้งค่าของเราดังนี้:

  • / var / svn /
  • / var / svn / bin
  • / var / svn / repository_files
  • / var / svn / svnroot
  • / var / svn / svnroot / repos1
  • / var / svn / svnroot / repos2
  • ...

ใน "bin" ฉันเก็บสคริปต์ที่ชื่อว่า svn-create.sh ซึ่งจะทำหน้าที่ตั้งค่าทั้งหมดในการสร้างที่เก็บว่าง ฉันยังเก็บสคริปต์สำรองไว้ที่นั่น

ใน "repository_files" ฉันเก็บไดเร็กทอรี "conf" และ "hooks" ทั่วไปซึ่งที่เก็บทั้งหมดมีลิงก์ sym จากนั้นจะมีไฟล์เพียงชุดเดียว ซึ่งจะช่วยลดความสามารถในการเข้าถึงแบบละเอียดต่อโครงการโดยไม่ทำลายลิงก์ นั่นไม่ใช่เรื่องน่ากังวลที่ฉันตั้งขึ้น

สุดท้ายฉันเก็บไดเร็กทอรีหลัก / var / svn ไว้ภายใต้การควบคุมแหล่งที่มาโดยไม่สนใจทุกอย่างใน svnroot ด้วยวิธีนี้ไฟล์และสคริปต์ที่เก็บจะอยู่ภายใต้การควบคุมซอร์สเช่นกัน

#!/bin/bash

# Usage:
# svn-create.sh repository_name

# This will:
# - create a new repository
# - link the necessary commit scripts
# - setup permissions
# - create and commit the initial directory structure
# - clean up after itself

if [ "empty" = ${1}"empty" ] ; then
  echo "Usage:"
  echo "    ${0} repository_name"
  exit
fi

SVN_HOME=/svn
SVN_ROOT=${SVN_HOME}/svnroot
SVN_COMMON_FILES=${SVN_HOME}/repository_files
NEW_DIR=${SVN_ROOT}/${1}
TMP_DIR=/tmp/${1}_$$

echo "Creating repository: ${1}"

# Create the repository
svnadmin create ${NEW_DIR}

# Copy/Link the hook scripts
cd ${NEW_DIR}
rm -rf hooks
ln -s ${SVN_COMMON_FILES}/hooks hooks

# Setup the user configuration
cd ${NEW_DIR}
rm -rf conf
ln -s ${SVN_COMMON_FILES}/conf conf

# Checkout the newly created project
svn co file://${NEW_DIR} ${TMP_DIR}

# Create the initial directory structure
cd ${TMP_DIR}
mkdir trunk
mkdir tags
mkdir branches

# Schedule the directories addition to the repository
svn add trunk tags branches

# Check in the changes
svn ci -m "Initial Setup"

# Delete the temporary working copy
cd /
rm -rf ${TMP_DIR}

# That's it!
echo "Repository ${1} created. (most likely)"

2

คล้ายกับ mlambie ของการใช้ repo เดียว แต่ไปไกลกว่านั้นด้วยโครงสร้างโฟลเดอร์เพื่อขยายไปยังโครงการประเภทใดประเภทหนึ่งได้อย่างง่ายดาย - โครงการที่ใช้เว็บ html เทียบกับ cs (C #) เทียบกับ sql (SQL create / execute scripts) เทียบกับ xyz ( ภาษาเฉพาะโดเมนเช่น afl (AmiBroker Formula Language) หรือ ts (TradeStation)):

/<src|lib>/<app-settings|afl|cs|js|iphone|sql|ts|web>/<ClientName>/<ProjectName>/<branches|tags>

หมายเหตุฉันมีลำต้นอาศัยอยู่ในกิ่งก้านเนื่องจากฉันถือว่าเป็นสาขาเริ่มต้น บางครั้งความเจ็บปวดเพียงอย่างเดียวคือเมื่อคุณต้องการสร้างโปรเจ็กต์อื่นอย่างรวดเร็วคุณต้องสร้างโครงสร้าง ProjectName / branch | tags ฉันใช้การตั้งค่าแอพเป็นสถานที่ในการเก็บไฟล์การตั้งค่าแอพที่เฉพาะเจาะจงไว้ใน repo เพื่อให้แชร์กับผู้อื่นได้อย่างง่ายดาย (และแทนที่ ClientName เป็น VendorName และ ProjectName เป็น AppName ในโครงสร้างโฟลเดอร์นี้และสาขา | แท็กจะมีประโยชน์ในการแท็กการตั้งค่าในหลักต่างๆ เวอร์ชันของผลิตภัณฑ์ของผู้จำหน่ายด้วย)

ยินดีต้อนรับสู่ความคิดเห็นใด ๆ เกี่ยวกับโครงสร้างของฉัน - ฉันเพิ่งเปลี่ยนเป็นสิ่งนี้และจนถึงตอนนี้ก็ค่อนข้างมีความสุข แต่บางครั้งก็เป็นภาระในการดูแลสาขา | โครงสร้างแท็กต่อโครงการ - โดยเฉพาะอย่างยิ่งหากโครงการเป็นเพียงการตั้งค่าโครงการเพื่อทดสอบหน่วยโครงการอื่น


1

ข้อเสนอแนะของฉันคือหนึ่ง เว้นแต่คุณจะมีผู้ใช้ที่แตกต่างกันในการเข้าถึงแต่ละคนฉันจะบอกว่าใช้หลายคน

แต่อีกครั้งแม้ว่านั่นไม่ใช่เหตุผลที่ดีที่จะใช้หลาย ๆ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.