SAPikachu的工作室

You can't call your encoding speed slow until you start measuring in seconds per frame.

小技巧:在VB中使用Module模拟C#的静态类

clock March 4, 2010 12:53 by author SAPikachu

VB中建立助手类一般有两种方法,一是使用Module,另一个是用Class然后把成员全部声明为Shared。

不过这两种方法都有缺点,第一种方法由于VB的特性会污染命名空间;第二个需要显式声明Shared,如果以后要把代码转换到实例方法会很麻烦。(还有个问题是我经常忘记加,在调用成员失败的时候才想起来。。。)

最近发现了一个很简单的方法,能把两者的优点结合起来,范例:

   1:  
   2: Namespace Utils
   3:     <HideModuleName()> _
   4:     Module Utils
   5:         Public Sub XXX()
   6:             ' ...
   7:         End Sub
   8:     End Module
   9: End Module
  10:  
  11: ' 使用方法时Import ExcelUtils的上层命名空间即可
  12: Utils.XXX()

HideModuleName属性使VS的Intellisense在显示Utils命名空间的时候不显示类名,这样这个命名空间里面就只有Utils类的成员了,间接实现了静态类的效果。

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Silverlight小技巧:在XAML设置ComboBox.ItemsSource及SelectedIndex时的注意点

clock February 10, 2010 17:00 by author SAPikachu

刚才碰到个问题,运行SL程序后ComboBox总是显示为空白,即使设置了SelectedIndex也是一样。

弄了很久才想起来,ComboBox设置ItemsSource之后会把SelectedIndex重置为-1,所以SelectedIndex必须放在ItemsSource后面。

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Silverlight3小技巧:从Binding获取值

clock February 7, 2010 21:32 by author SAPikachu

BlendSDK里面的交互模式很好用,不过交互的类全部从DependencyObject继承,没办法绑定很不方便。于是就弄了这个类出来:

   1: Public NotInheritable Class BindingEvaluator(Of T)
   2:     Private Shared ReadOnly DummyProperty As DependencyProperty = DependencyProperty.RegisterAttached("Dummy", GetType(T), GetType(BindingEvaluator(Of T)), New PropertyMetadata(DependencyProperty.UnsetValue))
   3:  
   4:     Private Shared Function GetDummy(ByVal element As DependencyObject) As T
   5:         ' IMPORTANT: To maintain parity between setting a property in XAML and procedural code, do not touch the getter and setter inside this dependency property!
   6:         If (element Is Nothing) Then
   7:             Throw New ArgumentNullException("element")
   8:         End If
   9:         Return CType(element.GetValue(BindingEvaluator(Of T).DummyProperty), T)
  10:     End Function
  11:     Private Shared Sub SetDummy(ByVal element As DependencyObject, ByVal value As T)
  12:         ' IMPORTANT: To maintain parity between setting a property in XAML and procedural code, do not touch the getter and setter inside this dependency property!
  13:         If (element Is Nothing) Then
  14:             Throw New ArgumentNullException("element")
  15:         End If
  16:         element.SetValue(BindingEvaluator(Of T).DummyProperty, value)
  17:     End Sub
  18:  
  19:     Public Shared Function GetValue(ByVal source As FrameworkElement, ByVal binding As Binding) As T
  20:         Dim value = GetRawValue(source, binding)
  21:         If value Is DependencyProperty.UnsetValue Then
  22:             Return Nothing
  23:         End If
  24:         Return CType(value, T)
  25:     End Function
  26:  
  27:     Public Shared Function GetRawValue(ByVal source As FrameworkElement, ByVal binding As Binding) As Object
  28:         If source Is Nothing Then
  29:             Throw New ArgumentNullException("source", "source is nothing.")
  30:         End If
  31:         If binding Is Nothing Then
  32:             Throw New ArgumentNullException("binding", "binding is nothing.")
  33:         End If
  34:         Dim newBinding As New Binding() With { _
  35:             .BindsDirectlyToSource = binding.BindsDirectlyToSource, _
  36:             .Converter = binding.Converter, _
  37:             .ConverterCulture = binding.ConverterCulture, _
  38:             .ConverterParameter = binding.ConverterParameter, _
  39:             .Mode = BindingMode.OneTime, _
  40:             .Path = binding.Path _
  41:         }
  42:         If Not String.IsNullOrEmpty(binding.ElementName) Then
  43:             newBinding.ElementName = binding.ElementName
  44:         ElseIf binding.RelativeSource IsNot Nothing Then
  45:             newBinding.RelativeSource = binding.RelativeSource
  46:         ElseIf binding.Source IsNot Nothing Then
  47:             newBinding.Source = binding.Source
  48:         Else
  49:             '    newBinding.Source = source.DataContext
  50:         End If
  51:  
  52:         source.SetBinding(DummyProperty, newBinding)
  53:         Dim value = GetDummy(source)
  54:         source.ClearValue(DummyProperty)
  55:  
  56:         Return value
  57:     End Function
  58:  
  59:     Private Sub New()
  60:  
  61:     End Sub
  62: End Class

