اولین درخواست «بهینه‌سازی مسیر» خود را… با سگ‌ها انجام دهید

توسعه‌دهندگان منطقه اقتصادی اروپا (EEA)

این سند به شما نشان می‌دهد که چگونه اولین درخواست خود را به Route Optimization API بااستفاده از یک سناریو کاربردی در دنیای واقعی ارسال کنید.

برای سادگی، در این مثال از HTTP و JSON برای نمایش REST API استفاده می‌شود. بااین‌حال، برای محیط تولید شما، توصیه کلی این است که از gRPC استفاده کنید تا از مزایای عملکرد آن بهره‌مند شوید. بااین‌حال، gRPC به نصب نیاز دارد. برای اطلاعات بیشتر، به کتابخانه‌های کارخواه Route Optimization API مراجعه کنید.

سناریو

نقشه‌ای از سان‌فرانسیسکو با سنجاق‌هایی برای «برج کویت»، «پارک میشن دولورس»، و «پارک زمین بازی ساوت سانست»

شما از ساعت ۷ صبح تا ۷ بعدازظهر در سان فرانسیسکو خدمات مهدکودک سگ ارائه می‌دهید. امروز صبح می‌خواهید سه سگ را از مکان‌های مختلف در شهر بردارید و آن‌ها را به مرکز مراقبت روزانه خود بیاورید.

سگ کوهستانی برنی و چی‌واوا مشتریان همیشگی هستند که هفته گذشته قرارشان را رزرو کردند. ژرمن شپرد یک درخواست جدید و لحظه آخری است. می‌خواهید درصورت امکان، ژرمن شپرد را بپذیرید، اما نه به قیمت ازدست دادن مشتریان همیشگی‌تان.

یک ون برای این کار دارید و به راننده ساعتی ۲۷ دلار پرداخت می‌کنید. راننده و ون روز را ساعت ۷ صبح در مهدکودک شما شروع می‌کنند و باید تا ظهر برای استراحت ناهار از سوار کردن صبحگاهی برگردند.

امروز ۱۳ فوریه ۲۰۲۴ است. همه زمان‌ها در این سناریو به وقت محلی سانفرانسیسکو است که در ماه فوریه «زمان استاندارد اقیانوس آرام» (UTC-8) است. راننده تکالیف زیر را دارد:

  • سگ کوهستانی برنیز را نزدیک برج کویت بردارید. مالک درخواست کرد که بازه زمانی تحویل محدود و بین ۸ تا ۸:۲۰ صبح باشد.
  • سگ شی‌واوا را در پارک زمین بازی South Sunset بردارید. مالک بازه زمانی تحویل انعطاف‌پذیرتری را بین ساعت ۷:۳۰ تا ۹:۳۰ صبح پیشنهاد داد.
  • ژرمن شپرد را در لندز اند سوار کن. مالک همچنین درخواست کرد که زمان تحویل گرفتن کوتاه و بین ساعت ۸ تا ۸:۲۰ صبح باشد.
  • سگ‌ها را در مرکز نگهداری روزانه در پارک میشن دولورس پیاده کنید. مهدکودک تحویل کودکان را بین ۹:۳۰ صبح تا ۱۱:۳۰ صبح الزامی کرده است.

هر بازدید تحویل گرفتن و تحویل دادن ۵ دقیقه طول می‌کشد تا سگ سوار یا پیاده شود.

چون Land's End از Coit Tower دور است و پنجره‌های تحویل آن‌ها باهم تداخل دارد، راننده نمی‌تواند هر سه تحویل را انجام دهد. بهینه‌ساز باید انتخاب کند که از کدام سگ صرف‌نظر کند تا هزینه کل (دستمزد راننده و هرگونه جریمه صرف‌نظر کردن) را به‌حداقل برساند.

قبل‌از شروع

برای اجرای کد در این سناریو نمونه، ابتدا باید دستورالعمل‌های موجود در راه‌اندازی Route Optimization API را تکمیل کنید.

۱. رویکرد بهینه‌سازی مسیرتان را انتخاب کنید

Route Optimization API روش‌های متعددی دارد که می‌توانید بسته به پیچیدگی مسئله بهینه‌سازی‌تان از بین آن‌ها انتخاب کنید.

