なぜソース管理システムのほとんどがまだファイルでバックアップされているのですか?


22

バージョンデータを保存する手段としてファイルを使用するソース管理システムが増えているようです。VaultとTFSはデータストアとしてSql Serverを使用します。これは、データの一貫性と速度の点で優れていると思います。

だから、実際にデータベースソフトウェアを使用する代わりに、SVN、GIT、CVSなどがファイルシステムを本質的にデータベースとして使用していると思うのはなぜですか(SVNサーバーが通常のコミット中に破損するため、この質問をします) MSSQL、Oracle、Postgreなど)?

編集:私の質問をする別の方法は、「VCS開発者が既存のシステムを使用するのではなく、なぜ独自の構造化データストレージシステムをロールバックするのですか?」


29
ほとんどのデータベースは基本的なバッキングとして何を使用すると思いますか?ほとんどはファイルを使用します(ただし、いくつかはハードディスクへの直接アクセスを使用します)。「ファイルだけ」を使用して、データベースのすべての機能を使用できます。
ヨアヒムザウアー

2
@JoachimSauer公正な点ですが、もちろん、データベースを自分で作成する必要があります。目的の機能セットが既存のソリューションの機能セットに近く、これらのいずれも使用しない非常に良い理由がない場合、これはばかげています。

1
@JoachimSauerはい、わかりましたが、DBMシステムには一貫性のないものがデータベースに入らないようにする方法があります。これらのファイルベースのリポジトリがTransactional NTSFのようなものを使用していない限り、破損している可能性がまだあります。そして、ソース管理システムにはデータの整合性が必要であることに同意できると思うので、私は一連の開発者が本質的に車輪を再発明するよりも実際のデータベースを信頼します。
アンディ

2
@delnanトランザクションサポートと内部一貫性。現在、SVNサーバーが想定されたすべてのファイルに適切に書き込めなかったテープb / cからSVNリポジトリを復元しています。また、膨大な量のデータを検索します。私のポイントは、なぜ車輪を再発明してみてください。
アンディ

7
すべての主要なオペレーティングシステムには、ファイルシステムが組み込まれています。これらのファイルシステムはすべて、同じ基本機能(ファイル、フォルダー、同じ永続性)を備えています。基本的に、データベースは、エンドユーザーがインストールして更新し続ける必要がある追加の依存関係です。ソース管理は、ほとんどの人の主要なビジネスではありません(sourceforgeまたはgithubでない限り)。VCは、多くの場合、チームの最新メンバーによってコマンドラインを介してサーバーにインストールされます。インストールとセットアップの容易さが重要です。
グレンペターソン

回答:


23

TL; DR:データベースが必要ないため、データベースを使用するバージョン管理システムはほとんどありません。

質問への回答の質問として、なぜそうではないのでしょうか?このコンテキストでは、ファイルシステムに対して「実際の」データベースシステムはどのような利点を提供しますか?

リビジョン管理では、ほとんどメタデータと多くのテキスト差分を追跡していると考えてください。テキストはより効率的にデータベースに保存されず、コンテンツのインデックス付け可能性は要因になりません。

Git(引数のため)がデータを格納するバックエンドにBDBまたはSQLite DBを使用したと仮定しましょう。それについてより信頼できるものは何でしょうか?単純なファイルが破損する可能性があるものはすべて、データベースも破損する可能性があります(これは、より複雑なエンコードの単純なファイルでもあるため)。

必要でない限り最適化しないというプログラマーのパラダイムから、リビジョン管理システムが十分に高速で信頼性の高い動作をする場合、なぜより複雑なシステムを使用するように設計全体を変更するのでしょうか?


2
TLDR?あなたの答えは2倍の長さで、質問は実に短いものでした!
ブラッド

25
@Brad次の3つの単語TL;DRは回答の短縮版であり、質問が長すぎて、回答する前に読んでいないという声明ではありません。

6
@Andy Mercurialにも「歴史のgrep」があり、gitにも同様にあります。また、すでに非常に高速です。専門家に任せることに関して:VCSを開発する人々専門家です。

