গ্লোবাল / সিলেটলেটগুলি গেম ডেভলপমেন্টে দরকারী এমন কোনও মামলা রয়েছে? [বন্ধ]


11

আমি জানি যে গ্লোবাল ভেরিয়েবল বা সিঙ্গেলটন ক্লাসগুলি এমন কেস তৈরি করে যা পরীক্ষা করা / পরিচালনা করা কঠিন হতে পারে এবং কোডগুলিতে এই ধরণগুলি ব্যবহার করে আমার ফাঁসানো হয়েছিল তবে প্রায়শই আপনি শিপিয়ে যান।

তাহলে এমন কিছু ঘটনা আছে যেখানে গ্লোবাল ভেরিয়েবল বা সিঙ্গেলনগুলি গেম বিকাশে আসলে কার্যকর?

উত্তর:


30

এই জিনিসগুলি সর্বদা দরকারী হতে পারে । এটি সবচেয়ে সুন্দর বা নিরাপদ সমাধান হোক বা না হোক এটি অন্য বিষয়, তবে আমি মনে করি গেমের বিকাশে একটি নির্দিষ্ট মাত্রার ব্যবহারিকতা জড়িত।


আমার মন্ত্রের খুব কাছে।
ইলফুর ওয়েজ

15

অবশ্যই একটি অ-নিষ্ক্রিয় তালিকা, তবে এখানে যায়:

কনস

  • লাইফটাইম ম্যানেজমেন্ট । কীভাবে সিস্টেমগুলি (উদাহরণস্বরূপ হিপ) প্রারম্ভিক হওয়ার আগে সিঙ্গলেট এবং গ্লোবালগুলি শুরু করতে পছন্দ করতে পারে, আপনি কীভাবে সেট আপ করবেন তার উপর নির্ভর করে। যদি আপনি কখনই সেগুলি ছিন্ন করতে চান (উদাহরণস্বরূপ, আপনি ফাঁস ট্র্যাকিং করছেন তবে দরকারী) আপনার টিয়ারডাউন অর্ডার সম্পর্কে সতর্কতা অবলম্বন করতে হবে বা ফিনিক্স সিলেটলেটের মতো জিনিসগুলি পেতে শুরু করতে হবে । ( স্থিতিশীল আরম্ভের অর্ডার ফিয়াস্কো দেখুন ))
  • অ্যাক্সেস নিয়ন্ত্রণ । রেন্ডারিংগুলিতে কেবল গেমের ডেটাতে কনস্ট অ্যাক্সেস থাকা উচিত, যখন আপডেটটি নন-কনস্ট্যান্ট পায়? সিঙ্গেলন এবং গ্লোবালগুলি প্রয়োগ করা এটি আরও কঠিন হতে পারে।
  • রাজ্য । কাজটি উল্লেখ করেছেন যে, ভাগ না করা-মেমরির আর্কিটেকচারে এককভাবে কাজ করতে সিলেটলেটগুলি কার্যকরীভাবে পচে যাওয়া এবং রূপান্তর করা শক্ত। এটির অন্যান্য ধরণের NUMA সিস্টেমে (স্থানীয় নয় এমন মেমরি অ্যাক্সেস করার জন্য) এর সম্ভাব্য কর্মক্ষমতা সম্পর্কিত প্রভাব রয়েছে । সিঙ্গলেটগুলি সাধারণত কেন্দ্রিকৃত রাষ্ট্রের প্রতিনিধিত্ব করে এবং এইভাবে রূপান্তরগুলির বিরোধীতা যা শুদ্ধতার দ্বারা সহজ করে তুলেছে।

