StrangeWorker's Blog

奇妙な労働者の雑記帳

ホーム 連絡をする 同期する ( RSS 2.0 ) Login
投稿数  18  : 記事  0  : コメント  117  : トラックバック  2

書庫

日記カテゴリ

image

今までコマンドプロンプトでは描画処理をやったことがなかったので、試しに作ってみました。両方同じ動きをしますが、まずはソースを2種類載せます。

TimerCallbackを使用したバージョン.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
 
namespace ConsoleApplication88
{
    class Program
    {
        static void Main(string[] args)
        {
            // ウィンドウサイズを適切に設定
            Console.WindowHeight = 10;
            Console.WindowWidth = 24;
 
            // 時計描画
            var timer = new Timer(new TimerCallback(DrawClock), null, 0, 1000);
 
            while (true)
            {
                Console.Write("終了しますか?[Y/N] : ");
 
                // 終了待ち
                if ("Y" == Console.ReadLine().ToUpper())
                {
                    timer.Dispose();
                    break;
                }
                else
                {
                    Console.CursorTop = 0;
                    Console.Clear();
                }
            }
        }
 
        /// 
        /// コンソールのウィンドウプロセスを取得
        /// 
        /// 
        static Process GetConsoleProcess()
        {
            foreach (Process p in Process.GetProcesses())
                if (p.MainWindowTitle == Console.Title)
                    return p;
            return null;
        }
 
        /// 
        /// 時計描画
        /// 
        static void DrawClock(object state)
        {
            // コンソールのウィンドウハンドルから描画クラス取得
            var g = Graphics.FromHwnd(GetConsoleProcess().MainWindowHandle);
 
            // チラつき防止のためのバッファ領域
            var bmp = new Bitmap(150, 150);
            var gBuffer = Graphics.FromImage(bmp);
 
            // 座標系の原点を変える
            gBuffer.TranslateTransform(110 / 2, 110 / 2, MatrixOrder.Append);
 
            var center = new Point(0, 0);
            var time = DateTime.Now;
            var r = Math.Min(110, 110) / 2;
 
            // 時計の部品を描画する
            DrawClockBase(gBuffer, time);
            DrawSecondLine(gBuffer, time, r, center);
            DrawMinuteLine(gBuffer, time, r, center);
            DrawHour(gBuffer, time, r, center);
 
            // 実描画
            g.DrawImage(bmp, new Point(40, 30));
        }
 
        /// 
        /// 秒針描画
        /// 
        /// 
        /// 
        /// 
        /// 
        private static void DrawSecondLine(Graphics gBuffer, DateTime time, int r, Point center)
        {
            using (var bluePen = new Pen(Color.AliceBlue, 1))
            {
                var secAng = 2.0f * Math.PI * time.Second / 60.0f;
                var secHandLength = Convert.ToInt32(0.9f * r);
                var secHand = new Point(Convert.ToInt32(secHandLength * Math.Sin(secAng)), Convert.ToInt32(-secHandLength * Math.Cos(secAng)));
                gBuffer.DrawLine(bluePen, center, secHand);
            }
        }
 
        /// 
        /// 分針描画
        /// 
        /// 
        /// 
        /// 
        /// 
        private static void DrawMinuteLine(Graphics gBuffer, DateTime time, int r, Point center)
        {
            using (var greenPen = new Pen(Color.LightGreen, 2))
            {
                var minAng = 2.0f * Math.PI * (time.Minute + time.Second / 60.0f) / 60.0f;
                var minHandLength = Convert.ToInt32(0.7f * r);
                var minHand = new Point(Convert.ToInt32(minHandLength * Math.Sin(minAng)), Convert.ToInt32(-minHandLength * Math.Cos(minAng)));
                gBuffer.DrawLine(greenPen, center, minHand);
            }
        }
 
        /// 
        /// 時針描画
        /// 
        /// 
        /// 
        /// 
        /// 
        private static void DrawHour(Graphics gBuffer, DateTime time, int r, Point center)
        {
            using (var redPen = new Pen(Color.LightPink, 2))
            {
                var hourAng = 2.0f * Math.PI * (time.Hour + time.Minute / 60.0f) / 12.0f;
                var hourHandLength = Convert.ToInt32(0.5f * r);
                var hourHand = new Point(Convert.ToInt32(hourHandLength * Math.Sin(hourAng)), Convert.ToInt32(-hourHandLength * Math.Cos(hourAng)));
                gBuffer.DrawLine(redPen, center, hourHand);
            }
        }
 
