1a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford/* 2a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford * Copyright (C) 2013 The Android Open Source Project 3a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford * 4a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford * Licensed under the Apache License, Version 2.0 (the "License"); 5a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford * you may not use this file except in compliance with the License. 6a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford * You may obtain a copy of the License at 7a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford * 8a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford * http://www.apache.org/licenses/LICENSE-2.0 9a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford * 10a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford * Unless required by applicable law or agreed to in writing, software 11a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford * distributed under the License is distributed on an "AS IS" BASIS, 12a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford * See the License for the specific language governing permissions and 14a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford * limitations under the License. 15a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford */ 16a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 17a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordpackage com.android.gallery3d.filtershow.colorpicker; 18a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 19a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordimport android.content.Context; 20a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordimport android.graphics.Bitmap; 21a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordimport android.graphics.Canvas; 22a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordimport android.graphics.Color; 23a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordimport android.graphics.LinearGradient; 24a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordimport android.graphics.Paint; 25a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordimport android.graphics.RadialGradient; 26a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordimport android.graphics.Rect; 27a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordimport android.graphics.RectF; 28a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordimport android.graphics.Shader; 29a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordimport android.graphics.SweepGradient; 30a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordimport android.util.AttributeSet; 31a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordimport android.util.DisplayMetrics; 32a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordimport android.view.MotionEvent; 33a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordimport android.view.View; 34a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 35a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordimport com.android.gallery3d.R; 36a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 37a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordimport java.util.ArrayList; 38a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 39a4f38c0f8f70c998391780b672eea5d5e49277c7John Hofordpublic class ColorSVRectView extends View implements ColorListener { 40a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford private float mDpToPix; 41a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 42a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford private float mCtrY = 100; 43a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford private Paint mPaint1; 44a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 45a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford private float mCtrX = 100; 46a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford private Paint mDotPaint = new Paint(); 47a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford private float mDotRadus; 48a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford private float mBorder; 49a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 50a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford private float mDotX = Float.NaN; 51a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford private float mDotY; 52a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford private int mSliderColor = 0xFF33B5E5; 53a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford private float[] mHSVO = new float[]{0, 1, 1, 1}; 54a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford RectF mRect = new RectF(); 55a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 56a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford private int mWidth; 57a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford private int mHeight; 58a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford public final static float DOT_SIZE = 20; 59a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford public final static float BORDER_SIZE = 20; 60a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford Bitmap mBitmap; 61a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 62a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford public ColorSVRectView(Context ctx, AttributeSet attrs) { 63a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford super(ctx, attrs); 64a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 65a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford DisplayMetrics metrics = ctx.getResources().getDisplayMetrics(); 66a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mDpToPix = metrics.density; 67a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mDotRadus = DOT_SIZE * mDpToPix; 68a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mBorder = BORDER_SIZE * mDpToPix; 69a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 70a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mPaint1 = new Paint(); 71a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 72a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 73a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mDotPaint.setStyle(Paint.Style.FILL); 74a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford if (isInEditMode()) { 75a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mDotPaint.setColor(0x646464); 76a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mSliderColor = 0x888888; 77a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } else { 78a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mDotPaint.setColor(ctx.getResources().getColor(R.color.slider_dot_color)); 79a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mSliderColor = ctx.getResources().getColor(R.color.slider_line_color); 80a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 81a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mPaint1.setStyle(Paint.Style.FILL); 82a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mPaint1.setAntiAlias(true); 83a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mPaint1.setFilterBitmap(true); 84a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 85a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mBitmap = Bitmap.createBitmap(64, 46, Bitmap.Config.ARGB_8888); 86a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford fillBitmap(); 87a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 88a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 896125a082a2b5ddc0d34a5198c5a7e826bd77e202John Hoford @Override 906125a082a2b5ddc0d34a5198c5a7e826bd77e202John Hoford protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 916125a082a2b5ddc0d34a5198c5a7e826bd77e202John Hoford super.onMeasure(widthMeasureSpec, widthMeasureSpec); 926125a082a2b5ddc0d34a5198c5a7e826bd77e202John Hoford } 936125a082a2b5ddc0d34a5198c5a7e826bd77e202John Hoford 94a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford void fillBitmap() { 95a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford int w = mBitmap.getWidth(); 96a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford int h = mBitmap.getHeight(); 97a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford int[] buff = new int[w * h]; 98a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford float[] hsv = new float[3]; 99a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford hsv[0] = mHSVO[0]; 100a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford for (int i = 0; i < w * h; i++) { 101a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford float sat = (i % w) / (float) w; 102a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford float val = (w - i / w) / (float) w; 103a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford hsv[1] = sat; 104a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford hsv[2] = val; 105a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford buff[i] = Color.HSVToColor(hsv); 106a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 107a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mBitmap.setPixels(buff, 0, w, 0, 0, w, h); 108a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 109a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 110a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford private void setUpColorPanel() { 111a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford updateDot(); 112a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford updateDotPaint(); 113a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford fillBitmap(); 114a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 115a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 116a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 117a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 118a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford @Override 119a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford protected void onDraw(Canvas canvas) { 120a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford super.onDraw(canvas); 121a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford Rect r = canvas.getClipBounds(); 122a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mRect.set(r); 123a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mRect.top += mBorder; 124a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mRect.bottom -= mBorder; 125a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mRect.left += mBorder; 126a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mRect.right -= mBorder; 127a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford canvas.drawBitmap(mBitmap, null, mRect, mPaint1); 128a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 129a900c0a7b4f3fd4797290428a97c48066a2689ebIan Rogers if (!Float.isNaN(mDotX)) { 130a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford canvas.drawCircle(mDotX, mDotY, mDotRadus, mDotPaint); 131a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 132a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 133a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 134a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 135a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford public boolean onDown(MotionEvent e) { 136a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford return true; 137a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 138a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 139a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford @Override 140a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford public boolean onTouchEvent(MotionEvent event) { 141a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 142a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford invalidate((int) (mDotX - mDotRadus), (int) (mDotY - mDotRadus), (int) (mDotX + mDotRadus), 143a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford (int) (mDotY + mDotRadus)); 144a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford float x = event.getX(); 145a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford float y = event.getY(); 146a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 147a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford x = Math.max(Math.min(x, mWidth - mBorder), mBorder); 148a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford y = Math.max(Math.min(y, mHeight - mBorder), mBorder); 149a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mDotX = x; 150a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mDotY = y; 151a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford float sat = 1 - (mDotY - mBorder) / (mHeight - 2 * mBorder); 152a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford if (sat > 1) { 153a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford sat = 1; 154a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 155a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 156a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford float value = (mDotX - mBorder) / (mHeight - 2 * mBorder); 157a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mHSVO[2] = sat; 158a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mHSVO[1] = value; 159a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford notifyColorListeners(mHSVO); 160a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford updateDotPaint(); 161a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford invalidate((int) (mDotX - mDotRadus), (int) (mDotY - mDotRadus), (int) (mDotX + mDotRadus), 162a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford (int) (mDotY + mDotRadus)); 163a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 164a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford return true; 165a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 166a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 167a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford @Override 168a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford protected void onSizeChanged(int w, int h, int oldw, int oldh) { 169a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mWidth = w; 170a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mHeight = h; 171a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mCtrY = h / 2f; 172a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mCtrX = w / 2f; 173a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 174a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford setUpColorPanel(); 175a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 176a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 177a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 178a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford private void updateDot() { 179a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 180a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford double hue = mHSVO[0]; 181a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford double sat = mHSVO[1]; 182a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford double val = mHSVO[2]; 183a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford double opc = mHSVO[3]; 184a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 185a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mDotX = (float) (mBorder + (mHeight - 2 * mBorder) * sat); 186a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mDotY = (float) ((1 - val) * (mHeight - 2 * mBorder) + mBorder); 187a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 188a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 189a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 190a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford private void updateDotPaint() { 191a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford int[] colors3 = new int[]{ 192a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mSliderColor, mSliderColor, 0x66000000, 0}; 193a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford RadialGradient g = new RadialGradient(mDotX, mDotY, mDotRadus, colors3, new float[]{ 194a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 0, .3f, .31f, 1}, Shader.TileMode.CLAMP); 195a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mDotPaint.setShader(g); 196a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 197a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 198a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 199a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford @Override 200a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford public void setColor(float[] hsvo) { 201a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford if (hsvo[0] == mHSVO[0] 202a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford && hsvo[1] == mHSVO[1] 203a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford && hsvo[2] == mHSVO[2]) { 204a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mHSVO[3] = hsvo[3]; // we don't update if color stays the same 205a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford return; 206a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 207a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford System.arraycopy(hsvo, 0, mHSVO, 0, mHSVO.length); 208a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 209a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford setUpColorPanel(); 210a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford invalidate(); 211a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 212a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford updateDot(); 213a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford updateDotPaint(); 214a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 215a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 216a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 217a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford ArrayList<ColorListener> mColorListeners = new ArrayList<ColorListener>(); 218a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 219a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford public void notifyColorListeners(float[] hsv) { 220a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford for (ColorListener l : mColorListeners) { 221a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford l.setColor(hsv); 222a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 223a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 224a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 225a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford public void addColorListener(ColorListener l) { 226a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mColorListeners.add(l); 227a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 228a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford 229a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford public void removeColorListener(ColorListener l) { 230a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford mColorListeners.remove(l); 231a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford } 232a4f38c0f8f70c998391780b672eea5d5e49277c7John Hoford} 233