layout_height / ayout_width = 0dp

When a LinearLayout is vertical, then the layout_weight will effect the height of the child Views (ListView). Setting the layout_height to 0dp will cause this attribute to be ignored. The reason to want to ignore the attribute is that if you didn’t ignore it, it would be used to calculate the layout which uses more CPU time.

This is usually used when having many views inside a linearlayout and have set android:layout_weight=”1″ in order both views to take equal space.

layout_weight体验(实现按比例显示)

按比例显示LinearLayout内各个子控件,需设置android:layout_width=”0dp”,如果为竖直方向的设置android:layout_height=”0dp”。在这种情况下某子个控件占用LinearLayout的比例为:本控件weight值 / LinearLayout内所有控件的weight值的和。

这三个TextView是按照1:2:3的比例进行显示的,这样看来似乎可以实现按照比例显示了,但是有个问题,如果TextView内的文本长度一同那么较长文本的TextView会宽度会有所增加,见下面配置及效果:

onfinishinflate 什么时候调用

onFinishInflate 当View中所有的子控件均被映射成xml后触发
onSizeChanged 当view的大小发生变化时触发

构造方法和onFinishInflate都是在setContentView(R.layout.buttonwaveview); 就开始执行了,然后再回执行onCreate后面的代码

自定义组合组件 大多有两种
1、在onSizeChanged里面写
2、在onFinishInflate里面写
onSizeChanged 
其实 上面的代码onSizeChanged是不会执行 ,它是在view大小发生改变时才执行的,所有代码都是在onSizeChanged里面写的 但是onSizeChanged不执行怎么办?所以在构造方法里面,设置了背景图片 认为的改变view 这样就可以调用onSizeChanged了

setBackgroundResource(R.drawable.tabswitcher_long);

onFinishInflate 

这个里面写也是可以的 但是 有一个问题
假如说 我在Activity里面 需要设置自定义组件ButtonWaveView 的一些变量,而且这些变量(例如 width,height)是必须在addview前面调用的
我们的set方法肯定是写在onCreat里面的 但是前面我们也看到了 onFinishInflate是先于onCreat()执行的  这时 我们的程序就有问题了

解决方法有两个

 

Android中资源文件夹res/raw和assets的使用

*res/raw和assets的相同点:

1.两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制。

*res/raw和assets的不同点:
1.res/raw中的文件会被映射到R.java文件中,访问的时候直接使用资源ID即R.id.filename;assets文件夹下的文件不会被映射到R.java中,访问的时候需要AssetManager类。assets文件夹本身就是存储资源的文件夹,而且相比resource文件夹,它其中的资源不会生成R中的ID,用来放图片很是合适。
2.res/raw不可以有目录结构,而assets则可以有目录结构,也就是assets目录下可以再建立文件夹

*读取文件资源:

1.读取res/raw下的文件资源,通过以下方式获取输入流来进行写操作

  • InputStream is = getResources().openRawResource(R.id.filename);

2.读取assets下的文件资源,通过以下方式获取输入流来进行写操作

  • AssetManager am = null;
  • am = getAssets();  
  • InputStream is = am.open(“filename”);  
  • assets下的文件是不在R.java中管理的在layout中不能直接应用的

    不过可以使用代码直接加载:

    InputStream is=getAssets().openFile(图片名);

    Bitmap bmp=BitmapFactory.decodeStream(is);
    image.setImageBitmap(bmp);

change the ratio aspect of bitmap

一、将图片按自己的要求缩放

// 图片源
Bitmap bm = BitmapFactory.decodeStream(getResources()
.openRawResource(R.drawable.dog));
// 获得图片的宽高
int width = bm.getWidth();
int height = bm.getHeight();
// 设置想要的大小
int newWidth = 320;
int newHeight = 480;
// 计算缩放比例
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// 取得想要缩放的matrix参数
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
// 得到新的图片
Bitmap newbm = Bitmap.createBitmap(bm, 0, 0, width, height, matrix,
true);
// 放在画布上
canvas.drawBitmap(newbm, 0, 0, paint);

二、bitmap的用法