3
付け加えておきたいのは、私があなたの要点を見ているということです。VCSが不正なデータを書き込む場合、そのデータをファイルまたはデータベースに書き込むかどうかは関係ありません。逆に、ファイルベースのリポジトリはおそらく一度に複数のファイルに書き込みを行っており、通常はそれに対するトランザクションのサポートがないため、1つのファイルが書き込み、別のファイルが失敗した場合、VCSはデータベース内の複数のテーブル書き込みに対して破損していますトランザクションは、ユニットとして失敗した場合にコミットします。データベースソフトウェアを構築している開発者のグループは、SVNを作成している人よりも多くの経験を持っているように感じますが、多分私は間違っています。
アンディ

6
「引数のため」のgitの選択は重要なポイントです。gitはオブジェクトを記述するための非常に優れたモデルを持っていますが、多くのツールはそうではありません。gitを使用すると、コミットの途中でコンピューターの電源がオフになった場合、オブジェクトの一部をファイルシステムに書き込んでしまい、それらは単に到達不能になります。他のVCSでは、変更をファイルの半分に追加した可能性があります(そして混乱が生じます)。 SQLトランザクションを使用して正しいことを行う方がはるかに簡単です。
エドワードトムソン

25

おそらくSVNとCVSの経験に基づいて、多くの仮定を立てているようです。

GitとMercurialは基本的にSVNとCVSに似ています

gitとCVSの比較は、iPadとAtariの比較に似ています。CVSは恐竜が地球を歩き回った時に作成されました。Subversionは基本的にCVSの改良版です。gitやMercurialのような最新のバージョン管理システムがそれらのように動作すると仮定しても、ほとんど意味がありません。

リレーショナルデータベースは、単一目的のデータベースよりも効率的です。

どうして?リレーショナルデータベースは非常に複雑で、単一目的のデータベースほど効率的ではありません。私の頭の上のいくつかの違い:

  • とにかく同時に複数のコミットを行うことはできないため、バージョン管理システムは複雑なロックを必要としません。
  • 分散バージョン管理システムは、ローカルデータベースがリポジトリの完全なコピーであるため、スペース効率が非常に高い必要があります。
  • バージョン管理システムで必要なのは、特定の2つの方法(作成者、リビジョンID、フルテキスト検索など)でデータを検索することだけです。著者/リビジョンIDの検索を処理できる独自のデータベースを作成するのは簡単であり、私が試したどのリレーショナルデータベースでも全文検索はそれほど高速ではありません。
  • バージョン管理システムは、複数のプラットフォームで動作する必要があります。これにより、インストールしてサービスとして実行する必要があるデータベース(MySQLやPostgreSQLなど)を使用することが難しくなります。
  • ローカルマシンのバージョン管理システムは、何かを実行しているとき(コミットなど)にのみ実行する必要があります。コミットしたい場合に備えて MySQLのようなサービスを常に実行したままにしておくのは無駄です。
  • ほとんどの場合、バージョン管理システムは履歴を削除するのではなく、履歴に追加するだけです。これにより、最適化が異なり、整合性を保護する方法が異なる場合があります。

リレーショナルデータベースの方が安全です

繰り返しますが、なぜですか?データはファイルに保存されるため、gitやMercurialなどのバージョン管理システムにはアトミックコミットはありませんが、そうするように思われます。リレーショナルデータベース、データベースをファイルとして保存します。ここで注目に値するのは、CVS アトミックコミットを行わないことですが、それはおそらく、リレーショナルデータベースを使用していないからではなく、暗黒時代からのものだからです。

また、データがデータベースに格納されると、データを破損から保護するという問題もあります。その答えは同じです。ファイルシステムが破損している場合、使用しているデータベースは関係ありません。ファイルシステムが破損していない場合、データベースエンジンが破損している可能性があります。なぜバージョン管理データベースがリレーショナルデータベースよりもこの傾向があるのか​​はわかりません。

分散型バージョン管理システム(gitやMercurialなど)は、一元化されたバージョン管理よりもデータベースの保護に適していると主張します。どのクローンからでもリポジトリ全体を復元できるからです。そのため、中央サーバーがすべてのバックアップとともに自発的に燃焼した場合git init、新しいサーバーで実行し、次に開発者のマシンgit pushから実行することで復元できます。

車輪の再発明は悪い