হয় প্রো বা কন

  • concurrency । সমসাময়িক পরিবেশে, সিঙ্গলেটগুলি হয় একটি ব্যথা হতে পারে (আপনার অবশ্যই ডেটা রেস / পুনর্বিবেচনার বিষয়গুলি বিবেচনা করতে হবে) বা আশীর্বাদ হতে পারে (কেন্দ্রীভূত করা সহজ এবং লকিং এবং রিসোর্স ম্যানেজমেন্ট সম্পর্কে কারণ)। থ্রেড লোকাল স্টোরেজের মতো জিনিসের চালাক ব্যবহার সম্ভাব্য সমস্যাগুলি কিছুটা কমিয়ে দিতে পারে, তবে এটি সাধারণত কোনও সহজ সমস্যা নয়।
  • কোডজেন (সংকলক, আর্কিটেকচার ইত্যাদির উপর নির্ভর করে): প্রথমবার ব্যবহারের ভিত্তিতে তৈরি সিঙ্গেলটন বাস্তবায়নের জন্য, আপনি প্রতিটি অ্যাক্সেসের জন্য একটি অতিরিক্ত শর্তাধীন মূল্যায়ন করতে পারেন। (এটি যোগ করতে পারে)) একটি ফাংশনে ব্যবহৃত একাধিক গ্লোবালগুলি ফুল ফোটে আক্ষরিক পুলটি । "সমস্ত গ্লোবালগুলির স্ট্রাক্ট" পদ্ধতির আক্ষরিক পুলে স্থান বাঁচাতে পারে: কাঠামোর গোড়ায় কেবল একটি প্রবেশ এবং তারপরে লোডের নির্দেশাবলীতে এনকোড করা অফসেটগুলি। অবশেষে, আপনি যদি কোনও মূল্যে গ্লোবাল এবং সিঙ্গলেটন এড়িয়ে চলে থাকেন তবে আপনাকে প্রায়শই পয়েন্টার, রেফারেন্স, বা চারপাশে অনুলিপিগুলি পাস করার জন্য কমপক্ষে কিছুটা অতিরিক্ত মেমোরি (রেজিস্ট্রার, স্ট্যাক, বা গাদা) ব্যবহার করতে হবে।

পেশাদাররা

  • সরলতা । যদি আপনি জানেন যে উপরের তালিকাভুক্ত বিধিগুলি আপনাকে তত বেশি প্রভাবিত করে না (যেমন আপনি একটি একক সিপিইউ হ্যান্ডহেল্ড প্ল্যাটফর্মের জন্য একক থ্রেডযুক্ত পরিবেশে কাজ করছেন), আপনি কিছু আর্কিটেকচার এড়িয়ে চলুন (যেমন পূর্বোক্ত আর্গুমেন্ট-পাসিং)। সিঙ্গেলটন এবং গ্লোবালগুলি কম অভিজ্ঞ কোডারদের জন্য বোঝা সহজ হতে পারে (যদিও এটি ভুলভাবে ব্যবহার করা সহজ হতে পারে)।
  • লাইফটাইম ম্যানেজমেন্ট (আবার)। আপনি যদি "গ্লোবাল স্ট্রাক্ট" বা কোনও ক্রম-অন-ফার্স্ট-অনুরোধ ব্যতীত অন্য কোনও কৌশল ব্যবহার করেন তবে আপনার আরম্ভ এবং ধ্বংসের আদেশের উপর সহজেই পড়া এবং সূক্ষ্ম কন্ট্রোল থাকতে পারে। আপনি এটিকে কিছুটা ডিগ্রিমে স্বয়ংক্রিয়ভাবে পরিচালনা করুন বা ম্যানুয়ালি এটিকে পরিচালনা করুন (এটি পরিচালনা করার পরে কোনও গ্লোবাল / সিঙ্গেলন এবং তাদের আন্তঃনির্ভরশীলতার সংখ্যার উপর নির্ভর করে প্রো বা কন হতে পারে)।

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

আপনি যদি আপনার এপিআই তুলনামূলকভাবে পরিষ্কার রাখেন তবে আপনার প্রয়োজনের সময় একটি সিঙ্গলটন প্যাটার্নের বাইরে (বা মধ্যে!) রিফ্যাক্টর পাওয়া খুব ভয়ঙ্কর নয় ...


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

হ্যাঁ, কোডজেন পুনরায়, কেবলমাত্র আমরা যা দেখতে পেয়েছি তা উল্লেখযোগ্য পার্থক্য তৈরি করে স্বতন্ত্র গ্লোবালগুলি থেকে একটি গ্লোবালটেবলে যাচ্ছিল: এটি আক্ষরিক পুলগুলিকে সঙ্কুচিত করে এবং তাই টেক্সট বিভাগের আকারটি কয়েক শতাংশ হারে সঙ্কুচিত করে। যা ছোট সিস্টেমে খুব সুন্দর একটি জিনিস। =) আক্ষরিকের জন্য ডেকেচে তেমন আঘাত না করার পারফরম্যান্স সুবিধাগুলি কেবল একটি দুর্দান্ত (বেশিরভাগ ক্ষেত্রেই ক্ষুদ্র হলেও) পার্শ্ব সুবিধা ছিল। গ্লোবাল টেবিলে যাওয়ার আরেকটি সুবিধা
হ'ল