        /// 
        /// 時計の針以外を描画
        /// 
        /// 
        static void DrawClockBase(Graphics gBuffer, DateTime time)
        {
            // 円
            using (var circlePen = new Pen(Color.AliceBlue, 2))
            {
                gBuffer.Clear(Color.Black);
                gBuffer.FillEllipse(Brushes.AliceBlue, -2.5f, -2.5f, 5f, 5f);
                gBuffer.DrawEllipse(circlePen, -110 / 2, -110 / 2, 110, 110);
            }
 
            // フォント指定
            var msGothicFont = new Font("MS ゴシック", 15, FontStyle.Bold, GraphicsUnit.Pixel);
 
            // 目盛り
            using (var scalePen = new Pen(Color.Aqua, 1))
            {
                Enumerable.Range(1, 60).ToList().ForEach(i =>
                {
                    var k = i * 6 * (Math.PI / 180);
 
                    // 見易いように5目盛りごとに長さを変える
                    var length = 0 == i % 5 ? 35 : 40;
                    var x = Convert.ToInt32(Math.Sin(k) * length);
                    var y = -Convert.ToInt32(Math.Cos(k) * length);
                    var x1 = Convert.ToInt32(Math.Sin(k) * 45);
                    var y1 = -Convert.ToInt32(Math.Cos(k) * 45);
                    gBuffer.DrawLine(scalePen, x, y, x1, y1);
 
                    // 5目盛りごとに数字を表示
                    if (0 == i % 5)
                    {
                        var timeText = (i / 5).ToString();
                        var fontSize = gBuffer.MeasureString(timeText, msGothicFont);
                        gBuffer.DrawString(timeText, msGothicFont, Brushes.White, new PointF(x1 - fontSize.Width / 2, y1 - fontSize.Height / 2));
                    }
                });
            }
            var textSize = gBuffer.MeasureString("HH:mm:ss", msGothicFont);
            gBuffer.DrawString(time.ToString("HH:mm:ss"), msGothicFont, Brushes.White, new PointF(-textSize.Width / 2, 65));
        }
    }
}

Thread.Abortによる強制終了を行うバージョン.cs

using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Threading;
 
namespace ConsoleApplication92
{
    class Program
    {
        private const int MAX_SIZE = 110;
        private const int DRAW_START = 40;
        private const int DIGITAL_TIME_TOP = 65;
        private const int FONT_SIZE = 15;
        private const int LONG_SCALE = 40;
        private const int SHORT_SCALE = 35;
        private const int SCALE_LENGTH = 45;
        private const int CIRCLE_WIDTH = 3;
        private const int WINDOW_HEIGHT = 10;
        private const int WINDOW_WIDTH = 24;
        private const string FONT_NAME = "MS ゴシック";
        private const string TIME_FORMAT = "HH:mm:ss";
 
        /// 
        /// メイン
        /// 
        /// 
        static void Main(string[] args)
        {
            // ウィンドウサイズを適切に設定
            Console.WindowHeight = WINDOW_HEIGHT;
            Console.WindowWidth = WINDOW_WIDTH;
 
            // 時計描画スレッド
            var thread = new Thread(DrawClock);
            thread.Start();
 
            // 入力待ちメインスレッド
            while (true)
            {
                Console.Write("終了しますか?[Y/N] : ");
 
                // 終了待ち
                if ("Y" == Console.ReadLine().ToUpper())
                {
                    ThreadStop(thread);
                    thread.Join();
                    break;
                }
                else
                {
                    Console.CursorTop = 0;
                    Console.Clear();
                }
            }
        }
 
        /// 
        /// スレッド中止
        /// 
        /// 
        static void ThreadStop(Thread thread)
        {
            try
            {
                thread.Abort();
            }
            catch (ThreadAbortException)
            {
                // あえてスルーする
            }
        }
 