ストレージの問題にリレーショナルデータベースを使用できるからといって、そうすべきだとは限りません。なぜリレーショナルデータベースの代わりに構成ファイルを使用するのですか?リレーショナルデータベースにデータを保存できるのに、なぜファイルシステムに画像を保存するのですか?すべてをリレーショナルデータベースに保存できるのに、コードをファイルシステムに保持するのはなぜですか?

「持っているのがハンマーだけなら、すべてが釘のように見えます。」

また、オープンソースプロジェクトは、商業プロジェクトと同じ種類のリソース制約がないため、都合の良いときにいつでも車輪を再発明する余裕があるという事実もあります。データベース作成のエキスパートであるボランティアがいる場合、それらを使用してみませんか?

リビジョン管理システムの作成者が何をしているのかを信頼できる理由については、他のVCSについては話すことはできませんが、Linus Torvalds はファイルシステムを理解していると確信しています

なぜ一部の商用バージョン管理システムはリレーショナルデータベースを使用するのですか?

ほとんどの場合、以下のいくつかの組み合わせ:

  • 一部の開発者は、データベースを書きたくありませ
  • 市販のバージョン管理システムの開発者には時間とリソースの制約があるため、既に望んでいるものに近いデータベースを作成する余裕はありません。また、開発者は高価であり、ほとんどの人はそのような経験がないため、データベース開発者(データベースを作成する人など)はおそらくより高価です。
  • 商用バージョン管理システムのユーザーは、リレーショナルデータベースを既に設定しているため、セットアップと実行のオーバーヘッドを気にしません。
  • 商用バージョン管理システムのユーザーは、リビジョンデータをバックアップするリレーショナルデータベースが必要になる可能性が高くなります。これは、プロセスとの統合性が向上する可能性があるためです(バックアップなど)。

1
一つのこと:SVNコミットアトミックです。実際、それは大きなセールスポイントです(または、少なくとも、CSVユーザーに切り替えを説得しなければならなかった頃はそうでした)。

1
@delnan- 作業ディレクトリ内の異なるディレクトリが異なるリビジョンにある場合の理論的な原子性と、またはで得られる真のリポジトリ全体の原子性の間には大きな違いがあることに注意してsvnください。svngithg
マークブース

2
@Andyそして、私のポイントは、本格的なリレーショナルデータベースがなくても、まったく同じシナリオを処理できるということです。2人がまったく同時にコミットする場合、サーバーは次々に実行できます。実装するのは複雑な機能ではありません。ローカルユーザーでそれをしたい場合は、ロックファイルを持っているだけです。コミットを開始すると、ファイルのロックを取得します。コミットを終了したら、ロックを解除します。一度に複数のブランチへのコミットを許可する場合は、各ブランチにロックファイルを使用します。確かに、SQLiteは私のためにこれを行いますが、それは必要ありません
モニカの復活

1
同様に、基本的なジャーナルの実装も複雑ではありません。(1)新しいコミットをファイルに書き出します。(2)古いインデックスファイルをコピーします。(3)新しいインデックスファイルを書き込みます。(4)古いインデックスファイルのコピーを削除します。手順1、2、または4で失敗した場合は、作成した新しいファイルをクリーンアップするだけです。手順3で失敗した場合は、古いインデックスファイルをコピーするだけです。ファイルシステムをよりよく理解している人は、おそらくこれをはるかに効率的なバージョンにすることができますが、必要な場合はいつでもSQLiteのソースコードを参照できます(パブリックドメイン)。
モニカの復活

1
@BrendanLong素晴らしい点。議論に感謝します。明確にするために、両方の種類のバッキングストアには長所と短所があると思います。正しい答えが1つだけあるとは思いません。ただし、SQLを使用するのは3つ(VaultとVercityを別々に数える場合は4つ)だけで、大部分はそうではないことに驚いたのです。
アンディ

18

svnリポジトリにBDBを使用するために実際に使用されます。これは、破損しやすいため、最終的に削除されました。

現在DB(SQLite)を使用している別のVCSはfossilです。また、バグトラッカーも統合されています。

本当の理由での私の推測は、VCSは多くのファイルで動作するということです。ファイルシステムは、単なる別の種類のデータベースです(階層的で、CLOB / BLOBストレージの効率に焦点を当てています)。通常のデータベースは、ファイルシステムがすでに存在する理由がないため、うまく処理しません。