4

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


2

আমি বলব যে সিঙ্গলটন ডিজাইন নিজেই মোটেই কার্যকর নয়। গ্লোবাল ভেরিয়েবলগুলি অবশ্যই কার্যকরভাবে কার্যকর হতে পারে তবে আমি বরং এগুলি একটি লিখিত ইন্টারফেসের আড়ালে দেখতে পেয়েছি যাতে আপনি তাদের অস্তিত্ব সম্পর্কে সচেতন না হন। সিঙ্গেলটনের সাহায্যে আপনি তাদের অস্তিত্ব সম্পর্কে নিশ্চিতভাবে অবগত আছেন।

ইঞ্জিনের মাধ্যমে অ্যাক্সেসের প্রয়োজন असलेल्या জিনিসের জন্য আমি প্রায়শই গ্লোবাল ভেরিয়েবল ব্যবহার করি। আমার পারফরম্যান্স সরঞ্জামটি একটি ভাল উদাহরণ যা আমি কল করার জন্য সমস্ত ইঞ্জিনের মধ্যে ব্যবহার করি। কলগুলি সহজ; প্রোবরেজিস্টার (), প্রোবহিট () এবং প্রোবস্কেপড ()। তাদের আসল অ্যাক্সেসটি কিছুটা জটিল এবং তাদের কিছু জিনিসের জন্য বিশ্বব্যাপী ভেরিয়েবল ব্যবহার করে।


2

গ্লোবালগুলি এবং দুর্বলভাবে প্রয়োগ করা সিঙ্গলেটনের মূল সমস্যাটি হ'ল অস্পষ্ট নির্মাণ এবং ডিকনস্ট্রাকশন বাগ।

সুতরাং আপনি যদি আদিমদের সাথে কাজ করেন যার মধ্যে এই সমস্যাগুলি নেই বা পয়েন্টার সহ সমস্যাটি সম্পর্কে খুব সচেতন are তারপরে সেগুলি নিরাপদে ব্যবহার করা যায়।

গ্লোবালগুলির নিজস্ব স্থান রয়েছে, গোটোসের মতো এবং হাতছাড়া হওয়া উচিত নয় বরং যত্ন সহ ব্যবহার করা উচিত।

গুগল সি ++ স্টাইল গাইডে এর একটি ভাল ব্যাখ্যা রয়েছে


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

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

1

গ্লোবালগুলি এমন কোনও সিস্টেমে দ্রুত প্রোটোটাইপ করার সময় দরকারী যা ফাংশন কলগুলির মধ্যে কিছু স্থিতি প্রয়োজন। একবার আপনি প্রতিষ্ঠিত করলেন যে সিস্টেমটি কাজ করে, রাষ্ট্রকে একটি শ্রেণিতে স্থানান্তরিত করুন এবং ফাংশনগুলিকে সেই শ্রেণীর পদ্ধতিতে পরিণত করুন।

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


1

আমি সিঙ্গেলনের পরিবর্তে কাস্টম লাইফটাইম ম্যানেজমেন্টের সাথে কিছু ধরণের ডিআই / আইওসি পাত্রে ব্যবহার করার পরামর্শ দেওয়ার প্রবণতা রাখি (এমনকি যদি আপনি "একক উদাহরণ" আজীবন ব্যবস্থাপক ব্যবহার করেন)। অন্ততপক্ষে পরীক্ষার সুবিধার্থে কার্যকরকরণের পরিবর্তন আনা সহজ।


আপনারা যারা জানেন না তাদের জন্য ডিআই হ'ল "নির্ভরতা ইনজেকশন", এবং আইওসি হ'ল "ইনভার্শন অফ কন্ট্রোল"। লিঙ্ক: martinfowler.com/articles/injection.html এই চমৎকার রূপান্তর উল্লেখ জন্য, যদিও (আমি এই সম্পর্কে আগে পড়া ছিল কিন্তু কখনও আদ্যক্ষরা দেখা, তাই এটি আমার অনুসন্ধানের একটি বিট গ্রহণ করেন।) + 1।
লিণ্ডার

0

আপনি যদি একটি সিঙ্গেলনের মেমরি সঞ্চয় বৈশিষ্ট্যগুলি চান তবে আপনি ফ্লাইওয়েট ডিজাইনের ধরণটি চেষ্টা করতে পারেন?

http://en.wikipedia.org/wiki/Flyweight_pattern

