একাধিক রফতানি প্রকারের জন্য একটি শক্তিশালী আর্কিটেকচার ডিজাইন করা?


10

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

আমি সমস্ত রেন্ডারিং এবং লেআউটকে কিছু প্রকার রেন্ডারিং বা লেআউট ইঞ্জিনের বিমূর্ত করার একটি উপায় সন্ধান করার চেষ্টা করছি যা আরও রফতানির লক্ষ্যমাত্রা সংযোজনকে পরিচালনা করে। এটির কাছে কীভাবে সহায়তা করা যায় সে সম্পর্কে কোনও পরামর্শ / পরামর্শ / সংস্থান প্রশংসিত হবে। আগাম ধন্যবাদ.

আমি কী অর্জন করার চেষ্টা করছি তার চিত্রিত উপস্থাপনার জন্য।

এখানে চিত্র বর্ণনা লিখুন


আপনি এতক্ষণ যা চেষ্টা করেছেন তা বর্ণনা করতে পারবেন? লেআউট ইঞ্জিনের প্রয়োজনীয়তা (দায়িত্ব) কী কী? উদাহরণস্বরূপ, পৃষ্ঠাগুলি এবং পৃষ্ঠার আকার নির্বাচন পরিচালনা করা আশা করা যায়?
রওয়ং

XML / JSON ডেটা একই আউটপুট রানে একাধিক আউটপুট ধরণের তৈরি করতে ব্যবহার করা যেতে পারে, অর্থাৎ আপনার এক্সএমএল ডেটা একটি পিডিএফ ডকুমেন্টে চিত্র এবং টেবিল এবং গ্রাফ তৈরি করে? অথবা এক্সএমএল / জেএসওএন ডেটা কেবল একটি পিডিএফ ডকুমেন্টের জন্য একটি সারণী বা গ্রাফ তৈরি করতে ব্যবহার করা যেতে পারে?
গিবসন

এগুলি সবই xkcd.com/927 - আপনি চাকাটি পুনঃস্থাপনের চেষ্টা করছেন কেন? ডকবুক, মার্কডাউন / প্যান্ডোক ইত্যাদি ইতিমধ্যে বিদ্যমান ...
হরিণ হান্টার

উত্তর:


2

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

দ্রষ্টব্য: ইন্টারফেসের পরিবর্তে আপনি বিমূর্ত বেস ক্লাসগুলিও ব্যবহার করতে পারেন, তবে একটি অপূর্ণতা হ'ল একক উত্তরাধিকারী ভাষার জন্য এটি আপনাকে একক বেস শ্রেণিতে সীমাবদ্ধ করে।

TRepresentationType = (rtImage, rtTable, rtGraph, ...);

Factory.RegisterReader(TJSONReader, 'json');
Factory.RegisterReader(TXMLReader, 'xml');

Factory.RegisterWriter(TPDFWriter, 'pdf');
Factory.RegisterWriter(TPowerPointWriter, 'ppt');
Factory.RegisterWriter(TWordWriter, 'doc');
Factory.RegisterWriter(TWordWriter, 'docx');

Factory.RegisterRepresentation(TPNGImage, rtImage, 'png');
Factory.RegisterRepresentation(TGIFImage, rtImage, 'gif');
Factory.RegisterRepresentation(TJPGImage, rtImage, 'jpg');
Factory.RegisterRepresentation(TCsvTable, rtTable, 'csv');
Factory.RegisterRepresentation(THTMLTable, rtTable, 'html');
Factory.RegisterRepresentation(TBarChart, rtTGraph, 'bar');
Factory.RegisterRepresentation(TPieChart, rtTGraph, 'pie');

কোডটি ডেল্ফি (পাস্কাল) বাক্যবিন্যাসে রয়েছে কারণ সেই ভাষাটি যার সাথে আমি সবচেয়ে বেশি পরিচিত।

সমস্ত বাস্তবায়নকারী ক্লাস কারখানার সাথে নিবন্ধিত হওয়ার পরে, আপনার এমন শ্রেণীর উদাহরণের জন্য একটি ইন্টারফেস রেফারেন্সের জন্য অনুরোধ করতে সক্ষম হওয়া উচিত। উদাহরণ স্বরূপ:

Factory.GetReader('SomeFileName.xml');
Factory.GetWriter('SomeExportFileName.ppt');
Factory.GetRepresentation(rtTable, 'html');

TXMLReader এর উদাহরণের জন্য একটি IReader রেফারেন্স ফিরিয়ে দেওয়া উচিত; টিপওয়ারপয়েন্ট রাইটারের একটি উদাহরণের জন্য একটি আইওয়ারাইটার রেফারেন্স এবং টিএইচটিএমএল টেবিলের একটি উদাহরণের জন্য একটি আইআরপিসারেশন রেফারেন্স।

এখন সমস্ত রেন্ডারিং ইঞ্জিনটি করা দরকার, সবকিছুকে এক সাথে বেঁধে রাখা:

procedure Render(
  aDataFile: string; 
  aExportFile: string;
  aRepresentationType: TRepresentationType;
  aFormat: string;
  );
var
  Reader: IReader;
  Writer: IWriter;
  Representation: IRepresentation;
begin
  Reader := Factory.GetReaderFor(aDataFile);
  Writer := Factory.GetWriterFor(aExportFile);
  Representation := Factory.GetRepresentationFor(aRepresentationType, aFormat);

  Representation.ConstructFrom(Reader);
  Writer.SaveToFile(Representation);
end;

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

আপনার ফাইলগুলির ডেটা প্রকৃতির আকারে টেবিলার হিসাবে ধরে নেওয়া, আইআরডিডার এবং এর সহায়ক ইন্টারফেসগুলি দেখতে দেখতে পারে:

IReader = interface(IInterface)
  function MoveNext: Boolean;
  function GetCurrent: IRow;
end;

IRow = interface(IInterface)
  function MoveNext: Boolean;
  function GetCurrent: ICol;
end;

ICol = interface(IInterface)
  function GetName: string;
  function GetValue: Variant;
end;

কোনও টেবিলের উপরে আইট্রেটেড করা তখন বিষয় হয়ে উঠবে

while Reader.MoveNext do
begin
  Row := Reader.GetCurrent;
  while Row.MoveNext do
  begin
    Col := Row.GetCurrent;
    // Do something with the column's name or value
  end;
end;

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


1

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

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


1
আমি মনে করি এটির চেয়ে কিছুটা বেশি জড়িত। উদাহরণস্বরূপ, ডায়াগ্রামের রেখাগুলি বরাবর ডেটা যোগাযোগ করার জন্য কোন প্রোটোকল ব্যবহার করা হবে? রেন্ডারিং / লেআউট ইঞ্জিনে কি কোনও সাধারণ উপাত্তের প্রতিনিধিত্ব হতে পারে, বা সেই ইঞ্জিনটি সম্পূর্ণ কাস্টম পদ্ধতিগুলির জন্য একটি কারখানা, চিত্রের প্রতিটি লাইনের জন্য একটি?
রবার্ট হার্ভে

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

শিরোনামে আসলে দুটি প্রশ্ন রয়েছে: সামগ্রী সম্পর্কে (জিআইএফ, পিডিএফ, এইচটিএমএল) এবং পরিবহন সম্পর্কে (স্থানীয় ফাইল, HTTP- প্রতিক্রিয়া-আইটেম)। @ অর্পোসুজার (+1) উত্তরটি প্রসারিত করার জন্য: আমি এমন একটি ফ্যাক্টরি ব্যবহার করে একটি স্ট্রিম তৈরি করব যা সহজেই ইউনিটযুক্ত এবং HTTP- প্রতিক্রিয়াটির জন্য সহজেই রেন্ডার করা যায়।
k3b

0

আপনি এরকম কিছু দিয়ে শেষ করতে পারেন।

দুটি কারখানা প্রায় ভিত্তিক:

1 - ইনপুট ধরণের (জসন / এক্সএমএল) রূপান্তর করার জন্য কীভাবে এই ডেটাটিকে চিত্র / গ্রাফে রূপান্তর করতে হয় তার একটি কংক্রিট বাস্তবায়নে

2 - একটি শব্দ নথি / পিডিএফ ডকুমেন্টে আউটপুট কীভাবে রেন্ডার করে তা স্থির করার জন্য দ্বিতীয় কারখানা

পলিমারফিজম সমস্ত রেন্ডার করা ডেটার জন্য একটি সাধারণ ইন্টারফেস ব্যবহার করে। সুতরাং একটি চিত্র / টেবিলকে একটি সহজ ইন্টারফেস হিসাবে প্রায় সরানো যেতে পারে।

1 - JSON / XML ডেটাটিকে একটি কংক্রিট বাস্তবায়নে রূপান্তর করার কারখানা:

public enum DataTypeToConvertTo
{
    Image,
    Table,
    Graph,
    OtherData
}

public interface IDataConverter
{
    IConvertedData ConvertJsonDataToOutput(Json jsonData);
    IConvertedData ConvertXmlDataToOutput(XDocument xmlData);
}

public abstract class DataConverter : IDataConverter
{
    public DataConverter()
    {

    }

    public abstract IConvertedData ConvertDataToOutput(string data);
}

নীচের কারখানাটি আপনাকে xML ডেটা বা জসন ডেটাটিকে সঠিক কংক্রিটের ধরণের রূপান্তর করতে দেয়।

public class DataConverterFactory
{
    public static IDataConverter GetDataConverter(DataTypeToConvertTo dataType)
    {
        switch(dataType)
        {
            case DataTypeToConvertTo.Image:
                return new ImageDataConverter();
            case DataTypeToConvertTo.Table:
                return new TableDataConverter();
            case DataTypeToConvertTo.OtherData:
                return new OtherDataConverter();
            default:
                throw new Exception("Unknown DataTypeToConvertTo");
        }
    }
}

কংক্রিট বাস্তবায়ন তথ্য প্রাসঙ্গিক ধরনের রূপান্তর সমস্ত ভারী কাজ করে। তারা ডেটাটি আইকনভার্টেড ডেটা ইন্টারফেসে রূপান্তর করে, যা বহুবিজ্ঞানের জন্য ব্যবহৃত হয়।

public sealed class ImageDataConverter : DataConverter
{
    public ImageDataConverter()
        : base()
    {

    }

    public override IConvertedData ConvertJsonDataToOutput(Json jsonData)
    {
        var convertedData = new ImageConvertedData();
        //Logic to convert to necessary datatype

        return convertedData;
    }

    public override IConvertedData ConvertXmlDataToOutput(XDocument xmlData)
    {
        var convertedData = new ImageConvertedData();
        //Logic to convert to necessary datatype

        return convertedData;
    }
}

public sealed class TableDataConverter : DataConverter
{
    public TableDataConverter()
        : base()
    {

    }

    public override IConvertedData ConvertJsonDataToOutput(Json jsonData)
    {
        var convertedData = new TableConvertedData();
        //Logic to convert to necessary datatype

        return convertedData;
    }

    public override IConvertedData ConvertXmlDataToOutput(XDocument xmlData)
    {
        var convertedData = new ImageConvertedData();
        //Logic to convert to necessary datatype

        return convertedData;
    }
}

public sealed class OtherDataConverter : DataConverter
{
    public OtherDataConverter()
        : base()
    {

    }

    public override IConvertedData ConvertJsonDataToOutput(Json jsonData)
    {
        var convertedData = new OtherConvertedData();
        //Logic to convert to necessary datatype

        return convertedData;
    }

    public override IConvertedData ConvertXmlDataToOutput(XDocument xmlData)
    {
        var convertedData = new OtherConvertedData();
        //Logic to convert to necessary datatype

        return convertedData;
    }
}

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

আইকনভার্টেডডাটা ইন্টারফেস আপনাকে পরবর্তী ধাপে একটি প্রকারের পাস করার অনুমতি দেয়: দ্রষ্টব্য: আপনি এখানে voids ফিরছেন না। এটি চিত্রগুলির জন্য বাইট [] বা ওয়ার্ডডোকামেন্টের জন্য একটি ওপেনএক্সএমএল নথি দ্বারা হতে পারে could প্রয়োজনীয় হিসাবে সামঞ্জস্য করুন।

public interface IConvertedData
{
    void RenderToPdf();
    void RenderToDocument();
    void RenderToOhter();
    void RenderToPowerPoint();
}

পলিমরফিজ্ম:

এটি সম্পর্কিত আউটপুট ধরণের ডেটা রূপান্তর করতে ব্যবহৃত হয়। অর্থাত্ চিত্রের ডেটার জন্য পিডিএফ-তে রেন্ডারিং, পাওয়ারপয়েন্টের জন্য বিভিন্ন উপস্থাপনের চিত্র ডেটা হতে পারে।

public sealed class ImageConvertedData : IConvertedData
{
    public void RenderToPdf()
    {
        //Logic to render Images
    }

    public void RenderToDocument()
    {
        //Logic to render Images
    }
}
public sealed class TableConvertedData : IConvertedData
{
    public void RenderToPdf()
    {
        //Logic to render Document
    }

    public void RenderToDocument()
    {
        //Logic to render Document
    }
}

public sealed class OtherConvertedData : IConvertedData
{
    public void RenderToPdf()
    {
        //Logic to render PDF
    }

    public void RenderToDocument()
    {
        //Logic to render PDF
    }
}

2 - আউটপুট ফর্ম্যাটটি নির্ধারণের জন্য কারখানা:

public enum ExportOutputType
{
    PDF,
    PowerPoint,
    Word,
    Other
}

public interface IOutputExporter
{
    void ExportData(IConvertedData data);
}


public class OutputExporterFactory
{
    public static IOutputExporter GetExportOutputType(ExportOutputType exportOutputType)
    {
        switch(exportOutputType)
        {
            case ExportOutputType.PDF:
                return new OutputExporterPdf();
            case ExportOutputType.PowerPoint:
                return new OutputExporterPowerPoint();
            case ExportOutputType.Other:
                return new OutputExporterOther();
            default:
                throw new Exception ("Unknown ExportOutputType");
        }
    }
}

প্রতিটি কংক্রিট বাস্তবায়ন একটি সাধারণ পদ্ধতি উদ্ঘাটন করে যা রেকর্ডিংটিকে আইকনভার্টেড ডেটা বাস্তবায়নে ফিরিয়ে দেওয়া হচ্ছে কী করে

public abstract class OutputExporter : IOutputExporter
{
    //Other base methods...
    public virtual void ExportData(IConvertedData data)
    {

    }
}

public sealed class OutputExporterPdf : OutputExporter
{
    public OutputExporterPdf()
        : base()
    {

    }

    public override void ExportData(IConvertedData data)
    {
        //Functionality to Export to Pdf
        data.RenderToPdf();
    }
}

public sealed class OutputExporterPowerPoint : OutputExporter
{
    public OutputExporterPowerPoint()
        : base()
    {

    }

    public override void ExportData(IConvertedData data)
    {
        //Functionality to Export to PowerPoint
        data.RenderToPowerPoint();
    }
}

public sealed class OutputExporterOther : OutputExporter
{
    public OutputExporterOther()
        : base()
    {

    }

    public override void ExportData(IConvertedData data)
    {
        //Functionality to Export to PowerPoint
        data.RenderToOhter();
    }
}

এই সমস্ত জন্য একটি নমুনা ক্লায়েন্ট হবে:

public class Client
{
    public Client()
    {

    }
    public void StartExportProcess(XDocument data)
    {
        IDataConverter converter = DataConverterFactory.GetDataConverter(DataTypeToConvertTo.Graph);

        IConvertedData convertedData = converter.ConvertXmlDataToOutput(data);


        IOutputExporter exportOutputer = OutputExporterFactory.GetExportOutputType(ExportOutputType.PDF);
        exportOutputer.ExportData(convertedData);
    }
}

0

আমরা এখানে একটি অনুরূপ সমস্যা সমাধান করেছি: https://ergebnisse.zensus2011.de/?locale=en সেখানে আমাদের বেশিরভাগই "টেবিল" এবং "গ্রাফ" বিভিন্ন ফর্ম্যাটে রফতানি করতে হয়: পিডিএফ, এক্সেল, ওয়েব। আমাদের ধারণাটি ছিল প্রতিটি শ্রেণিকে ইন্টারফেসগুলির সাথে একটি শ্রেণি তৈরি এবং পড়ার জন্য নিজস্ব জাভা শ্রেণি হিসাবে রেন্ডার করা হবে। আপনার ক্ষেত্রে (এক্সএমএল, জসন) তৈরির জন্য প্রতিটি বস্তুর জন্য দুটি বাস্তবায়ন এবং রেন্ডারিং (পড়ার) জন্য 4 টি বাস্তবায়ন হবে।

উদাহরণ: টেবিলগুলির জন্য আপনার কয়েকটি শ্রেণির প্রয়োজন হবে: শ্রেণি সারণী (টেবিলের কাঠামো, বৈধকরণ এবং সামগ্রীগুলি পরিচালনা করে) ইন্টারফেস ক্রিয়েট টেবিল (সারণীর ডেটা, কোষ, স্প্যানস, সামগ্রী সরবরাহ করে) ইন্টারফেস রিড টেবিল (সমস্ত ডেটার জন্য গেটার)

সম্ভবত আপনার ইন্টারফেসের প্রয়োজন নেই (বা কেবল একটি) তবে আমি মনে করি এটি সর্বদা পরীক্ষার ক্ষেত্রে বিশেষত কার্যকর একটি ভাল ডিকোপলিং সরবরাহ করে।


0

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

অন্যরা যেমন উল্লেখ করেছে, সাধারণত সব শ্রেণি একই ইন্টারফেস প্রয়োগ করে (বা একই বেস শ্রেণি থেকে অবতরণ করে) এবং কারখানার মাধ্যমে বাস্তবায়ন চয়ন করে এটি সম্পন্ন হয়।

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