ক্রোমে পৃষ্ঠার লোডে পপস্টেট


94

আমি আমার ওয়েব অ্যাপ্লিকেশনটির জন্য ইতিহাস এপিআই ব্যবহার করছি এবং একটি সমস্যা আছে। পৃষ্ঠাটিতে পুনরায় লোড ছাড়াই ব্রাউজারের অবস্থান বার আপডেট করার জন্য আমি পৃষ্ঠায় কিছু ফলাফল আপডেট করতে এবং ইতিহাস.pushState () ব্যবহার করতে আজাক্স কল করি । তারপরে অবশ্যই ব্যাক-বোতামটি ক্লিক করার পরে আমি পূর্বের অবস্থাটি পুনরুদ্ধার করতে উইন্ডো.পপস্টেট ব্যবহার করি ।

সমস্যাটি সুপরিচিত - ক্রোম এবং ফায়ারফক্স সেই পপস্টেট ইভেন্টটিকে অন্যরকম আচরণ করে। যদিও ফায়ারফক্স প্রথম লোডে এটি জ্বালিয়ে দেয় না, ক্রোম করে। আমি ফায়ারফক্স-স্টাইলটি রাখতে চাই এবং ইভেন্টটিকে লোডে না ছড়িয়ে দিতে পারি কারণ এটি ঠিক একই লোডের সাথে ফলাফলগুলি আপডেট করে। হিস্টরি.জে ব্যবহার না করে কি কোনও কার্যকারিতা রয়েছে ? আমি এটি ব্যবহার করার মতো বোধ করি না কারণ - এটি নিজে থেকেই অনেক বেশি জেএস লাইব্রেরি প্রয়োজন এবং যেহেতু আমার এটি ইতিমধ্যে খুব বেশি জেএস সহ কোনও সিএমএসে প্রয়োগ করা প্রয়োজন, আমি এতে জেএসকে কমিয়ে আনতে চাই ।

সুতরাং, ক্রোম লোড-এ 'পপস্টেট' না জ্বালানোর উপায় আছে কিনা তা জানতে চাই বা সম্ভবত, কোনও লাইব্রেরি একত্রে ফাইলে একসাথে ইতিহাস.js ব্যবহার করার চেষ্টা করেছিল।


4
যোগ করার জন্য, ফায়ারফক্সের আচরণটি নির্দিষ্ট এবং সঠিক আচরণ। ক্রোম 34 হিসাবে, এখন এটি স্থির! ওপেরা দেবদের জন্য ইয়ে!
হেনরি

উত্তর:


49

গুগল ক্রোমে 19 সংস্করণে @ স্প্লিটারের সমাধান কাজ করা বন্ধ করে দিয়েছে। @ জোহনিমায়ার যেমন উল্লেখ করেছেন, ক্রোম ১৯-এ ইতিহাসের ইতিহাস উপস্থিত রয়েছে, তবে এটি বাতিল।

আমার কাজটি হ'ল উইন্ডো হিস্ট্রি.স্টেট যুক্ত করা! == উইন্ডো হিস্টোরিতে রাষ্ট্রের উপস্থিতি আছে কিনা তা পরীক্ষা করে দেখার জন্য নালালি:

var popped = ('state' in window.history && window.history.state !== null), initialURL = location.href;

আমি এটি সমস্ত বড় ব্রাউজারগুলিতে এবং ক্রোম সংস্করণ 19 এবং 18 তে পরীক্ষা করেছি It দেখে মনে হচ্ছে এটি কাজ করে।


5
সতর্ক থাকুন জন্য ধন্যবাদ; আমি মনে করি আপনি সহজ করতে পারেন inএবং nullচেক করতে পারেন != nullযেহেতু এটি undefinedপাশাপাশি যত্ন নেবে ।
pimvdb

