প্রথম বন্ধনী ছাড়াই একটি ফাংশন চালানো


275

আমাকে আজ বলা হয়েছিল যে প্রথম বন্ধনী ছাড়াই কোনও ফাংশন শুরু করা সম্ভব। শুধুমাত্র উপায়ে কথা আমার মনে পড়েছে মতো কাজগুলির ব্যবহার করছিলেন applyবা call

f.apply(this);
f.call(this);

তবে এগুলির জন্য প্রথম বন্ধনে আবদ্ধ হওয়া applyএবং callআমাদের ছেড়ে যাওয়া দরকার। আমি ইভেন্ট হ্যান্ডলারের কোনও ধরণের কাছে ফাংশনটি পাস করার ধারণাটিও বিবেচনা করেছি setTimeout:

setTimeout(f, 500);

কিন্তু তারপরে প্রশ্নটি হয়ে যায় "আপনি প্রথম setTimeoutবন্ধনী ছাড়া কীভাবে প্রার্থনা করবেন ?"

তাহলে এই ধাঁধার সমাধান কী? বন্ধনী ব্যবহার না করে আপনি কীভাবে জাভাস্ক্রিপ্টে কোনও ফাংশন শুরু করতে পারেন?


59
অভদ্র হওয়ার চেষ্টা করছি না, তবে আমাকে অবশ্যই জিজ্ঞাসা করতে হবে: কেন?
jehna1

36
@ jehna1 কারণ আমি কীভাবে ফাংশনগুলি চাওয়া হয় এবং কীভাবে সংশোধন করা হয়েছিল সে সম্পর্কে একটি প্রশ্নের উত্তর দিচ্ছিলাম যখন আমি বলেছিলাম যে তাদের শেষদিকে বন্ধনী প্রয়োজন required
মাইক ক্লক

3
অ্যামেজিং! এই প্রশ্নের এতটা আকর্ষণ থাকবে বলে আমি ভাবিনি .. সম্ভবত আমার নিজেই এটি জিজ্ঞাসা করা উচিত ছিল :-)
অমিত

5
এটি আমার মনকে ভেঙে দেওয়ার মতো প্রশ্ন। এই ধরনের অপব্যবহার এবং শোষণের মাধ্যমে সম্ভবত আর কী ভাল আসতে পারে? আমি এমন একটি বৈধ ব্যবহারের মামলাটি জানতে চাই যেখানে <insert any solution>উদ্দেশ্যগতভাবে আরও ভাল বা এর চেয়ে বেশি কার্যকর f()
আপনাকে ধন্যবাদ

5
অ্যারোন: আপনি বলছেন যে এর কোনও বৈধ কারণ নেই, তবে আলেকজান্ডার ওমারার উত্তরটি উল্লেখ করার সাথে সাথে কেউ এই প্রশ্নটি বিবেচনা করছেন যে কোড কার্যকর করা রোধ করতে ব্র্যাকেট অপসারণ যথেষ্ট কিনা - বা একটি অস্পষ্ট জাভাস্ক্রিপ্ট প্রতিযোগিতা সম্পর্কে কী? রক্ষণাবেক্ষণযোগ্য কোডটি লেখার চেষ্টা করার সময় অবশ্যই এটি একটি অযৌক্তিক উদ্দেশ্য, তবে এটি একটি মজাদার কুইজেশন।
পিজেট্রাইল

উত্তর:


429

বন্ধনী ছাড়াই একটি ফাংশন কল করার বিভিন্ন উপায় রয়েছে।

ধরে নেওয়া যাক আপনার এই ফাংশনটি সংজ্ঞায়িত হয়েছে:

function greet() {
    console.log('hello');
}

তারপরে এখানে প্রথম greetবন্ধনী ছাড়াই কল করার কিছু উপায় অনুসরণ করুন :

1. কনস্ট্রাক্টর হিসাবে

newআপনি প্রথম বন্ধনী ছাড়াই একটি ফাংশন শুরু করতে পারেন:

new greet; // parentheses are optional in this construct.

অপারেটরটিতে এমডিএনnew থেকে :

বাক্য গঠন

new constructor[([arguments])]

2. হিসাবে toStringবা valueOfবাস্তবায়ন