1
BDBは、SQLiteのようにインプロセスデータベースであるため、正確に信頼できるとは見なされません。そうは言っても、Oracle / MSSQL / MySQL / Postgresの信頼性は、それらをどのように構成するかにもよりますが、ファイルシステムとそれほど変わらないと思います。主な問題は、RDBMSがVCSで一般的に機能する階層構造およびグラフ構造用に構築されていないことです。その場合、ファイルシステムが勝つだけです。
マイクラーセン

3
@Andy:FossilはSQLiteの作成者によって作成されました。それほど驚くべきことではありません:
ヨルグWミットタグ

1
@アンディ:私はSQLiteをOracleやMSSQLよりもはるかに信頼しています。これが最も使用されているSQLデータベースであることは、驚くべきことではありません。また、ほとんどの異なるアーキテクチャに移植されたものであり、それぞれが独自の一連の課題を抱えており、共有コードを非常に強力なものにします。
ハビエル

1
@Javier MSSQLやOracleほどSQLiteを信頼しません。マイクが言ったように、処理中の部分は私を怖がらせます。あたかもあなたのアプリが死んで、今あなたのデータベースが壊れたままになっているかのように。クライアント/サーバーデータベースでは、クライアントが死にかけているとトランザクションが中止されます。CS DBが破損することは不可能だとは言いませんが、DBエンジンをアプリケーションと組み合わせるよりも、その可能性は低いと思います。
アンディ

5
@Andy、それがトランザクションの目的です。どの時点で適切なDBエンジンを強制終了しても、特定のトランザクションはコミットされるかされません。SQLiteのアトミックコミット(sqlite.org/atomiccommit.html)の実装は、特に洗練されたものです。
ハビエル

10
  1. ファイルシステムデータベースです。もちろん、リレーショナルデータベースではありませんが、ほとんどは非常に効率的なキー/値ストアです。また、アクセスパターンがキーと値のストア(たとえば、gitリポジトリ形式)向けに適切に設計されている場合、データベースを使用しても、ファイルシステムを使用するよりも大きな利点はおそらくないでしょう。(実際、邪魔になるのは抽象化の別のレイヤーにすぎません。)

  2. データベースの機能の多くは、単なる超過手荷物です。全文検索?全文検索はソースコードにとって意味がありますか?または、それを別の方法でトークン化する必要がありますか?また、すべてのリビジョンで完全なファイルを保存する必要がありますが、これは一般的ではありません。多くのバージョン管理システムは、スペースを節約するために、同じファイルのリビジョン間の差分を保存します。たとえば、SubversionGit(少なくとも、パックファイルを使用する場合)。

  3. クロスプラットフォームの要件により、データベースの使用はより困難になります。

    ほとんどのバージョン管理ツールは、複数のプラットフォームで実行するように構築されています。集中型バージョン管理ツールの場合、これはサーバーコンポーネントにのみ影響しますが、UNIXユーザーはMicrosoft SQL Serverをインストールできず、WindowsユーザーはPostgreSQLまたはMySQLをインストールすることを望まない可能性があるため、単一のデータベースサーバーに依存することは依然として困難です。ファイルシステムは、最も一般的な分母です。ただし、サーバーをWindowsマシンにインストールする必要があるため、SourceGear VaultやMicrosoft Team Foundation Serverなど、SQL Serverを必要とするツールがいくつかあります

    すべてのユーザーがリポジトリのコピーを取得するため、分散バージョン管理システムでは、これがさらに困難になります。これは、すべてのユーザーがリポジトリを配置するデータベースを必要とすることを意味します。これは、ソフトウェアが次のことを意味します。

    1. 特定のデータベースが存在するプラットフォームのサブセットに限定されます
    2. クロスプラットフォームの単一のデータベースバックエンド(SQLiteなど)を対象としています。
    3. プラグ可能なストレージバックエンドを対象とするため、希望するデータベース(ファイルシステムを含む可能性がある)を使用できます。

    したがって、ほとんどの分散バージョン管理システムは、ファイルシステムを使用するだけです。注目すべき例外は、SourceGearののある信憑性のSQLiteデータベース(ローカルリポジトリに便利)やSQL Serverなどのリレーショナルデータベースに保存することができ、(サーバーの可能性が便利。)彼らのクラウドホスト型の提供が可能アマゾンのSimpleDBなどの非リレーショナルストレージバックエンドを使用します、しかしこれが真実であるとは知らない。