SL4就要支持DependencyObject绑定了,期待。。。

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


WinDbg调试小记:STAThread+COM调用+Console.ReadLine=内存泄漏

clock October 1, 2009 14:20 by author SAPikachu

这两天发现某服务器进程出现内存泄漏,遂抓dump调试之。

调试内存泄漏首先当然是!dumpheap -stat:

.....

71861128    52018      2913008 System.Threading.Thread
71862cf0    22130      2962628 System.Int32[]
0040a230      198      3034188      Free
71e7fcf8   680643     13612860 System.Threading.SafeCompressedStackHandle
05ac45cc  1412552     22600832 System.Net.IPEndPoint
05fb5690   675403     24314508 UDT.UDTSocket
71860b54   727921     34970436 System.String
718542d4  1350915     37825620 System.UInt16[]
05a7b37c  1350904     54036160 System.Net.IPAddress

.....

一看吓了一跳,Thread应该是会被垃圾回收掉的,不可能会有这么多留在堆里面。于是看看Finalize Queue:

0:000> !finalizequeue
SyncBlocks to be cleaned up: 0
MTA Interfaces to be released: 0
STA Interfaces to be released: 0
----------------------------------
generation 0 has 16 finalizable objects (0f751b0c->0f751b4c)
generation 1 has 4 finalizable objects (0f751afc->0f751b0c)
generation 2 has 1719 finalizable objects (0f750020->0f751afc)
Ready for finalization 1406640 objects (0f751b4c->0fcaf60c)

.....

 

100W+个对象等待Finalize,基本可以确定Finalizer thread出问题了。切到里面看看Call stack:

0:000> ~2s
eax=00000001 ebx=ffffffff ecx=00000000 edx=00000000 esi=00000000 edi=00000000
eip=77b191d5 esp=049eea00 ebp=049eea6c iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
ntdll!ZwWaitForSingleObject+0x15:
77b191d5 c20c00          ret     0Ch
0:002> k
ChildEBP RetAddr  
049ee9fc 77611270 ntdll!ZwWaitForSingleObject+0x15
049eea6c 776111d8 kernel32!WaitForSingleObjectEx+0xbe
049eea80 770bed85 kernel32!WaitForSingleObject+0x12
049eeaa4 771b9427 ole32!GetToSTA+0xad
049eead0 771b9b4d ole32!CRpcChannelBuffer::SwitchAptAndDispatchCall+0x132
049eebb0 770d37b4 ole32!CRpcChannelBuffer::SendReceive2+0xef
049eec28 770be868 ole32!CAptRpcChnl::SendReceive+0xaf
049eec7c 75dd1074 ole32!CCtxComChnl::SendReceive+0x95
049eec98 75dd102b rpcrt4!NdrProxySendReceive+0x49
049eeca4 75dd0146 rpcrt4!NdrpProxySendReceive+0xb
049ef0ac 75dd11ee rpcrt4!NdrClientCall2+0x18f
049ef0d0 75d45f22 rpcrt4!ObjectStublessClient+0x90
049ef0e0 770bf163 rpcrt4!ObjectStubless+0xf
049ef168 770a2b14 ole32!CObjectContext::InternalContextCallback+0x128
049ef1b8 72dc3fb7 ole32!CObjectContext::ContextCallback+0x87
049ef204 72dc4bcc mscorwks!CtxEntry::EnterContextOle32BugAware+0x2b
049ef324 72df9aeb mscorwks!CtxEntry::EnterContext+0x325
049ef358 72df9b90 mscorwks!RCWCleanupList::ReleaseRCWListInCorrectCtx+0xc4
049ef3a8 72d2befb mscorwks!RCWCleanupList::CleanupAllWrappers+0xdb
049ef3ec 72d2be0b mscorwks!SyncBlockCache::CleanupSyncBlocks+0xec

 