toStringএবং valueOfবিশেষ পদ্ধতি: কোনও রূপান্তর প্রয়োজন হলে এগুলি স্পষ্টভাবে কল হয়:

var obj = {
    toString: function() {
         return 'hello';
    }
}

'' + obj; // concatenation forces cast to string and call to toString.

greetবন্ধনী ছাড়াই কল করতে আপনি (আব) এই প্যাটার্নটি ব্যবহার করতে পারেন :

'' + { toString: greet };

বা সাথে valueOf:

+{ valueOf: greet };

valueOfএবং toStringপ্রকৃতপক্ষে @@ টু প্রিমিটিভ পদ্ধতি থেকে (ES6) থেকে ডেকে আনা হয় এবং আপনি সেই পদ্ধতিটি প্রয়োগ করতে পারেন :

+{ [Symbol.toPrimitive]: greet }
"" + { [Symbol.toPrimitive]: greet }

2. বি valueOfফাংশন প্রোটোটাইপ ওভাররাইডিং

প্রোটোটাইপটিতেvalueOf পদ্ধতিটি ওভাররাইড করার জন্য আপনি পূর্ববর্তী ধারণাটি নিতে পারেন :Function

Function.prototype.valueOf = function() {
    this.call(this);
    // Optional improvement: avoid `NaN` issues when used in expressions.
    return 0; 
};

এটি করা হয়ে গেলে আপনি লিখতে পারেন:

+greet;

এবং যদিও এই লাইনের সাথে বন্ধনী রয়েছে তবে প্রকৃত ট্রিগার অনুরোধটির কোনও বন্ধনী নেই। "জাভাস্ক্রিপ্টে কলিংয়ের পদ্ধতিগুলি, আসলে তাদের কল না করে" ব্লগে এই সম্পর্কে আরও দেখুন

3. জেনারেটর হিসাবে

আপনি একটি জেনারেটর ফাংশন (সহ *) সংজ্ঞায়িত করতে পারেন , যা কোনও পুনরুক্তকারীকে ফেরত দেয় । আপনি এটিকে স্প্রেড সিনট্যাক্স ব্যবহার করে বা সিনট্যাক্সের সাহায্যে কল করতে পারেন for...of

প্রথমে আমাদের মূল greetফাংশনের জেনারেটর বৈকল্পিক প্রয়োজন :

function* greet_gen() {
    console.log('hello');
}

এবং তারপরে আমরা এড্রেটরিটিস ছাড়াই এটিকে @@ পুনরুক্তি পদ্ধতিটি সংজ্ঞায়িত করে কল করি :

[...{ [Symbol.iterator]: greet_gen }];

সাধারণত জেনারেটরের yieldকোথাও একটি কীওয়ার্ড থাকে তবে ফাংশনটি কল করার জন্য এটির প্রয়োজন হয় না।

শেষ বিবৃতিটি ফাংশনটির জন্য অনুরোধ করে, তবে এটি ধ্বংসাত্মকতার সাথেও করা যেতে পারে :

[,] = { [Symbol.iterator]: greet_gen };

বা একটি for ... ofনির্মাণ, কিন্তু এটির নিজস্ব বন্ধনী রয়েছে:

for ({} of { [Symbol.iterator]: greet_gen });

নোট আপনি যে পারেন মূল সঙ্গে উপরে না greetপাশাপাশি ফাংশন, কিন্তু এটি প্রক্রিয়ায় একটি ব্যতিক্রম আরম্ভ হবে, পরে greet মৃত্যুদন্ড কার্যকর এটি (এফএফ এবং ক্রোমে পরীক্ষিত)। আপনি একটি try...catchব্লক দিয়ে ব্যতিক্রম পরিচালনা করতে পারেন ।

4. প্রাপ্তি হিসাবে

@ jehna1 এর এ সম্পর্কে পুরো উত্তর রয়েছে, তাই তাকে ক্রেডিট দিন। অবহেলিত পদ্ধতিটি এড়িয়ে বিশ্বব্যাপী সুযোগে কোনও ফাংশন বন্ধন-কমকে কল করার একটি উপায় এখানে । এটি পরিবর্তে ব্যবহার করে।__defineGetter__Object.defineProperty