おそらく悪魔の支持者のコメントのように、これらのタイプの「データベースを使用しない理由」の質問をするほとんどの人は、「RDBMSを使用しない理由」を意味するように見えます。すべてのACIDコンプライアンスおよびその他の問題が含まれます。すべてのファイルシステムが既に破棄されている独自の同類のデータベースであるという事実。
ミケバブコック

6

私が多くの製品で見た限りでは、ファイルはジョブに「十分」であるように思えます。1日の終わりにVCSesの出力もファイルであることを考慮すると、妥当なものです。

svn / git / etcインターフェースを備えたRDBMSバックエンドを提供している会社はたくさんあります。したがって、あなたが求めているものは基本的にすでに存在しています。


5

これは、バージョン管理システムの主要なデータ構造がDAGであり、データベースへのマッピングが非常に悪いためだと思います。また、多くのデータはコンテンツアドレス指定可能であり、データベースへのマッピングも非常に不十分です。

データの整合性はVCSの唯一の関心事ではなく、バージョン履歴の整合性にも関心があります。データベースはあまり得意ではありません。言い換えると、バージョンを取得するとき、そのバージョンに現在の欠陥がないことを確認するだけでなく、その履歴全体で何も不正に変更されていないことも確認する必要があります。

VCSは、エンタープライズ製品に加えて消費者製品でもあります。人々は小さな、一人の趣味のプロジェクトでそれらを使用します。データベースサーバーのインストールと構成の手間を追加すると、市場のその部分の多くを疎外することになります。自宅に多くのVaultとTFSのインストールが表示されないのではないかと思います。これは、スプレッドシートやワードプロセッサがデータベースを使用しないのと同じ理由です。

また、これはDVCSのより多くの理由ですが、データベースを使用しないことで非常にポータブルになります。データベースサーバープロセスを構成しなくても、ソースツリーをサムドライブにコピーして任意のマシンで再利用できます。

これまでコミット時に破損などとして、VCSは、同時アクセスを防止するためのデータベースとまったく同じ技術を使用して、トランザクションがアトミックにする、などの両方で破損のは非常にまれですが、彼らはない が起こります。すべての意図と目的において、VCSデータストアデータベースです。


1
「データベースへのマッピングは非常に不十分です」しかし、VaultとTFSはまさにこれを行います。「VCSの懸念事項はデータの整合性だけではありません。バージョン履歴の整合性にも関心があり、データベースはあまり得意ではありません」バージョン履歴を保存すると、データベース上のファイルにどのように役立つのか、特にそれを行う製品に名前を付けたので、見当たりません。「両方の破損は非常にまれですが、実際に起こります。」最初のページのこれらの結果のいずれも、Vaultサーバーデータベースが破損していることについて言及していません。Vaultソフトウェアについても問題を語っているリンクの1つは、WCが破損したことです。
アンディ

「すべての意図と目的において、VCSデータストアはデータベースです。」まあ...それは私のポイントです。独自のデータをローリングするのではなく、実際のデータベースシステムにデータを貼り付けるだけではどうですか?
アンディ

2
@Andyはい、それはデータベースですが、すべてのデータベースが相互に代替可能であるわけではありません。各データベースには、世界に関する特定のビューがあります(たとえば、SQL DBは基本的にリレーショナルモデルを実装します)。この回答の詳細として、VCSが保存するデータとデータの使用方法は、リレーショナルモデルに適合しません。一部のNoSQL dbの方が優れているかどうかはわかりませんが、それらはかなり新しく、まだその優位性を証明していません(一部の深刻な整合性の問題の報告を思い出します)。そして、その上に他のすべての問題があります。

DAGはDVCSでのみ使用されます(線形履歴を非常に単純なDAGと考える場合を除きますが、それは実際には有用な抽象化ではありません)。 。
エドワードトムソン

単調に増加するバージョン番号は、VCSにとってあまり意味がありません。私はそれらのかなりの数を使用しましたが、一元化されたバージョン番号(CVSとSVNは私が最もよく知っている2)であるものは、合併するのが苦痛になる傾向があります。そして、それらもマージを試みるときにDAGを使用します。ストレージの表現が基になっていないからといって、それが使用されないわけではありません。
マイクラーセン