        /// 
        /// 時計描画
        /// 
        static void DrawClock()
        {
            // コンソールのウィンドウハンドルから描画クラス取得
            var process = Process.GetProcesses().ToList().Where(p => p.MainWindowTitle == Console.Title).SingleOrDefault();
            var g = Graphics.FromHwnd(process.MainWindowHandle);
 
            // チラつき防止のためのバッファ領域
            var msGothicFont = new Font(FONT_NAME, FONT_SIZE, FontStyle.Bold, GraphicsUnit.Pixel);
            var fontSize = g.MeasureString(string.Empty, msGothicFont);
            var bmp = new Bitmap(MAX_SIZE + CIRCLE_WIDTH, MAX_SIZE + CIRCLE_WIDTH + DIGITAL_TIME_TOP + Convert.ToInt32(fontSize.Height));
            var gBuffer = Graphics.FromImage(bmp);
 
            // 座標系の原点を変える
            gBuffer.TranslateTransform((MAX_SIZE + CIRCLE_WIDTH) / 2, (MAX_SIZE + CIRCLE_WIDTH) / 2, MatrixOrder.Append);
 
            var center = new Point(0, 0);
            var r = MAX_SIZE / 2;
 
            while (true)
            {
                var time = DateTime.Now;
 
                // 時計の部品を描画する
                DrawClockBase(gBuffer, time);
                DrawSecondLine(gBuffer, time, r, center);
                DrawMinuteLine(gBuffer, time, r, center);
                DrawHourLine(gBuffer, time, r, center);
 
                // 実描画
                g.DrawImage(bmp, new Point(DRAW_START, DRAW_START));
 
                // 一秒置き
                Thread.Sleep(1000);
            }
        }
 
        /// 
        /// 秒針描画
        /// 
        /// 
        /// 
        /// 
        /// 
        private static void DrawSecondLine(Graphics gBuffer, DateTime time, int r, Point center)
        {
            using (var bluePen = new Pen(Color.AliceBlue, 1))
            {
                var secAng = 2.0f * Math.PI * time.Second / 60.0f;
                var secHandLength = Convert.ToInt32(0.9f * r);
                var secHand = new Point(Convert.ToInt32(secHandLength * Math.Sin(secAng)), Convert.ToInt32(-secHandLength * Math.Cos(secAng)));
                gBuffer.DrawLine(bluePen, center, secHand);
            }
        }
 
        /// 
        /// 分針描画
        /// 
        /// 
        /// 
        /// 
        /// 
        private static void DrawMinuteLine(Graphics gBuffer, DateTime time, int r, Point center)
        {
            using (var greenPen = new Pen(Color.LightGreen, 2))
            {
                var minAng = 2.0f * Math.PI * (time.Minute + time.Second / 60.0f) / 60.0f;
                var minHandLength = Convert.ToInt32(0.7f * r);
                var minHand = new Point(Convert.ToInt32(minHandLength * Math.Sin(minAng)), Convert.ToInt32(-minHandLength * Math.Cos(minAng)));
                gBuffer.DrawLine(greenPen, center, minHand);
            }
        }
 
        /// 
        /// 時針描画
        /// 
        /// 
        /// 
        /// 
        /// 
        private static void DrawHourLine(Graphics gBuffer, DateTime time, int r, Point center)
        {
            using (var redPen = new Pen(Color.LightPink, 2))
            {
                var hourAng = 2.0f * Math.PI * (time.Hour + time.Minute / 60.0f) / 12.0f;
                var hourHandLength = Convert.ToInt32(0.5f * r);
                var hourHand = new Point(Convert.ToInt32(hourHandLength * Math.Sin(hourAng)), Convert.ToInt32(-hourHandLength * Math.Cos(hourAng)));
                gBuffer.DrawLine(redPen, center, hourHand);
            }
        }
 
        /// 
        /// 時計の針以外を描画
        /// 
        /// 
        static void DrawClockBase(Graphics gBuffer, DateTime time)
        {
            // 外円
            DrawCircle(gBuffer);
 
            // 目盛り
            DrawScale(gBuffer);
 
            // デジタル時計
            DrawDigitalTime(gBuffer, time);
        }
 
        /// 
        /// 外円描画
        /// 
        /// 
        static void DrawCircle(Graphics gBuffer)
        {
            using (var circlePen = new Pen(Color.AliceBlue, CIRCLE_WIDTH))
            {
                gBuffer.Clear(Color.Black);
                gBuffer.FillEllipse(Brushes.AliceBlue, -2.5f, -2.5f, 5f, 5f);
                gBuffer.DrawEllipse(circlePen, -MAX_SIZE / 2, -MAX_SIZE / 2, MAX_SIZE, MAX_SIZE);
            }
        }
 
