.css()を使用して!importantを適用する方法は?


735

あるスタイルを適用できません!important。私はもう試した:

$("#elem").css("width", "100px !important");

これは何もしませ。幅スタイルは適用されません。上書きせずにそのようなスタイルを適用するjQuery風の方法はありますかcssText(つまり、最初に解析する必要があるなど)。

編集:インラインスタイルで!importantオーバーライドしようとしているスタイルのスタイルシートがあることを追加する必要があります!important。そのため.width()、外部!importantスタイルによってオーバーライドされるため、使用などは機能しません。

また、以前の値をオーバーライドする値が計算されるため、単純に別の外部スタイルを作成することはできません。


注目に値するのは、これは実際には(少なくとも私にとっては)Chromeでは機能するが、Firefoxでは機能しないことです。
Peter Jaric、2011年

これはChrome 17.xとSafari 5.1.1でも機能しますが、FF 8.0では機能しません。
DavidJ

JQuery 1.8.2を使用しているChromium 20.0.xでは動作しません。
アルバメンデス

7
jQueryのバグ#11173は固定についてだった.css!importantjQueryのコアに。バグは「修正されない」としてクローズされました。ただし、そのバグのテストケースは、この質問の場合ほど限定的ではありませんでした。テストケースには!important、オーバーライドしようとしたインラインスタイルがありませんでした。したがって、そのバグで提案されている回避策は、この場合は機能しません。
Rory O'Kane 2013

2
可能性のある重複した!CSSやjQueryを使って、重要なのオーバーライド -この1つは古く、より高度に投票している間、もう一方のは明確な、最も貴重な答えを得ました。
Jason C

回答:


603

問題はjQueryが理解していないことが原因です !important属性を、そのためルールを適用できません。

次のようにして、その問題を回避し、それを参照してルールを適用できる場合がありますaddClass()

.importantRule { width: 100px !important; }

$('#elem').addClass('importantRule');

またはを使用してattr()

$('#elem').attr('style', 'width: 100px !important');

ただし、後者のアプローチでは、以前に設定されたインラインスタイルルールの設定が解除されます。慎重に使用してください。

もちろん、@ Nick Craverの方法の方が簡単/賢明であるという良い議論があります。

上記のattr()アプローチは、元のstyle文字列/プロパティを維持するために少し変更され、コメントでfalkoによって提案されたように変更されました。

$('#elem').attr('style', function(i,s) { return (s || '') + 'width: 100px !important;' });

2
私はあなたの後者のアプローチに傾いていますが、悲しいことは、おそらくそれを破棄することができないため、おそらく前のcssTextを解析する必要があるということです
mkoryak

1
ああ、申し訳ありませんでした。時々、英語のユーモアが私の理解を超えてしまいます... :)
シナン

1
ネストされた引用符とは何ですか( '"width:100px!important"')?それは私にとってはうまくいきませんでしたが、内側の引用を削除するとうまくいきました。ありがとう!
Peter Jaric、2011年

15
スタイルが空の場合の小さな修正:$( '#elem')。attr( 'style'、function(i、s){return(s || '')+ 'width:100px!important;'});
ファルコ2013年

4
@falkoの修正を追加する必要があります。Firefoxでは'undefinedwidth: 100px !important;'、現在のスタイルが空のときに最後のスニペットでスタイルが設定されます。
acdcjunior 2014年

332

私は本当の解決策を見つけたと思います。私はそれを新しい関数にしました:

jQuery.style(name, value, priority);

これを使用して、と.style('name')同じよう.css('name')に値を取得したり、CSSStyleDeclarationを使用して取得したり、値を設定したりすることができ.style()ます-優先度を「重要」として指定できます。参照してくださいこれを

デモ

var div = $('someDiv');
console.log(div.style('color'));
div.style('color', 'red');
console.log(div.style('color'));
div.style('color', 'blue', 'important');
console.log(div.style('color'));
console.log(div.style().getPropertyPriority('color'));

出力は次のとおりです。

null
red
blue
important

関数