2
  • 災害復旧の改善(最悪のシナリオ:昔のように目で解析します)

  • おそらくVCSシステムの障害によって引き起こされるこのような災害の追跡とデバッグを容易にします。

  • 依存関係の数を減らします。(これらのシステムの1つがカーネルを処理しおり、もう1つが想定されていたことを忘れないでください)

  • テキストエディタは常に利用可能です。(MS SQL Serverのライセンス...それほどではありません)


この答えは悪いです。唯一の本当のポイントは、依存関係の数を減らすことです。適切なバックアップを行う必要があるため、両方のバッキングシステムは同等である必要があります。DBアプリケーションのデバッグは、ファイルを書き込むアプリケーションのデバッグと同じくらい難しくありません。また、テキストエディタは常に使用できます。VCS自体はテキストエディタを使用しないので、あなたのポイントがどこにあるのかさえわかりません。 dbサーバーのないdbバックアップソリューションの欠如は、要因ではありません。
アンディ

1
@Andy ...プログラマはテキストエディタを使用するために使用します。ご存知のように、テキスト編集は、お気に入りのIDEでも二次機能として利用できます。
ZJR

1
@Andy sqliteは、現代のDVCSが提供する膨大な量の分散シナリオを考えると、テキストファイルの唯一の可能な代替手段です。何か他のものがあまりにも面倒(設定+ファイアウォール+ライセンス)だろう(多分あなたはDVCSの「分散型」の部分を見逃している可能性があります、IDKの)あるいは愚かなことを分散。その後、sqliteに対して最悪のシナリオの事後分析を再度行うと、困難になる可能性があります。
-ZJR

1
@ZJR:元の質問分散バージョン管理を指定したことはないと思いますが、バージョン管理システム全般について尋ねました。さらに、多くのシステムが単なるフラットテキストファイルを保存しないため、テキストエディターの引数は少しフラットです。gitでさえ、テキストエディターを役に立たなくする多くのバイナリファイル形式(ルーズオブジェクト、パックファイルなど)を持っています。
エドワードトムソン

@ZJRテキストエディターでのコードの編集は、VCSのバッキングストアとどのように関連していますか?SVNのデータベースなど、手動で編集することを提案していますか?また、私の質問はDVCSに限定されないので、なぜあなたがそれに疑問を抱いているのかわかりません。
アンディ

2

Fossilは優れた分散バージョン管理システム(DVCS)であり、ストレージにSQLiteを使用し、プレーンテキストファイルは使用しません。

バグ追跡、Wiki、そして実際に配布されていることを本当に気に入っています。本当にオフラインで作業してバグを修正できるということです。

Fossilは、アプリケーションファイル形式としてSqliteを使用します。PgCon基調講演で、Richard Hipp博士は、sqliteをアプリケーションファイルシステムとして使用する利点について説明し、データベースをファイルシステムとして使用する利点についてかなり説得力のある議論をしています。

2番目の主要なトピックは、SQLiteをアプリケーションファイル形式と見なすべきであるということです。これは、独自のファイル形式を発明したり、ZIPで圧縮されたXMLを使用する代わりになります。「SQLiteはPostgreSQLに置き換わるものではありません。SQLiteは、fopen()”の代わりになるものです(スライド21)。最後に、Richardは、SQLiteがデータ(クラッシュセーフ、ACID)を処理するという事実に多くの重点を置いていますuse-the-index.com

現在、Hipp博士は、データベースにコードを保存することに関する懸念に対処しています。

  • Fossilが分散NoSQLデータベースではなくSQLiteに基づいているのはなぜですか?

FossilはSQLiteに基づいていません。Fossilの現在の実装では、SQLiteを分散データベースのコンテンツのローカルストアとして、および迅速かつ簡単に表示できるように事前計算された分散データベースに関するメタ情報のキャッシュとして使用しています。ただし、この役割でのSQLiteの使用は実装の詳細であり、設計の基本ではありません。Fossilの将来のバージョンでは、SQLiteを廃止し、SQLiteの代わりにファイルの山またはキー/値データベースを置き換える可能性があります。(実際には、SQLiteが現在の役割で驚くほどうまく機能するため、これは起こりそうにありませんが、ポイントはFossilからSQLiteを省略することは理論的な可能性です。)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.