        /// 
        /// 目盛り描画
        /// 
        /// 
        static void DrawScale(Graphics gBuffer)
        {
            var msGothicFont = new Font(FONT_NAME, FONT_SIZE, FontStyle.Bold, GraphicsUnit.Pixel);
 
            using (var scalePen = new Pen(Color.Aqua, 1))
            {
                Enumerable.Range(1, 60).ToList().ForEach(i =>
                {
                    var angle = i * 6 * (Math.PI / 180);
 
                    // 見易いように5目盛りごとに長さを変える
                    var length = 0 == i % 5 ? SHORT_SCALE : LONG_SCALE;
                    var x = Convert.ToInt32(Math.Sin(angle) * length);
                    var y = -Convert.ToInt32(Math.Cos(angle) * length);
                    var x1 = Convert.ToInt32(Math.Sin(angle) * SCALE_LENGTH);
                    var y1 = -Convert.ToInt32(Math.Cos(angle) * SCALE_LENGTH);
                    gBuffer.DrawLine(scalePen, x, y, x1, y1);
 
                    // 5目盛りごとに数字を表示
                    if (0 == i % 5)
                    {
                        var timeText = (i / 5).ToString();
                        var fontSize = gBuffer.MeasureString(timeText, msGothicFont);
                        gBuffer.DrawString(timeText, msGothicFont, Brushes.White, new PointF(x1 - fontSize.Width / 2, y1 - fontSize.Height / 2));
                    }
                });
            }
        }
 
        /// 
        /// デジタル時計描画
        /// 
        /// 
        /// 
        static void DrawDigitalTime(Graphics gBuffer, DateTime time)
        {
            var msGothicFont = new Font(FONT_NAME, FONT_SIZE, FontStyle.Bold, GraphicsUnit.Pixel);
            var textSize = gBuffer.MeasureString(TIME_FORMAT, msGothicFont);
            gBuffer.DrawString(time.ToString(TIME_FORMAT), msGothicFont, Brushes.White, new PointF(-textSize.Width / 2, DIGITAL_TIME_TOP));
        }
    }
}

基本構造はどちらも同じです。違うのはスレッドの扱いのみ。

Thread.Abort版の方が無駄が少ないように思うので、もう少しいじってみようと思います。

現時点ではここまで。

投稿日時 : 2009年3月11日 2:00

コメント

# re: コマンドプロンプトで動くアナログ時計を作る 2009/03/11 2:11 StrangeWorker
やっとまともに投稿できた。

画像の格納先URLが間違っててずっと非表示になってしまっていました。
それで疑問なんですが、この構造のプログラムの場合、
TimerCallbackを使った場合と、Thread.Abortで落とす場合、
どちらがいいんでしょう?

気持ち的にはTimerCallbackかなと思うんですが、
そうするとウィンドウハンドルの取得とかビットマップの再生成とか
何度もやらなくていいことを何度もやることになってしまっています。
(privateメンバで持ってればいいだけと言う気もしますが)

読むのは面倒だと思うのですが、基本的に新規プロジェクトに
コピペしてもらえば動くようにしてあるので、
「ここはこうした方がいい」とかいうのを教えてください。

# re: コマンドプロンプトで動くアナログ時計を作る 2009/03/11 11:17 とっちゃん
Timer は、System.Threading.Timer のタイマーですよね?

この場合は、再入が考慮がなされていない(上書きされまくり)ので、対策としては今一つですね...

ま、それはそれとして、Graphics オブジェクトは Dispose が必要です。

using( var g=Graphics....)
として、Dispose してあげましょう。

それと、スレッドの終了に Abort を使ってはいけません。

今回の場合、スレッド内部で Graphics などの IDisposable インターフェースを抱えたオブジェクトがいるのでなおさらです。

このような場合は、ManualResetEvent クラスなどを使って、明確な終了シグナルを送れるようにすることをお勧めします。

そのうえで、段取り的には、スレッド内の Sleep() してるループを
WaitOne(1000) でタイムアウト待ちというループにすることで、安全に作業をすることができるようになります。
最悪パターンでも描画時間(かかって100ミリ秒程度)でスレッド終了の段取りになるので、大きな影響もないと思います。