چون این سناریوی مهد سگ‌ها درخواستی کوچک و ساده است، از روش مسدودسازی مثل optimizeTours استفاده کنید که نتایج را به‌سرعت برای درخواست‌های کوچک ارائه می‌دهد. برای اطلاعات بیشتر درباره نقاط پایانی Route Optimization API، انتخاب نقطه پایانی را ببینید.

از نشانی وب زیر برای ایجاد درخواست HTTP POST به روش optimizeTours استفاده کنید:

https://routeoptimization.googleapis.com/v1/projects/PROJECT_OR_ID:optimizeTours

همچنین باید تنظیمات مهلت و زمان اتمام را کوتاه کنید تا زمان انتظار غیرضروری کاهش یابد. برای این سناریوی مهد سگ، بهینه‌ساز به زمان زیادی برای پاسخ دادن به درخواست شما نیاز ندارد، بنابراین از تنظیمات زیر استفاده کنید:

  • پارامتر timeout را روی ۲ ثانیه تنظیم کنید.
  • تنظیمات مهلت را روی پیش‌فرض بگذارید که برای درخواست‌های REST،‏ ۶۰ ثانیه است.

۲. ساختن متن اصلی پیام درخواست

پس‌از انتخاب روش مسدود کردن optimizeTours و تعریف تنظیمات مهلت و زمان اتمام، مرحله بعدی شما ساختن بدنه پیام درخواست است.

برای این سناریو، درخواست یک پیام OptimizeToursRequest است که به‌صورت JSON در REST API کدگذاری شده است.

برای ساختن پیام درخواست، مراحل زیر را دنبال کنید:

  1. با ساختار درخواست پایه شروع کنید که به‌صورت زیر است:

    {
      "timeout": ...,
      "model": {
        "shipments": [...],
        "vehicles": [...],
        "globalStartTime": "...",
        "globalEndTime": "..."
      }
    }
    

    برای اطلاعات بیشتر درباره ساختار، به راهنمای مفهوم کلیدی برای ساختار پایه (ShipmentModel،‏ Shipment، و Vehicle) مراجعه کنید.

  2. محموله‌ها را تعریف کنید. در فیلد shipments، برای هر سگی که باید صبح تحویل گرفته شود و برگردانده شود، پیامی Shipment اضافه کنید. اینجا جایی است که هریک از مکان‌ها و زمان‌های ترجیحی صاحب سگ برای تحویل گرفتن سگ و مکان و زمان‌های مرکز نگهداری روزانه برای تحویل دادن سگ را تعریف می‌کنید.

    1. برای هر سگ، یک VisitRequest برای تحویل گرفتن و یک دیگر برای تحویل دادن ایجاد کنید که در این سناریو به آن تحویل دادن به مهدکودک گفته می‌شود.

      • در pickups،‏ arrivalWaypoint را روی مکان سوار کردن سگ تنظیم کنید (Coit Tower برای سگ کوهستانی برنی، South Sunset Playground Park برای چی‌واوا، یا Land's End برای ژرمن شپرد). timeWindows را روی زمان تحویل درخواستی مالک تنظیم کنید (۸ تا ۸:۲۰ صبح برای سگ کوهستانی برنی و ژرمن شپرد، و ۷:۳۰ تا ۹:۳۰ صبح برای چی‌واوا).

      • در تحویل‌ها، arrivalWaypoint را روی مهدکودک و timeWindows را روی زمان تحویل موردنیاز (۹:۳۰ صبح تا ۱۱:۳۰ صبح) تنظیم کنید.

      • برای همه تحویل گرفتن‌ها و تحویل دادن‌ها، duration را روی ۵ دقیقه (300s) تنظیم کنید تا زمان سوار و پیاده کردن سگ‌ها درنظر گرفته شود.

      برای اطلاعات بیشتر درباره پنجره‌های زمانی، به پنجره‌های زمانی مراجعه کنید.

    2. برای اولویت دادن به مشتریان همیشگی، penaltyCost را برای سگ کوهستانی برنیز و چی‌واوا روی 1000 و برای ژرمن شپرد روی 100 تنظیم می‌کنید. با تنظیم هزینه‌های جریمه، بهینه‌ساز می‌تواند از هرکدام از سگ‌ها صرف‌نظر کند، اما اگر محدودیت‌ها انجام همه سوار کردن‌ها را غیرممکن کند، ابتدا صرف‌نظر کردن از ژرمن شپرد (که جریمه کمتری دارد) را درنظر می‌گیرد.

    3. می‌توانید از فیلد label برای افزودن شناسه برای هر محموله استفاده کنید، مثلاً «سگ کوهستانی برن»، «چی‌واوا»، و «ژرمن شپرد». این کار می‌تواند به شما کمک کند محموله‌ها را در پاسخ شناسایی کنید.

    برای اطلاعات بیشتر درباره تعریف محموله‌ها، به محموله مراجعه کنید.

  3. تعریف وسایل نقلیه. در فیلد vehicles، پیامی Vehicle برای یک ون خود اضافه کنید که مهدکودک را به‌عنوان نقطه شروع و پایان، هزینه دستمزد راننده، و ساعات عملیاتی ون نشان دهد.

    1. startWaypoint و endWaypoint را برای ون روی مکان‌های شروع و پایان روز تنظیم کنید، که همان مهدکودک نزدیک پارک میشن دولورس است.

    2. برای به‌حداقل رساندن هزینه‌های عملیات، باید محدودیت‌های هزینه کسب‌وکارتان را تعریف کنید. پارامتر هزینه costPerHour را روی 27 تنظیم کنید، که همان مبلغی است که به راننده برای راندن ون مهد سگ‌ها پرداخت می‌کنید. برای اطلاعات بیشتر درباره پارامترهای هزینه، به مدل هزینه مراجعه کنید.

    3. برای اطمینان از اینکه بهینه‌ساز مسیری را در ساعات عملیاتی ون ایجاد می‌کند، یک پنجره عملیاتی برای خودرو تعریف کنید. این پنجره محدودیت‌های زمانی شروع و پایان را برای مسیر تعیین می‌کند. با تعریف کردن فقط یک نیمه از هر پنجره زمانی، به بهینه‌ساز انعطاف‌پذیری می‌دهید تا مسیر را دیرتر شروع کند یا زودتر به‌پایان برساند:

      • تنظیم کردن startTime در startTimeWindows روی ۷ صبح یعنی راننده می‌تواند نوبت کاری‌اش را از ساعت ۷ صبح شروع کند. همچنین اگر سوار کردن صبح زود وجود نداشته باشد، می‌تواند دیرتر شروع کند.

      • تنظیم endTime در endTimeWindows روی ظهر به این معنی است که راننده باید نوبت کاری‌اش را تا ظهر تمام کند. همچنین می‌توانند به‌محض تکمیل آخرین تحویل، شیفت خود را به‌پایان برسانند.

      حذف نیمه دیگر پنجره‌ها زمان انتظار و انحراف راننده را به حداقل می‌رساند. برای اطلاعات بیشتر درباره پنجره‌های زمانی، به پنجره‌های زمانی مراجعه کنید.

    برای اطلاعات بیشتر درباره تعریف خودروها، خودرو را ببینید.

  4. پنجره زمانی سراسری تنظیم کنید. پنجره زمانی جهانی نشان‌دهنده بازه زمانی‌ای است که ون می‌تواند درطول روز برای مهدکودک شما سوار و پیاده کند. برای این سناریو، globalStartTime را روی ساعت ۷ صبح و globalEndTime را روی ساعت ۷ عصر برای ۱۳ فوریه ۲۰۲۴ تنظیم کنید که نشان‌دهنده ساعات کاری مهد سگ شما است.

۳. ارسال درخواست

در زیر یک درخواست ساده curl براساس سناریو مهد سگ‌ها آورده شده است و از روش مسدودسازی optimizeTours استفاده می‌کند.

قبل‌از ارسال درخواست، PROJECT_NUMBER_OR_ID را در کد نمونه با شناسه پروژه Google Cloud خودتان جایگزین کنید.

curl -X POST 'https://routeoptimization.googleapis.com/v1/projects/PROJECT_NUMBER_OR_ID:optimizeTours' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
--data @- << EOM
{
  "timeout": "2s",
  "model": {
    "shipments": [
      {
        "pickups": [
          {
            "arrivalWaypoint": {
              "location": {
                "latLng": {
                  "latitude": 37.802395,
                  "longitude": -122.405822
                }
              }
            },
            "timeWindows": [
              {
                "startTime": "2024-02-13T08:00:00-08:00",
                "endTime": "2024-02-13T08:20:00-08:00"
              }
            ],
            "duration": "300s"
          }
        ],
        "deliveries": [
          {
            "arrivalWaypoint": {
              "location": {
                "latLng": {
                  "latitude": 37.759719,
                  "longitude": -122.42798
                }
              }
            },
            "timeWindows": [
              {
                "startTime": "2024-02-13T09:30:00-08:00",
                "endTime": "2024-02-13T11:30:00-08:00"
              }
            ],
            "duration": "300s"
          }
        ],
        "label": "Bernese mountain dog",
        "penaltyCost": 1000
      },
      {
        "pickups": [
          {
            "arrivalWaypoint": {
              "location": {
                "latLng": {
                  "latitude": 37.738067,
                  "longitude": -122.498593
                }
              }
            },
            "timeWindows": [
              {
                "startTime": "2024-02-13T07:30:00-08:00",
                "endTime": "2024-02-13T09:30:00-08:00"
              }
            ],
            "duration": "300s"
          }
        ],
        "deliveries": [
          {
            "arrivalWaypoint": {
              "location": {
                "latLng": {
                  "latitude": 37.759719,
                  "longitude": -122.42798
                }
              }
            },
            "timeWindows": [
              {
                "startTime": "2024-02-13T09:30:00-08:00",
                "endTime": "2024-02-13T11:30:00-08:00"
              }
            ],
            "duration": "300s"
          }
        ],
        "label": "Chihuahua",
        "penaltyCost": 1000
      },
      {
        "pickups": [
          {
            "arrivalWaypoint": {
              "location": {
                "latLng": {
                  "latitude": 37.78018,
                  "longitude": -122.51194
                }
              }
            },
            "timeWindows": [
              {
                "startTime": "2024-02-13T08:00:00-08:00",
                "endTime": "2024-02-13T08:20:00-08:00"
              }
            ],
            "duration": "300s"
          }
        ],
        "deliveries": [
          {
            "arrivalWaypoint": {
              "location": {
                "latLng": {
                  "latitude": 37.759719,
                  "longitude": -122.42798
                }
              }
            },
            "timeWindows": [
              {
                "startTime": "2024-02-13T09:30:00-08:00",
                "endTime": "2024-02-13T11:30:00-08:00"
              }
            ],
            "duration": "300s"
          }
        ],
        "label": "German shepherd",
        "penaltyCost": 100
      }
    ],
    "vehicles": [
      {
        "startWaypoint": {
          "location": {
            "latLng": {
              "latitude": 37.759719,
              "longitude": -122.42798
            }
          }
        },
        "endWaypoint": {
          "location": {
            "latLng": {
              "latitude": 37.759719,
              "longitude": -122.42798
            }
          }
        },
        "costPerHour": 27,
        "startTimeWindows": [
          {
            "startTime": "2024-02-13T07:00:00-08:00"
          }
        ],
        "endTimeWindows": [
          {
            "endTime": "2024-02-13T12:00:00-08:00"
          }
        ]
      }
    ],
    "globalStartTime": "2024-02-13T07:00:00-08:00",
    "globalEndTime": "2024-02-13T19:00:00-08:00"
  }
}
EOM

پارامترهای درخواست استفاده‌شده در درخواست

جدول زیر پارامترهای درخواست استفاده‌شده در بدنه درخواست سناریوی نمونه را شرح می‌دهد. می‌توانید محتوا را براساس والد یا جستجوی نوشتاری فیلتر کنید.

والدین پارامتر نوع خصوصیت شرح
OptimizeToursRequest model شیء (ShipmentModel) این هسته درخواست شما است. این یک شیء واحد است که در آن کل مسئله خود را تعریف می‌کنید، ازجمله همه سگ‌هایی که باید سوار و پیاده کنید (shipments) و ون موجود در ناوگان شما (vehicles). آن را به‌عنوان طرح کامل مسئله‌ای که باید بهینه‌سازی کنید درنظر بگیرید.
timeout مدت این پارامتر حداکثر زمانی را که سرور روی درخواست کار می‌کند پیش‌از برگرداندن پاسخ مشخص می‌کند. از این پارامتر برای کوتاه کردن زمان انتظار استفاده کنید. برای درخواست‌های کوچک و سریع، مثل این سناریو مهد سگ، این مقدار را روی ۲ ثانیه تنظیم کنید.
ShipmentModel shipments[] آرایه اشیا (Shipment) این آرایه‌ای از اشیا است که هر شیء نشان‌دهنده سگی است که باید سوار یا پیاده شود.
vehicles[] آرایه اشیا (Vehicle) این آرایه‌ای از اشیا است که هر شیء یک خودرو را در ناوگان شما تعریف می‌کند. در این بخش منابعتان را شرح می‌دهید، مثلاً ونی که مسافران را سوار و پیاده می‌کند. برای دریافت مسیر بهینه‌سازی‌شده، باید حداقل یک خودرو تعریف کنید.
globalStartTime مُهر زمان این زودترین زمان ممکن برای وقوع هر رویدادی در کل مدل شما است. این پارامتر مسئله بهینه‌سازی را ازنظر زمانی محدود می‌کند که برای محاسبات دقیق ترافیک و مسیریابی بسیار مهم است. برای این سناریو مهد سگ، این مقدار را روی زودترین زمانی که راننده می‌تواند ون را در آن روز براند تنظیم کنید، که ۷ صبح ۱۳ فوریه ۲۰۲۴ است.
globalEndTime مُهر زمان این آخرین زمان ممکن برای وقوع هر رویدادی در کل مدل شما است. برای این سناریوی مهد سگ، این مقدار را روی زمانی تنظیم کنید که انتظار می‌رود ون کار خود را به‌پایان برساند، یعنی ساعت ۷ بعدازظهر ۱۳ فوریه ۲۰۲۴.
Shipment pickups[] آرایه اشیا (VisitRequest) این فهرست همه گزینه‌های ممکن برای تحویل گرفتن محموله است. بهینه‌ساز بهترین روش را برای حل مسئله شما انتخاب می‌کند. برای این سناریو مهدکودک سگ‌ها، مکان‌های تحویل و بازه‌های زمانی را که هر مالک برای هر سگ ارائه کرده است فهرست کن.
deliveries[] آرایه اشیا (VisitRequest) این فهرستی از همه گزینه‌های ممکن برای تحویل محموله است. بهینه‌ساز بهترین روش را برای حل مسئله شما انتخاب می‌کند. برای این سناریو مهدکلاغ سگ‌ها، مکان مهدکلاغ سگ‌ها و بازه زمانی‌ای را که راننده باید برای ناهار هر سگ برگردد فهرست کن.
label رشته این شناسه مربوط به محموله خاصی در درخواست شما است. می‌توانید برچسب‌ها را در درخواستتان مشخص کنید تا خواندن پاسخ آسان‌تر شود. برای این سناریوی مهد سگ‌ها، از رشته توصیفی مانند «Chihuahua»، «Bernese mountain dog»، یا نام سگ استفاده کنید تا وقتی پاسخ میانای برنامه‌سازی کاربردی را دریافت می‌کنید، راه‌حل با ورودی شما مطابقت داشته باشد.
penaltyCost دو نفره این هزینه جریمه‌ای است که درصورت رد شدن این محموله توسط بهینه‌ساز اعمال می‌شود. به‌طور پیش‌فرض، محموله‌ها اجباری هستند—بهینه‌ساز اولویت را به حداقل رساندن محموله‌های اجباری نادیده‌گرفته‌شده می‌دهد و فقط زمانی آن‌ها را نادیده می‌گیرد که گزینه دیگری وجود نداشته باشد. تنظیم هزینه جریمه به بهینه‌ساز اجازه می‌دهد تا اگر ارسال محموله غیرممکن یا بسیار پرهزینه باشد، از آن صرف‌نظر کند و به شما امکان می‌دهد اولویت‌ها را بین محموله‌ها بسنجید. در این سناریو، هزینه جریمه بالاتری (1000) برای مشتریان همیشگی‌تان (سگ کوهستانی برنی و چی‌واوا) و هزینه جریمه پایین‌تری (100) برای درخواست لحظه آخری ژرمن شپرد تعیین می‌کنید. این به بهینه‌ساز می‌گوید که مشتریان عادی را در اولویت قرار دهد، بنابراین وقتی نمی‌تواند همه تحویل‌ها را انجام دهد، ابتدا صرف‌نظر کردن از ژرمن شپرد را درنظر می‌گیرد.
VisitRequest arrivalWaypoint شیء (Waypoint) این مکان بازدید خاصی در مسیر است. می‌توانید این را بااستفاده از مختصات طول و عرض جغرافیایی، شناسه مکان، یا عنوان تعریف کنید. در این سناریو مهدکودک سگ، این را روی مکانی که مالک برای pickups ارائه کرده است و روی نشانی مهدکودک برای deliveries تنظیم کنید.
timeWindows[] آرایه اشیا (TimeWindow) این آرایه‌ای از اشیاء است که محدودیت‌های زمانی را برای تحویل گرفتن یا تحویل دادن تعریف می‌کند. برای این سناریو، از این مورد برای تعریف پنجره زمانی تحویل گرفتن هریک از سگ‌ها و پنجره زمانی قابل‌قبول برای تحویل دادن سگ‌ها به مرکز نگهداری روزانه استفاده کنید.
duration مدت این پارامتر مدت بازدید را مشخص می‌کند (مثلاً زمان بارگیری یا تخلیه بار). در این سناریو، شما یک بافر ۵ دقیقه‌ای (300s) برای همه سوار کردن‌ها و تحویل‌ها تنظیم می‌کنید تا زمان بارگیری و تخلیه سگ‌ها توسط راننده را درنظر بگیرید.
Vehicle startWaypoint شیء (Waypoint) این مکان شروع مسیر خودرو است که با مختصات طول و عرض جغرافیایی یا شناسه مکان تعریف می‌شود. این پارامتر به بهینه‌ساز می‌گوید که خودرو باید مسیر را از کجا شروع کند. اگر این نقطه‌مسیر را تعریف نکنید، بهینه‌ساز یکی از تحویل‌ها یا ارسال‌ها را به‌عنوان مکان شروع انتخاب می‌کند. برای این سناریو مهدکودک سگ‌ها، چون راننده روز را در مهدکودک شروع می‌کند، از مختصات Mission Dolores Park استفاده کنید.
endWaypoint شیء (Waypoint) این مقصد نهایی برای مسیر خودرو است که با مختصات طول و عرض جغرافیایی یا شناسه مکان تعریف می‌شود. این پارامتر به بهینه‌ساز می‌گوید که وسیله نقلیه کجا باید مسیر را به‌پایان برساند. اگر این نقطه‌مسیر را تعریف نکنید، بهینه‌ساز یکی از سوار کردن‌ها یا تحویل‌ها را به‌عنوان پایان مسیر انتخاب می‌کند. برای این سناریو مهدکودک سگ، چون راننده باید روز را در مرکز مهدکودک به‌پایان برساند، از مختصات Mission Dolores Park استفاده کنید.
costPerHour شماره این هزینه برای هر ساعت استفاده از وسیله نقلیه، صرف‌نظر از اینکه درحال حرکت باشد یا متوقف شده باشد، محاسبه می‌شود. برای این سناریو مهدکودک سگ، از این برای مدل‌سازی دستمزد ساعتی راننده استفاده کنید.
startTimeWindows[] آرایه اشیا (TimeWindow) این بازه زمانی قابل‌قبول برای زمانی است که راننده می‌تواند نوبت کاری خود را شروع کند. برای این سناریو مهد سگ‌ها، startTime را ۷ صبح تعریف کنید اما endTime را حذف کنید. این کار به بهینه‌ساز اجازه می‌دهد شروع نوبت کاری را درصورتی‌که اولین سوار کردن دیرتر در صبح باشد به‌تأخیر بیندازد. توجه داشته باشید که حتی اگر endTime را برای startTimeWindows ارائه نکنید، زمان شروع به‌طور ضمنی توسط endTimeWindows محدود می‌شود. خودرو باید قبل‌از پایان مسیر، آن را شروع کند.
endTimeWindows[] آرایه اشیا (TimeWindow) این بازه زمانی قابل‌قبول برای راننده است تا مسیر را تمام کند. برای این سناریو مهدکودک سگ، endTime را به‌عنوان ظهر تعریف کنید اما startTime را حذف کنید. این کار به راننده اجازه می‌دهد بلافاصله پس‌از آخرین پیاده کردن، به مهدکودک برگردد.

بعدی

تفسیر پاسخ