(function($) {    
  if ($.fn.style) {
    return;
  }

  // Escape regex chars with \
  var escape = function(text) {
    return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
  };

  // For those who need them (< IE 9), add support for CSS functions
  var isStyleFuncSupported = !!CSSStyleDeclaration.prototype.getPropertyValue;
  if (!isStyleFuncSupported) {
    CSSStyleDeclaration.prototype.getPropertyValue = function(a) {
      return this.getAttribute(a);
    };
    CSSStyleDeclaration.prototype.setProperty = function(styleName, value, priority) {
      this.setAttribute(styleName, value);
      var priority = typeof priority != 'undefined' ? priority : '';
      if (priority != '') {
        // Add priority manually
        var rule = new RegExp(escape(styleName) + '\\s*:\\s*' + escape(value) +
            '(\\s*;)?', 'gmi');
        this.cssText =
            this.cssText.replace(rule, styleName + ': ' + value + ' !' + priority + ';');
      }
    };
    CSSStyleDeclaration.prototype.removeProperty = function(a) {
      return this.removeAttribute(a);
    };
    CSSStyleDeclaration.prototype.getPropertyPriority = function(styleName) {
      var rule = new RegExp(escape(styleName) + '\\s*:\\s*[^\\s]*\\s*!important(\\s*;)?',
          'gmi');
      return rule.test(this.cssText) ? 'important' : '';
    }
  }

  // The style function
  $.fn.style = function(styleName, value, priority) {
    // DOM node
    var node = this.get(0);
    // Ensure we have a DOM node
    if (typeof node == 'undefined') {
      return this;
    }
    // CSSStyleDeclaration
    var style = this.get(0).style;
    // Getter/Setter
    if (typeof styleName != 'undefined') {
      if (typeof value != 'undefined') {
        // Set style property
        priority = typeof priority != 'undefined' ? priority : '';
        style.setProperty(styleName, value, priority);
        return this;
      } else {
        // Get style property
        return style.getPropertyValue(styleName);
      }
    } else {
      // Get CSSStyleDeclaration
      return style;
    }
  };
})(jQuery);

CSS値を読み取って設定する方法の例については、こちらをご覧ください。私の問題は、私がすでに設定したことでした!important他のテーマCSSとの競合を避けるためにCSSの幅をし、jQueryで幅に加えた変更は、style属性に追加されるため、影響を受けません。

互換性

この記事では、setProperty関数を使用して優先度を設定するために、IE 9+およびその他のすべてのブラウザーがサポートされていると述べています。私はIE 8を試してみましたが失敗しました。そのため、関数でサポートしました(上記を参照)。それは、setPropertyを使用する他のすべてのブラウザーで動作しますが、IE 9未満で動作するには、カスタムコードが必要です。


他のブラウザでこれをテストしましたか?
mkoryak 2012年

2
数年前に公開されたjQuery.importantプラグインもあります。私はそれを本番
環境で

14
$( '.someclass').each(function(){this.style.setProperty( 'border'、 'none'、 'important');}); stackoverflow.com/questions/11962962/… シンプルでクリーンで効率的です。

3
これに対処する唯一の良い方法は、直接的なスタイル注入ではなく、クラスを使用することです。
リチャード

3
@Richard、これに対処するための唯一の良い方法はありません使用することに!important...少なくともあなたはjQueryを使って変更しようとしているもののために、あなたのスタイルである限り、彼らがそうであるように、あなたのスタイル。生徒がコード化したページ内でコードが実行され、!important2番目のスタイルごとに平準化して特定性のルールを知らない問題に対処する場合、!importants遅かれ早かれ最初にこれらの1つに突き当たります。
Septagram、2014年

149

次の.width()ようにして幅を直接設定できます:

$("#elem").width(100);

コメント用に更新: このオプションも使用できますが、要素のすべてのcssが置き換えられるため、これ以上実行可能かどうかはわかりません。

$('#elem').css('cssText', 'width: 100px !important');

わかりました。例として使用しましたが、重要なのは!importantの設定です。
mkoryak 2010

1
また、状況をよりよく反映するように質問を編集しました。基本的に、インラインで上書きする必要がある何か悪い値に設定された外部の重要な幅があります。width()がこの理由で機能しない
mkoryak

@mkoryak-他の唯一の非クラスオプションで更新されました。状況に合うかどうかは不明です。
Nick Craver

1
ただし、要素に直接適用される他のスタイルは上書きされます。stackoverflow.com/a/11723492/491044は、実装が最も簡単です。
trgraglia 2013年