# re: コマンドプロンプトで動くアナログ時計を作る 2009/03/11 18:57 StrangeWorker
> とっちゃんさん

色々ありがとうございます。
順を追って修正して行こうと思います!

# re: コマンドプロンプトで動くアナログ時計を作る 2009/03/11 20:41 StrangeWorker
Graphicsの対応は単純に終わったのですが、
ManualResetEvent の方が理解できません。
一応無理矢理↓のようにやってもみたのですが、
これじゃ利点がないですよね?
もう少しヒントをお願いします。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ConsoleApplication94
{
class Class1
{
private static ManualResetEvent m_ManualReset;
private static bool m_Loop = true;

public static void Main()
{
m_ManualReset = new ManualResetEvent(false);
var thread =new Thread(new ThreadStart(ThreadMethod));
thread.Start();

Console.WriteLine("Enterキーを押してください");
Console.ReadLine();

m_ManualReset.Set();
m_Loop = false;

Console.WriteLine("メインスレッド終了");
Console.ReadLine();
}

private static void ThreadMethod()
{
Console.WriteLine("別スレッド開始");
while (m_Loop)
{
Console.WriteLine("別スレッド実行中");
m_ManualReset.WaitOne(1000);
}
Console.WriteLine("別スレッド終了");
}
}
}

# re: コマンドプロンプトで動くアナログ時計を作る 2009/03/11 20:50 StrangeWorker
インデントが潰れないように全角に置き換えてみました

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ConsoleApplication94
{
  class Class1
  {
    private static ManualResetEvent m_ManualReset;
    private static bool m_Loop = true;

    public static void Main()
    {
      m_ManualReset = new ManualResetEvent(false);
      var thread =new Thread(new ThreadStart(ThreadMethod));
      thread.Start();

      Console.WriteLine("Enterキーを押してください");
      Console.ReadLine();

      m_ManualReset.Set();
      m_Loop = false;

      Console.WriteLine("メインスレッド終了");
      Console.ReadLine();
    }

    private static void ThreadMethod()
    {
      Console.WriteLine("別スレッド開始");
      while (m_Loop)
      {
        Console.WriteLine("別スレッド実行中");
        m_ManualReset.WaitOne(1000);
      }
      Console.WriteLine("別スレッド終了");
    }
  }
}

# スレッドの安全な終了 2009/03/11 21:35 とっちゃん's Blog
スレッドの安全な終了

# re: コマンドプロンプトで動くアナログ時計を作る 2009/03/11 21:38 とっちゃん
TB飛んでるけど、メールいかないので。。。コメントw
サンプルソースをおいらのブログに貼り付けました。

あえて解説は入れてませんが、わかりやすさを前面に押し出して、変数は局所性を持たせています。


# re: コマンドプロンプトで動くアナログ時計を作る 2009/03/11 22:01 StrangeWorker
わざわざThread.Startにobjectを渡せる意味がやっとわかりました。クラスさえ用意すればいくらでも何でもローカル変数で扱えますね。
向こうにコメント書けなかったので、こちらで失礼します。

# re: コマンドプロンプトで動くアナログ時計を作る 2009/03/11 22:43 とっちゃん
そうですね。クラスオブジェクトを渡すことでいろいろなものを一括して渡せるようになります。

受け渡し用のオブジェクトでロックもかけられるし、そういう点では、.NET Framework はマルチスレッドアプリを作りやすくなっているというのはありますね。
#この程度なら、Native で書いてもコード量的には大差ないですけどw

>向こうにコメント書けなかったので
わんくま鯖がキャパぎりぎりで動いているので
しょっちゅう内部的にリセット処理が入っているようです。

なので、Submitボタンを押す前にテキストの内容をコピーしておいて、失敗したらまたリトライできるようにしておくといいですよw


# re: コマンドプロンプトで動くアナログ時計を作る 2009/03/13 8:42 StrangeWorker
なるほど、やっぱりわんくまサーバーは常時不安定な状態なんですね。
今後はテキスト内容のコピーを徹底するようにします!

# re: コマンドプロンプトで動くアナログ時計を作る 2009/03/13 10:58 とっちゃん
今は、残念ながら常時といえる状況です...orz
どうも .Text の設計キャパシティ超えてるらしくて...
要するに人大杉ってことなんですがねw