যতটা উপরে উল্লিখিত মাল্টি-থ্রেড ইস্যুগুলি থ্রেডগুলির মধ্যে ভাগ করা যায় এমন সংস্থানগুলির জন্য একটি লক প্রক্রিয়া বাস্তবায়নের জন্য কিছুটা দূরদর্শিতার সাথে মোটামুটিভাবে হওয়া উচিত। http://en.wikipedia.org/wiki/Read/write_lock_pattern


0

প্রারম্ভিক প্রোটোটাইপে কোনও অংশীদারি স্টেট সংরক্ষণ করার জন্য সিঙ্গলেটগুলি হ'ল এক দুর্দান্ত উপায়।

এগুলি কোনও রূপালী বুলেট নয় এবং কিছু সমস্যা নিয়ে আসে তবে তারা নির্দিষ্ট ইউআই / লজিকের রাজ্যের জন্য খুব দরকারী প্যাটার্ন।

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


0

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


আমার প্রশ্ন তখন হবে, কেন কেন একক ব্যবহার? আমি দেখতে পাচ্ছি যে লোকেরা সিঙ্গেলন বা ক্লাসগুলির সাথে এপিআইগুলি মোড়ানো পছন্দ করে যেগুলি কেবল স্থির ফাংশন নিয়ে গঠিত তবে শ্রেণীর সাথে কেন মোটেই বিরক্ত করবেন না? কেবলমাত্র ফাংশন কলগুলি (আপনার ইচ্ছামতোভাবে মোড়ানো) করা আমার পক্ষে আরও সহজ বলে মনে হয়, তবে তারপরে তাদের অভ্যন্তরীণভাবে "গ্লোবাল" অবস্থানে প্রবেশ করতে পারে। উদাহরণস্বরূপ লগ :: গেটইনস্ট্যান্স () -> লগইয়েরার (...) ঠিক সেইসাথে লগইরার (...) হতে পারে যা ক্লায়েন্ট কোড সম্পর্কে এটি না জেনে অভ্যন্তরীণভাবে কোনও বিশ্বব্যাপী অবস্থানে প্রবেশ করে।
ড্যাশ-টম-ব্যাং

0

কেবলমাত্র যখন আপনার কাছে কোনও আইটেম থাকে যার কেবলমাত্র একটি নিয়ামক থাকে তবে বেশ কয়েকটি মডিউল দ্বারা পরিচালিত হয়।

যেমন, উদাহরণস্বরূপ, মাউস ইন্টারফেস। বা জয়স্টিক ইন্টারফেস। বা সঙ্গীত প্লেয়ার। বা সাউন্ড প্লেয়ার। বা পর্দা। বা সেভ ফাইল ম্যানেজার।


-1

গ্লোবাল অনেক দ্রুত! সুতরাং এটি কোনও গেমের মতো পারফরম্যান্স নিবিড় অ্যাপ্লিকেশনটির জন্য পুরোপুরি ফিট করে।

সিঙ্গলেটগুলি আরও ভাল গ্লোবাল, আইএমও এবং এইভাবে সঠিক সরঞ্জাম।

অল্প পরিমাণে এটি ব্যবহার করুন!


অনেক তাড়াতাড়ি কি ? গ্লোবালগুলি কোনও পয়েন্টার হয়ে থাকলে কিছু এলোমেলো মেমরি পৃষ্ঠায় থাকবে এবং কিছু স্থির তবে সম্ভবত দূরবর্তী মেমরি পৃষ্ঠা যদি তারা মান হয় value সংকলক তাদের উপর কোনও কার্যকর পিফহোল অপটিমাইজেশন ব্যবহার করতে পারে না। যে কোনও পরিমাপের দ্বারা আমি ভাবতে পারি, গ্লোবালগুলি ধীরে ধীরে

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

তবে গ্লোবালগুলির সাথে যে কোনও সিঙ্ক্রোনাইজেশন সমস্যাগুলি সমাধান করার জন্য আপনার তাদের জন্য গেটার / সেটারগুলি প্রয়োজন, যাতে এটি প্রকৃতপক্ষে প্রাসঙ্গিক নয়। বৈশ্বিক রাষ্ট্রের (এবং এর বিরল উপকার) সমস্যাটি হ'ল এটি বিশ্বব্যাপী রাষ্ট্র, ইন্টারফেসের গতি বা (কার্যকরভাবে) বাক্য গঠন সম্পর্কে কোনও উদ্বেগ নয়।
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.