5
আপনি যদি সর্বদা nullআপনার history.pushState()পদ্ধতিতে ব্যবহার করেন তবে এটি ব্যবহার করা কার্যকর হবে history.pushState(null,null,'http//example.com/)। মঞ্জুর, এটি সম্ভবত বেশিরভাগ ব্যবহার হবে (এটি এটি jquery.pjax.js এবং অন্যান্য ডেমোতে সেট আপ করা হয়)। কিন্তু ব্রাউজার কার্যকরী যদি window.history.state(হ এবং Chrome 19+ মতো) window.history.state একটি ব্রাউজার রিস্টার্ট একটি রিফ্রেশ বা পরে অ নাল হতে পারে
unexplainedBacn

19
এটি ক্রোম 21-এ আমার জন্য আর কাজ করছে না I আমি কেবলমাত্র পৃষ্ঠা লোডে মিথ্যাতে পপড সেট করে এবং তারপরে কোনও ধাক্কা বা পপসে সত্যায় পপড সেট করে আছি। এই লোকেদের প্রথম ক্রমের ক্রোমের পপ। এটি এখানে আরও ভালভাবে ব্যাখ্যা করা হয়েছে: github.com/defunkt/jquery-pjax/issues/143#issuecomment-6194330
চাদ ভন নউ

4
@ চ্যাডভননউ দুর্দান্ত ধারণা, এবং এটি একটি ট্রিট কাজ করে - ধন্যবাদ অনেক ধন্যবাদ!
sowasred2012

আমি এই একই সমস্যাটি নিয়ে এসেছি এবং সহজ @ চাদভননউ সমাধানটি ব্যবহার করে শেষ করেছি।
ফেরিমাসন

30

আপনি অনপপস্টেটে যে প্রতিটি হ্যান্ডলারের সাথে বিশেষ যোগ করতে চান না সে ক্ষেত্রে, আমার সমাধানটি আপনার জন্য আকর্ষণীয় হতে পারে। এই সমাধানের একটি বড় প্লাসটি হ'ল পৃষ্ঠা লোডিং শেষ হওয়ার আগে অনপপস্টেট ইভেন্টগুলি পরিচালনা করা যায়।

কোনও অনপপস্টেট হ্যান্ডলার যুক্ত করার আগে একবার এই কোডটি চালান এবং প্রত্যাশার সাথে সবকিছু কাজ করা উচিত (ওরফে মজিলা like এর মতো)

(function() {
    // There's nothing to do for older browsers ;)
    if (!window.addEventListener)
        return;
    var blockPopstateEvent = document.readyState!="complete";
    window.addEventListener("load", function() {
        // The timeout ensures that popstate-events will be unblocked right
        // after the load event occured, but not in the same event-loop cycle.
        setTimeout(function(){ blockPopstateEvent = false; }, 0);
    }, false);
    window.addEventListener("popstate", function(evt) {
        if (blockPopstateEvent && document.readyState=="complete") {
            evt.preventDefault();
            evt.stopImmediatePropagation();
        }
    }, false);
})();

কিভাবে এটা কাজ করে:

ডকুমেন্টটি লোড হয়ে গেলে ক্রোম , সাফারি এবং সম্ভবত অন্যান্য ওয়েবকিট ব্রাউজারগুলি অনপপস্টেট ইভেন্টে আগুন জ্বালিয়ে দেয়। এটি উদ্দেশ্যযুক্ত নয়, সুতরাং ডকুমেন্টটি লোড হওয়ার পরে প্রথম ইভেন্টের লুপ কিকাল না হওয়া পর্যন্ত আমরা পপস্টেট ইভেন্টগুলি অবরুদ্ধ করি। এটি প্রতিরোধ-ডিফল্ট এবং স্টপআইমিডিয়েট্রোপেজেশন কলগুলি দ্বারা করা হয় (স্টপপ্রোপেশন স্টপের বিপরীতেআইমিডিয়েটপ্রপাগেশন সমস্ত ইভেন্ট হ্যান্ডলার কল তাত্ক্ষণিকভাবে থামিয়ে দেয়)।

তবে, যেহেতু দস্তাবেজের রেডিস্ট্যাটটি ইতিমধ্যে "সম্পূর্ণ" রয়েছে যখন ক্রম অনপপস্টেটকে ভুল করে ফায়ার করে, আমরা ডকুমেন্টটি লোড হওয়ার আগে অনপপস্টেট কল করার আগে ডকুমেন্ট লোডিং শেষ হওয়ার আগেই অপোপস্টেট ইভেন্টগুলি বরখাস্ত করা হয়।

আপডেট 2014-04-23: পৃষ্ঠাটি লোড হওয়ার পরে স্ক্রিপ্টটি কার্যকর করা হলে পপস্টেট ইভেন্টগুলি ব্লক করা হয়েছে এমন একটি বাগ স্থির করে।


4
আমার পক্ষে এখন পর্যন্ত সেরা সমাধান। আমি বছরের পর বছর ধরে সেটটাইমআউট পদ্ধতিটি ব্যবহার করে আসছি তবে পৃষ্ঠা ধীরে ধীরে লোড হচ্ছে / যখন ব্যবহারকারী খুব দ্রুত পুশস্টেট ট্রিগার করে তখন এটি বাগি আচরণের কারণ হয়। window.history.stateকোনও রাষ্ট্র সেট করা থাকলে পুনরায় লোডে ব্যর্থ হয়। পুশস্টেট ক্লটার্স কোডের আগে পরিবর্তনশীল সেট করা। আপনার সমাধানটি মার্জিত এবং বাকী কোডবেসকে প্রভাবিত না করেই অন্যান্য স্ক্রিপ্টগুলির উপরে ফেলে দেওয়া যেতে পারে। ধন্যবাদ
কিক

4
এটাই সমাধান! এই সমস্যাটি সমাধান করার চেষ্টা করার সময় আমি যদি কেবল এটি পড়তে পারি days এই একমাত্র নির্দোষভাবে কাজ করেছেন। ধন্যবাদ!
বেন ফ্লেমিং

4
দুর্দান্ত ব্যাখ্যা এবং চেষ্টা করার একমাত্র সমাধান।
সানি আর গুপ্ত

এটি একটি দুর্দান্ত সমাধান। লেখার সময়, সর্বশেষ ক্রোম এবং এফএফ সূক্ষ্ম, ইস্যুটি সাফারি (ম্যাক এবং আইফোন) এর সাথে রয়েছে। এই সমাধান একটি কবজ মত কাজ করে।
ভিন

4
পাছা! যদি সাফারি আপনার দিনটিকে নষ্ট করে দিচ্ছে, তবে আপনি যে কোডগুলি সন্ধান করছেন তা এগুলি!
ড্যানো

28

সেটটাইমআউট ব্যবহার করা কেবলমাত্র সঠিক সমাধান নয় কারণ আপনার কোনও ধারণা নেই যে সামগ্রীটি লোড হতে কত সময় লাগবে তাই পপস্টেট ইভেন্টের সময়সীমা শেষ হওয়ার পরে এটি সম্ভব।

এখানে আমার সমাধান: https://gist.github.com/3551566

/*
* Necessary hack because WebKit fires a popstate event on document load
* https://code.google.com/p/chromium/issues/detail?id=63040
* https://bugs.webkit.org/process_bug.cgi
*/
window.addEventListener('load', function() {
  setTimeout(function() {
    window.addEventListener('popstate', function() {
      ...
    });
  }, 0);
});

এটি আমার জন্য কাজ করা একমাত্র সমাধান। ধন্যবাদ!
জাস্টিন

4
মিষ্টি! সর্বাধিক উত্সাহিত এবং / বা গৃহীত উত্তরের চেয়ে আরও ভাল কাজ করে!
সমস্যাগুলি

কারও কি এই সমাধানটির সক্রিয় লিঙ্ক রয়েছে, আমি প্রদত্ত লিঙ্কটি পৌঁছতে পারছি না gist.github.com/3551566
হারবীর

4
তোমার सारটা কেন দরকার?
ওলেগ ভাস্কেভিচ

নিখুঁত উত্তর. ধন্যবাদ
সিডোরক্সাইলন

25

সমাধান jquery.pjax.js লাইনে 195-225 পাওয়া গেছে :

// Used to detect initial (useless) popstate.
// If history.state exists, assume browser isn't going to fire initial popstate.
var popped = ('state' in window.history), initialURL = location.href


// popstate handler takes care of the back and forward buttons
//
// You probably shouldn't use pjax on pages with other pushState
// stuff yet.
$(window).bind('popstate', function(event){
  // Ignore inital popstate that some browsers fire on page load
  var initialPop = !popped && location.href == initialURL
  popped = true
  if ( initialPop ) return

  var state = event.state

  if ( state && state.pjax ) {
    var container = state.pjax
    if ( $(container+'').length )
      $.pjax({
        url: state.url || location.href,
        fragment: state.fragment,
        container: container,
        push: false,
        timeout: state.timeout
      })
    else
      window.location = location.href
  }
})

8
এই সমাধানটি উইন্ডোজ (ক্রোম 19) এ এখনও ম্যাক (ক্রোম 18) এ কাজ করে আমার জন্য কাজ করা বন্ধ করে দিয়েছে working মনে হয় history.state, Chrome 19 বিদ্যমান কিন্তু 18
johnnymire

4
: @johnnymire আমি, Chrome 19 নিম্ন আমার সমাধান পোস্ট stackoverflow.com/a/10651028/291500
পাভেল Linkesch

এই পোস্ট ক্রোম 19 আচরণ প্রতিফলিত করার জন্য কারও এই উত্তরটি সম্পাদনা করা উচিত।
জর্গে সুরেজ ডি লিস

5
যে কোনও সমাধানের সন্ধানের জন্য, টরবেনের উত্তর বর্তমান ক্রোম এবং ফায়ারফক্সের সংস্করণগুলিতে আজকের মতো মনোযোগের মতো কাজ করে
জর্জি সুরেজ ডি লিস

4
এখন 2015 এপ্রিলে, আমি সাফারির সাথে কোনও সমস্যা সমাধানের জন্য এই সমাধানটি ব্যবহার করেছি। কর্ডোভা ব্যবহার করে হাইব্রিড আইওএস / অ্যান্ড্রয়েড অ্যাপ্লিকেশনটিতে ব্যাক বোতাম টিপুন একটি হ্যান্ডলিং অর্জন করতে আমাকে অনপপস্টেট ইভেন্টটি ব্যবহার করতে হয়েছিল। সাফারি পুনরায় লোড হওয়ার পরেও তার অনপপস্টেটটিকে গুলি করে, যা আমি প্রোগ্রামিকভাবে বলেছি। আমার কোডটি সেটআপ করার সাথে সাথে পুনরায় লোড () কল করার পরে এটি একটি অসীম লুপে চলে গেল। এটি এটি স্থির করে। ইভেন্টের ঘোষণার পরে আমার কেবল প্রথম 3 টি লাইন দরকার ছিল (শীর্ষে অ্যাসাইনমেন্টগুলি)।
মার্টাভিস পি।

14

রিজিমুলেশনিং পাইজ্যাক্সের চেয়ে আরও সরাসরি সমাধানটি পুশস্টেটে একটি পরিবর্তনশীল সেট করা হয় এবং পপস্টেটে ভেরিয়েবলটি পরীক্ষা করে দেখানো হয়, তাই প্রাথমিক পপস্টেটটি ভারসাম্যহীনভাবে লোড জ্বালিয়ে দেয় না (কেবল ইভেন্টের জন্য এটি ব্যবহার করে জ্যাকারি-নির্দিষ্ট সমাধান নয়):

$(window).bind('popstate', function (ev){
  if (!window.history.ready && !ev.originalEvent.state)
    return; // workaround for popstate on load
});

// ... later ...

function doNavigation(nextPageId) {
  window.history.ready = true;

  history.pushState(state, null, 'content.php?id='+ nextPageId); 
  // ajax in content instead of loading server-side
}

সবসময় যদি মিথ্যা হিসাবে মূল্যায়ন হয় না? আমি বলতে চাইতেছি,window.history.ready সর্বদা সত্য।
অ্যান্ড্রি দ্রোজডিয়ুক 30'12

আরও কিছুটা পরিষ্কার হওয়ার জন্য উদাহরণটি আপডেট করুন। মূলত, একবার আপনি সমস্ত পরিষ্কার করে দেওয়ার পরে আপনি কেবল পপস্টেট ইভেন্টগুলি পরিচালনা করতে চান। আপনি লোডের পরে সেটটাইমআউট 500 মিমি দিয়ে একই প্রভাব অর্জন করতে পেরেছিলেন তবে সত্য বলতে গেলে এটি কিছুটা সস্তা।
টম ম্যাকেনজি

4
এটি উত্তর আইএমও হওয়া উচিত, আমি পাভেলস সমাধানটি চেষ্টা করেছিলাম এবং এটি ফায়ারফক্সে সঠিকভাবে কাজ করে না
পোরকো

এটি আমার জন্য এই বিরক্তিকর সমস্যার সহজ সমাধান হিসাবে কাজ করেছিল। অনেক ধন্যবাদ!
নিরাজুল

!window.history.ready && !ev.originalEvent.state- পৃষ্ঠাটি রিফ্রেশ করার সময় এই দুটি জিনিস কখনই সংজ্ঞায়িত হয় না । সুতরাং কোনও কোড কার্যকর করে না।
chovy

4

ওয়েবকিটের প্রাথমিক অনপপস্টেট ইভেন্টের কোনও রাজ্য বরাদ্দ নেই, তাই আপনি এটি অযাচিত আচরণের জন্য যাচাই করতে পারেন:

window.onpopstate = function(e){
    if(e.state)
        //do something
};

মূল পৃষ্ঠায় ফিরে নেভিগেশনকে মঞ্জুরি দেওয়ার জন্য একটি বিস্তৃত সমাধান এই ধারণাটি তৈরি করবে:

<body onload="init()">
    <a href="page1" onclick="doClick(this); return false;">page 1</a>
    <a href="page2" onclick="doClick(this); return false;">page 2</a>
    <div id="content"></div>
</body>

<script>
function init(){
   openURL(window.location.href);
}
function doClick(e){
    if(window.history.pushState)
        openURL(e.getAttribute('href'), true);
    else
        window.open(e.getAttribute('href'), '_self');
}
function openURL(href, push){
    document.getElementById('content').innerHTML = href + ': ' + (push ? 'user' : 'browser'); 
    if(window.history.pushState){
        if(push)
            window.history.pushState({href: href}, 'your page title', href);
        else
            window.history.replaceState({href: href}, 'your page title', href);
    }
}
window.onpopstate = function(e){
    if(e.state)
        openURL(e.state.href);
};
</script>

যদিও এটি এখনও দু'বার জ্বলতে পারে (কিছু নিফটি নেভিগেশন সহ) তবে এটি পূর্ববর্তী href এর বিরুদ্ধে চেক করে কেবল পরিচালনা করা যেতে পারে।


4
ধন্যবাদ Pjax সমাধান আইওএস 5.0 কাজ কারণ বন্ধ window.history.stateএছাড়াও iOS এ নাল হয়। ইস্টেস্টেট সম্পত্তি নাল কিনা তা পরীক্ষা করেই যথেষ্ট।
হুস্কি

এই সমাধানের সাথে কোনও জ্ঞাত সমস্যা আছে? এটি আমি পরীক্ষিত যে কোনও ব্রাউজারে পুরোপুরি কাজ করে।
জ্যাকব এউইং

3

এটি আমার কাজ

window.setTimeout(function() {
  window.addEventListener('popstate', function() {
    // ...
  });
}, 1000);

উবুন্টুতে ক্রোমিয়াম 28-এ আমার জন্য নয়। কখনও কখনও, ইভেন্ট এখনও বহিস্কার করা হয়।
জর্গে সুরেজ ডি লিস

এটি নিজে চেষ্টা করেছি, সবসময় কাজ করে না। কখনও কখনও পপস্টেটটি প্রাথমিক পৃষ্ঠা লোডের উপর নির্ভর করে টাইমআউটের পরে আগুন লাগে
অ্যান্ড্রু

1

এখানে আমার সমাধান:

var _firstload = true;
$(function(){
    window.onpopstate = function(event){
        var state = event.state;

        if(_firstload && !state){ 
            _firstload = false; 
        }
        else if(state){
            _firstload = false;
            // you should pass state.some_data to another function here
            alert('state was changed! back/forward button was pressed!');
        }
        else{
            _firstload = false;
            // you should inform some function that the original state returned
            alert('you returned back to the original state (the home state)');
        }
    }
})   

0

কোনও পৃষ্ঠা লোডে ক্রপ পপস্টেটে না ফেলার সর্বোত্তম উপায় হল https://code.google.com/p/chromium/issues/detail?id=63040 । তারা জেনে গেছে যে ক্রোম এখন পুরো দুটি বছর ধরে এইচটিএমএল 5 টি অনুপস্থিতিতে অনুসরণ করে না এবং এখনও এটি ঠিক করে নি!


4
এটি ক্রোম 34
matys84pl

0

ব্যবহারের ক্ষেত্রে event.state !== nullইতিহাসে প্রথম ফিরে আসা পৃষ্ঠাতে ফিরে আসা অ মোবাইল ব্রাউজারগুলিতে কাজ করবে না। আমি যখন এজ্যাক্স নেভিগেশন সত্যিই শুরু হয় তখন চিহ্নিত করতে আমি সেশনস্টোরেজ ব্যবহার করি।

history.pushState(url, null, url);
sessionStorage.ajNavStarted = true;

window.addEventListener('popstate', function(e) {
    if (sessionStorage.ajNavStarted) {
        location.href = (e.state === null) ? location.href : e.state;
    }
}, false);


উইন্ডো.অনলোড = ফাংশন () {যদি (ইতিহাস.স্টেট === নাল) {ইতিহাস.রেপসস্টেট (অবস্থান.পথনাম + অবস্থান.সন্ধান + অবস্থান.হ্যাশ, নাল, অবস্থান.পথনাম + অবস্থান.সন্ধান + অবস্থান.হ্যাশ); }}; window.addEventListener ('popstate', ফাংশন (e) {যদি (e.state! == নাল) {location.href = e.state;}}, মিথ্যা);
ইলিউশনবাদী

-1

উপস্থাপিত সমাধানগুলিতে পৃষ্ঠা পুনরায় লোড করার ক্ষেত্রে একটি সমস্যা রয়েছে। নিম্নলিখিতটি আরও ভাল কাজ করছে বলে মনে হচ্ছে, তবে আমি কেবল ফায়ারফক্স এবং ক্রোম পরীক্ষা করেছি। এটি বাস্তবতা ব্যবহার করে, মনে হয় যে e.event.stateএবং এর মধ্যে পার্থক্য রয়েছে window.history.state

window.addEvent('popstate', function(e) {
    if(e.event.state) {
        window.location.reload(); // Event code
    }
});

e.eventundefined হয়
chovy

-1

আমি জানি আপনি এর বিপরীতে জিজ্ঞাসা করেছেন, তবে এটি মিলিয়ন ব্রাউজারের অসম্পূর্ণতাগুলি পরিষ্কার করার সাথে সাথে আপনার কেবল ইতিহাস.js ব্যবহার করা উচিত। আমি ম্যানুয়াল ফিক্স রুটটি কেবল পরে গিয়েছিলাম আরও অনেক বেশি সমস্যা ছিল যা আপনি কেবল রাস্তায় নামার পথটি খুঁজে পাবেন। আজকাল এটি আসলেই এতটা কঠিন নয়:

<script src="//cdnjs.cloudflare.com/ajax/libs/history.js/1.8/native.history.min.js" type="text/javascript"></script>

এবং এপিআইটি https://github.com/browserstate/history.js এ পড়ুন


-1

এটি আমার জন্য সমস্যার সমাধান। আমি সমস্তই একটি টাইমআউট ফাংশন সেট করেছিলাম যা ফাংশনটি কার্যকর করতে বিলম্ব করে যা পপলোডের ইভেন্টটি পেজলোডে ছড়িয়ে দেওয়া মিস করতে পারে

if (history && history.pushState) {
  setTimeout(function(){
    $(window).bind("popstate", function() {
      $.getScript(location.href);
    });
  },3000);
}

-2

আপনি কোনও ইভেন্ট তৈরি করতে পারেন এবং এটি আপনার লোড হ্যান্ডলারের পরে ফায়ার করতে পারেন।

var evt = document.createEvent("PopStateEvent");
evt.initPopStateEvent("popstate", false, false, { .. state object  ..});
window.dispatchEvent(evt);

দ্রষ্টব্য, এটি ক্রোম / সাফারিতে কিছুটা ভাঙা হয়েছে তবে আমি প্যাচটি ওয়েবকিটে জমা দিয়েছি এবং এটি শীঘ্রই পাওয়া উচিত, তবে এটি "সবচেয়ে সঠিক" উপায়।


-2

এটি আমার জন্য ফায়ারফক্স এবং ক্রোমে কাজ করেছে

window.onpopstate = function(event) { //back button click
    console.log("onpopstate");
    if (event.state) {
        window.location.reload();
    }
};
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.