10
$('#elem').css('cssText', $('#elem').css('cssText')+'width: 100px !important');以前の値と連結してオーバーライドを防止します
Abel Callejo '20

81
const elem = $("#elem");
elem[0].style.removeAttribute('width');
elem[0].style.setProperty('width', '100px', 'important');

注:Chromeを使用すると、次のようなエラーが返される場合があります。

elem [0] .style.removeAttributeは関数ではありません

問題.removePropertyelem[0].style.removeProperty('width');修正するなどの機能を使用するように行を変更しました。


10
これは最良の答えの1つです。シンプルで機能します。そして、それは多くの説明を必要としません。jQueryセレクターを除いて、これは通常のJavaScriptです。jQueryは「重要」のサポートを提供しないので、通常のJSを使用する方法です
OMA

2
バニラを使いたい場合var = document.getElementById('elem');は、elem [0]ではなく、elemでスタイルメソッドを作成して実行します。乾杯。
humbolight、

3
バニラJSでは、removeAttributeは機能しません。以下をせよ。 var style = document.getElementById('elem'); style.removeProperty('width'); style.setProperty('width, '100px', 'important')
mcoenca

2
にも問題がありました.removeAttribute。あるように思わIEのみの方法。@mcoencaコメントは正しいです。.removeProperty正常に動作します。MSDNに
FelipeAls

2
@Dejan、非常に遅く答えて申し訳ありませんが、これは動作するはずです:elem.next().get(0).style...
RedClover

54

David Thomasの回答は、の使用方法を説明していますが$('#elem').attr('style', …)、それを使用すると、style属性に以前に設定されたスタイルが削除されることを警告しています。attr()その問題なく使用する方法を次に示します。

var $elem = $('#elem');
$elem.attr('style', $elem.attr('style') + '; ' + 'width: 100px !important');

関数として:

function addStyleAttribute($element, styleAttribute) {
    $element.attr('style', $element.attr('style') + '; ' + styleAttribute);
}
addStyleAttribute($('#elem'), 'width: 100px !important');

こちらがJS Binのデモです。


2
addStyleAttribute()jQuery.css()と同じパラメーターを取るように変更することもできます。たとえば、CSSプロパティとその値のマップの取得をサポートできます。これを行うと、基本的に.css()!importantバグが修正された状態で再実装されますが、最適化は行われません。
Rory O'Kane

1
幅はCSSクラスで定義されており、ブラウザーウィンドウとコンテンツの幅に基づいて計算された値で動的にオーバーライドする必要があるため、これは私にとってはうまくいきました。
Chris Rasco、2014

30

他の答えを読んで実験した後、これは私にとってうまくいきます:

$(".selector")[0].style.setProperty( 'style', 'value', 'important' );

ただし、これはIE 8以下では機能しません。


1
そして、まだIE8をサポートする必要があるので(私たちの中には不運な人もいます)、これは良くありません。
mkoryak 2014

27

あなたはこれを行うことができます:

$("#elem").css("cssText", "width: 100px !important;");

プロパティ名として「cssText」を使用し、CSSに値として追加したいものを使用します。


5
これの欠点cssTextは、以前そこにあったものを上書きすることです。そのため、実際に自由に使用することはできません
mkoryak

1
とにかく、あなたは$( "#elem")。css( "cssText"、 "+ =; width:100px!important;");を使うことができます
lexa-b

18

これは、次の2つの方法で実現できます。

$("#elem").prop("style", "width: 100px !important"); // this is not supported in chrome
$("#elem").attr("style", "width: 100px !important");

実際、この.prop()関数はjQuery v1.6で追加され、Chromeで動作します...これはpropページから引用されています。jQuery1.6より前は、.attr()メソッドが一部の属性を取得するときにプロパティ値を考慮することがあり、これにより一貫性のない動作が発生する可能性がありました。jQuery 1.6以降、この.prop()メソッドは、.attr()属性を取得しながら、プロパティ値を明示的に取得する方法を提供します。
Mottie、2016年

1
一般的なソリューションとしてはあまり良い考えではありません。これを使用して、既存のスタイルをオーバーライドできます。
Nirav Zaveri 2017

14

@AramKocharyanの回答の複雑さを理解する必要も、スタイルタグを動的に挿入する必要もありません。

スタイルを上書きするだけですが、何も解析する必要はありません。なぜでしょうか。

// Accepts the hyphenated versions (i.e. not 'cssFloat')
function addStyle(element, property, value, important) {
    // Remove previously defined property
    if (element.style.setProperty)
        element.style.setProperty(property, '');
    else
        element.style.setAttribute(property, '');

    // Insert the new style with all the old rules
    element.setAttribute('style', element.style.cssText +
        property + ':' + value + ((important) ? ' !important' : '') + ';');
}

ChromeのルールがremoveProperty()削除されないため、を 使用できません!important。Firefoxではキャメルケースしか受け付け
ないためelement.style[property] = ''、は使用できません。

おそらくjQueryでこれを短くすることができますが、このバニラ関数は最新のブラウザー、Internet Explorer 8などで実行されます。


12

これがこの問題に遭遇した後に私がしたことです...

var origStyleContent = jQuery('#logo-example').attr('style');
jQuery('#logo-example').attr('style', origStyleContent + ';width:150px !important');

ありがとうございます。これは、カスタムプラグインよりもはるかに簡単に実装できます(他のインラインスタイルを破壊する可能性がある場合でも)。
Phrogz

9

このソリューションは、以前のスタイルをオーバーライドするのではなく、必要なスタイルを適用するだけです。

var heightStyle = "height: 500px !important";
if ($("foo").attr('style')) {
  $("foo").attr('style', heightStyle + $("foo").attr('style').replace(/^height: [-,!,0-9,a-z, A-Z, ]*;/,''));
else {
  $("foo").attr('style', heightStyle);
}

9

それがあまり関連性がなく、である1つの要素を扱っている#elemので、そのIDを別のものに変更して、希望どおりにスタイルを設定できます...

$('#elem').attr('id', 'cheaterId');

そしてあなたのCSSで:

#cheaterId { width: 100px;}

9
なぜCSSクラスを追加するのではなくCSSを適用するようにIDを変更するのですか?
TeKapa

8

css()関数を使用する代わりに、関数を試してくださいaddClass()

  <script>
  $(document).ready(function() {
    $("#example").addClass("exampleClass");
  });
  </script>

  <style>
  .exampleClass{
    width:100% !important;
    height:100% !important;
  }
  </style>

OPは、プロパティの値は動的に計算されるので、あなたの答えは彼には役に立たないと書いています。
Sebastian Zartner、2014年

この解決策は私にとってうまくいきました。私は元のポスターとして正確なニーズがあるとは思いませんが、css()が機能しない場合は機能します。
leekei 2014年

2
これは確かに問題に対する完全に合理的な解決策です...ただこの問題ではありません!
mkoryak 2014年

8

私からのこの問題の最も簡単で最良の解決策は、単に.css()または.attr()の代わりにaddClass()を使用することでした。

例えば:

$('#elem').addClass('importantClass');

そしてあなたのCSSファイルで:

.importantClass {
    width: 100px !important;
}

1
幅はJavaScriptで計算されるため、これは問題を解決しません。
Chris


7

これらの回答のほとんどは古くなっており、IE7のサポートは問題ではありません。

IE11 +とすべての最新のブラウザーサポートするこれを行う最善の方法は次のとおりです。

const $elem = $("#elem");
$elem[0].style.setProperty('width', '100px', 'important');

または、必要に応じて、これを行う小さなjQueryプラグインを作成できます。このプラグインcss()は、サポートするパラメーターがjQuery独自のメソッドと厳密に一致します。

/**
 * Sets a CSS style on the selected element(s) with !important priority.
 * This supports camelCased CSS style property names and calling with an object 
 * like the jQuery `css()` method. 
 * Unlike jQuery's css() this does NOT work as a getter.
 * 
 * @param {string|Object<string, string>} name
 * @param {string|undefined} value
 */   
jQuery.fn.cssImportant = function(name, value) {
  const $this = this;
  const applyStyles = (n, v) => {
    // Convert style name from camelCase to dashed-case.
    const dashedName = n.replace(/(.)([A-Z])(.)/g, (str, m1, upper, m2) => {
      return m1 + "-" + upper.toLowerCase() + m2;
    }); 
    // Loop over each element in the selector and set the styles.
    $this.each(function(){
      this.style.setProperty(dashedName, v, 'important');
    });
  };
  // If called with the first parameter that is an object,
  // Loop over the entries in the object and apply those styles. 
  if(jQuery.isPlainObject(name)){
    for(const [n, v] of Object.entries(name)){
       applyStyles(n, v);
    }
  } else {
    // Otherwise called with style name and value.
    applyStyles(name, value);
  }
  // This is required for making jQuery plugin calls chainable.
  return $this;
};
// Call the new plugin:
$('#elem').cssImportant('height', '100px');

// Call with an object and camelCased style names:
$('#another').cssImportant({backgroundColor: 'salmon', display: 'block'});

// Call on multiple items:
$('.item, #foo, #bar').cssImportant('color', 'red');

jsfiddleの例はこちら


1
これが答えです。他の回答を確認する必要はありません
Shwet

6

まず、以前のスタイルを削除する必要があります。正規表現で削除します。色を変更する例を次に示します。

var SetCssColorImportant = function (jDom, color) {
       var style = jDom.attr('style');
       style = style.replace(/color: .* !important;/g, '');
       jDom.css('cssText', 'color: ' + color + ' !important;' + style); }

3
cssTextメソッドが正常に機能するのに、非常に多くのソリューションがスタイルタグを要素にハッキングする理由がわかりません...例$selector.css('cssText','margin-bottom: 0 !important')
frumbert

6

頭にスタイルを追加する別の方法:

$('head').append('<style> #elm{width:150px !important} </style>');

これにより、すべてのCSSファイルの後にスタイルが追加されるため、他のCSSファイルよりも優先されて適用されます。


6

それはこのように見えるかもしれません:

キャッシュ

var node = $( '。selector')[0];
または
var node = document.querySelector( '。selector');

CSSを設定

node.style.setProperty( 'width'、 '100px'、 'important');

CSSを削除

node.style.removeProperty( 'width');
または
node.style.width = '';

6

私はそれがうまくいくと思い、以前に他のCSSを上書きすることができます(これ:DOM要素):

this.setAttribute('style', 'padding:2px !important');


5

このソリューションは、計算されたすべてのJavaScriptを残して、要素に重要なタグを追加します。

$('exampleDiv').css('width', '');
//This will remove the width of the item
var styles = $('exampleDiv').attr('style');
//This will contain all styles in your item
//ex: height:auto; display:block;
styles += 'width: 200px !important;'
//This will add the width to the previous styles
//ex: height:auto; display:block; width: 200px !important;
$('exampleDiv').attr('style', styles);
//This will add all previous styles to your item

4

3つの作業例

私も同じような状況でしたが、.closest()と長い間苦労した後、多くのバリエーションを伴って.find()を使用しました。

コード例

// Allows contain functions to work, ignores case sensitivity

jQuery.expr[':'].contains = function(obj, index, meta, stack) {
    result = false;
    theList = meta[3].split("','");
    var contents = (obj.textContent || obj.innerText || jQuery(obj).text() || '')
    for (x=0; x<theList.length; x++) {
        if (contents.toLowerCase().indexOf(theList[x].toLowerCase()) >= 0) {
            return true;
        }
    }
    return false;
};

$(document).ready(function() {
    var refreshId = setInterval( function() {
        $("#out:contains('foo', 'test456')").find(".inner").css('width', '50px', 'important');
    }, 1000); // Rescans every 1000 ms
});

オルタナティブ

$('.inner').each(function () {
    this.style.setProperty('height', '50px', 'important');
});

$('#out').find('.inner').css({ 'height': '50px'});

動作中:http : //jsfiddle.net/fx4mbp6c/


私はあなたに反対票を投じますが、.indexOf()機能をよりブラウザ互換性のあるものに置き換えることを選ぶべきです。代わりに、.match()または.test()代わりに.indexOf()
Alexander Dixon

なぜセミコロンがないのvar contents = ですか?
Peter Mortensen

3

状況に応じて適切な場合とそうでない場合がありますが、これらのタイプの多くの状況でCSSセレクターを使用できます。

たとえば、.cssTextの3番目と6番目のインスタンスに異なる幅を持たせたい場合は、次のように記述できます。

.cssText:nth-of-type(3), .cssText:nth-of-type(6) {width:100px !important;}

または:

.container:nth-of-type(3).cssText, .container:nth-of-type(6).cssText {width:100px !important;}

これは、の3番目と6番目のインスタンスと一致しませ.cssText:nth-of-type()あなたが思っていることをしません。説明はこちらをご覧ください。
BoltClock

けっこうだ。私はリンクを読みましたが、あなたのポイントを理解したかわかりません。これが意図したとおりに機能し
Tim Cut

2
フィドルでは、一連のli要素を扱っています。これらはすべて同じ要素タイプliであり、セレクターが扱います。同じ親で異なる要素を混合:nth-of-type()すると、動作が異なります。特に、クラスセレクターを混合に追加すると、動作が異なります。
BoltClock

3

追加せずに試したと思います!importantか?

インラインCSS(JavaScriptがスタイルを追加する方法)は、スタイルシートCSSをオーバーライドします。スタイルシートのCSSルールがそうであっても、それは事実だと確信してい!importantます。

別の質問(馬鹿げた質問かもしれませんが、尋ねる必要があります。):作業しようとしている要素はありますdisplay:block;display:inline-block;

CSSの専門知識がわからない...インライン要素が期待どおりに動作しない場合があります。


4
!importantを持つcssルールは、場所に関係なくすべてをオーバーライドします。例外として、!importantを含むインラインスタイルは!importantを含むスタイルシートスタイルをオーバーライドします。これは私が抱えている問題です。重要な!を指定したスタイルシートルールがあります。さらに、提供する必要がある値はJSを介して計算する必要があるため、スタイルシート自体を変更することはできません。
mkoryak 2010

3

setPropertyまたはcssTextを使用して、 !importantJavaScriptを使用して、 DOM要素ます。

例1:

elem.style.setProperty ("color", "green", "important");

例2:

elem.style.cssText='color: red !important;'

2

また、特定の要素または(Bootstrapなどの)アドオンには、などの特別なクラスケース!importantやのような他の回避策.addClass/.removeClassがあるため、オン/オフを切り替える必要があることも発見しました。

たとえば<table class="table-hover">、行の色などの要素を正常に変更する唯一の方法のようなものを使用する場合table-hover、このようにクラスをオン/オフに切り替えることです

$(your_element).closest("table").toggleClass("table-hover");

うまくいけば、この回避策は誰かに役立つでしょう!:)


2

「イベント」のときにメニュー項目のテキストの色を変更しようとすると、同じ問題が発生しました。これと同じ問題が発生したときに見つけた最良の方法は、次のとおりです。

最初のステップ:CSSで、この目的を持つ新しいクラスを作成します。次に例を示します。

.colorw{ color: white !important;}

最後のステップ:次のようにaddClassメソッドを使用してこのクラスを適用します。

$('.menu-item>a').addClass('colorw');

問題が解決しました。


1
私の意見では、ベストアンサーです。最も便利なもの。
2018年

おかげで@Siyah CSSは大量のpplで知られていますが、ごく一部しか理解されていません。これは悲しいことであり、一部のプログラマーは嫌いですlol
JoelBonetR

ただし、jsでCSS値を生成する場合は、たとえば、JSで定義されている色の値は必要ありません。それ以外の場合はこれがいいです。
カールパプワース

なぜjsで色を定義したいのですか?
JoelBonetR

2

これに対する最も安全な回避策は:-)クラスを追加して、CSSで魔法を行うことです、addClass()そしてremoveClass()作業を行う必要があります。


1

https://jsfiddle.net/xk6Ut/256/

別のアプローチは、JavaScriptでCSSクラスを動的に作成および更新することです。これを行うには、スタイル要素を使用でき、CSSクラスを更新できるようにスタイル要素のIDを使用する必要があります

function writeStyles(styleName, cssText) {
    var styleElement = document.getElementById(styleName);
    if (styleElement) document.getElementsByTagName('head')[0].removeChild(
        styleElement);
    styleElement = document.createElement('style');
    styleElement.type = 'text/css';
    styleElement.id = styleName;
    styleElement.innerHTML = cssText;
    document.getElementsByTagName('head')[0].appendChild(styleElement);
}

...

  var cssText = '.testDIV{ height:' + height + 'px !important; }';
  writeStyles('styles_js', cssText)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.