Google一番后发现,如果Finalizer thread的调用里面出现ole32!GetToSTA并且卡死的话,多半由于主线程为STA并且使用了COM,然后调用了阻塞的方法。(http://support.microsoft.com/?id=828988

这程序在初始化之后就调用了Console.ReadLine,工作全部在其它线程进行。程序并没有直接调用COM,但是使用了Remoting和MAF。推测是里面隐式调用了COM,导致出现了这问题。。。

解决方法那篇KB里面有给出,这里就不说了。话说要不是会一点WinDBG,应该就找不出问题根源了吧。。。M$的东西还真是。。。

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


EP翻墙法:OpenVPN+FoxyProxy

clock September 23, 2009 09:26 by author SAPikachu

之前一直没用过VPN翻墙,因为VPN需要手动打开关闭,对我等用惯FG+FoxyProxy自动切换的人来说实在是很麻烦。。。(话说我连FG都设成服务让它自动启动了。。。

不过最近60大寿,FG和U相继RP,基本是没法用了。前两天实在无法忍受墙内的日子,弄了个OpenVPN回来研究,EP了半天终于研究出来了。。。

说起来原理其实很简单,只要不让OpenVPN修改全局路由,然后弄个代理服务器程序把本地端口绑定到虚拟网卡就可以了。不过这程序倒是费了一番周折,Google根本找不到小型能指定本地绑定ip的代理服务器。。。最后只好自己写一个。。。

不罗嗦了,这里简单说下步骤:

  1. 配置OpenVPN到可用状态,Google很多教程,这里就不说了。目前我用过AlonWebUltraVPN的服务,感觉上UltraVPN快一点,而且没有广告。
  2. 在配置文件加上以下内容(如有重复可以删除,路径请自行修正):
    route-noexec
    
    route-up "cmd /c D:\\OpenVPN\\config\\runproxy.cmd"
    
    script-security 3 system
    
    down "cmd /c taskkill /f /im proxy.exe & echo DOWN"
  3. runproxy.cmd(注意if后面的数字要改成自己机器虚拟网卡的编号,可在CMD运行Route print查看):
    @echo off 
    cd /d "%~dp0"
    route delete %route_network_1% mask %route_netmask_1%  if 32
    route delete 0.0.0.0 mask 0.0.0.0  if 32
    
    
    route add %route_network_1% mask %route_netmask_1% %route_gateway_1% metric 1 if 32
    route add 0.0.0.0 mask 0.0.0.0 %route_vpn_gateway% metric 1 if 32
    
    taskkill /f /im proxy.exe
    start proxy.exe %ifconfig_local%
  4. 启动OpenVPN后,把FoxyProxy的代理设置为127.0.0.1:8119即可。

 

配置模板、代理程序及源代码

(代理程序需要.Net 2.0)

祝各位翻墙愉快。。。

Across the Great FireWall we can reach every corner in the world.

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


VFRHelper 1.2.3[9.17更新]

clock September 17, 2009 10:09 by author SAPikachu

Update 9.17:部分Bug修复。。。于是新功能还是没时间弄。。。orz

前几天弄某个DVDRip的时候写OVR写得我吐血。。。于是就有了这次更新。。。orz

Update 12.4:一些小更新。。。主要是界面的问题。。。

Update 12.4#2:囧。。。又发现一个bug。。。请各位下载升级包覆盖一下。。。orz

 TFMOVR

      
VFRHelper - MKV章节制作工具(不要问我为什么叫这个名字。。。
更新日志:
1.2.3
(*)修复部分MKV章节文件无法加载的问题
(*)Bug修复
1.2.2
(*)FFMpegSource更新到2.0 beta 4
1.2.1
(*)Bug修复及易用性改动
1.2.0
(+)新增插件框架,章节编辑器改为插件形式
(+)新增插件:TFM OVR文件编辑器
(*)一些小改动
1.1.1
(+)新增功能:按时间跳转
1.1.0
(*)视频代码重写,速度提高
(+)FFMpegSource更新到2.0 beta 3,现在打开非avs文件不需要AviSynth了
(+)使用FFMpegSource打开文件时,在标题栏显示索引进度
(+)新增支持读取VFR MP4的Timecode
(*)一些小改动及bug修复
1.0.2
(+)新增1个快捷键
(+)FFMpegSource更新到1.19
(-)使用按钮能够正常打开非AVI文件了
1.0.1
(+)新增2个快捷键
(+)快捷键现在可以自定义
(*)退出程序时会询问是否保留临时文件(如果有的话)
1.0.0
初始版本
功能:
*可视化制作MKV章节文件
*支持打开TXT及XML格式的章节
*支持VFR(只支持V2的Timecode,如果是V1的话请预先转换好
*查看V2 Timecode各帧的时间(附带功能
*编辑TFM的OVR文件
支持的视频格式:
AVI
AVS
MKV
MP4
FLV
MKV、MP4及FLV需要FFMS2.dll支持。
快捷键说明:
方向键左/右					跳转至上一个/下一个关键帧
Shift+方向键左/右			跳转至上一帧/下一帧(注意:跳转的时候会忽略空帧)
方向键上/下					上一个/下一个章节
空格								设置当前选中章节的时间
F12									解码速度测试(可以无视
快捷键可以自定义,使用记事本之类的工具编辑keymappings.xml即可。按键名称可查看KeyNames.htm获得。
一些注意事项:
*章节文件的格式无法被改变(即只能保存为打开时候的格式)
*新建章节只支持TXT格式

 

下载:

完整包(内附源代码)

更新包

系统需求:

.Net Framework 2.0

Windows(废话

AviSynth(可选

源代码编译需求VS2008

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


AG完结。。。

clock August 24, 2009 11:23 by author SAPikachu

感慨万千啊。。。5年的长征。。。

很多感想。。。却不知道从何说起。。。

就这样吧。。。继续努力。。。

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


小记:MPlayer的承载窗口不支持透明

clock August 13, 2009 15:29 by author SAPikachu

准确来说,是不支持WS_EX_LAYERED属性。。。如果使用的话,某些机器(据我所知主要为XP系统。。。我的Vista和Win7都没出现。。。orz)有可能会出现以下情况:

  1. 窗口闪动
  2. 画面错误(颜色/大小等)
  3. DirectX非加速输出无法使用(诡异的是加速就没问题。。。
  4. Mplayer崩溃(某台机器上用gl输出的话一定会出现。。。)

 

解决方法很简单。。。就是不要用这属性(拖走)。。。顺带连TransparencyKey和Opacity也不能用了。。。orz

已经被这问题困扰很久了。。。最崩溃的是在我的机器上完全正常。。。到其它人那才会出问题。。。搞得调试也非常麻烦。。。orz

接着还得头疼怎么把窗口四周的圆角弄回来。。。难道真的要逼我改皮肤么。。。囧

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


网易有道难题。。。止步于复赛。。。

clock June 22, 2009 08:46 by author SAPikachu

昨晚看见第3题就囧了。。。套用某人一句话。。。这俨然不是为我等小菜准备的。。。

做好前两道题用了1小时左右。。。剩下的时间都浪费在第3道上了。。。没做完是一定的。。。结果系统测试的时候第2题挂掉了。。。orz

下来以后越想越郁闷。。。第2题估计就是漏了一个处理。。。如果直接放弃第3题的话应该是可以检查出来的。。。

只能说经验不足了。。。其实第一次参加编程比赛。。。这个成绩也是意料之内。。。下次再接再厉了。。。

第一题代码:

    Public Function getNext(ByVal A As Long) As Long


        A += 1 ' bigger than a
        Dim sA As String = A.ToString()

        Dim i As Integer
        For i = 0 To sA.Length - 2
            If sA(i) = sA(i + 1) Then
                Exit For
            End If
        Next
        If i = sA.Length - 1 Then
            Return A ' A is non repeating number
        End If
        Dim leftPart As Long = (Long.Parse(sA.Substring(0, i + 1)))
        Dim rightPart As New System.Text.StringBuilder
        Dim isZero As Boolean = True

        Dim rightFirst As Long = Long.Parse(sA(i + 1)) + 1
        If rightFirst > 9 Then
            rightFirst = 0
            leftPart = getNext(leftPart)
            Dim newA As String = leftPart & rightFirst
            If i + 2 < sA.Length Then
                newA = newA & sA.Substring(i + 2)
            End If
            Return getNext(Long.Parse(newA))
        End If

        rightPart.Append(rightFirst)
        For j As Integer = i + 2 To sA.Length - 1
            If isZero Then
                rightPart.Append("0")
            Else
                rightPart.Append("1")
            End If
            isZero = Not isZero
        Next
        Return Long.Parse(leftPart & rightPart.ToString())

    End Function

 

第二题:

 

	Public Function maximize(ByVal word As String, ByVal maxChanges As Integer) As Integer


        If word.Length = 1 Then
            Return 1
        End If
        Dim counts As IDictionary(Of Char, Integer) = CountChars(word)
        Dim chars As Char() = word.ToCharArray()
        Dim changes As Integer = 0
        For i As Integer = 0 To word.Length \ 2
            If chars(i) <> chars(chars.Length - i - 1) Then
                If changes = maxChanges Then
                    'not a palindrome
                    Return 0
                End If
                changes += 1
		' 这里我忘记修正字符数了。。。应该就是这个原因而挂掉了。。。迟一点要去平台再试试。。。
                If counts(chars(i)) > counts(chars(chars.Length - i - 1)) Then
                    chars(chars.Length - i - 1) = chars(i)
                Else
                    chars(i) = chars(chars.Length - i - 1)
                End If
            End If
        Next
        If changes = maxChanges Then
            Return Score(New String(chars))
        ElseIf (chars.Length And 1) = 1 Then
            Return 1
        Else
            Return maximize(New String(chars, 0, chars.Length \ 2), maxChanges - changes) + 1
        End If
    End Function

    Private Function CountChars(ByVal word As String) As IDictionary(Of Char, Integer)
        Dim charCounts As New SortedList(Of Char, Integer)
        For Each ch As Char In word
            If charCounts.ContainsKey(ch) Then
                charCounts(ch) += 1
            Else
                charCounts(ch) = 1
            End If
        Next
        Return charCounts
    End Function

    Private Function Score(ByVal word As String) As Integer
        For i As Integer = 0 To word.Length \ 2
            If word.Chars(i) <> word.Chars(word.Length - i - 1) Then
                Return 0 ' not a palindrome
            End If
        Next
        If (word.Length And 1) = 1 Then
            Return 1 ' odd length
        Else
            Return Score(word.Substring(word.Length \ 2)) + 1
        End If
    End Function

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


杂记两则

clock May 12, 2009 09:46 by author SAPikachu

很久没有发文了。。。于是记一下最近捣鼓项目的经验。。。

1、缩小Mplayer体积

Mplayer默认编译版有10MB之巨。。。其实有很多功能是不需要的,特别是我这个项目定死了视频的编码,更是可以把没用的编码全部禁用。要点有两个:

(1) FFMpeg单独编译

Mplayer虽然内置了FFmpeg,但是配置非常不方便,而且没用的功能禁用不干净。。。单独编译的时候,只需要几行参数就可以禁掉所有东西,在后面再启用需要的功能就可以了。

编译的时候要注意,光禁用_a结尾启用_so结尾的参数还不够,要手动指定库路径才能正常链接(也可能是我这的MinGW有问题。。。)。如:

--disable-libavutil_a   \
--disable-libavcodec_a   \
--disable-libavformat_a  \
--disable-libpostproc_a   \
--disable-libswscale_a    \
--enable-libavutil_so   \
--enable-libavcodec_so   \
--enable-libavformat_so  \
--enable-libpostproc_so   \
--enable-libswscale_so    \
--extra-libs-mplayer="/local/lib/libavformat.a /local/lib/libavcodec.a /local/lib/libswscale.a /local/lib/libpostproc.a /local/lib/libavutil.a" \

另外库的顺序非常重要,错了链接就会不成功。(想当初我试了N次才试出这个顺序。。。

(2) 编译后删除所有内嵌符号

这个是我最近才发现的,原来gcc会在输出文件中内嵌调试符号。。。直接导致程序大幅膨胀。这些符号基本是没有用处的(很少会有人在Windows用gdb调试吧。。。),完全是浪费空间。

还好删除符号也很简单,在Cygwin或MinGW环境下运行以下命令就可以了:

strip --strip-all <输出文件名>

弄完这些之后,MPlayer就只剩下5MB左右了,足足缩小了50%,而且基本的功能也不会缺少。

 

 

2、使Mono支持加载路径包含非ASCII字符的程序集

于是这个应该是很老的bug了,但是修复起来很简单。。。patch已经发到mono开发组了,希望下个版本可以包含吧。

2.4的Patch:

--- E:/image-2.4.c	四 四月 30 15:39:45 2009
+++ E:/image.c	四 四月 30 15:46:49 2009
@@ -878,11 +878,23 @@
 	MonoImage *image;
 	FILE *filed;
 	struct stat stat_buf;
-
+#ifdef PLATFORM_WIN32
+	gsize bytes_written;
+	gchar *fname_ansi = g_locale_from_utf8 (fname, -1, NULL, &bytes_written, NULL);
+	filed = fopen (fname_ansi, "rb");
+	g_free (fname_ansi);
+	if (filed == NULL){
+#else
 	if ((filed = fopen (fname, "rb")) == NULL){
+#endif // PLATFORM_WIN32
 		if (IS_PORTABILITY_SET) {
 			gchar *ffname = mono_portability_find_file (fname, TRUE);
 			if (ffname) {
+#ifdef PLATFORM_WIN32
+				gchar *ffname_utf8 = ffname;
+				ffname = g_locale_from_utf8 (ffname_utf8, -1, NULL, &bytes_written, NULL);
+				g_free (ffname_utf8);
+#endif // PLATFORM_WIN32
 				filed = fopen (ffname, "rb");
 				g_free (ffname);
 			}

 

由于在SVN的代码中fopen的调用改到另一个地方了,所以需要另一个patch:

--- E:/mono-filemap.c	三 四月 29 20:05:26 2009

+++ E:/mono-filemap-2.c	三 四月 29 20:11:35 2009

@@ -25,7 +25,17 @@

 MonoFileMap *
 mono_file_map_open (const char* name)
 {
-	return (MonoFileMap *)fopen (name, "rb");
+#ifdef PLATFORM_WIN32
+	// fopen in msvcrt.dll accepts ANSI string, but name is UTF-8 encoded
+	gsize bytes_written;
+	gchar *name_utf8 = name;
+	name = g_locale_from_utf8 (name_utf8, -1, NULL, &bytes_written, NULL);
+#endif // PLATFORM_WIN32
+	MonoFileMap *map = (MonoFileMap *)fopen (name, "rb");
+#ifdef PLATFORM_WIN32
+	g_free (name);
+#endif // PLATFORM_WIN32
+	return map;
 }
 
 guint64 

 

应用之后参照Mono主页的教程在Cygwin编译就可以了。(编译好要记得删符号。。。不然mono.dll会比发布版大N倍。。。

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5



Recent Comments

Calendar

<<  March 2010  >>
MoTuWeThFrSaSu
22232425262728
1234567
891011121314
15161718192021
22232425262728
2930311234

View posts in large calendar

Sign in