BitmapFactory.Options option = new BitmapFactory.Options();
option.inSampleSize = 2; //将图片设为原来宽高的1/2,防止内存溢出
Bitmap bm = BitmapFactory.decodeFile(“”,option);//文件流

URL url = new URL(“”);
InputStream is = url.openStream();
Bitmap bm = BitmapFactory.decodeStream(is);

 android:scaleType:

android:scaleType是控制图片如何resized/moved来匹对ImageView的size。ImageView.ScaleType / android:scaleType值的意义区别:

  •   CENTER /center 按图片的原来size居中显示,当图片长/宽超过View的长/宽,则截取图片的居中部分显示
  •   CENTER_CROP / centerCrop 按比例扩大图片的size居中显示,使得图片长(宽)等于或大于View的长(宽)
  •   CENTER_INSIDE / centerInside 将图片的内容完整居中显示,通过按比例缩小或原来的size使得图片长/宽等于或小于View的长/宽
  •   FIT_CENTER / fitCenter 把图片按比例扩大/缩小到View的宽度,居中显示
  •   FIT_END / fitEnd 把图片按比例扩大/缩小到View的宽度,显示在View的下部分位置
  •   FIT_START / fitStart 把图片按比例扩大/缩小到View的宽度,显示在View的上部分位置
  •   FIT_XY / fitXY 把图片 不按比例 扩大/缩小到View的大小显示
  •   MATRIX / matrix 用矩阵来绘制,动态缩小放大图片来显示。
Bitmap.createScaledBitmap(Bitmap,width,height,true); //第一个参数是待修改的Bitmap,第二第三个参数分别为修改后的宽、高

ColorMatrixColorFilter

Every pixel in an image is a mixture of red, green, and blue. These primary colors, when combined, can make any other color:

Image from Wikimedia Commons. Thanks to Mike Horvath and jacobolus.

The amount of red in a pixel can vary from zero (no red at all) to 255. Same for green and blue. So, from the image above, you can see that a pure yellow pixel has red = 255, and green = 255. White has red, green, and blue all set to 255. Black has all three set to zero.

The color matrix filter looks at each pixel in a source image and changes them based on how much red, blue, and green is in the pixel. You end up with a whole new image; the destination image.

To control the saturation of the Bitmap, a ColorMatrix, a ColorMatrixColorFilter and a Paint object are going to be required.

Then, the saturation is set by the ColorMatrix which is passed as a parameter to the ColorMatrixColorFilter that, in turn, is set as the color filter to the Paint object. After that, the paint is applied when rendering the Bitmap.

 

via

Android: Changing image color saturation

 

Skia brief outline

Google Skia is a complete 2D graphic library for drawing Text, Geometries, and Images.

  • 3×3 matrices w/ perspective
  • antialiasing, transparency, filters
  • shaders, xfermodes, maskfilters, patheffects
  • subpixel text

Skia是一个C++的开源2D图形库,Raster、OpenGL和PDF目前都在使用它。Skia可提供的功能包括:

  • 3 × 3 带角度的矩阵
  • 抗锯齿、透明化和滤镜
  • 阴影、XFER模式、模板过滤器、通道效果

picture from Google

Chrome开发者Elliot Poger宣布Chrome for Mac将很快换用Skia 2D图形库替换以前的Apple核心图形库,这也使得Linux、Windows和Mac OS X系统使用的图形库完全统一。

使用 Skia 的 API 进行图形绘制时主要会用到一下几个类:其实现代码主要在 src/core 目录下。

  • SkBitmap 用来设置像素;
  • SkCanvas 写入位图;
  • SkPaint 设置颜色和样式;
  • SkRect 用来绘制矩形。

使用 Skia 绘图的步骤:

a) 定义一个位图 32 位像素并初始化 SkBitmap bitmap;

b) 分配位图所占的空间

c) 指定输出设备

d) 设备绘制的风格

图形图像特效 

skia中effect文件夹中的类继承图

src/effects 目录的文件主要实现一些图形图像的特效,包括 遮罩、浮雕、模糊、滤镜、渐变色、离散、透明以及 PATH 的各种特效等。

除了颜色、笔画、字体大小这样的简单属性,paint也支持effect, effect是绘图管线不同方面的子类,(每个effect都是引用计数的)当一个effect被一个paint引用的时候,将会覆盖paint的绘制管线的一些部分。例如 ,使用gradient代替单个也是,给paint指定一个SkShader:

SkShader* shader = SkGradientShader::CreateLinear(...);
paint.setShader(shader);
shader->unref();

现在,所有使用这个paint绘制的东西都会使用由CreateLiner指定的gradient,CreateLiner返回的Shader对象是引用计数的。当一个像shader这样的effect对象被指定给一个paint的时候,paint会增加他的引用计数,为了平衡引用计数,上面的例子调用了shader的unref(),现在这个paint就是shader的唯一拥有者,这样,无论是出了paint作用域或者指定了其他的shader(可以为空),会自动调用shader的unref()。

有6种effect可以绑定到paint:

paint也保持SkTypeface的引用,SkTypeface代表指定的字体风格,可以用来测量和绘制文字,也就是说不仅可以用于绘制文本,还可以用来测量文本

动画

src/animator 目录的文件主要实现了 Skia 的动画效果,Android不支持。

界面 UI 库

src/view 目录 构建了一套界面 UI 库。 组件包括 Window,Menu, TextBox, ListView, ProgressBar, Widget, ScrollBar,TagList,Image 等。

Skia 的图像编解码部分

这部分的接口主要是:

  • external/include/image/SKImageDecoder.h // 把图像文件或者流解码到 skia 的内部内存 SKBitmap 中 ;
  • external/include/image/SKImageEncoder.h // 把 skia 内部内存 SKBitmap 编码成文件或流的形式;

这些接口需要具体的类实现,主要代码在 src/image 文件中。

Android 图形系统的 JNI 接口

主要提供了从 Skia 底层库到 Java 上层的支持,代码路径为:frameworks/base/core/jni/android/graphic/,主要为 Canvas.cpp 文件。

GDI+Windows的一套图形绘制库

Windows系统下,所有图形图像绘制,最终都是通过GDI来实现的。Android下也需要一套能绘制出点、线、面等复杂图形,或者渲染界面等图像方面的一个可供开发者调用的绘图函数接口,Skia就是这套绘制工具。

e.g.现在让你来画一幅画,比如我们的国画山水画。画一幅画需要哪些工具呢?从常识上来说,我们需要一张纸,比如白纸,或者带有某些背景图的纸张;需要毛笔不同型号的毛笔墨汁颜料等等。然后我们规定在纸张的哪个区域画图,用什么样的毛笔,用什么样的颜色,画什么样的图形,是点、线、面?还是花草等。Skia就是类似上面画图所有需要的一系列设备、工具等。要Android画图或者渲染图像,都需要Skia提供的API接口,或者是间接提供。

所有Activity或者View或者其他控件的显示,在底层都是通过Skia提供的函数进行显示的。常见的Canvas类,假如你跟踪一下代码,会发现,Canvas是通过Native方式,调用底层的SkCanvas的。Android系统下,通过OpenGL ES绘制的3d图形,最终还是被合并到Skia定义的显示缓存中进行显示的。

2393479_1.jpg

Skia 主要涉及到的3个库:

  •      libcorecg.so  包含/skia/src/core的部分内容,比如其中的Region,Rect是在SurfaceFlinger里面计算可是区域的操作基本单位
  •      libsgl.so        包含/skia/src/core|effects|images|ports|utils的部分和全部内容,这个实现了skia大部分的图形效果,以及图形格式的编解码
  •      libskiagl.so   包含/skia/src/gl里面的内容,主要用来调用opengl实现部分效果

要想在底层使用skia的接口来画图需要全面了解skia的一整套机制,实际上skia开源到现在还没多久,在网上能找到的资料是也是很粗浅的,如果将来真需要在这方面下功夫肯定是需要一定的工作量的。

Skiaandroid源码里的目录位置

  • 头文件(也可以说是internal API, 因为google没有在NDK里面提供他)位置:android/external/skia/include。其中还包含以下几个子目录:animator, core, effects, images, views…, 最重要的就是core目录了,我们在这里的分析也主要针对core目录里面的API。
  • 源文件位于: android/external/skia/src目录,子目录结构和头文件目录相同。
  • 封装层:android对Skia引擎进行了封装,以便让java代码方便的调用,对skia封装的代码存在于android/framework/base/core/jni以及android/framework/base/core/jni/android/graphics目录下面。主要是对Canvas, Bitmap, Graphics, Picture等等的封装,以及和libui库的结合使用。

在Android apk里面画图有2种方式 [2D]:

1、Simple Graphics in View
就是直接使用Android已经实现的一些画图操作,比如说images,shapes,colors,pre-defined animation等等,这些简单的画图操作实际上是由skia来提供的2D图形操作。

如贴一张背景图啊,画出简单地形状阿,实现一些简单的动画之类的操作。没有一笔一画地构造出一个图形出来,我们只是把我们的Graphic 资源放入View体系中,由系统 来将这些Graphic画出来。

种方式只能画静态或者极为简单的2D图画,对于实时性很强的动画,高品质的游戏都是没法实现 的。

2、Canvas
首先我们要明白这个Canvas是一个2D的概念,是在Skia中定义的。也就是说在这个方式下还是说的画2D图形。我们可以把这个Canvas理解成系统提供给我们的一块内存区域(但实际上它只是一套画图的API,真正的内存是下面的Bitmap),而且它还提供了一整套对这个内存区域进行操作的方法, 所有的这些操作都是画图API。

能一笔一划或者使用Graphic来画我们所需要的东西了,要画什么要显示什么都由我们自己 控制。这种方式根据环境还分为两种:

  • 使用普通View的canvas画图,适合处理量比较小,帧率比较小的动画,比如说象棋游戏之类的
  • 使用专门的SurfaceView的canvas来画图。主要用在游戏,高品质动画方面的画图。
    • 可以在SurfaceView中定义一个专门的线程来完成画图工作,应用程序不需要等待View的刷图,提高性能。

关于Activity的 :
(1) 首先尽量把UI的设计放在XML中实现,而不要放在代码中实现,这样方便设计,修改和移植
(2) 所有使用到的component都必须在manifest中声明,不然程序中找不到相应的conponet的时候会报错 ;
(3) 一般每一个Activity都对应于一个类和一个相应的布局文件xml
(4) 每一个Activity只有使用setContentView()绑定内容后才会显示,而且你才能从这个内容(比如xml中)获取到你需要的元素
(5) res/drawable和res/raw中的元素的区别是drawable中的元素像素可能会被系统优化,而raw中的不会被优化 ;
(6) 当多个Activity都从res/drawable中获得同一个元素,如果其中一个修改它的属性,所有其他的Activity中这个元素的相应属性都会改变 ;
(7) res/anim中保存的是动画相关的xml ;

2405240_1.png

https://sites.google.com/site/skiadocs/home

Android Graphic : apk and Skia/OpenGL|ES

check Inputstream is empty or not

inputstream.available().

It does not tell you whether its empty but it can give you an indication as to whether data is there to be read or not.

InputStream is designed to work with remote resources, so you can’t know if it’s there until you actually read from it.

Display new Activity on top of previous Activity

problem:

SecondActivity overlay on FirstActivity, FirstActivity gets dimmed, SecondActivity gets displayed on top of FirstActivity.

possible solution:

1. Dialog

  • set SecondActivity up as a dialog — which will dim the background
  • If you want to do this using an Activity instead of a Dialog, you can do this by setting the activity’s theme to android:theme="@android:style/Theme.Dialog" in the manifest – this will make the activity appear like a dialog (floating on top of whatever was underneath it).

2. Fragments can be used to fill a part of the screen, while doing something else entirely in a different one.

e.g. A app containing a main content area and a music player. The music player stays in place while the main content changes.

Android User Interface Design: Working With Fragments

一个Activity 可以启动另一个Activity,即使这个Activity是定义在别一个应用程序里的,比如说,想要给用户展示一个地图的信息,现在已经有一个Activity可以做这件事情,那么现在你的Activity需要做的就是将请求信息放进一个Intent对象里,并且将这个Intent对象传递给startActivity(),那么地图就可显示出来了,但用户按下Back键之后,你的Activity又重新出现在屏幕上。

Android将你的Activity和借用的那个Activity被放进一个Task中以维持用户的体验。当一个Activity启动另一个Activity时,新启动的Activity被压进栈中,成为正在运行的Activity。旧的Activity仍然在栈中。当用户按下BACK键之后,正在运行的Activity弹出栈,旧的Activity恢复成为运行的Activity

栈中包含对象,因此如果一个任务中开启了同一个Activity子类的的多个对象——例如,多个地图浏览器——则栈对每一个实例都有一个单独的入口。栈中的Activity不会被重新排序,只会被、弹出。

Task是一组Activity实例组成的栈,不是在manifest文件里的某个类或元素,所以无法设定一个Task的属性而不管它的Activity,一个Task的所有属性值是在底部的Activity里设置的,这就需要用于Affinity。

Affinity

affinity用于指定activity所属的task。默认状态下,一个app中的所有activity都有相同的affinity,所以它们会运行在同一个task。而通过<activity>的taskAffinity属性可以指定affinity。

taskAffinity要用<manifest>中定义的唯一包名来取值,系统通过包名定位到app的默认task。

taskAffinity在以下2种情况中发生作用:

  • 使用FLAG_ACTIVITY_NEW_TASK启动一个activity。如果该activity指定了taskAffinity,系统会将activity实例置于指定的task中。 注意的是,此情况下如果用户点击HOME键,必须要确定有办法能回到那个task中!(例如task所属的app在launcher有自己icon)
  • activity 设置了 allowTaskReparenting = “true”。 当activity所在的task被移到前台时,该activity会被移动到affinity指定的task中。

的launchMode属性

<activity>下的launchMode属性可以设置四种启动方式:

  1. standard (默认模式)
  2. singleTop
  3. singleTask
  4. singleInstance

这四个模式有以下的几个不同点:

  1. 响应Intent时Activity将被装入哪个task。

对于standard和singleTop模式,由产生该Intent(调用startActivity())的task持有该Activity——除非Intent对象里含有FLAG_ACTIVITY_NEW_TASK标志,那么就会寻找一个新的task。相反的,singTask和singleInstance模式,总是标志Activity为task的root Activity,开启这样的活动会新建一个task,而不是装入某个正在运行的任务。

一些应用(例如Notification)总是在一个新的Task里打开Activity,而从来不在自己的Task中打开,所以它们总是将包含FLAG_ACTIVITY_NEW_TASK的Intent传递给startActivity()。所以如果有一个可以被其他的东西以这个控制标志调用的Activity,请注意让应用程序有独立的回到原Activity的方法。

2. 一个Activity是否可以有多个实例。

一个standard或者singleTop属性的Activity可以实例化多次,他们可以属于多个不同的task,而且一个task也可以含有相同Activity的多个实例。 相反的,singleTask或者singleInstance属性的Activity只能有一个实例(单例),因为这些Activity是位于task的底部,这种限制意味着同一设备的同一时刻该task只能有一个实例。

3. 实例是否能允许在它的task里有其他的Activity。

  一个singleInstance属性的Activity是它所在的task里仅有的一个Activity,如果他启动了另一个Activity,那个Activity会被加载进一个不同的task而无视它的启动模式——就如Intent里有FLAG_ACTIVITY_NEW_TASK标识一样。在其他的方面,singleInstance和singleTask一样的。 其他三个模式允许有多个Activity在一个task里,一个singleTask属性的Activity总是一个task里的root Activity,但是他可以启动另外的Activity并且将这个新的Activity装进同一个task里,standard和singleTop属性的Activity可以出现在task的任何位置。

4. 是否创建一个新的Activity实例来处理一个新的Intent。

  对于默认的standard方式,将会生成新的实例来处理每一个新的Intent。每个实例处理一个新的Intent。

对singleTop模式,如果一个已经存在的实例在目标task的栈顶,那么就重用这个实例来处理这个新的Intent,如果这个实例存在但是不在栈顶,那就不重用他,而是重新创建一个实例来处理这个新的Intent并且将这个实例压入栈。

via

Android实现程序前后台切换效果

任务和返回栈(tasks and back stack)

 

Shape Drawable Resources 【android xml】

Shape Drawable Resources

shape是一个通过声明属性来自定义图形的xml文件的根节点,可以做图片使用。

  • 经常需要自己设置某个view的背景,比如类似新浪微博客户端微博源内容的灰底圆角效果,这个时候我们就可以使用Shape。
  • 自定义一个圆角Button,点击Button有些效果的变化,就要用到shape和selector。

Shape Drawable Resources是指一个XML文件,它定义了几何形状,包括颜色和渐变。放在res/Drawable文件夹下,文件名即为资源id,可以在其他layout中调用R.drawable.filename,对应的类为ShapeDrawable .

shape必须为根元素,Android上支持以下几种属性shape、gradient、stroke、corners、padding、solid等。

1. shape定义了形状,默认为矩形。<shape>  android:shape=[“rectangle” | “oval” | “line” | “ring”]

<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient android:startColor="#FFFF0000"
android:endColor="#80FF00FF"
android:angle="270" />
<padding android:left="50dp"
android:top="20dp" android:right="7dp"
android:bottom="7dp" />
<corners android:radius="8dp" />
</shape>

2. <gradient>  渐变

  • android:startColor  起始颜色
  • android:endColor  结束颜色
  • android:angle  渐变角度,0从上到下,90表示从左到右,数值为45的整数倍默认为0;
  • android:type  渐变的样式 liner线性渐变 radial环形渐变 sweep

3.  <solid >  填充

4. <stroke > 描边

  • android:width 描边的宽度
  • android:color 描边的颜色
  • android:dashWidth 表示’-‘横线的宽度
  • android:dashGap 表示’-‘横线之间的距离
  • android:color  填充的颜色

<?xml version="1.0" encoding="UTF-8"?>
<shape android:shape="rectangle"
xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#b4000000" />
<stroke android:width="2.0dip"
android:color="#b4ffffff"
android:dashWidth="3.0dip"
android:dashGap="0.0dip" />
<padding android:left="7.0dip"
android:top="7.0dip" android:right="7.0dip"
android:bottom="7.0dip" />
<corners android:radius="8.0dip" />
</shape>

5. <corners > 圆角

  • android:radius  圆角的半径 值越大角越圆
  • android:topRightRadius  右上圆角半径
  • android:bottomLeftRadius 右下圆角角半径
  • android:topLeftRadius 左上圆角半径
  • android:bottomRightRadius 左下圆角半径

也可以通过代码的方式来实现Shape画图,对应类为ShapeDrawable. 对应关系为:

  • 父节点 shape   —   ShapeDrawable
    •  [子节点] gradient   —
    •  [子节点] padding   —
    •  [子节点] corners   —   setCornerRadius 、setCornerRadii
    •  [子节点] solid       —
    •  [子节点]  stroke   —   setStroke
    •  [子节点]  size —   setSize

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<corners android:radius="10dp" />
<padding android:left="10dp" />
<solid android:color="#29acf5" />
<stroke  android:width="10dp"  android:color="#f0f0f0" />
</shape>

image

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
<corners android:radius="10dp" />
<padding android:left="10dp" />
<solid android:color="#29acf5" />
<stroke android:width="10dp" android:color="#f0f0f0" />
</shape>

image

via

Android Shape Drawable Resources

【Android进阶学习】shape和selector的结合使用

【Android UI】 Shape详解 (GradientDrawable)

Drawable Shape

生活在西班牙

自己动手丰衣足食

BlueAsteroid

Just another WordPress.com site

Jing's Blog

Just another WordPress.com site

Start from here......

我的心情魔方

天才遠私廚

希望能做一個分享各種資訊的好地方

语义噪声

西瓜大丸子汤的博客

笑对人生,傲立寰宇

Just another WordPress.com site

Where On Earth Is Waldo?

A Project By Melanie Coles

the Serious Computer Vision Blog

A blog about computer vision and serious stuff

Cauthy's Blog

paper review...

Cornell Computer Vision Seminar Blog

Blog for CS 7670 - Special Topics in Computer Vision

datarazzi

Life through nerd-colored glasses

Luciana Haill

Brainwaves Augmenting Consciousness

槑烎

1,2,∞

Dr Paul Tennent

and the university of nottingham

turn off the lights, please

A bunch of random, thinned and stateless thoughts around the Web

John's Weblog

Just another WordPress.com weblog