এর জন্য আমাদের মূল greetফাংশনের একটি বৈকল্পিক তৈরি করতে হবে :

Object.defineProperty(window, 'greet_get', { get: greet });

এবং তারপর:

greet_get;

windowআপনার গ্লোবাল অবজেক্ট যাই হোক না কেন এটি প্রতিস্থাপন করুন ।

আপনি greetগ্লোবাল অবজেক্টের উপর কোনও চিহ্ন রেখেই মূল ফাংশনটি কল করতে পারেন:

Object.defineProperty({}, 'greet', { get: greet }).greet;

তবে কেউ যুক্তি দিতে পারে যে এখানে আমাদের প্রথম বন্ধনী রয়েছে (যদিও তারা প্রকৃত প্রার্থনায় জড়িত নয়)।

5. ট্যাগ ফাংশন হিসাবে

যেহেতু ES6 আপনি কোনও ফাংশনটিকে কল করতে পারেন যা এই সিনট্যাক্সের সাহায্যে একটি টেম্পলেটটি আক্ষরিক অর্থে :

greet``;

দেখুন "বাঁধা টেমপ্লেট লিটারেল"

6. প্রক্সি হ্যান্ডলার হিসাবে

ES6 সাল থেকে আপনি একটি প্রক্সি সংজ্ঞায়িত করতে পারেন :

var proxy = new Proxy({}, { get: greet } );

এবং তারপরে কোনও সম্পত্তি মান পড়তে অনুরোধ জানাবে greet:

proxy._; // even if property not defined, it still triggers greet

এর বিভিন্ন প্রকরণ রয়েছে। আরও একটি উদাহরণ:

var proxy = new Proxy({}, { has: greet } );

1 in proxy; // triggers greet

7. উদাহরণস্বরূপ পরীক্ষক হিসাবে

instanceofঅপারেটর executes @@hasInstanceযখন সংজ্ঞায়িত দ্বিতীয় প্রতীক, উপর পদ্ধতি:

1 instanceof { [Symbol.hasInstance]: greet } // triggers greet

1
এটি ব্যবহার করে একটি খুব আকর্ষণীয় পদ্ধতির valueOf
মাইক ক্লক

4
আপনি ES6 সম্পর্কে ভুলে গেছেন:func``;
ইসমাইল মিগুয়েল

1
আপনি ইভাল কল করে বন্ধনী ব্যবহার করেছেন :)
ট্রিনকোট

1
সেক্ষেত্রে ফাংশনটি কার্যকর হয় না, তবে কলারের হাতে দেওয়া হয়।
ট্রিনকোট

1
@ ট্রিনকোট পাইপলাইন অপারেটরের সাহায্যে শীঘ্রই আর একটি পদ্ধতি সম্ভব হবে :'1' |> alert
ডেনিরো

224

এটি করার সহজতম উপায় newঅপারেটরের সাথে:

function f() {
  alert('hello');
}

new f;

যদিও এটি অপ্রচলিত এবং অপ্রাকৃতিক, এটি কাজ করে এবং পুরোপুরি আইনী।

newঅপারেটর বন্ধনী প্রয়োজন হয় না কোন প্যারামিটার ব্যবহার করা হয় পারেন।


6
সংশোধন, এটি করার সহজতম উপায় হ'ল এমন একটি অপরেন্ড প্রেন্ডিং করা যা ফাংশন প্রকাশকে মূল্যায়ন করতে বাধ্য করে। !fকনস্ট্রাক্টর ফাংশনের কোনও উদাহরণ ইনস্ট্যান্ট না করে একই জিনিসটির ফলাফল হয় (যার জন্য একটি নতুন এই প্রসঙ্গে তৈরি করা প্রয়োজন)। এটি অনেক বেশি পারফরম্যান্ট এবং অনেক জনপ্রিয় লাইব্রেরিতে (বুটস্ট্র্যাপের মতো) ব্যবহৃত হয়।
এ'চ্যাড

6
@ থিচ্যাড - একটি এক্সপ্রেশনকে মূল্যায়ন করা কোনও ফাংশন সম্পাদন করার মতো নয়, তবে যদি আপনার কোনও আলাদা (সুন্দর? আরও অবাক করা?) পদ্ধতি থাকে তবে কোনও ফাংশনটি আহ্বানের (মৃত্যুদণ্ড কার্যকর করা) পদ্ধতি - একটি উত্তর পোস্ট করুন!
অমিত

একটি বিস্ময়বোধক চিহ্ন, বা অন্য কোন একক অক্ষর ইউনারী অপারেটর (prepending বিন্দু +, -, ~) যেমন গ্রন্থাগারে, পাঠাগার যেখানে ফেরত মান প্রয়োজন নেই এর মিনিমাইজ সংস্করণে একটি বাইট সংরক্ষণ করতে হয়। (অর্থাত্ !function(){}()) স্বাভাবিক স্ব-কলিং সিনট্যাক্সটি (function(){})()(দুর্ভাগ্যক্রমে সিনট্যাক্স function(){}()ক্রস ব্রাউজার নয়) যেহেতু শীর্ষস্থানীয় স্ব-কলিং ফাংশনটিতে সাধারণত ফিরে আসার কিছুই থাকে না, এটি সাধারণত এই বাইট সংরক্ষণ কৌশলটির লক্ষ্য
আলটিমেটার

1
পছন্দ করুন আমি কেবল এটি ক্রোমে চেষ্টা করেছি, এবং ফাংশন সম্পাদন হচ্ছে না। function foo() { alert("Foo!") };উদাহরণস্বরূপ: !fooরিটার্নfalse
গ্লেন 'দেবালিয়া'

95

আপনি গেটর এবং সেটটার ব্যবহার করতে পারেন।

var h = {
  get ello () {
    alert("World");
  }
}

এই স্ক্রিপ্টটি কেবল এর সাথে চালান:

h.ello  // Fires up alert "world"

সম্পাদনা:

আমরা যুক্তিও করতে পারি!

var h = {
  set ello (what) {
    alert("Hello " + what);
  }
}

h.ello = "world" // Fires up alert "Hello world"

সম্পাদনা 2:

আপনি গ্লোবাল ফাংশনগুলি সংজ্ঞায়িত করতে পারেন যা প্রথম বন্ধনী ছাড়াই চালানো যেতে পারে:

window.__defineGetter__("hello", function() { alert("world"); });
hello;  // Fires up alert "world"

এবং যুক্তি সহ:

window.__defineSetter__("hello", function(what) { alert("Hello " + what); });
hello = "world";  // Fires up alert "Hello world"

দাবি পরিত্যাগী:

যেমন @ মোন্কিজেউস বলেছেন: আপনার উদ্দেশ্যগুলি যত ভালই হোক না কেন আপনি কখনও এই কোডের টুকরোটি উত্পাদনে ব্যবহার করতে পারবেন না।


9
পিওভির কড়া কথায় "আমি একটি কুড়াল চালাচ্ছি এমন এক পাগল মানুষ যা আপনার কোডটি গ্রহণ করার গৌরব অর্জন করেছে কারণ আপনি আরও বড় এবং ভাল জিনিসগুলিতে চলে এসেছেন; তবুও আমি জানি আপনি কোথায় থাকেন"। আমি সত্যিই আশা করি এটি সাধারণ লোল নয়। আপনি বজায় রাখার মতো কোনও প্লাগইনের অভ্যন্তরে এটি ব্যবহার করে নিন acceptable ব্যবসায়ের-যুক্তিযুক্ত কোডটি
লিখছেন

3
@ মনকিজেস হা হা, হ্যাঁ! ভবিষ্যতের কোডারদের জন্য এমন একটি দাবি যুক্ত করা হয়েছে যা এটি গুগল থেকে খুঁজে পেতে পারে
jehna1

আসলে এই দাবি অস্বীকার খুব কঠোর। "ফাংশন কল হিসাবে গেটর" এর জন্য বৈধ ব্যবহারের কেস রয়েছে। আসলে এটি একটি খুব সফল লাইব্রেরিতে ব্যাপকভাবে ব্যবহৃত হয়েছে। (আপনি কি কোনও ইঙ্গিত চান ?? :-)
অমিত

1
নোট যে __defineGetter__হ্রাস করা হয়েছে। Object.definePropertyপরিবর্তে ব্যবহার করুন।
ফেলিক্স ক্লিং

2
@ মোনকিজেস - যেমন আমি মন্তব্যে স্পষ্টভাবে লিখেছি - এই স্টাইলের অনুরোধের বিন্যাসটি অভ্যন্তরীণভাবে নয়, খুব সফল জনসাধারণের গ্রন্থাগারে, ব্যাপকভাবে এবং ইচ্ছাকৃতভাবে ব্যবহৃত হচ্ছে
অমিত

23

একটি নির্দিষ্ট পরিস্থিতির জন্য এখানে একটি উদাহরণ :

window.onload = funcRef;

যদিও উক্ত বিবৃতিটি প্রকৃতপক্ষে প্রার্থনা করে না তবে ভবিষ্যতের আহ্বানে নেতৃত্ব দেয় ।

তবে, আমি ধূসর অঞ্চলগুলি এই ধরণের ধাঁধাগুলির জন্য ঠিক থাকতে পারি :)


6
এটি দুর্দান্ত তবে এটি জাভাস্ক্রিপ্ট নয়, এটি ডম।
অমিত

6
@ অমিত, ডিওএম ব্রাউজারের জেএস পরিবেশের অংশ, যা এখনও জাভাস্ক্রিপ্ট।
zzzzBov

3
@zzzzBov সমস্ত ইসিএমএসক্রিপ্ট ওয়েব ব্রাউজারে চলছে না। অথবা আপনি নোডের বিপরীতে এইচটিএমএল ডিওএম এর সাথে ইএস সংযুক্ত করার জন্য বিশেষভাবে "জাভাস্ক্রিপ্ট" ব্যবহার করেন এমন লোকদের মধ্যে রয়েছেন?
দামিয়ান ইয়ারিক

9
@ দামিয়ানইরিক, আমি ডমকে কিছু জেএস পরিবেশে উপলব্ধ একটি লাইব্রেরি হিসাবে বিবেচনা করি যা এটি কিছু পরিবেশে আন্ডারস্কোরের চেয়ে কম জাভাস্ক্রিপ্ট তৈরি করে না। এটি এখনও জাভাস্ক্রিপ্ট, এটি কেবল এমন একটি অংশ নয় যা ইসমাস্ক্রিপ্টের নির্দিষ্টকরণে উল্লিখিত হয়েছে।
zzzzBov

3
@zzzzBov, "যদিও DOM প্রায়শই জাভাস্ক্রিপ্ট ব্যবহার করে অ্যাক্সেস করা হয় তবে এটি জাভাস্ক্রিপ্ট ভাষার অংশ নয়। অন্যান্য ভাষাও এটি অ্যাক্সেস করতে পারে।" । উদাহরণস্বরূপ, ফায়ারফক্স ডোম বাস্তবায়নের জন্য এক্সপিআইডিএল এবং এক্সপিসিএম ব্যবহার করে। এটি এতটা স্ব-স্পষ্ট নয় যে আপনার নির্দিষ্ট কলব্যাক ফাংশনের কলটি জাভাস্ক্রিপ্টে প্রয়োগ করা হয়েছে। DOM অন্যান্য জাভাস্ক্রিপ্ট লাইব্রেরির মতো একটি API নয়।
ট্রিনকোট

17

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

1. locationএবং javascript:প্রোটোকল:

এই জাতীয় একটি কৌশল হ'ল নিয়োগের javascript:প্রোটোকলটি অপব্যবহার করা location

কাজের উদাহরণ:

location='javascript:alert\x281\x29'

যদিও প্রযুক্তিগতভাবে \x28\x29 কোডটি একবার মূল্যায়িত হয়ে গেলে এবং এখনও বন্ধনী হয় তবে প্রকৃত (এবং )চরিত্রটি উপস্থিত হয় না। প্রথম বন্ধনীগুলি জাভাস্ক্রিপ্টের একটি স্ট্রিংয়ে পালিয়ে যায় যা কার্যনির্বাহে মূল্যায়ন হয়।


onerrorএবং eval:

একইভাবে, ব্রাউজারের উপর নির্ভর করে আমরা গ্লোবালটিকে onerrorএটিকে সেট করে eval, এবং এমন কিছু নিক্ষেপ করতে পারি যা বৈধ জাভাস্ক্রিপ্টে রূপান্তরিত করে। এটি একটি কৌশলযুক্ত, কারণ ব্রাউজারগুলি এই আচরণে অসঙ্গত, তবে ক্রোমের জন্য এখানে একটি উদাহরণ।

ক্রোমের জন্য কার্যকারী উদাহরণ (ফায়ারফক্স নয়, অন্যরা অপরীক্ষিত নয়):

window.onerror=eval;Uncaught=0;throw';alert\x281\x29';

এটি ক্রোমে কাজ করে কারণ এটি প্রথম যুক্তি হিসাবে throw'test'পাস করবে যা প্রায় বৈধ জাভাস্ক্রিপ্ট। পরিবর্তে আমরা এটি পাস হলে'Uncaught test'onerrorthrow';test''Uncaught ;test' । এখন আমাদের বৈধ জাভাস্ক্রিপ্ট আছে! কেবলমাত্র সংজ্ঞায়িত করুন Uncaught, এবং পেডলোডের সাথে পরীক্ষাটি প্রতিস্থাপন করুন।


উপসংহারে:

এই জাতীয় কোডটি সত্যই ভয়ঙ্কর , এবং এটি কখনও ব্যবহার করা উচিত নয় , তবে কখনও কখনও এক্সএসএস আক্রমণে ব্যবহৃত হয়, তাই গল্পের নৈতিকতা এক্সএসএসকে প্রতিরোধ করতে ফিল্টারিং বন্ধনীর উপর নির্ভর করে না। এই জাতীয় কোড প্রতিরোধের জন্য একটি সিএসপি ব্যবহার করাও ভাল ধারণা হবে।


evalআসলেই প্রথম বন্ধনী অক্ষর ব্যবহার না করে স্ট্রিংটি ব্যবহার এবং লেখার মতো নয়।
জেভ স্পিটজ

@ জেনস্পিৎস হ্যাঁ, তবে evalসাধারণত বন্ধনীগুলির প্রয়োজন হয়, তাই এই ফিল্টার ফাঁকি হ্যাক।
আলেকজান্ডার ও'মারা

5
তর্কযুক্ত \x28এবং \x29এখনও বন্ধনী হয়। '\x28' === '('
ট্রিনকোট

@ ট্রিনকোট যা উত্তরের দিকটি আমি উত্তরে coveredেকে দিয়েছি, এটি একটি পার্শ্বীয় চিন্তাভাবনা পদ্ধতির যা কোনও কারণ দেখায় যাতে এটি করা যেতে পারে। আমি উত্তরে আরও স্পষ্ট করে দিয়েছি।
আলেকজান্ডার ও'মার

এছাড়াও, যে কেউ এটি মুছে ফেলার পক্ষে ভোট দিয়েছেন, দয়া করে উত্তরগুলি মুছার জন্য নির্দেশিকা পর্যালোচনা করুন
আলেকজান্ডার ও'মারা

1

ES6- এ, আপনি ট্যাগযুক্ত টেম্পলেট লিটারালস নামে পরিচিত ।

উদাহরণ স্বরূপ:

function foo(val) {
    console.log(val);
}

foo`Tagged Template Literals`;


3
প্রকৃতপক্ষে, এই উত্তরটি আমি আপনার 1.5 বছর আগে পোস্ট করেছি ... নিশ্চিত না কেন এটি একটি নতুন উত্তরের জন্য প্রাপ্য?
ট্রিনকোট

2
কারণ এই মুহূর্তে একই জিনিস বাস্তবায়ন করতে চান এমন আরও কিছু লোক নতুন উত্তরটি ব্যবহার করতে পারেন।
মেহতা-রোহন

3
@ মেহতা-রোহন, আমি এই মন্তব্যটি বুঝতে পারি না। যদি এটি বোঝা যায় তবে কেন একই উত্তরটি বারবার উপকারে নকল করবেন না? কিভাবে এটি দরকারী হবে তা আমি দেখতে পাচ্ছি না।
ট্রিনকোট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.