現在ほかのBlogエンジンへの入れ替えを検討しているので
いずれ、まともになる。。。と思います。

あとは、場合によっては、ブラウザの戻るボタンで復帰できることもありますw<期待してはいけないw

# ルイビトン 激安 2017/06/19 14:57 hxyufte@ezweb.ne.jp
ヴィトンコピー品激安販売店2017新品大SALE
ルイ・ヴィトンコピー品激安販売店の新品大SALEが開催します。
ルイヴィトン人気コピー品、コピールイヴィトン新作、ルイヴィトンダミエコピー、ルイヴィトンモノグラムコピー、コピーブランド腕時計…
いろいろ新品が続々登場します。バッグ、靴、帽子、スカーフ...
お綺麗を展示ため、ぜひおすすめの逸品です。
時間の制限がない、いつでもご愛用頂きます。
ルイビトン 激安 http://www.bbagok.com

# ブランド通販店 2019/09/16 23:41 Georgefipse
弊社は各ランクのブランド商品満載し、ブランド通販店で一番信用のある店なので!。
品質はこちらが間違いなく保証します。
https://www.ginzaoff.com

■取扱ブランド ロレックス時計コピー、カルティエ時計コピー、IWC時計コピー、
ブライトリング時計コピー、パネライ時計コピー.
◆ スタイルが多い、品質がよい、価格が低い、実物写真!
◆ ご入金頂いてから最速4日、遅くとも7日程度でご指定場所へ発送出来る予定でございます
◆ 商品送料を無料にいたします

◆信用第一、良い品質、低価格は 私達の勝ち残りの切り札です。
◆ 当社の商品は絶対の自信が御座います。
◇ N品質 シリアル付きも有り 付属品完備!

◆ 必ずご満足頂ける品質の商品のみ販売しております。
◇ 品質を最大限本物と同等とする為に相応の材質にて製作している為です。
◆ 絶対に満足して頂ける品のみ皆様にお届け致します。

興味あれば、是非一度サイトをご覧になって下さい。
今後ともよろしくご愛顧くださいますよう、お願い申し上げます
https://www.ginzaoff.com
お取り引きを開始させていただきたく思います。
詳細に関してはどうぞお気軽にご連絡ください。

# 腕時計ショップ 2021/12/03 20:57 ldchjcjhoci@goo.ne.jp
ルイヴィトン財布
弊店では信用第一主義を徹底しており社員全員下記の方針のもとに頑張っています。
1.不適合品を入荷しない。
厳しく受け入れ検査を行い、お客様に満足いただける品質のいい物だけを入荷する。
2.不適合品を出荷しない。
出荷前に細部まで二重確認を行い、お客様からご注文頂いた商品を納期通り出荷する。
3.お客様からのクレームゼロ
お客様第一主義を徹底し、お客様からのお問い合わせ、苦情等に対して積極的かつ丁寧に対応いたします。

# シャネル チーク 72 楽天 2023/11/11 7:01 ukmdjx@ocn.ne.jp
発送も早く梱包も丁寧で、何より、手書きの手紙が入っていて心が温かくなりました!
また機会があったら、こちらのお店をのぞいてみたいと思います♪
ありがとうございました!
シャネル チーク 72 楽天 https://www.b2tokei.com/product/detail.aspx-id=9446.htm

# abella danger video https://abelladanger.online/ abella danger filmleri
2024/03/04 15:04 Adella
abella danger video https://abelladanger.online/ abella danger filmleri


# eva elfie new videos https://evaelfie.site/ eva elfie new video
2024/03/07 2:06 EvaElfie
eva elfie new videos https://evaelfie.site/ eva elfie new video


# como jogar aviator em moçambique https://aviatormocambique.site aviator moçambique
2024/03/11 20:48 AviatorMaz
como jogar aviator em moçambique https://aviatormocambique.site aviator moçambique


# play aviator: https://aviatorghana.pro/ aviator ghana
2024/03/12 6:37 AviatorGh
play aviator: https://aviatorghana.pro/ aviator ghana


# Misoprostol 200 mg buy online https://cytotec.club/ Abortion pills online 2024/04/27 18:56 Cytotec
Misoprostol 200 mg buy online https://cytotec.club/ Abortion pills online

Post Feedback

タイトル
名前
Url:
コメント: