am b574cf87: am 7b00a8ae: Merge "SDK doc change: fix android:glEsVersion description, add live_wallpaper feature, indicate market filtering on features." into eclair

Merge commit 'b574cf876e64d8a9330b052d48dcc64c5abdd70a'

* commit 'b574cf876e64d8a9330b052d48dcc64c5abdd70a':
  SDK doc change: fix android:glEsVersion description, add live_wallpaper feature, indicate market filtering on features.
diff --git a/awt/javax/imageio/metadata/IIOMetadataNode.java b/awt/javax/imageio/metadata/IIOMetadataNode.java
index adc6d67..efbaae8 100644
--- a/awt/javax/imageio/metadata/IIOMetadataNode.java
+++ b/awt/javax/imageio/metadata/IIOMetadataNode.java
@@ -27,6 +27,8 @@
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
+import org.w3c.dom.TypeInfo;
+import org.w3c.dom.UserDataHandler;
 
 //???AWT
 //import org.w3c.dom.TypeInfo;
@@ -924,6 +926,14 @@
         return userObject;
     }
 
+    public TypeInfo getSchemaTypeInfo() {
+        throw new UnsupportedOperationException();
+    }
+
+    public Object setUserData(String key, Object data, UserDataHandler handler) {
+        throw new UnsupportedOperationException();
+    }
+
     /**
      * Sets the user object associated with this node.
      * 
diff --git a/calendar/Android.mk b/calendar/Android.mk
new file mode 100644
index 0000000..fd20dfa
--- /dev/null
+++ b/calendar/Android.mk
@@ -0,0 +1,18 @@
+# Copyright 2009 Google, Inc.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := calendar
+LOCAL_SRC_FILES := \
+	../core/java/android/provider/Calendar.java \
+	../core/java/android/pim/EventRecurrence.java \
+	../core/java/android/pim/ICalendar.java \
+	../core/java/android/pim/RecurrenceSet.java \
+	../core/java/android/pim/ContactsAsyncHelper.java \
+	../core/java/android/pim/DateException.java
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Include this library in the build server's output directory
+$(call dist-for-goals, droid, $(LOCAL_BUILT_MODULE):calendar.jar)
diff --git a/camera/libcameraservice/CameraHardwareStub.cpp b/camera/libcameraservice/CameraHardwareStub.cpp
index 8ad1f69..8b66389 100644
--- a/camera/libcameraservice/CameraHardwareStub.cpp
+++ b/camera/libcameraservice/CameraHardwareStub.cpp
@@ -47,16 +47,18 @@
 {
     CameraParameters p;
 
-    p.setPreviewSize(176, 144);
+    p.set("preview-size-values","320x240");
+    p.setPreviewSize(320, 240);
     p.setPreviewFrameRate(15);
     p.setPreviewFormat("yuv422sp");
 
-    p.setPictureSize(kCannedJpegWidth, kCannedJpegHeight);
+    p.set("picture-size-values", "320x240");
+    p.setPictureSize(320, 240);
     p.setPictureFormat("jpeg");
 
     if (setParameters(p) != NO_ERROR) {
         LOGE("Failed to set default parameters?!");
-    } 
+    }
 }
 
 void CameraHardwareStub::initHeapLocked()
@@ -80,14 +82,14 @@
 
     mPreviewFrameSize = how_big;
 
-    // Make a new mmap'ed heap that can be shared across processes. 
+    // Make a new mmap'ed heap that can be shared across processes.
     // use code below to test with pmem
     mPreviewHeap = new MemoryHeapBase(mPreviewFrameSize * kBufferCount);
     // Make an IMemory for each frame so that we can reuse them in callbacks.
     for (int i = 0; i < kBufferCount; i++) {
         mBuffers[i] = new MemoryBase(mPreviewHeap, i * mPreviewFrameSize, mPreviewFrameSize);
     }
-    
+
     // Recreate the fake camera to reflect the current size.
     delete mFakeCamera;
     mFakeCamera = new FakeCamera(preview_width, preview_height);
@@ -153,34 +155,34 @@
         ssize_t offset = mCurrentPreviewFrame * mPreviewFrameSize;
 
         sp<MemoryHeapBase> heap = mPreviewHeap;
-    
+
         // this assumes the internal state of fake camera doesn't change
         // (or is thread safe)
         FakeCamera* fakeCamera = mFakeCamera;
-        
+
         sp<MemoryBase> buffer = mBuffers[mCurrentPreviewFrame];
-        
+
     mLock.unlock();
 
     // TODO: here check all the conditions that could go wrong
     if (buffer != 0) {
         // Calculate how long to wait between frames.
         int delay = (int)(1000000.0f / float(previewFrameRate));
-    
+
         // This is always valid, even if the client died -- the memory
         // is still mapped in our process.
         void *base = heap->base();
-    
+
         // Fill the current frame with the fake camera.
         uint8_t *frame = ((uint8_t *)base) + offset;
         fakeCamera->getNextFrameAsYuv422(frame);
-    
+
         //LOGV("previewThread: generated frame to buffer %d", mCurrentPreviewFrame);
-        
+
         // Notify the client of a new frame.
         if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME)
             mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, mCallbackCookie);
-    
+
         // Advance the buffer pointer.
         mCurrentPreviewFrame = (mCurrentPreviewFrame + 1) % kBufferCount;
 
@@ -205,7 +207,7 @@
 void CameraHardwareStub::stopPreview()
 {
     sp<PreviewThread> previewThread;
-    
+
     { // scope for the lock
         Mutex::Autolock lock(mLock);
         previewThread = mPreviewThread;
@@ -356,7 +358,6 @@
     }
 
     mParameters = params;
-
     initHeapLocked();
 
     return NO_ERROR;
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 6419a5c..405d471 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -16,7 +16,6 @@
 ** limitations under the License.
 */
 
-//#define LOG_NDEBUG 0
 #define LOG_TAG "CameraService"
 #include <utils/Log.h>
 
@@ -95,7 +94,7 @@
 sp<ICamera> CameraService::connect(const sp<ICameraClient>& cameraClient)
 {
     int callingPid = getCallingPid();
-    LOGD("CameraService::connect E (pid %d, client %p)", callingPid,
+    LOGV("CameraService::connect E (pid %d, client %p)", callingPid,
             cameraClient->asBinder().get());
 
     Mutex::Autolock lock(mServiceLock);
@@ -106,30 +105,30 @@
             sp<ICameraClient> currentCameraClient(currentClient->getCameraClient());
             if (cameraClient->asBinder() == currentCameraClient->asBinder()) {
                 // This is the same client reconnecting...
-                LOGD("CameraService::connect X (pid %d, same client %p) is reconnecting...",
+                LOGV("CameraService::connect X (pid %d, same client %p) is reconnecting...",
                     callingPid, cameraClient->asBinder().get());
                 return currentClient;
             } else {
                 // It's another client... reject it
-                LOGD("CameraService::connect X (pid %d, new client %p) rejected. "
+                LOGV("CameraService::connect X (pid %d, new client %p) rejected. "
                     "(old pid %d, old client %p)",
                     callingPid, cameraClient->asBinder().get(),
                     currentClient->mClientPid, currentCameraClient->asBinder().get());
                 if (kill(currentClient->mClientPid, 0) == -1 && errno == ESRCH) {
-                    LOGD("The old client is dead!");
+                    LOGV("The old client is dead!");
                 }
                 return client;
             }
         } else {
             // can't promote, the previous client has died...
-            LOGD("New client (pid %d) connecting, old reference was dangling...",
+            LOGV("New client (pid %d) connecting, old reference was dangling...",
                     callingPid);
             mClient.clear();
         }
     }
 
     if (mUsers > 0) {
-        LOGD("Still have client, rejected");
+        LOGV("Still have client, rejected");
         return client;
     }
 
@@ -141,7 +140,7 @@
     // the refcount.
     client->trackMe(true, true);
 #endif
-    LOGD("CameraService::connect X");
+    LOGV("CameraService::connect X");
     return client;
 }
 
@@ -157,7 +156,7 @@
 
     if (mClient == 0) {
         // This happens when we have already disconnected.
-        LOGD("removeClient (pid %d): already disconnected", callingPid);
+        LOGV("removeClient (pid %d): already disconnected", callingPid);
         return;
     }
 
@@ -165,7 +164,7 @@
     // Client::~Client() -> disconnect() -> removeClient().
     client = mClient.promote();
     if (client == 0) {
-        LOGD("removeClient (pid %d): no more strong reference", callingPid);
+        LOGV("removeClient (pid %d): no more strong reference", callingPid);
         mClient.clear();
         return;
     }
@@ -178,7 +177,7 @@
         mClient.clear();
     }
 
-    LOGD("removeClient (pid %d) done", callingPid);
+    LOGV("removeClient (pid %d) done", callingPid);
 }
 
 // The reason we need this count is a new CameraService::connect() request may
@@ -198,7 +197,7 @@
 static sp<MediaPlayer> newMediaPlayer(const char *file)
 {
     sp<MediaPlayer> mp = new MediaPlayer();
-    if (mp->setDataSource(file) == NO_ERROR) {
+    if (mp->setDataSource(file, NULL /* headers */) == NO_ERROR) {
         mp->setAudioStreamType(AudioSystem::ENFORCED_AUDIBLE);
         mp->prepare();
     } else {
@@ -212,7 +211,7 @@
         const sp<ICameraClient>& cameraClient, pid_t clientPid)
 {
     int callingPid = getCallingPid();
-    LOGD("Client::Client E (pid %d)", callingPid);
+    LOGV("Client::Client E (pid %d)", callingPid);
     mCameraService = cameraService;
     mCameraClient = cameraClient;
     mClientPid = clientPid;
@@ -236,8 +235,9 @@
 
     // Callback is disabled by default
     mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
+    mOrientation = 0;
     cameraService->incUsers();
-    LOGD("Client::Client X (pid %d)", callingPid);
+    LOGV("Client::Client X (pid %d)", callingPid);
 }
 
 status_t CameraService::Client::checkPid()
@@ -253,7 +253,7 @@
 status_t CameraService::Client::lock()
 {
     int callingPid = getCallingPid();
-    LOGD("lock from pid %d (mClientPid %d)", callingPid, mClientPid);
+    LOGV("lock from pid %d (mClientPid %d)", callingPid, mClientPid);
     Mutex::Autolock _l(mLock);
     // lock camera to this client if the the camera is unlocked
     if (mClientPid == 0) {
@@ -267,13 +267,13 @@
 status_t CameraService::Client::unlock()
 {
     int callingPid = getCallingPid();
-    LOGD("unlock from pid %d (mClientPid %d)", callingPid, mClientPid);
+    LOGV("unlock from pid %d (mClientPid %d)", callingPid, mClientPid);
     Mutex::Autolock _l(mLock);
     // allow anyone to use camera
     status_t result = checkPid();
     if (result == NO_ERROR) {
         mClientPid = 0;
-        LOGD("clear mCameraClient (pid %d)", callingPid);
+        LOGV("clear mCameraClient (pid %d)", callingPid);
         // we need to remove the reference so that when app goes
         // away, the reference count goes to 0.
         mCameraClient.clear();
@@ -286,7 +286,7 @@
     int callingPid = getCallingPid();
 
     // connect a new process to the camera
-    LOGD("Client::connect E (pid %d, client %p)", callingPid, client->asBinder().get());
+    LOGV("Client::connect E (pid %d, client %p)", callingPid, client->asBinder().get());
 
     // I hate this hack, but things get really ugly when the media recorder
     // service is handing back the camera to the app. The ICameraClient
@@ -310,14 +310,14 @@
 
             // did the client actually change?
             if ((mCameraClient != NULL) && (client->asBinder() == mCameraClient->asBinder())) {
-                LOGD("Connect to the same client");
+                LOGV("Connect to the same client");
                 return NO_ERROR;
             }
 
             mCameraClient = client;
             mClientPid = -1;
             mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
-            LOGD("Connect to the new client (pid %d, client %p)",
+            LOGV("Connect to the new client (pid %d, client %p)",
                 callingPid, mCameraClient->asBinder().get());
         }
 
@@ -344,7 +344,7 @@
     int callingPid = getCallingPid();
 
     // tear down client
-    LOGD("Client::~Client E (pid %d, client %p)",
+    LOGV("Client::~Client E (pid %d, client %p)",
             callingPid, getCameraClient()->asBinder().get());
     if (mSurface != 0 && !mUseOverlay) {
 #if HAVE_ANDROID_OS
@@ -373,23 +373,23 @@
     // make sure we tear down the hardware
     mClientPid = callingPid;
     disconnect();
-    LOGD("Client::~Client X (pid %d)", mClientPid);
+    LOGV("Client::~Client X (pid %d)", mClientPid);
 }
 
 void CameraService::Client::disconnect()
 {
     int callingPid = getCallingPid();
 
-    LOGD("Client::disconnect() E (pid %d client %p)",
+    LOGV("Client::disconnect() E (pid %d client %p)",
             callingPid, getCameraClient()->asBinder().get());
 
     Mutex::Autolock lock(mLock);
     if (mClientPid <= 0) {
-        LOGD("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
+        LOGV("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
         return;
     }
     if (checkPid() != NO_ERROR) {
-        LOGD("Different client - don't disconnect");
+        LOGV("Different client - don't disconnect");
         return;
     }
 
@@ -397,7 +397,7 @@
     // from the user directly, or called by the destructor.
     if (mHardware == 0) return;
 
-    LOGD("hardware teardown");
+    LOGV("hardware teardown");
     // Before destroying mHardware, we must make sure it's in the
     // idle state.
     mHardware->stopPreview();
@@ -421,13 +421,13 @@
     mCameraService->removeClient(mCameraClient);
     mCameraService->decUsers();
 
-    LOGD("Client::disconnect() X (pid %d)", callingPid);
+    LOGV("Client::disconnect() X (pid %d)", callingPid);
 }
 
 // pass the buffered ISurface to the camera service
 status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface)
 {
-    LOGD("setPreviewDisplay(%p) (pid %d)",
+    LOGV("setPreviewDisplay(%p) (pid %d)",
          ((surface == NULL) ? NULL : surface.get()), getCallingPid());
     Mutex::Autolock lock(mLock);
     status_t result = checkPid();
@@ -438,7 +438,7 @@
     // asBinder() is safe on NULL (returns NULL)
     if (surface->asBinder() != mSurface->asBinder()) {
         if (mSurface != 0) {
-            LOGD("clearing old preview surface %p", mSurface.get());
+            LOGV("clearing old preview surface %p", mSurface.get());
             if ( !mUseOverlay)
             {
                 mSurface->unregisterBuffers();
@@ -487,7 +487,7 @@
 {
     int callingPid = getCallingPid();
 
-    LOGD("startCameraMode(%d) (pid %d)", mode, callingPid);
+    LOGV("startCameraMode(%d) (pid %d)", mode, callingPid);
 
     /* we cannot call into mHardware with mLock held because
      * mHardware has callbacks onto us which acquire this lock
@@ -512,7 +512,7 @@
 
     default: // CAMERA_PREVIEW_MODE
         if (mSurface == 0) {
-            LOGD("mSurface is not set yet.");
+            LOGV("mSurface is not set yet.");
         }
         return startPreviewMode();
     }
@@ -520,7 +520,7 @@
 
 status_t CameraService::Client::startRecordingMode()
 {
-    LOGD("startRecordingMode (pid %d)", getCallingPid());
+    LOGV("startRecordingMode (pid %d)", getCallingPid());
 
     status_t ret = UNKNOWN_ERROR;
 
@@ -547,7 +547,7 @@
 
 status_t CameraService::Client::setOverlay()
 {
-    LOGD("setOverlay");
+    LOGV("setOverlay");
     int w, h;
     CameraParameters params(mHardware->getParameters());
     params.getPreviewSize(&w, &h);
@@ -571,9 +571,10 @@
             // wait in the createOverlay call if the previous overlay is in the 
             // process of being destroyed.
             for (int retry = 0; retry < 50; ++retry) {
-                mOverlayRef = mSurface->createOverlay(w, h, OVERLAY_FORMAT_DEFAULT);
+                mOverlayRef = mSurface->createOverlay(w, h, OVERLAY_FORMAT_DEFAULT,
+                                                      mOrientation);
                 if (mOverlayRef != NULL) break;
-                LOGD("Overlay create failed - retrying");
+                LOGW("Overlay create failed - retrying");
                 usleep(20000);
             }
             if ( mOverlayRef.get() == NULL )
@@ -602,15 +603,9 @@
     CameraParameters params(mHardware->getParameters());
     params.getPreviewSize(&w, &h);
 
-    uint32_t transform = 0;
-    if (params.getOrientation() ==
-        CameraParameters::CAMERA_ORIENTATION_PORTRAIT) {
-      LOGV("portrait mode");
-      transform = ISurface::BufferHeap::ROT_90;
-    }
     ISurface::BufferHeap buffers(w, h, w, h,
                                  PIXEL_FORMAT_YCbCr_420_SP,
-                                 transform,
+                                 mOrientation,
                                  0,
                                  mHardware->getPreviewHeap());
 
@@ -623,7 +618,7 @@
 
 status_t CameraService::Client::startPreviewMode()
 {
-    LOGD("startPreviewMode (pid %d)", getCallingPid());
+    LOGV("startPreviewMode (pid %d)", getCallingPid());
 
     // if preview has been enabled, nothing needs to be done
     if (mHardware->previewEnabled()) {
@@ -659,14 +654,14 @@
 
 status_t CameraService::Client::startPreview()
 {
-    LOGD("startPreview (pid %d)", getCallingPid());
+    LOGV("startPreview (pid %d)", getCallingPid());
 
     return startCameraMode(CAMERA_PREVIEW_MODE);
 }
 
 status_t CameraService::Client::startRecording()
 {
-    LOGD("startRecording (pid %d)", getCallingPid());
+    LOGV("startRecording (pid %d)", getCallingPid());
 
     if (mMediaPlayerBeep.get() != NULL) {
         // do not play record jingle if stream volume is 0
@@ -687,7 +682,7 @@
 // stop preview mode
 void CameraService::Client::stopPreview()
 {
-    LOGD("stopPreview (pid %d)", getCallingPid());
+    LOGV("stopPreview (pid %d)", getCallingPid());
 
     // hold main lock during state transition
     {
@@ -701,7 +696,7 @@
 
         mHardware->stopPreview();
         mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
-        LOGD("stopPreview(), hardware stopped OK");
+        LOGV("stopPreview(), hardware stopped OK");
 
         if (mSurface != 0 && !mUseOverlay) {
             mSurface->unregisterBuffers();
@@ -718,7 +713,7 @@
 // stop recording mode
 void CameraService::Client::stopRecording()
 {
-    LOGD("stopRecording (pid %d)", getCallingPid());
+    LOGV("stopRecording (pid %d)", getCallingPid());
 
     // hold main lock during state transition
     {
@@ -737,7 +732,7 @@
 
         mHardware->stopRecording();
         mHardware->disableMsgType(CAMERA_MSG_VIDEO_FRAME);
-        LOGD("stopRecording(), hardware stopped OK");
+        LOGV("stopRecording(), hardware stopped OK");
     }
 
     // hold preview buffer lock
@@ -805,14 +800,14 @@
     int nw, cnt = 0;
     uint32_t written = 0;
 
-    LOGD("opening file [%s]\n", fname);
+    LOGV("opening file [%s]\n", fname);
     int fd = open(fname, O_RDWR | O_CREAT);
     if (fd < 0) {
         LOGE("failed to create file [%s]: %s", fname, strerror(errno));
         return;
     }
 
-    LOGD("writing %d bytes to file [%s]\n", size, fname);
+    LOGV("writing %d bytes to file [%s]\n", size, fname);
     while (written < size) {
         nw = ::write(fd,
                      buf + written,
@@ -825,7 +820,7 @@
         written += nw;
         cnt++;
     }
-    LOGD("done writing %d bytes to file [%s] in %d passes\n",
+    LOGV("done writing %d bytes to file [%s] in %d passes\n",
          size, fname, cnt);
     ::close(fd);
 }
@@ -833,7 +828,7 @@
 
 status_t CameraService::Client::autoFocus()
 {
-    LOGD("autoFocus (pid %d)", getCallingPid());
+    LOGV("autoFocus (pid %d)", getCallingPid());
 
     Mutex::Autolock lock(mLock);
     status_t result = checkPid();
@@ -849,7 +844,7 @@
 
 status_t CameraService::Client::cancelAutoFocus()
 {
-    LOGD("cancelAutoFocus (pid %d)", getCallingPid());
+    LOGV("cancelAutoFocus (pid %d)", getCallingPid());
 
     Mutex::Autolock lock(mLock);
     status_t result = checkPid();
@@ -866,7 +861,7 @@
 // take a picture - image is returned in callback
 status_t CameraService::Client::takePicture()
 {
-    LOGD("takePicture (pid %d)", getCallingPid());
+    LOGV("takePicture (pid %d)", getCallingPid());
 
     Mutex::Autolock lock(mLock);
     status_t result = checkPid();
@@ -920,12 +915,6 @@
     if (mSurface != 0 && !mUseOverlay) {
         int w, h;
         CameraParameters params(mHardware->getParameters());
-        uint32_t transform = 0;
-        if (params.getOrientation() == CameraParameters::CAMERA_ORIENTATION_PORTRAIT) {
-            LOGV("portrait mode");
-            transform = ISurface::BufferHeap::ROT_90;
-        }
-
         if (size == NULL) {
             params.getPictureSize(&w, &h);
         } else {
@@ -933,10 +922,10 @@
             h = size->height;
             w &= ~1;
             h &= ~1;
-            LOGD("Snapshot image width=%d, height=%d", w, h);
+            LOGV("Snapshot image width=%d, height=%d", w, h);
         }
         ISurface::BufferHeap buffers(w, h, w, h,
-            PIXEL_FORMAT_YCbCr_420_SP, transform, 0, mHardware->getRawHeap());
+            PIXEL_FORMAT_YCbCr_420_SP, mOrientation, 0, mHardware->getRawHeap());
 
         mSurface->registerBuffers(buffers);
     }
@@ -952,7 +941,7 @@
 #if DEBUG_HEAP_LEAKS && 0 // debugging
     if (gWeakHeap == NULL) {
         if (gWeakHeap != heap) {
-            LOGD("SETTING PREVIEW HEAP");
+            LOGV("SETTING PREVIEW HEAP");
             heap->trackMe(true, true);
             gWeakHeap = heap;
         }
@@ -1189,7 +1178,7 @@
 // set preview/capture parameters - key/value pairs
 status_t CameraService::Client::setParameters(const String8& params)
 {
-    LOGD("setParameters(%s)", params.string());
+    LOGV("setParameters(%s)", params.string());
 
     Mutex::Autolock lock(mLock);
     status_t result = checkPid();
@@ -1201,6 +1190,7 @@
     }
 
     CameraParameters p(params);
+
     return mHardware->setParameters(p);
 }
 
@@ -1215,17 +1205,41 @@
     }
 
     String8 params(mHardware->getParameters().flatten());
-    LOGD("getParameters(%s)", params.string());
+    LOGV("getParameters(%s)", params.string());
     return params;
 }
 
 status_t CameraService::Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
 {
-    LOGD("sendCommand (pid %d)", getCallingPid());
+    LOGV("sendCommand (pid %d)", getCallingPid());
     Mutex::Autolock lock(mLock);
     status_t result = checkPid();
     if (result != NO_ERROR) return result;
 
+    if (cmd == CAMERA_CMD_SET_DISPLAY_ORIENTATION) {
+        // The orientation cannot be set during preview.
+        if (mHardware->previewEnabled()) {
+            return INVALID_OPERATION;
+        }
+        switch (arg1) {
+            case 0:
+                mOrientation = ISurface::BufferHeap::ROT_0;
+                break;
+            case 90:
+                mOrientation = ISurface::BufferHeap::ROT_90;
+                break;
+            case 180:
+                mOrientation = ISurface::BufferHeap::ROT_180;
+                break;
+            case 270:
+                mOrientation = ISurface::BufferHeap::ROT_270;
+                break;
+            default:
+                return BAD_VALUE;
+        }
+        return OK;
+    }
+
     if (mHardware == 0) {
         LOGE("mHardware is NULL, returning.");
         return INVALID_OPERATION;
@@ -1327,7 +1341,7 @@
     status_t err = BnCameraService::onTransact(code, data, reply, flags);
 
 #if DEBUG_HEAP_LEAKS
-    LOGD("+++ onTransact err %d code %d", err, code);
+    LOGV("+++ onTransact err %d code %d", err, code);
 
     if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
         // the 'service' command interrogates this binder for its name, and then supplies it
@@ -1335,7 +1349,7 @@
         // ISurfaceComposer (since we delegated the INTERFACE_TRANSACTION handling to
         // BnSurfaceComposer before falling through to this code).
 
-        LOGD("+++ onTransact code %d", code);
+        LOGV("+++ onTransact code %d", code);
 
         CHECK_INTERFACE(ICameraService, data, reply);
 
@@ -1345,13 +1359,13 @@
             if (gWeakHeap != 0) {
                 sp<IMemoryHeap> h = gWeakHeap.promote();
                 IMemoryHeap *p = gWeakHeap.unsafe_get();
-                LOGD("CHECKING WEAK REFERENCE %p (%p)", h.get(), p);
+                LOGV("CHECKING WEAK REFERENCE %p (%p)", h.get(), p);
                 if (h != 0)
                     h->printRefs();
                 bool attempt_to_delete = data.readInt32() == 1;
                 if (attempt_to_delete) {
                     // NOT SAFE!
-                    LOGD("DELETING WEAK REFERENCE %p (%p)", h.get(), p);
+                    LOGV("DELETING WEAK REFERENCE %p (%p)", h.get(), p);
                     if (p) delete p;
                 }
                 return NO_ERROR;
diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
index 3e3e54f..b3d20f6 100644
--- a/camera/libcameraservice/CameraService.h
+++ b/camera/libcameraservice/CameraService.h
@@ -182,6 +182,7 @@
                     sp<CameraService>           mCameraService;
                     sp<ISurface>                mSurface;
                     int                         mPreviewCallbackFlag;
+                    int                         mOrientation;
 
                     sp<MediaPlayer>             mMediaPlayerClick;
                     sp<MediaPlayer>             mMediaPlayerBeep;
diff --git a/camera/libcameraservice/CannedJpeg.h b/camera/libcameraservice/CannedJpeg.h
index 532560a..b6266fb 100644
--- a/camera/libcameraservice/CannedJpeg.h
+++ b/camera/libcameraservice/CannedJpeg.h
@@ -1,1546 +1,734 @@
-const int kCannedJpegWidth = 213;
-const int kCannedJpegHeight = 350;
-const int kCannedJpegSize = 18474;
+const int kCannedJpegWidth = 320;
+const int kCannedJpegHeight = 240;
+const int kCannedJpegSize = 8733;
 
 const char kCannedJpeg[] = {
-  0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,
-  0x01, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43,
-  0x00, 0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04, 0x04, 0x04, 0x05,
-  0x05, 0x05, 0x06, 0x07, 0x0c, 0x08, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b,
-  0x0b, 0x09, 0x0c, 0x11, 0x0f, 0x12, 0x12, 0x11, 0x0f, 0x11, 0x11, 0x13,
-  0x16, 0x1c, 0x17, 0x13, 0x14, 0x1a, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18,
-  0x1a, 0x1d, 0x1d, 0x1f, 0x1f, 0x1f, 0x13, 0x17, 0x22, 0x24, 0x22, 0x1e,
-  0x24, 0x1c, 0x1e, 0x1f, 0x1e, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x05, 0x05,
-  0x05, 0x07, 0x06, 0x07, 0x0e, 0x08, 0x08, 0x0e, 0x1e, 0x14, 0x11, 0x14,
-  0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
-  0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
-  0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
-  0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
-  0x1e, 0x1e, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x01, 0x5e, 0x00, 0xd5, 0x03,
-  0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x00,
-  0x1c, 0x00, 0x00, 0x02, 0x02, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x05, 0x07, 0x01, 0x03,
-  0x04, 0x02, 0x08, 0xff, 0xc4, 0x00, 0x55, 0x10, 0x00, 0x01, 0x03, 0x04,
-  0x00, 0x03, 0x03, 0x05, 0x0a, 0x09, 0x08, 0x09, 0x02, 0x06, 0x03, 0x00,
-  0x01, 0x02, 0x03, 0x04, 0x00, 0x05, 0x06, 0x11, 0x07, 0x12, 0x21, 0x13,
-  0x31, 0x41, 0x14, 0x22, 0x51, 0x61, 0x71, 0x15, 0x23, 0x32, 0x34, 0x37,
-  0x72, 0x75, 0x81, 0xb1, 0xb3, 0x08, 0x17, 0x33, 0x42, 0x52, 0x62, 0x76,
-  0x93, 0xb2, 0x16, 0x24, 0x43, 0x53, 0x56, 0x91, 0xa1, 0xd2, 0x25, 0x36,
-  0x63, 0x73, 0x82, 0x92, 0xa2, 0xc1, 0xd1, 0x65, 0xf0, 0x26, 0x27, 0x64,
-  0x66, 0x74, 0xe1, 0x83, 0xc2, 0xf1, 0xff, 0xc4, 0x00, 0x1b, 0x01, 0x01,
-  0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xff,
-  0xc4, 0x00, 0x35, 0x11, 0x00, 0x02, 0x01, 0x03, 0x03, 0x01, 0x05, 0x05,
-  0x07, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
-  0x04, 0x11, 0x12, 0x21, 0x31, 0x41, 0x05, 0x22, 0x32, 0x51, 0x61, 0x06,
-  0x13, 0x71, 0x81, 0xb1, 0x14, 0x33, 0x42, 0x91, 0xa1, 0xc1, 0xd1, 0x15,
-  0x23, 0xe1, 0xf0, 0x24, 0x53, 0x92, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01,
-  0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xfb, 0x2e, 0x8a, 0x2b,
-  0xca, 0x95, 0xae, 0xfe, 0xea, 0x03, 0xd5, 0x15, 0x8d, 0xfb, 0x28, 0xdf,
-  0xb2, 0x80, 0xcd, 0x15, 0x8d, 0xfb, 0x28, 0xdf, 0xb2, 0x80, 0xcd, 0x15,
-  0x8d, 0xfb, 0x28, 0xe6, 0xa0, 0x33, 0x45, 0x63, 0x9a, 0xb3, 0x40, 0x14,
-  0x51, 0x45, 0x00, 0x51, 0x45, 0x14, 0x01, 0x45, 0x14, 0x50, 0x05, 0x14,
-  0x56, 0x37, 0x40, 0x66, 0x8a, 0x37, 0xd6, 0xb1, 0xbf, 0x65, 0x01, 0x9a,
-  0x2b, 0x1b, 0xf6, 0x51, 0xbf, 0x65, 0x01, 0x9a, 0x2b, 0x1b, 0xf6, 0x51,
-  0xbf, 0x65, 0x01, 0x9a, 0x2b, 0xc9, 0x56, 0xbb, 0xeb, 0xd0, 0xa0, 0x0a,
-  0x2b, 0xca, 0x95, 0xa3, 0x45, 0x01, 0xea, 0x93, 0x78, 0xe1, 0xb1, 0xc1,
-  0xec, 0xb8, 0x82, 0x41, 0xf7, 0x1e, 0x4f, 0x71, 0xd7, 0xf4, 0x66, 0x9c,
-  0xa9, 0x37, 0x8e, 0x5f, 0x23, 0xb9, 0x77, 0xd0, 0xf2, 0x7e, 0xec, 0xd0,
-  0x15, 0xb3, 0x5c, 0x3c, 0xc1, 0xd4, 0xd2, 0x14, 0x71, 0x7b, 0x69, 0x25,
-  0x20, 0x9f, 0x7a, 0xaf, 0x5f, 0x8b, 0xbc, 0x1b, 0xfb, 0x2d, 0x6c, 0xfd,
-  0xd5, 0x33, 0x31, 0xf9, 0x16, 0xfe, 0x68, 0xfb, 0x2b, 0xdd, 0x7b, 0x9a,
-  0x23, 0xe4, 0x78, 0x9a, 0xe5, 0xe6, 0x2b, 0x7e, 0x2e, 0xf0, 0x6f, 0xec,
-  0xb5, 0xb3, 0xf7, 0x54, 0x1e, 0x1e, 0x60, 0xc3, 0xaf, 0xf2, 0x5a, 0xd9,
-  0xaf, 0xf7, 0x54, 0xc7, 0x36, 0x54, 0x68, 0x50, 0xde, 0x99, 0x32, 0x43,
-  0x51, 0xa3, 0x30, 0x92, 0xb7, 0x5e, 0x75, 0x41, 0x28, 0x42, 0x40, 0xea,
-  0x54, 0x4f, 0x40, 0x2a, 0x2e, 0xcf, 0x13, 0x28, 0xcd, 0xf9, 0x5c, 0xb3,
-  0x07, 0xb1, 0xcc, 0x7d, 0x63, 0x7e, 0xeb, 0x49, 0x67, 0xf9, 0xd4, 0x94,
-  0xfa, 0x63, 0x34, 0xaf, 0x80, 0x93, 0xe0, 0xe3, 0x83, 0xae, 0xf6, 0x10,
-  0x7a, 0x1a, 0xce, 0xa4, 0xa9, 0x53, 0x59, 0x92, 0x46, 0x94, 0xe3, 0x52,
-  0xa3, 0xc4, 0x5b, 0x17, 0x2f, 0x98, 0xdf, 0x0b, 0xec, 0xaa, 0x65, 0xa9,
-  0xf6, 0x1b, 0x60, 0x92, 0xff, 0x00, 0x48, 0xf1, 0x19, 0x8c, 0xa7, 0xa4,
-  0x3e, 0x7d, 0x08, 0x69, 0x00, 0xad, 0x5f, 0x50, 0xd7, 0xa7, 0x55, 0x98,
-  0x1c, 0x28, 0x93, 0x91, 0x84, 0x2a, 0x0e, 0x09, 0x62, 0xc5, 0x20, 0xa8,
-  0xef, 0xca, 0x6e, 0xcc, 0x87, 0xe5, 0x91, 0xae, 0xf4, 0xc7, 0x42, 0xb9,
-  0x50, 0x7e, 0x7a, 0xf6, 0x3f, 0x46, 0xae, 0x9c, 0x33, 0x0a, 0xc7, 0x71,
-  0x46, 0xd6, 0xbb, 0x4c, 0x1f, 0xe7, 0x6f, 0x0f, 0xe7, 0x33, 0xa4, 0x2c,
-  0xbb, 0x2a, 0x41, 0xf4, 0xad, 0xd5, 0x79, 0xc7, 0xbb, 0xbb, 0xa2, 0x47,
-  0x80, 0x14, 0xc5, 0xaa, 0xf3, 0xea, 0x5c, 0x6a, 0xf0, 0xa4, 0x8e, 0xfa,
-  0x74, 0x34, 0xee, 0xdb, 0x65, 0x47, 0x8e, 0x7e, 0x0f, 0x1c, 0x37, 0xb6,
-  0xbe, 0x26, 0x5c, 0x6d, 0xef, 0xdf, 0x26, 0xeb, 0xf2, 0x93, 0x1c, 0xe5,
-  0x6d, 0x3e, 0x90, 0x96, 0x5b, 0xe5, 0x6c, 0x0f, 0x68, 0x27, 0xd7, 0x4c,
-  0xbf, 0x8a, 0x2e, 0x19, 0xff, 0x00, 0x62, 0xac, 0xff, 0x00, 0xb8, 0xa7,
-  0x8a, 0x2b, 0x9c, 0xe8, 0x12, 0x3f, 0x14, 0x7c, 0x33, 0xfe, 0xc5, 0x59,
-  0xff, 0x00, 0x71, 0x47, 0xe2, 0x8f, 0x86, 0x7f, 0xd8, 0xab, 0x3f, 0xee,
-  0x29, 0xde, 0x8a, 0x01, 0x09, 0xce, 0x16, 0x70, 0xad, 0xb7, 0xd0, 0xc3,
-  0x98, 0x8d, 0x89, 0x0e, 0xb9, 0xf0, 0x10, 0xa6, 0xc0, 0x52, 0xbd, 0x83,
-  0x7d, 0x6b, 0x77, 0xe2, 0x8f, 0x86, 0x7f, 0xd8, 0xab, 0x3f, 0xee, 0x2b,
-  0xb6, 0xef, 0xef, 0x9c, 0x40, 0xb5, 0x23, 0xaf, 0x98, 0xca, 0xd5, 0xf6,
-  0xd3, 0x55, 0x72, 0xdb, 0xd7, 0x75, 0x65, 0x51, 0x63, 0xc2, 0xf1, 0xfa,
-  0x27, 0xfb, 0x90, 0x9e, 0x44, 0x8f, 0xc5, 0x1f, 0x0c, 0xff, 0x00, 0xb1,
-  0x56, 0x7f, 0xdc, 0x51, 0xf8, 0xa3, 0xe1, 0x9f, 0xf6, 0x2a, 0xcf, 0xfb,
-  0x8a, 0x77, 0xa2, 0xba, 0x89, 0x12, 0x3f, 0x14, 0x7c, 0x33, 0xfe, 0xc5,
-  0x59, 0xff, 0x00, 0x71, 0x58, 0x57, 0x08, 0xb8, 0x66, 0xa4, 0x94, 0x9c,
-  0x2a, 0xd1, 0xa2, 0x34, 0x74, 0xce, 0xa9, 0xe2, 0x8a, 0x02, 0x91, 0xbe,
-  0x7e, 0x0e, 0x38, 0x70, 0x75, 0xd9, 0x58, 0xa9, 0x16, 0xa7, 0xd4, 0x76,
-  0x23, 0x4c, 0x6b, 0xcb, 0xa1, 0xa8, 0xfa, 0x0a, 0x1c, 0x3c, 0xe9, 0xdf,
-  0xea, 0xad, 0x3e, 0xca, 0x58, 0xb8, 0x61, 0x36, 0xcc, 0x68, 0x7f, 0xf1,
-  0x8f, 0x0c, 0xe0, 0x37, 0x19, 0x3f, 0x0a, 0xeb, 0x68, 0x69, 0x52, 0xa2,
-  0x01, 0xae, 0xf5, 0xa3, 0x5d, 0xab, 0x43, 0xd6, 0x52, 0xa4, 0x8f, 0xd2,
-  0xf1, 0xaf, 0xa5, 0x48, 0x1b, 0xdd, 0x63, 0x42, 0xb4, 0x85, 0x47, 0x0e,
-  0x0c, 0xe7, 0x4d, 0x4f, 0x93, 0xe7, 0xfb, 0x76, 0x11, 0xc3, 0xab, 0x94,
-  0x26, 0xe6, 0xdb, 0xac, 0x36, 0x59, 0x91, 0x9d, 0x1b, 0x6d, 0xe6, 0x12,
-  0x16, 0x85, 0x8f, 0x51, 0x49, 0x23, 0xff, 0x00, 0x7a, 0xae, 0x81, 0xc3,
-  0xbc, 0x1b, 0x5f, 0xea, 0xb5, 0xb3, 0xf7, 0x54, 0xf1, 0x95, 0x70, 0xce,
-  0xdf, 0x2a, 0x73, 0xf7, 0x8c, 0x56, 0x51, 0xc6, 0xef, 0x4e, 0x9e, 0x67,
-  0x1c, 0x61, 0xb0, 0xa8, 0xb2, 0x95, 0xff, 0x00, 0xd4, 0x31, 0xd1, 0x2b,
-  0xdf, 0xe9, 0x0e, 0x55, 0x8f, 0xd2, 0xf0, 0xa5, 0x58, 0xb7, 0x89, 0xd0,
-  0xef, 0x28, 0xc7, 0xb2, 0xab, 0x7a, 0x2d, 0x17, 0x85, 0x82, 0x63, 0x94,
-  0xb8, 0x57, 0x16, 0x78, 0x1d, 0xea, 0x8e, 0xe1, 0x1d, 0x74, 0x3a, 0x94,
-  0x11, 0xcc, 0x91, 0xe9, 0x1e, 0x75, 0x77, 0xd2, 0xad, 0x4e, 0xa6, 0xcd,
-  0x24, 0xce, 0x0a, 0xb4, 0x6a, 0x53, 0xdd, 0x36, 0xd1, 0xc3, 0xf8, 0xbb,
-  0xc1, 0xbf, 0xb2, 0xd6, 0xcf, 0xdd, 0x51, 0xf8, 0xbb, 0xc1, 0xbf, 0xb2,
-  0xd6, 0xcf, 0xdd, 0x53, 0x48, 0xee, 0xa2, 0xba, 0x74, 0x47, 0xc8, 0xe7,
-  0xd7, 0x2f, 0x31, 0x0e, 0xf1, 0x88, 0xe3, 0x36, 0x4b, 0xc6, 0x2d, 0x3a,
-  0xd1, 0x65, 0x87, 0x06, 0x50, 0xc9, 0x2d, 0xe8, 0xed, 0x59, 0x47, 0x2a,
-  0xb9, 0x4b, 0xa0, 0x11, 0xbf, 0x41, 0x15, 0xf4, 0x60, 0xee, 0xaa, 0x3f,
-  0x33, 0xf8, 0xd6, 0x2d, 0xfb, 0x4f, 0x6e, 0xfb, 0xe1, 0x57, 0x80, 0xee,
-  0xaf, 0x36, 0xed, 0x25, 0x53, 0x63, 0xd2, 0xb5, 0x6d, 0xc3, 0x73, 0x04,
-  0x6c, 0xf7, 0xd1, 0x59, 0xa2, 0xb9, 0x4e, 0x90, 0xa4, 0xde, 0x39, 0x7c,
-  0x8e, 0xe5, 0xdf, 0x43, 0xc9, 0xfb, 0xb3, 0x4e, 0x54, 0x9b, 0xc7, 0x2f,
-  0x91, 0xdc, 0xbb, 0xe8, 0x79, 0x3f, 0x76, 0x68, 0x05, 0xe6, 0x3f, 0x22,
-  0xdf, 0xcd, 0x1f, 0x65, 0x68, 0xbb, 0xdc, 0x61, 0x5a, 0x2d, 0x92, 0x2e,
-  0x57, 0x29, 0x08, 0x8f, 0x12, 0x3a, 0x39, 0xdd, 0x71, 0x5b, 0xd0, 0x1e,
-  0xaf, 0x49, 0x27, 0x40, 0x01, 0xd4, 0x92, 0x05, 0x74, 0x31, 0xf9, 0x26,
-  0xc7, 0xa5, 0x20, 0x0e, 0x9e, 0xaa, 0xe0, 0xe1, 0xed, 0xa1, 0x19, 0xbe,
-  0x42, 0x8c, 0xba, 0x7a, 0x79, 0xf1, 0xfb, 0x5c, 0x85, 0x26, 0xc6, 0xc2,
-  0xbe, 0x0c, 0x99, 0x08, 0x3c, 0xab, 0x98, 0xa1, 0xe2, 0x12, 0xa0, 0x52,
-  0xd8, 0x3d, 0x3a, 0x15, 0xf7, 0x94, 0x91, 0xec, 0xd6, 0xaa, 0xa9, 0x47,
-  0x27, 0x8f, 0x46, 0x93, 0xa9, 0x2c, 0x1d, 0x18, 0x8e, 0x17, 0x33, 0x29,
-  0x97, 0x1f, 0x22, 0xcd, 0xa1, 0xae, 0x3c, 0x26, 0x5c, 0x4b, 0xd6, 0xcb,
-  0x0b, 0xa3, 0xa3, 0x64, 0x1d, 0xa5, 0xf9, 0x43, 0xb9, 0x4e, 0xf8, 0x86,
-  0xfa, 0xa5, 0xbf, 0x5a, 0xb6, 0x45, 0xb0, 0x07, 0x4a, 0x00, 0x1a, 0xe9,
-  0xfe, 0x15, 0x9a, 0xf2, 0x25, 0x27, 0x37, 0x96, 0x7a, 0xd1, 0x82, 0x8a,
-  0xc2, 0x0a, 0x2b, 0x92, 0xee, 0xfc, 0xa8, 0xd0, 0x1c, 0x7a, 0x1c, 0x6f,
-  0x29, 0x79, 0x23, 0xcd, 0x6f, 0x7a, 0xdd, 0x71, 0xe3, 0xf7, 0xf8, 0x77,
-  0x64, 0x72, 0x02, 0x59, 0x92, 0x9e, 0x8e, 0x32, 0xbe, 0x8a, 0x07, 0xfe,
-  0xf5, 0xcd, 0x2b, 0x9a, 0x71, 0xaa, 0xa9, 0x49, 0xe1, 0xbe, 0x3d, 0x49,
-  0xcf, 0x42, 0x5e, 0x8a, 0xd7, 0x25, 0xf6, 0x63, 0x30, 0xa7, 0x9f, 0x71,
-  0x2d, 0xb6, 0x91, 0xb2, 0xa5, 0x1d, 0x0a, 0xae, 0xb2, 0x8c, 0xe9, 0xf7,
-  0xd4, 0xb8, 0xd6, 0x8f, 0x7a, 0x6b, 0xb8, 0xbc, 0x7e, 0x12, 0xbd, 0x9e,
-  0x8a, 0xe6, 0xbf, 0xed, 0x3a, 0x16, 0x30, 0xd5, 0x55, 0xef, 0xd1, 0x75,
-  0x64, 0x4a, 0x49, 0x72, 0x3e, 0x5c, 0xae, 0xd6, 0xdb, 0x72, 0x79, 0xa6,
-  0xcc, 0x69, 0x9f, 0x51, 0x3d, 0x7f, 0xb8, 0x75, 0xa5, 0xc9, 0x9c, 0x40,
-  0xb4, 0xb4, 0x48, 0x61, 0x97, 0xdf, 0xf5, 0xeb, 0x42, 0xab, 0x17, 0x9d,
-  0x75, 0xe7, 0x0b, 0x8f, 0x38, 0xa7, 0x16, 0x7b, 0xd4, 0xa3, 0xb3, 0x5e,
-  0x2b, 0xe3, 0xae, 0x7d, 0xab, 0xb9, 0x9b, 0xfe, 0xd4, 0x54, 0x57, 0xe6,
-  0xff, 0x00, 0xdf, 0x91, 0x93, 0xaa, 0xfa, 0x0d, 0xef, 0x66, 0x0c, 0xb9,
-  0x93, 0xb5, 0x77, 0x30, 0x97, 0xc8, 0xdb, 0x25, 0xb0, 0x8e, 0x71, 0xbe,
-  0xbe, 0x34, 0xc7, 0x0f, 0x88, 0x16, 0x87, 0x54, 0x03, 0xed, 0x3e, 0xc6,
-  0xfc, 0x48, 0xd8, 0xff, 0x00, 0x0a, 0xab, 0x40, 0x24, 0x80, 0x01, 0x24,
-  0xf7, 0x01, 0x5d, 0x73, 0x6d, 0x97, 0x08, 0x4d, 0x21, 0xd9, 0x51, 0x1d,
-  0x65, 0x0b, 0xf8, 0x2a, 0x52, 0x7a, 0x1a, 0xe3, 0xb6, 0xed, 0xcb, 0xfa,
-  0x5a, 0xa7, 0x1d, 0xd3, 0x79, 0x7b, 0x10, 0xa7, 0x22, 0xea, 0xb7, 0x5d,
-  0x20, 0x5c, 0x51, 0xcf, 0x0e, 0x53, 0x6e, 0x8f, 0x40, 0x3d, 0x47, 0xd5,
-  0x5d, 0x95, 0x41, 0x46, 0x90, 0xfc, 0x67, 0x43, 0xb1, 0xdd, 0x5b, 0x4b,
-  0x1d, 0xca, 0x49, 0xd1, 0xab, 0x07, 0x10, 0xcd, 0xbb, 0x65, 0xa2, 0x15,
-  0xdd, 0x41, 0x2b, 0x3d, 0x10, 0xf7, 0x70, 0x3e, 0xda, 0xfa, 0x5e, 0xcd,
-  0xf6, 0x9a, 0x95, 0xc4, 0x95, 0x3a, 0xeb, 0x4b, 0x7d, 0x7a, 0x7f, 0x83,
-  0x48, 0xd4, 0x4f, 0x91, 0xf2, 0x8a, 0x01, 0x04, 0x6c, 0x1d, 0x83, 0x45,
-  0x7d, 0x41, 0xa0, 0x51, 0x45, 0x14, 0x06, 0x0a, 0x41, 0x3b, 0xa8, 0x7c,
-  0xbf, 0x1b, 0xb3, 0xe5, 0x56, 0x47, 0xac, 0xf7, 0xa8, 0xbe, 0x51, 0x19,
-  0xc5, 0x05, 0xa4, 0xa4, 0xf2, 0xad, 0xa7, 0x13, 0xd5, 0x2e, 0x21, 0x43,
-  0xaa, 0x16, 0x93, 0xd4, 0x28, 0x75, 0x15, 0x33, 0x46, 0xa8, 0x0a, 0x45,
-  0x2e, 0x5d, 0x71, 0x5b, 0xf3, 0x58, 0xae, 0x51, 0x24, 0x4a, 0x32, 0x36,
-  0x2c, 0xf7, 0x52, 0x9e, 0x41, 0x38, 0x24, 0x6c, 0xb4, 0xe0, 0xee, 0x4b,
-  0xe9, 0x03, 0x67, 0x5d, 0x16, 0x3c, 0xe1, 0xae, 0xa2, 0xa7, 0xa9, 0xdb,
-  0x33, 0xc6, 0xed, 0x99, 0x56, 0x3f, 0x2a, 0xcb, 0x74, 0x6d, 0x65, 0x87,
-  0x80, 0x28, 0x71, 0xb5, 0x72, 0xba, 0xcb, 0x89, 0xea, 0x87, 0x1b, 0x50,
-  0xea, 0x95, 0xa4, 0x80, 0xa0, 0x7d, 0x35, 0x57, 0xe3, 0x13, 0x2e, 0x3d,
-  0xa4, 0xeb, 0x05, 0xfb, 0x93, 0xdd, 0xcb, 0x3b, 0x81, 0x89, 0x6a, 0x42,
-  0x42, 0x53, 0x21, 0x24, 0x73, 0x35, 0x21, 0x00, 0x77, 0x25, 0xc4, 0xec,
-  0xeb, 0xc1, 0x41, 0x43, 0xc3, 0x55, 0xe9, 0x5a, 0xd7, 0xd5, 0xdd, 0x97,
-  0x27, 0x9b, 0x73, 0x43, 0x4f, 0x7a, 0x3c, 0x1a, 0x73, 0x3f, 0x8d, 0x62,
-  0xdf, 0xb4, 0xf6, 0xef, 0xbe, 0x15, 0x78, 0x0e, 0xea, 0xa3, 0xb3, 0x3f,
-  0x8d, 0x62, 0xdf, 0xb4, 0xf6, 0xdf, 0xbe, 0x15, 0x78, 0x8e, 0xea, 0xe7,
-  0xbc, 0xfb, 0xcf, 0x91, 0xd1, 0x69, 0xf7, 0x61, 0x45, 0x14, 0x57, 0x29,
-  0xd4, 0x14, 0x9b, 0xc7, 0x2f, 0x91, 0xdc, 0xbb, 0xe8, 0x79, 0x3f, 0x76,
-  0x69, 0xca, 0x93, 0x38, 0xe4, 0x7f, 0xf9, 0x3d, 0x97, 0x74, 0xdf, 0xfa,
-  0x22, 0x4f, 0xdd, 0x9a, 0x01, 0x03, 0x28, 0x12, 0xae, 0x49, 0xb5, 0x62,
-  0x56, 0xd7, 0x96, 0xcc, 0xdb, 0xfb, 0xbe, 0x4c, 0xa7, 0x50, 0x74, 0xa6,
-  0x22, 0xa5, 0x1c, 0xd2, 0x1d, 0x1e, 0x82, 0x10, 0x39, 0x47, 0xeb, 0x2d,
-  0x35, 0x74, 0x5a, 0xa0, 0x44, 0xb6, 0x5b, 0x23, 0x5b, 0x60, 0x30, 0x88,
-  0xf1, 0x22, 0xb4, 0x96, 0x58, 0x69, 0x03, 0xcd, 0x42, 0x12, 0x34, 0x90,
-  0x3d, 0x80, 0x0a, 0xac, 0x78, 0x51, 0x10, 0xdc, 0xf8, 0x87, 0x90, 0xdf,
-  0x1d, 0x4f, 0x33, 0x56, 0x98, 0xac, 0x59, 0xe2, 0x1d, 0xf4, 0x0b, 0x52,
-  0x43, 0xf2, 0x0e, 0xbd, 0x27, 0x99, 0x81, 0xbf, 0xd4, 0xab, 0x60, 0x56,
-  0xf7, 0x35, 0x35, 0xcd, 0xfa, 0x18, 0x5b, 0x43, 0x44, 0x17, 0xa8, 0x01,
-  0xa1, 0xaa, 0x28, 0xa2, 0xb0, 0x37, 0x0a, 0x81, 0xc8, 0xf1, 0xf8, 0xb3,
-  0x41, 0x9a, 0xc3, 0x9e, 0x47, 0x31, 0xa1, 0xcc, 0x97, 0xd1, 0xd3, 0xbb,
-  0xd3, 0x53, 0xd4, 0x9d, 0xc4, 0xfb, 0xb9, 0x87, 0x6d, 0x4d, 0xbd, 0x95,
-  0x69, 0xd9, 0x3f, 0x0b, 0xd4, 0x8a, 0xf3, 0xfb, 0x52, 0x74, 0x69, 0xda,
-  0xca, 0x75, 0x96, 0x52, 0xfa, 0xf4, 0xc1, 0x59, 0x63, 0x1b, 0x89, 0x59,
-  0x06, 0x45, 0x73, 0xb9, 0xb4, 0x88, 0x72, 0x5f, 0x4a, 0x9b, 0x6b, 0xcd,
-  0x25, 0x1d, 0x03, 0x84, 0x78, 0x9a, 0x84, 0xad, 0x91, 0x63, 0xbd, 0x29,
-  0xf4, 0xb3, 0x1d, 0xa5, 0x38, 0xe2, 0xbb, 0x92, 0x91, 0xd4, 0xd7, 0xb9,
-  0xd0, 0xa5, 0x41, 0x7b, 0xb1, 0x96, 0xc2, 0xd9, 0x5e, 0xb7, 0xa5, 0x0d,
-  0x57, 0xe5, 0xd5, 0xaa, 0x56, 0xb8, 0x6e, 0xad, 0x4c, 0xbe, 0x99, 0xfd,
-  0xb2, 0x73, 0xbc, 0xbd, 0xcd, 0x14, 0x51, 0x45, 0x73, 0x10, 0x74, 0x5b,
-  0x24, 0x08, 0x97, 0x06, 0x24, 0xa9, 0x1c, 0xe1, 0xa5, 0x85, 0x14, 0xfa,
-  0x75, 0x4e, 0x19, 0x9e, 0x59, 0x6f, 0xba, 0xd9, 0x84, 0x38, 0x8d, 0x2c,
-  0xad, 0x6a, 0x05, 0x45, 0x69, 0xd7, 0x2e, 0xa9, 0x1e, 0x8a, 0xee, 0xb7,
-  0xed, 0x0a, 0xd6, 0xf4, 0x67, 0x46, 0x1c, 0x4b, 0x92, 0x54, 0x9a, 0x58,
-  0x0a, 0x28, 0x48, 0x2a, 0x3a, 0x00, 0x92, 0x7c, 0x05, 0x30, 0x59, 0xb1,
-  0x3b, 0x9c, 0xf4, 0x87, 0x5d, 0x48, 0x8b, 0x1f, 0xbc, 0xb8, 0xef, 0x4e,
-  0x9e, 0xca, 0xc2, 0x85, 0xb5, 0x5b, 0x89, 0x69, 0xa5, 0x16, 0xd8, 0x49,
-  0xbe, 0x06, 0xae, 0x1a, 0xe4, 0x0a, 0x96, 0xd1, 0xb5, 0x4b, 0x5e, 0xdd,
-  0x6c, 0x6d, 0xa5, 0x1e, 0xf5, 0x27, 0xd1, 0xed, 0xa7, 0x47, 0xdd, 0x6d,
-  0x86, 0x56, 0xf3, 0xcb, 0x4a, 0x1b, 0x40, 0xda, 0x94, 0x4e, 0x80, 0x15,
-  0x5d, 0xc7, 0x93, 0x8c, 0xe3, 0x0e, 0x85, 0xb0, 0xa5, 0xcf, 0x9a, 0x9e,
-  0x9c, 0xe0, 0xf4, 0x4d, 0x4a, 0x71, 0x16, 0xe0, 0x5f, 0xc4, 0xa3, 0xbf,
-  0x15, 0x5e, 0xf3, 0x25, 0x69, 0xe6, 0x23, 0xd1, 0xa2, 0x75, 0xff, 0x00,
-  0xbf, 0x45, 0x7d, 0xf5, 0x8f, 0x68, 0x3b, 0x6b, 0x29, 0x46, 0xac, 0x94,
-  0xa7, 0x4d, 0x70, 0x9e, 0x76, 0xe9, 0x96, 0x6d, 0x19, 0x61, 0x6e, 0x78,
-  0x9f, 0xc4, 0x38, 0x4d, 0x3e, 0x5b, 0x8b, 0x0d, 0xc7, 0xd0, 0x0f, 0xc3,
-  0x2a, 0xe5, 0x07, 0xd8, 0x2a, 0x6f, 0x1a, 0xc9, 0x60, 0x5f, 0x01, 0x43,
-  0x04, 0xb6, 0xfa, 0x46, 0xd4, 0xd2, 0xfb, 0xf5, 0xe9, 0x1e, 0x9a, 0xa6,
-  0x6b, 0xb2, 0xcb, 0x3d, 0xcb, 0x65, 0xd1, 0x89, 0xad, 0x13, 0xb6, 0xd5,
-  0xb2, 0x07, 0x88, 0xf1, 0x1f, 0xdd, 0x5e, 0x0d, 0xaf, 0xb4, 0xf7, 0x4a,
-  0xba, 0x75, 0x9a, 0x71, 0x7c, 0xac, 0x71, 0xf0, 0x28, 0xaa, 0x3c, 0xee,
-  0x5e, 0xb4, 0x56, 0xa8, 0x8f, 0xb7, 0x2a, 0x2b, 0x52, 0x1a, 0x50, 0x53,
-  0x6e, 0x24, 0x29, 0x24, 0x78, 0x83, 0x5b, 0x6b, 0xf4, 0x24, 0xd4, 0x96,
-  0x51, 0xb8, 0x6b, 0xae, 0xea, 0xae, 0xe3, 0x5c, 0x1f, 0x72, 0x2e, 0x16,
-  0x9c, 0xfa, 0x38, 0xe5, 0x4c, 0x25, 0xa6, 0x05, 0xdf, 0x47, 0x41, 0x70,
-  0x9e, 0x58, 0x01, 0x47, 0xfd, 0xd3, 0xa5, 0x0b, 0x1e, 0x80, 0x57, 0xe9,
-  0xab, 0x46, 0xa3, 0xb2, 0x5b, 0x4c, 0x5b, 0xf5, 0x82, 0xe1, 0x64, 0x9a,
-  0x9e, 0x68, 0xd3, 0xe3, 0x39, 0x19, 0xdf, 0x9a, 0xb4, 0x94, 0x9d, 0x7a,
-  0xfa, 0xd5, 0xe3, 0x2d, 0x2d, 0x34, 0x56, 0x51, 0x52, 0x4d, 0x32, 0xa0,
-  0xcc, 0xc1, 0x12, 0xb1, 0x60, 0x7b, 0xc6, 0x4f, 0x6e, 0xfb, 0xe1, 0x57,
-  0x80, 0xee, 0xaf, 0x9b, 0xad, 0xd3, 0xa4, 0xcf, 0xc5, 0x70, 0x57, 0x27,
-  0x12, 0x67, 0x31, 0x92, 0x5b, 0xe2, 0x4b, 0xdf, 0x7f, 0x6e, 0xcc, 0x8e,
-  0xc9, 0xcd, 0xfa, 0xca, 0x90, 0x4f, 0xd7, 0x5f, 0x48, 0x8e, 0xea, 0xde,
-  0xed, 0xea, 0x9a, 0x7e, 0x86, 0x16, 0xab, 0x4c, 0x1a, 0xf5, 0x0a, 0x28,
-  0xa2, 0xb9, 0x8e, 0x90, 0xa4, 0xde, 0x37, 0x8d, 0xf0, 0x7f, 0x2e, 0x1b,
-  0xd7, 0xfa, 0x22, 0x47, 0xdd, 0x9a, 0x72, 0xa4, 0xee, 0x37, 0x74, 0xe1,
-  0x06, 0x5c, 0x7d, 0x16, 0x89, 0x1f, 0x76, 0x68, 0x08, 0x8f, 0xc1, 0xcd,
-  0x21, 0xee, 0x1b, 0x0b, 0xc7, 0x4e, 0xd2, 0xef, 0x73, 0x9b, 0x35, 0x64,
-  0x7a, 0xe4, 0x2d, 0x09, 0xff, 0x00, 0xa1, 0x08, 0x15, 0x64, 0x55, 0x7b,
-  0xf8, 0x37, 0xa5, 0x23, 0x81, 0xb8, 0x98, 0x1e, 0x30, 0x42, 0x8f, 0xb4,
-  0xad, 0x44, 0xff, 0x00, 0x89, 0x35, 0x61, 0x51, 0xee, 0xf2, 0x42, 0xd8,
-  0x28, 0xa2, 0x8a, 0x12, 0x15, 0x4e, 0xf1, 0x02, 0x62, 0xa5, 0xe4, 0xf2,
-  0x7c, 0xe2, 0x52, 0xc9, 0xec, 0xd2, 0x3d, 0x1a, 0xab, 0x88, 0xf7, 0x55,
-  0x17, 0x7e, 0x25, 0x57, 0xa9, 0xa4, 0xf7, 0xf6, 0xea, 0xfb, 0x6b, 0xe4,
-  0xfd, 0xad, 0xa8, 0xe3, 0x6f, 0x08, 0x2e, 0xaf, 0xe8, 0x8c, 0xaa, 0xf0,
-  0x76, 0xe1, 0x97, 0x76, 0x6c, 0xd7, 0x94, 0xca, 0x90, 0xd9, 0x5b, 0x65,
-  0x25, 0x27, 0x97, 0xbc, 0x6f, 0xc6, 0xbb, 0x33, 0xdb, 0xf4, 0x5b, 0xdc,
-  0x96, 0x3c, 0x91, 0xb5, 0x04, 0x34, 0x0f, 0x9e, 0xa1, 0xa2, 0x77, 0x4b,
-  0x34, 0x57, 0xc7, 0xc7, 0xb4, 0x2b, 0x46, 0xd5, 0xda, 0xaf, 0x0b, 0x79,
-  0x32, 0xd4, 0xf1, 0x80, 0xa2, 0xbd, 0xb2, 0xd3, 0xaf, 0x38, 0x1b, 0x65,
-  0xb5, 0x38, 0xb3, 0xdc, 0x12, 0x36, 0x69, 0x9a, 0xd9, 0x87, 0x48, 0x53,
-  0x42, 0x4d, 0xd9, 0xf4, 0x41, 0x8e, 0x3a, 0x9e, 0x63, 0xe7, 0x1a, 0xce,
-  0xda, 0xce, 0xb5, 0xcb, 0xc5, 0x28, 0xe7, 0xe9, 0xf3, 0x61, 0x26, 0xc5,
-  0x74, 0x21, 0x6e, 0x28, 0x25, 0x09, 0x2a, 0x51, 0xee, 0x00, 0x6e, 0x99,
-  0x2d, 0x18, 0x7c, 0xf9, 0x2d, 0x89, 0x13, 0x54, 0x98, 0x51, 0xfb, 0xca,
-  0x9c, 0x3a, 0x3a, 0xf6, 0x54, 0x83, 0x97, 0xcb, 0x05, 0x89, 0x05, 0xab,
-  0x2c, 0x31, 0x25, 0xf1, 0xd0, 0xbe, 0xe0, 0xe9, 0x4b, 0x77, 0x7b, 0xdd,
-  0xca, 0xe8, 0xe1, 0x54, 0xb9, 0x2b, 0x52, 0x7c, 0x10, 0x0e, 0x92, 0x3e,
-  0xaa, 0xed, 0xf7, 0x36, 0x76, 0xbf, 0x7b, 0x2f, 0x79, 0x2f, 0x28, 0xf1,
-  0xf3, 0x7d, 0x7e, 0x44, 0xe1, 0x21, 0x94, 0xdc, 0x71, 0x9c, 0x78, 0x72,
-  0xdb, 0xd8, 0xf7, 0x42, 0x58, 0xfe, 0x95, 0x7f, 0x04, 0x1a, 0x5f, 0xbc,
-  0xe4, 0x57, 0x4b, 0xa2, 0x88, 0x7e, 0x41, 0x43, 0x5e, 0x0d, 0xa3, 0xa2,
-  0x45, 0x44, 0xd1, 0x58, 0x57, 0xed, 0x2a, 0xd5, 0x63, 0xee, 0xe3, 0xdd,
-  0x8f, 0x92, 0xd9, 0x7c, 0xfc, 0xfe, 0x64, 0x39, 0x36, 0x14, 0xed, 0x87,
-  0x38, 0x8b, 0xd6, 0x39, 0x37, 0x1d, 0x7d, 0x43, 0xb4, 0x4a, 0x7b, 0x48,
-  0xe4, 0xf8, 0x1f, 0xff, 0x00, 0xdf, 0xfb, 0xd2, 0x4d, 0x77, 0x58, 0x2e,
-  0x0e, 0x5b, 0x2e, 0xcc, 0x4c, 0x6c, 0xfc, 0x05, 0x79, 0xc3, 0xd2, 0x3c,
-  0x45, 0x57, 0xb3, 0xae, 0x55, 0xbd, 0x74, 0xe7, 0xe1, 0x7b, 0x3f, 0x83,
-  0xe4, 0x45, 0xe1, 0x9c, 0x6e, 0xb6, 0xb6, 0x9d, 0x5b, 0x4e, 0x24, 0xa5,
-  0x68, 0x51, 0x4a, 0x81, 0xf0, 0x23, 0xbc, 0x57, 0x9a, 0x6a, 0xe2, 0x35,
-  0xbd, 0xb6, 0xae, 0x0d, 0x5d, 0x62, 0xf5, 0x8d, 0x39, 0x21, 0x7b, 0x1e,
-  0x0a, 0xd7, 0xfd, 0xc7, 0xfd, 0xe9, 0x56, 0xb2, 0xbc, 0xb6, 0x76, 0xd5,
-  0xa5, 0x49, 0xf4, 0xfd, 0x57, 0x47, 0xf9, 0x06, 0xb0, 0xf0, 0x59, 0x7c,
-  0x2b, 0xbb, 0x76, 0xf0, 0x1c, 0xb5, 0xba, 0xad, 0xad, 0x8f, 0x39, 0xbd,
-  0xf8, 0xa4, 0xff, 0x00, 0xe0, 0xff, 0x00, 0xda, 0x9d, 0xaa, 0x8e, 0xc7,
-  0x2e, 0x4b, 0xb5, 0x5e, 0x18, 0x98, 0x92, 0x79, 0x52, 0xad, 0x2c, 0x7a,
-  0x52, 0x7b, 0xea, 0xee, 0x65, 0xc4, 0x3c, 0xca, 0x1d, 0x6c, 0x85, 0x21,
-  0x60, 0x10, 0x47, 0x88, 0xaf, 0xbe, 0xf6, 0x6a, 0xfb, 0xed, 0x16, 0xbe,
-  0xea, 0x4f, 0xbd, 0x0d, 0xbe, 0x5d, 0x3f, 0x83, 0x6a, 0x72, 0xca, 0x3d,
-  0xd6, 0x08, 0xeb, 0x59, 0xa3, 0x55, 0xf4, 0x66, 0x87, 0xce, 0x37, 0x58,
-  0xc2, 0xdb, 0x9b, 0xcf, 0xb5, 0x05, 0xf3, 0x06, 0xf8, 0x8b, 0x6f, 0x96,
-  0x9f, 0x52, 0x64, 0x86, 0x5e, 0x3f, 0xf5, 0x29, 0x75, 0xf4, 0x70, 0xee,
-  0xaf, 0x9e, 0x33, 0x51, 0xae, 0x33, 0xdc, 0xff, 0x00, 0x6a, 0x71, 0xd3,
-  0xf5, 0xf2, 0x01, 0xff, 0x00, 0x8a, 0xfa, 0x1c, 0x77, 0x56, 0x93, 0x79,
-  0xc7, 0xc0, 0xce, 0x1c, 0xbf, 0x8f, 0xf0, 0x14, 0x51, 0x45, 0x66, 0x68,
-  0x14, 0x9b, 0xc6, 0xf3, 0xae, 0x10, 0x65, 0xa7, 0xff, 0x00, 0x48, 0x91,
-  0xf7, 0x66, 0x9c, 0xa9, 0x33, 0x8e, 0x5f, 0x23, 0xb9, 0x77, 0xd0, 0xf2,
-  0x7e, 0xec, 0xd0, 0x11, 0x9f, 0x83, 0x79, 0x2d, 0xf0, 0x82, 0xd5, 0x05,
-  0x67, 0xdf, 0x60, 0x3f, 0x2e, 0x1b, 0xa0, 0xf7, 0x82, 0xdc, 0x97, 0x53,
-  0xaf, 0xee, 0x03, 0xfb, 0xea, 0xc6, 0xaa, 0xb7, 0x82, 0xb2, 0xbc, 0x87,
-  0x22, 0xcb, 0x31, 0xb7, 0x34, 0x92, 0x64, 0xb5, 0x78, 0x8f, 0xb3, 0xf0,
-  0x9b, 0x90, 0xd8, 0x4a, 0xf4, 0x3d, 0x01, 0xd6, 0x9c, 0xff, 0x00, 0x98,
-  0x7a, 0x6a, 0xd2, 0x1d, 0xd5, 0x69, 0xad, 0x32, 0x68, 0xac, 0x25, 0xaa,
-  0x29, 0x85, 0x14, 0x51, 0x55, 0x2c, 0x15, 0x4a, 0xe6, 0x71, 0x8c, 0x4c,
-  0x9a, 0x6b, 0x44, 0x10, 0x0b, 0x9c, 0xc3, 0xd8, 0x7a, 0xd5, 0xd5, 0x4a,
-  0xd9, 0x8d, 0x86, 0xd7, 0x26, 0x4a, 0x6e, 0xd7, 0x17, 0xd4, 0xcb, 0x4d,
-  0x23, 0x95, 0xce, 0x51, 0xf0, 0xbd, 0x15, 0xe0, 0xfb, 0x43, 0x61, 0x2b,
-  0xcb, 0x65, 0xa3, 0x98, 0xbc, 0xef, 0xb6, 0xdd, 0x4a, 0x4e, 0x39, 0x45,
-  0x59, 0x16, 0x34, 0x89, 0x4e, 0x86, 0xa3, 0xb2, 0xb7, 0x56, 0x7b, 0x82,
-  0x46, 0xe9, 0xa6, 0x06, 0x1e, 0x19, 0x68, 0x4a, 0xbe, 0xcb, 0x6e, 0x1b,
-  0x3d, 0xfc, 0x9b, 0xf3, 0x8d, 0x7b, 0x97, 0x96, 0x43, 0xb7, 0xb4, 0x63,
-  0x63, 0xd0, 0x50, 0xca, 0x7b, 0xbb, 0x65, 0x8f, 0x38, 0xfa, 0xe9, 0x5a,
-  0x7c, 0xe9, 0x73, 0x9e, 0x2e, 0xcb, 0x90, 0xb7, 0x54, 0x7f, 0x48, 0xd7,
-  0xc5, 0x62, 0xca, 0xd7, 0x9f, 0xee, 0xcb, 0xf2, 0x8f, 0xf2, 0xcc, 0x76,
-  0x43, 0x5b, 0xf9, 0x2d, 0xa6, 0xd0, 0xd9, 0x63, 0x1f, 0x82, 0x92, 0xbe,
-  0xe2, 0xfb, 0x83, 0xad, 0x2c, 0x5c, 0xee, 0x93, 0xee, 0x4e, 0x97, 0x26,
-  0x49, 0x5b, 0x87, 0xd1, 0xbe, 0x83, 0xea, 0xae, 0x3a, 0x2b, 0x9a, 0xe7,
-  0xb4, 0x2b, 0xdc, 0x2d, 0x2d, 0xe2, 0x3e, 0x4b, 0x65, 0xf9, 0x10, 0xe4,
-  0xd8, 0x51, 0x45, 0x15, 0xc2, 0x40, 0x51, 0x45, 0x14, 0x01, 0x45, 0x14,
-  0x50, 0x0f, 0x18, 0xe2, 0x86, 0x41, 0x88, 0xca, 0xb2, 0x38, 0x41, 0x93,
-  0x18, 0x76, 0x91, 0xc9, 0xff, 0x00, 0x0f, 0xfc, 0x7d, 0x74, 0x8e, 0xa0,
-  0x52, 0xa2, 0x95, 0x02, 0x08, 0x3a, 0x20, 0xf8, 0x54, 0x9e, 0x2f, 0x73,
-  0x55, 0xaa, 0xf4, 0xc4, 0xa0, 0x4f, 0x20, 0x57, 0x2b, 0x83, 0xd2, 0x93,
-  0xdf, 0x52, 0x5c, 0x42, 0xb6, 0x26, 0x1d, 0xe0, 0x4c, 0x8e, 0x37, 0x1a,
-  0x6a, 0x7b, 0x54, 0x11, 0xdd, 0xbf, 0x1f, 0xfc, 0xfd, 0x75, 0xec, 0x57,
-  0xff, 0x00, 0x95, 0x67, 0x1a, 0xdf, 0x8a, 0x9f, 0x75, 0xfc, 0x3f, 0x0b,
-  0xfd, 0xbf, 0x22, 0xcf, 0x75, 0x91, 0x6a, 0xad, 0x2e, 0x18, 0x5d, 0xbc,
-  0xb2, 0xd0, 0x60, 0x3a, 0xad, 0xbb, 0x17, 0xa2, 0x77, 0xe2, 0x83, 0xdd,
-  0xfd, 0xdd, 0xd5, 0x56, 0xd4, 0xc6, 0x19, 0x71, 0x5d, 0xb7, 0x21, 0x8c,
-  0xea, 0x49, 0xe4, 0x71, 0x41, 0xb7, 0x07, 0xa4, 0x13, 0xaf, 0xfc, 0x1a,
-  0xaf, 0x62, 0xde, 0xbb, 0x3b, 0xb8, 0xc9, 0xf0, 0xf6, 0x7f, 0x07, 0xfc,
-  0x08, 0x3c, 0x32, 0xe9, 0xac, 0x13, 0xaa, 0xcd, 0x68, 0x9b, 0x25, 0x98,
-  0x91, 0x9e, 0x95, 0x25, 0xc4, 0xb4, 0xc3, 0x2d, 0xa9, 0xc7, 0x16, 0xa3,
-  0xa0, 0x94, 0xa4, 0x6c, 0x93, 0xec, 0x15, 0xfa, 0xa1, 0xd2, 0x7c, 0xf9,
-  0x92, 0x3c, 0xdc, 0xde, 0x27, 0x5c, 0xee, 0x0c, 0xab, 0x99, 0x07, 0x3b,
-  0xb3, 0xc3, 0xdf, 0xeb, 0x32, 0xdb, 0x01, 0x5f, 0xf5, 0x28, 0xd7, 0xd1,
-  0x43, 0xba, 0xbe, 0x69, 0xb3, 0xa1, 0xd7, 0x71, 0xfc, 0x56, 0xef, 0x25,
-  0xb2, 0xdc, 0x9b, 0xde, 0x63, 0x16, 0xec, 0xf2, 0x7d, 0x06, 0x44, 0xa2,
-  0xb4, 0x8f, 0xa9, 0x05, 0x03, 0xea, 0xaf, 0xa5, 0x85, 0x6b, 0x56, 0x3a,
-  0x70, 0xbd, 0x0c, 0x68, 0xcb, 0x56, 0x5f, 0xa8, 0x51, 0x45, 0x15, 0x91,
-  0xb0, 0x52, 0x67, 0x1c, 0xbe, 0x47, 0x72, 0xef, 0xa1, 0xe4, 0xfd, 0xd9,
-  0xa7, 0x3a, 0x4c, 0xe3, 0x91, 0xd7, 0x07, 0x72, 0xfd, 0xf7, 0x7b, 0x91,
-  0x27, 0xee, 0xcd, 0x00, 0x83, 0x74, 0x98, 0x31, 0x9c, 0x8e, 0xc3, 0x9a,
-  0x95, 0x72, 0x44, 0x86, 0x0c, 0x1b, 0xa9, 0x1e, 0x10, 0xde, 0x29, 0xf7,
-  0xc5, 0x78, 0xe9, 0xb7, 0x03, 0x6b, 0xf9, 0xbc, 0xf5, 0x78, 0xa7, 0xb8,
-  0x55, 0x65, 0x1a, 0xd0, 0xf5, 0xde, 0x12, 0xa2, 0x18, 0x7e, 0x53, 0x1d,
-  0xe6, 0xbb, 0x37, 0x50, 0xe0, 0xd2, 0x16, 0x92, 0x34, 0x52, 0x49, 0xf0,
-  0x20, 0x91, 0x5d, 0x5c, 0x36, 0x9f, 0x37, 0x19, 0x9c, 0x9e, 0x1c, 0xe4,
-  0x6f, 0xf3, 0xbf, 0x19, 0x92, 0xbb, 0x1c, 0xc5, 0x9d, 0xf9, 0x7c, 0x34,
-  0xfe, 0x66, 0xfc, 0x5e, 0x6b, 0xa2, 0x54, 0x3b, 0xca, 0x79, 0x55, 0xd7,
-  0x6a, 0xd7, 0x5d, 0xdc, 0x62, 0xa5, 0x94, 0xce, 0x4b, 0x49, 0x4b, 0x4e,
-  0x1a, 0xe0, 0xb0, 0xea, 0x37, 0x23, 0xbb, 0xb3, 0x65, 0xb6, 0x2e, 0x63,
-  0xc3, 0x98, 0x8e, 0x88, 0x46, 0xf5, 0xcc, 0xaf, 0x45, 0x49, 0x0a, 0x4a,
-  0xe2, 0xd3, 0x2e, 0xae, 0xd5, 0x15, 0xd4, 0x6c, 0xa1, 0x0e, 0x9e, 0x7d,
-  0x7a, 0xc7, 0x4a, 0xf1, 0xbb, 0x4e, 0xe2, 0x76, 0xf6, 0x93, 0xab, 0x4f,
-  0x94, 0x8e, 0xa9, 0x3c, 0x21, 0x5a, 0x5e, 0x69, 0x7e, 0x7d, 0xf2, 0xe2,
-  0x25, 0x06, 0x53, 0xbe, 0x88, 0x42, 0x46, 0xa9, 0x8b, 0x1b, 0xc8, 0x7f,
-  0x94, 0x71, 0x9e, 0xb2, 0x5d, 0x12, 0x8e, 0xd9, 0xc6, 0xc8, 0x42, 0xc0,
-  0xd0, 0x57, 0xff, 0x00, 0xba, 0xae, 0xab, 0x7d, 0xbe, 0x53, 0x90, 0xa6,
-  0xb3, 0x2d, 0xa3, 0xa5, 0xb4, 0xb0, 0xa1, 0x5f, 0x9d, 0x5a, 0xf6, 0xc5,
-  0xcd, 0x3a, 0xba, 0xaa, 0xcd, 0xca, 0x2f, 0x94, 0xf7, 0xca, 0xea, 0x73,
-  0xa9, 0xbc, 0xee, 0x17, 0x08, 0xae, 0x42, 0x9a, 0xf4, 0x57, 0x46, 0x96,
-  0xd2, 0x8a, 0x4d, 0x68, 0xa7, 0x1e, 0x20, 0x45, 0x6e, 0x5c, 0x78, 0x99,
-  0x04, 0x50, 0x0b, 0x72, 0x10, 0x03, 0x9a, 0xf0, 0x55, 0x27, 0x57, 0x25,
-  0xf5, 0xb7, 0xd9, 0xab, 0xca, 0x9a, 0xe3, 0x95, 0xea, 0x9f, 0x04, 0x49,
-  0x61, 0x85, 0x14, 0x51, 0x5c, 0x64, 0x05, 0x14, 0x51, 0x40, 0x14, 0x51,
-  0x45, 0x00, 0x51, 0x45, 0x14, 0x01, 0x4f, 0x56, 0x84, 0xff, 0x00, 0x29,
-  0xf0, 0xb7, 0x2d, 0xa4, 0x83, 0x36, 0x11, 0xe6, 0x64, 0x9e, 0xf2, 0x3c,
-  0x07, 0xda, 0x3e, 0xb1, 0x48, 0xb5, 0x33, 0x86, 0xdd, 0x0d, 0xa6, 0xfa,
-  0xcb, 0xe4, 0x9e, 0xc9, 0x67, 0x91, 0xc1, 0xea, 0x35, 0xe9, 0x76, 0x65,
-  0x78, 0x52, 0xad, 0xa2, 0xa7, 0x82, 0x7d, 0xd7, 0xf0, 0x7d, 0x7e, 0x5c,
-  0x96, 0x8b, 0xc3, 0x22, 0xa4, 0xc7, 0x7a, 0x33, 0xca, 0x65, 0xf6, 0x94,
-  0xdb, 0x89, 0x3a, 0x29, 0x50, 0xd5, 0x32, 0xf0, 0xff, 0x00, 0x1f, 0x7e,
-  0xe3, 0x74, 0x6e, 0x6b, 0xc8, 0x28, 0x89, 0x1d, 0x41, 0x44, 0x91, 0xf0,
-  0xd4, 0x3b, 0x92, 0x3f, 0xef, 0x56, 0x83, 0xd0, 0xe1, 0x4a, 0xe5, 0x71,
-  0xd8, 0xcc, 0xbb, 0xe2, 0x14, 0xa4, 0x03, 0x5b, 0x9b, 0x42, 0x1b, 0x40,
-  0x43, 0x68, 0x4a, 0x12, 0x3b, 0x82, 0x46, 0x80, 0xaf, 0xab, 0xb4, 0xf6,
-  0x5a, 0x14, 0xab, 0xaa, 0x93, 0x9e, 0xa8, 0xad, 0xd2, 0xc7, 0xd4, 0xd1,
-  0x53, 0xc3, 0x3d, 0x55, 0x75, 0xc7, 0x7b, 0x82, 0xd7, 0x8e, 0x47, 0xc4,
-  0x22, 0x3a, 0x51, 0x37, 0x25, 0x7b, 0xc8, 0xc9, 0x49, 0xf3, 0x9b, 0x88,
-  0x00, 0x54, 0xa7, 0x3d, 0x81, 0xbd, 0xa3, 0xda, 0xe2, 0x69, 0xea, 0xf1,
-  0x72, 0x83, 0x67, 0xb5, 0xca, 0xba, 0x5c, 0xa5, 0x37, 0x16, 0x14, 0x46,
-  0x94, 0xf3, 0xef, 0x38, 0x74, 0x94, 0x21, 0x23, 0x64, 0x93, 0x54, 0xed,
-  0x95, 0xc9, 0xb9, 0x0d, 0xfe, 0x6e, 0x6f, 0x75, 0x8c, 0xe4, 0x77, 0xa6,
-  0xb6, 0x23, 0xdb, 0x62, 0x3a, 0x34, 0xb8, 0x70, 0x41, 0xda, 0x42, 0xc7,
-  0x83, 0x8e, 0x1f, 0x3d, 0x43, 0xbc, 0x6d, 0x29, 0xfc, 0xda, 0xfb, 0x3a,
-  0x14, 0x9d, 0x49, 0xe0, 0x8a, 0xd5, 0x55, 0x38, 0xe7, 0xa9, 0xa7, 0x2e,
-  0x43, 0x6d, 0x3d, 0x8a, 0xb4, 0xd2, 0x02, 0x1b, 0x4e, 0x4b, 0x6d, 0x4a,
-  0x52, 0x06, 0x82, 0x40, 0x78, 0x68, 0x0f, 0x65, 0x5e, 0x63, 0xba, 0xa8,
-  0xec, 0xcb, 0xe3, 0x38, 0xb7, 0x7f, 0xfa, 0xcf, 0x6e, 0xfb, 0xe1, 0x57,
-  0x88, 0xee, 0xad, 0x2f, 0x3e, 0xf3, 0xe4, 0x67, 0x67, 0xf7, 0x61, 0x45,
-  0x14, 0x57, 0x29, 0xd4, 0x14, 0x99, 0xc7, 0x1f, 0x91, 0xec, 0xb7, 0xe8,
-  0x89, 0x1f, 0xc0, 0x69, 0xce, 0x93, 0x38, 0xe3, 0xf2, 0x3d, 0x97, 0x7d,
-  0x11, 0x23, 0xf8, 0x0d, 0x00, 0xdb, 0x11, 0x09, 0x4c, 0x56, 0x92, 0x90,
-  0x00, 0x09, 0x1d, 0x00, 0xa8, 0x5c, 0xe7, 0x17, 0x81, 0x95, 0xd9, 0xc4,
-  0x09, 0x6b, 0x76, 0x3b, 0xec, 0xb8, 0x99, 0x10, 0x66, 0xb2, 0x74, 0xf4,
-  0x39, 0x09, 0xf8, 0x0e, 0xb6, 0x7f, 0x48, 0x1f, 0x0e, 0xe2, 0x36, 0x08,
-  0x20, 0x9a, 0x9c, 0x8d, 0xf1, 0x76, 0xfe, 0x60, 0xfb, 0x2b, 0x61, 0x1b,
-  0xa0, 0x11, 0xf1, 0x3c, 0xb6, 0x74, 0x7b, 0xab, 0x78, 0x96, 0x6c, 0xdb,
-  0x30, 0xaf, 0xda, 0x3e, 0x47, 0x29, 0x03, 0x96, 0x35, 0xd9, 0x03, 0xf3,
-  0xd9, 0x27, 0xb9, 0xc0, 0x3a, 0xa9, 0xa3, 0xe7, 0x0e, 0xa4, 0x6d, 0x3d,
-  0x69, 0xbe, 0xe1, 0x12, 0x3d, 0xc2, 0x13, 0x91, 0x24, 0xa0, 0x2d, 0xa7,
-  0x06, 0x88, 0xae, 0x3c, 0x9b, 0x1f, 0xb3, 0xe4, 0x96, 0x87, 0x2d, 0x57,
-  0xb8, 0x2d, 0xcc, 0x88, 0xb2, 0x15, 0xc8, 0xad, 0x82, 0x85, 0x0e, 0xe5,
-  0xa1, 0x43, 0xaa, 0x14, 0x3b, 0xc2, 0x92, 0x41, 0x07, 0xba, 0x93, 0xfb,
-  0x4c, 0xd7, 0x05, 0x46, 0x9f, 0x4c, 0xbc, 0xd3, 0x1e, 0x47, 0x73, 0xad,
-  0x80, 0x6e, 0xb1, 0x13, 0xd7, 0xe1, 0x27, 0xa2, 0x64, 0xa4, 0x00, 0x3a,
-  0x8e, 0x57, 0x3d, 0x4b, 0x3d, 0x4d, 0x65, 0x15, 0x24, 0xe3, 0x25, 0x94,
-  0xc1, 0x1d, 0x91, 0xe1, 0x17, 0x1b, 0x79, 0x53, 0xf0, 0x42, 0xa6, 0xc6,
-  0xef, 0xf3, 0x47, 0xbe, 0x27, 0xda, 0x3c, 0x7d, 0xa2, 0x95, 0x08, 0x20,
-  0x90, 0x41, 0x04, 0x74, 0x20, 0xd5, 0xd1, 0x8a, 0xe4, 0xf6, 0x2c, 0xa2,
-  0x07, 0x97, 0x58, 0xae, 0x6c, 0x4d, 0x69, 0x27, 0x95, 0xc0, 0x82, 0x43,
-  0x8c, 0xab, 0xf4, 0x5c, 0x41, 0xd2, 0x90, 0xaf, 0xd5, 0x50, 0x07, 0xd5,
-  0x5e, 0xaf, 0x58, 0xed, 0xa2, 0xef, 0xb5, 0x4a, 0x8a, 0x90, 0xef, 0xf5,
-  0xad, 0xf9, 0xab, 0xfe, 0xf1, 0xdf, 0xf5, 0xee, 0xbe, 0x46, 0xff, 0x00,
-  0xd9, 0x58, 0xcd, 0xb9, 0xda, 0xcb, 0x1e, 0x8f, 0x8f, 0x93, 0x32, 0x95,
-  0x3f, 0x21, 0x27, 0x06, 0x7d, 0xbb, 0xa5, 0xa2, 0x66, 0x3b, 0x24, 0xef,
-  0x99, 0x25, 0x6c, 0x6f, 0xc0, 0xd2, 0x7c, 0xa6, 0x1c, 0x8d, 0x25, 0xc6,
-  0x1d, 0x1a, 0x5b, 0x6a, 0x29, 0x22, 0xac, 0x04, 0x61, 0x13, 0xad, 0x77,
-  0x26, 0x67, 0xda, 0x26, 0xa1, 0xde, 0xc9, 0x7b, 0xec, 0xdd, 0x1c, 0xaa,
-  0x23, 0xc4, 0x6c, 0x74, 0x3f, 0xe1, 0x5c, 0x5c, 0x48, 0xb1, 0xc9, 0xf2,
-  0xe4, 0x5c, 0xe3, 0x45, 0x71, 0x49, 0x79, 0x3e, 0xfc, 0x10, 0x92, 0xae,
-  0x55, 0x7a, 0xf5, 0x5e, 0x55, 0xef, 0x67, 0x5c, 0xfd, 0x8d, 0x3a, 0xb0,
-  0x7a, 0xa9, 0xed, 0xe7, 0x98, 0xbe, 0x38, 0xf2, 0x7f, 0xa1, 0x57, 0x17,
-  0x8d, 0xc4, 0x8a, 0x28, 0x20, 0x82, 0x41, 0x04, 0x11, 0xe0, 0x68, 0xaf,
-  0x9a, 0x33, 0x0a, 0x28, 0xa2, 0x80, 0x28, 0xa2, 0xbd, 0x34, 0xd3, 0x8f,
-  0x2c, 0x21, 0xa6, 0xd6, 0xe2, 0x8f, 0x72, 0x52, 0x9d, 0x9a, 0x94, 0x9b,
-  0xd9, 0x03, 0xcd, 0x15, 0x39, 0x6f, 0xc4, 0xaf, 0xf3, 0x48, 0x29, 0x80,
-  0xb6, 0x50, 0x7f, 0x39, 0xff, 0x00, 0x33, 0x5f, 0x51, 0xeb, 0xfe, 0x14,
-  0xd3, 0x69, 0xe1, 0xdb, 0x28, 0x21, 0x77, 0x49, 0xa5, 0xc3, 0xe2, 0xdb,
-  0x03, 0x43, 0xfe, 0x63, 0xd4, 0xff, 0x00, 0x70, 0xaf, 0x4e, 0xdb, 0xb1,
-  0xaf, 0x6e, 0x5f, 0x76, 0x9b, 0x4b, 0xcd, 0xec, 0xbf, 0x5f, 0xd8, 0xb2,
-  0x83, 0x65, 0x7d, 0x16, 0x3b, 0xf2, 0x9f, 0x4b, 0x11, 0x99, 0x5b, 0xce,
-  0xab, 0xb9, 0x28, 0x4e, 0xc9, 0xa7, 0xbc, 0x67, 0x02, 0x51, 0x52, 0x24,
-  0xde, 0xd5, 0xca, 0x06, 0x88, 0x8e, 0x85, 0x75, 0x3f, 0x38, 0x8f, 0xb0,
-  0x7f, 0x7d, 0x3b, 0xdb, 0x2d, 0x90, 0x2d, 0x8c, 0xf6, 0x50, 0x62, 0xb6,
-  0xc2, 0x7c, 0x4a, 0x47, 0x53, 0xed, 0x3d, 0xe7, 0xeb, 0xae, 0xa2, 0x48,
-  0xaf, 0xad, 0xec, 0xff, 0x00, 0x66, 0x28, 0xd1, 0x6a, 0x77, 0x0f, 0x53,
-  0xf2, 0xe9, 0xfe, 0x7f, 0xdd, 0x8d, 0x63, 0x4d, 0x2e, 0x41, 0xb4, 0x25,
-  0xb6, 0xd2, 0xda, 0x12, 0x12, 0x94, 0x80, 0x12, 0x07, 0x70, 0x02, 0xb9,
-  0x6e, 0xd7, 0x18, 0x36, 0x9b, 0x74, 0x8b, 0x95, 0xca, 0x5b, 0x10, 0xe1,
-  0x46, 0x6c, 0xb8, 0xfb, 0xef, 0x2c, 0x25, 0x0d, 0xa4, 0x77, 0x92, 0x4f,
-  0x41, 0x4b, 0x79, 0x46, 0x7d, 0x6c, 0xb5, 0x5c, 0x7d, 0xc4, 0xb5, 0xc7,
-  0x7f, 0x20, 0xc8, 0x54, 0x3c, 0xcb, 0x5d, 0xbf, 0x4b, 0x71, 0x1e, 0x85,
-  0x3c, 0xb2, 0x79, 0x18, 0x47, 0x77, 0x9c, 0xb2, 0x3d, 0x41, 0x47, 0xa5,
-  0x70, 0x5b, 0xf0, 0xeb, 0xa5, 0xfe, 0xe6, 0xc5, 0xef, 0x88, 0x72, 0x62,
-  0xcd, 0x5c, 0x77, 0x03, 0xb0, 0xac, 0xb1, 0x49, 0x30, 0x21, 0xac, 0x1f,
-  0x35, 0x6a, 0xe6, 0x00, 0xbe, 0xe8, 0xfd, 0x25, 0x00, 0x94, 0x9f, 0x82,
-  0x90, 0x7a, 0xd7, 0xd4, 0xf0, 0x68, 0x72, 0x44, 0x8b, 0x33, 0x89, 0x37,
-  0x18, 0xd7, 0x7b, 0xc4, 0x57, 0xe0, 0xe2, 0x11, 0x1e, 0x43, 0xf6, 0xeb,
-  0x73, 0xc9, 0x28, 0x76, 0xe8, 0xea, 0x4e, 0xd3, 0x21, 0xf4, 0x9e, 0xa9,
-  0x65, 0x24, 0x02, 0xdb, 0x67, 0xaa, 0x88, 0xe7, 0x5e, 0x86, 0x93, 0x4e,
-  0xf7, 0x3b, 0x34, 0x19, 0xe9, 0xdb, 0x8d, 0xf2, 0x39, 0xe0, 0xb4, 0x74,
-  0x23, 0xff, 0x00, 0x35, 0x22, 0x00, 0xd5, 0x1a, 0x1a, 0xa9, 0x8c, 0x9c,
-  0x5e, 0x51, 0x59, 0x45, 0x49, 0x61, 0x95, 0x17, 0x12, 0xec, 0xd2, 0x6d,
-  0xd2, 0x31, 0x67, 0x54, 0xa4, 0xb8, 0xc9, 0xca, 0x2d, 0xa0, 0x2c, 0x74,
-  0x23, 0xdf, 0x87, 0x78, 0xab, 0x78, 0x77, 0x52, 0x27, 0x19, 0x47, 0xf3,
-  0x2c, 0x5f, 0xf6, 0xaa, 0xd9, 0xf7, 0xe2, 0x9e, 0xea, 0xd5, 0x2a, 0x4a,
-  0xa3, 0xcc, 0x88, 0xa7, 0x4d, 0x53, 0x58, 0x41, 0x45, 0x79, 0x24, 0x83,
-  0xa0, 0x01, 0xfa, 0xe8, 0xaa, 0x17, 0x3d, 0x52, 0x67, 0x1c, 0x7e, 0x47,
-  0xb2, 0xef, 0xa2, 0x24, 0x7f, 0x01, 0xa7, 0x3a, 0x4c, 0xe3, 0x8f, 0xc8,
-  0xf6, 0x5d, 0xf4, 0x44, 0x8f, 0xe0, 0x34, 0x03, 0x7c, 0x6f, 0x8b, 0xb7,
-  0xf3, 0x07, 0xd9, 0x5b, 0x2b, 0x5c, 0x6f, 0x8b, 0xb7, 0xf3, 0x07, 0xd9,
-  0x5b, 0x28, 0x03, 0x5d, 0x68, 0xd5, 0x14, 0x50, 0x0a, 0xd9, 0x3e, 0x07,
-  0x8e, 0xdf, 0xa7, 0x7b, 0xa6, 0xe4, 0x77, 0xad, 0xf7, 0x74, 0x8d, 0x22,
-  0xe9, 0x6e, 0x78, 0xc6, 0x96, 0x9f, 0x57, 0x68, 0x8d, 0x15, 0x0f, 0xd5,
-  0x5f, 0x32, 0x7d, 0x55, 0x14, 0x22, 0xf1, 0x37, 0x1e, 0xf8, 0x94, 0xfb,
-  0x5e, 0x63, 0x0d, 0x00, 0xe9, 0xa9, 0xc3, 0xc8, 0x66, 0x81, 0xe0, 0x03,
-  0xa8, 0x49, 0x69, 0x67, 0xda, 0x84, 0x7b, 0x7c, 0x69, 0xf7, 0x5d, 0x77,
-  0x47, 0x28, 0xa0, 0x11, 0x07, 0x13, 0x6d, 0xd6, 0xf0, 0x53, 0x95, 0xd8,
-  0x72, 0x1c, 0x64, 0xa0, 0x00, 0xa7, 0x66, 0x40, 0x53, 0xb1, 0xb7, 0xea,
-  0x7d, 0x9e, 0x76, 0xf5, 0xeb, 0x51, 0x4f, 0xd5, 0x4c, 0xb6, 0x2c, 0x9f,
-  0x1d, 0xbf, 0xa4, 0xaa, 0xc7, 0x7d, 0xb6, 0x5c, 0xf4, 0x36, 0x44, 0x59,
-  0x48, 0x70, 0x81, 0xeb, 0x09, 0x24, 0x8a, 0x96, 0xd5, 0x2e, 0x5f, 0xf0,
-  0x2c, 0x2a, 0xfc, 0xb5, 0x39, 0x77, 0xc5, 0xad, 0x12, 0xde, 0x57, 0x7b,
-  0xca, 0x8a, 0x80, 0xef, 0xd4, 0xb0, 0x02, 0x87, 0xd4, 0x68, 0x09, 0xc9,
-  0x31, 0x22, 0x49, 0x1f, 0xce, 0x62, 0x30, 0xf8, 0xff, 0x00, 0x68, 0xd8,
-  0x57, 0xdb, 0x51, 0xee, 0xe3, 0x36, 0x07, 0xb7, 0xcf, 0x69, 0x8c, 0x3e,
-  0x6a, 0x79, 0x7e, 0xca, 0x5b, 0x5f, 0x0b, 0xac, 0x6c, 0x21, 0x2d, 0xd9,
-  0x6f, 0x59, 0x55, 0x91, 0x29, 0xee, 0x4c, 0x2b, 0xe4, 0x8e, 0x41, 0xff,
-  0x00, 0x03, 0x8a, 0x5a, 0x7f, 0xc2, 0xa1, 0x32, 0xf0, 0x30, 0xb8, 0x61,
-  0xdb, 0x9f, 0x1c, 0xa6, 0xd9, 0x5a, 0xd7, 0x98, 0x2e, 0xc8, 0x82, 0xea,
-  0x97, 0xec, 0x05, 0xa4, 0xa9, 0x5f, 0x56, 0xeb, 0x1a, 0x96, 0xd4, 0x6a,
-  0x78, 0xe0, 0x9f, 0xc5, 0x26, 0x46, 0x10, 0xee, 0xac, 0x37, 0x1b, 0x27,
-  0xad, 0xb0, 0x7d, 0x4f, 0x38, 0x3f, 0xfe, 0xd5, 0x94, 0x61, 0xf8, 0xda,
-  0x4f, 0x4b, 0x62, 0x4f, 0xb5, 0xd5, 0x9f, 0xb5, 0x55, 0x4e, 0x5a, 0xb8,
-  0x99, 0x16, 0x74, 0xd1, 0x16, 0x0f, 0xe1, 0x11, 0x8b, 0x29, 0xd3, 0xf0,
-  0x53, 0x70, 0xb0, 0x25, 0x90, 0xaf, 0x62, 0x94, 0xeb, 0x60, 0xfd, 0x54,
-  0xfd, 0x0a, 0xdb, 0xc4, 0xc9, 0xb1, 0xd1, 0x26, 0x1f, 0x12, 0x31, 0xb9,
-  0x0c, 0x2c, 0x6d, 0x0e, 0x35, 0x8f, 0x73, 0x21, 0x43, 0xd2, 0x08, 0x93,
-  0xa3, 0x58, 0x7f, 0x4e, 0xb3, 0xff, 0x00, 0xaa, 0x3f, 0xf9, 0x5f, 0xc0,
-  0xd2, 0xbc, 0x87, 0x06, 0x31, 0xeb, 0x13, 0x3d, 0x5b, 0xb4, 0xc4, 0xd8,
-  0xf1, 0x53, 0x41, 0x5f, 0x6e, 0xea, 0x41, 0x96, 0x9a, 0x65, 0x1c, 0xac,
-  0xb4, 0xdb, 0x49, 0xf4, 0x21, 0x3a, 0x14, 0x88, 0x31, 0xae, 0x26, 0x39,
-  0xf9, 0x7e, 0x27, 0xc5, 0x6f, 0xff, 0x00, 0xc7, 0xc7, 0x1a, 0x4e, 0xbf,
-  0xe7, 0x71, 0x75, 0xb5, 0x58, 0x3e, 0x41, 0x2d, 0xbe, 0x5b, 0xa7, 0x13,
-  0xb2, 0x97, 0x7f, 0xfc, 0x36, 0xe2, 0x45, 0x1f, 0xf4, 0x33, 0xbf, 0xf1,
-  0xae, 0x8a, 0x74, 0x29, 0xd3, 0xf0, 0x45, 0x2f, 0x82, 0x27, 0x08, 0x79,
-  0x27, 0xd5, 0x50, 0xf9, 0x56, 0x51, 0x60, 0xc5, 0xa1, 0x22, 0x66, 0x43,
-  0x75, 0x8d, 0x6f, 0x65, 0xc5, 0x72, 0x34, 0x5d, 0x57, 0x9c, 0xe2, 0xb5,
-  0xbe, 0x54, 0x24, 0x75, 0x51, 0xd7, 0x80, 0x04, 0xd2, 0x3d, 0x8e, 0xcc,
-  0xdd, 0x87, 0x8c, 0xf0, 0x6d, 0x71, 0x2f, 0x77, 0xe9, 0xe3, 0xf9, 0x3f,
-  0x26, 0x4c, 0xb1, 0x71, 0xb9, 0xbd, 0x27, 0x9b, 0x6f, 0xb0, 0x86, 0xcf,
-  0x2a, 0x89, 0x48, 0xf8, 0x2e, 0x6b, 0x40, 0x78, 0xd4, 0x8c, 0x12, 0x32,
-  0x6e, 0x31, 0xbf, 0x3d, 0xb0, 0x95, 0xdb, 0xb1, 0x58, 0x8b, 0x84, 0xdb,
-  0x9e, 0x06, 0x7c, 0x8e, 0x55, 0x3a, 0x12, 0x7c, 0x7b, 0x36, 0x92, 0xda,
-  0x4f, 0xa0, 0xba, 0x47, 0x78, 0xad, 0x41, 0xb1, 0x59, 0xf5, 0xd2, 0xea,
-  0x4a, 0x31, 0x0c, 0x22, 0xf5, 0x73, 0x04, 0x8e, 0x59, 0x77, 0x04, 0x7b,
-  0x9b, 0x17, 0x94, 0xfe, 0x76, 0xde, 0x1d, 0xaa, 0x87, 0xcd, 0x6c, 0xd7,
-  0x93, 0x8a, 0xe6, 0x39, 0x01, 0xde, 0x5f, 0x96, 0x98, 0x90, 0xd4, 0x7c,
-  0xeb, 0x66, 0x3e, 0x95, 0x46, 0x42, 0x87, 0x5e, 0x8b, 0x90, 0xad, 0xbc,
-  0xa0, 0x47, 0x7f, 0x2f, 0x67, 0xec, 0xa7, 0xd0, 0x01, 0x1e, 0x04, 0x1f,
-  0x55, 0x67, 0x42, 0x80, 0x8a, 0xc6, 0x71, 0xdb, 0x1e, 0x37, 0x6d, 0x16,
-  0xfb, 0x0d, 0xae, 0x35, 0xba, 0x30, 0x3c, 0xca, 0x43, 0x28, 0xd7, 0x3a,
-  0xbc, 0x54, 0xa3, 0xde, 0xa5, 0x1f, 0x15, 0x12, 0x49, 0xf4, 0xd4, 0xae,
-  0xba, 0x6a, 0x8a, 0x28, 0x02, 0x8a, 0x28, 0xa0, 0x11, 0x38, 0xcb, 0xf1,
-  0x2c, 0x5f, 0xf6, 0xaa, 0xd9, 0xf7, 0xe2, 0x9e, 0xe9, 0x13, 0x8c, 0xbf,
-  0x12, 0xc5, 0xff, 0x00, 0x6a, 0xad, 0x9f, 0x7e, 0x29, 0xee, 0x80, 0xc1,
-  0xef, 0xdd, 0x14, 0x1a, 0x2a, 0x51, 0x56, 0xcc, 0xd2, 0x67, 0x1c, 0x7e,
-  0x47, 0xb2, 0xef, 0xa2, 0x24, 0x7f, 0x01, 0xa7, 0x3a, 0x4c, 0xe3, 0x8f,
-  0xc8, 0xf6, 0x5d, 0xf4, 0x44, 0x8f, 0xe0, 0x35, 0x05, 0x86, 0xf8, 0xdf,
-  0x17, 0x6f, 0xe6, 0x0f, 0xb2, 0xb6, 0x56, 0xb8, 0xdf, 0x17, 0x6f, 0xe6,
-  0x0f, 0xb2, 0xb6, 0x50, 0x05, 0x14, 0x56, 0x09, 0x3b, 0xee, 0xa0, 0x33,
-  0x58, 0x2a, 0xd7, 0x7d, 0x28, 0xe7, 0x3c, 0x48, 0xc3, 0xf0, 0xd7, 0x51,
-  0x16, 0xf5, 0x77, 0x47, 0xba, 0x2e, 0xfe, 0x42, 0xdb, 0x15, 0xb5, 0x48,
-  0x98, 0xf1, 0xf0, 0x09, 0x65, 0xb0, 0x56, 0x77, 0xd3, 0xa9, 0x00, 0x7a,
-  0xe9, 0x64, 0xe4, 0x1c, 0x56, 0xcc, 0x55, 0xc9, 0x8c, 0xe3, 0x4c, 0xe1,
-  0x16, 0xc5, 0x74, 0xf7, 0x4f, 0x21, 0x48, 0x7a, 0x62, 0x87, 0xfb, 0x38,
-  0x8d, 0xab, 0x49, 0x3f, 0xef, 0x56, 0x3d, 0x94, 0x05, 0x8d, 0x7d, 0xbd,
-  0x5a, 0x6c, 0x36, 0xc7, 0x6e, 0x77, 0xbb, 0x94, 0x4b, 0x6c, 0x26, 0x46,
-  0xdc, 0x91, 0x29, 0xd4, 0xb6, 0x84, 0xff, 0x00, 0xc4, 0xa2, 0x05, 0x57,
-  0x6b, 0xe2, 0xe4, 0x8b, 0xfa, 0x8b, 0x3c, 0x34, 0xc2, 0xaf, 0x19, 0x60,
-  0x3b, 0xd5, 0xc5, 0xd1, 0xee, 0x7d, 0xb8, 0x6b, 0xd0, 0xfb, 0xc3, 0x6b,
-  0xeb, 0xfa, 0x09, 0x57, 0xb6, 0xba, 0xac, 0x7c, 0x1d, 0xc7, 0xd3, 0x76,
-  0x66, 0xff, 0x00, 0x97, 0xcf, 0xb8, 0x66, 0xb7, 0xc6, 0xba, 0xb7, 0x2a,
-  0xf2, 0xb0, 0xb6, 0x59, 0x3f, 0xec, 0xa3, 0xa4, 0x06, 0x9b, 0x1f, 0xf0,
-  0x93, 0xeb, 0xab, 0x19, 0x29, 0x4a, 0x3c, 0xd4, 0x80, 0x00, 0x1d, 0x00,
-  0x1d, 0x05, 0x01, 0x56, 0x1c, 0x3b, 0x89, 0xb9, 0x67, 0xfa, 0xeb, 0x9d,
-  0x33, 0x62, 0x80, 0xb1, 0xe7, 0xdb, 0x31, 0x56, 0x94, 0xd2, 0xd4, 0x35,
-  0xf0, 0x57, 0x2d, 0xcd, 0xb9, 0xed, 0xe4, 0x4a, 0x37, 0x4c, 0x18, 0x8f,
-  0x0a, 0x38, 0x77, 0x8b, 0xc8, 0x13, 0x2d, 0x38, 0xa5, 0xbc, 0x4e, 0xef,
-  0x33, 0x64, 0xa4, 0xc9, 0x90, 0x4f, 0xa4, 0xba, 0xe9, 0x52, 0xf7, 0xf5,
-  0xd3, 0xa8, 0x03, 0x54, 0x6f, 0xc3, 0x54, 0x07, 0x0d, 0xda, 0xc9, 0x67,
-  0xbb, 0xb1, 0xe4, 0xf7, 0x6b, 0x54, 0x1b, 0x83, 0x3a, 0xd7, 0x67, 0x2a,
-  0x3a, 0x1d, 0x4e, 0xbd, 0x1a, 0x50, 0x22, 0xaa, 0x9c, 0xb3, 0x0d, 0x77,
-  0x86, 0x12, 0x3f, 0x96, 0xdc, 0x31, 0xb7, 0x3e, 0xd4, 0x16, 0x17, 0xcf,
-  0x7d, 0xc6, 0xe2, 0x28, 0xf9, 0x3c, 0xd8, 0xff, 0x00, 0x9e, 0xeb, 0x2d,
-  0x1e, 0x88, 0x7d, 0x03, 0xa8, 0xe5, 0xd0, 0x50, 0x04, 0x6b, 0x75, 0x70,
-  0xbc, 0xf3, 0x6c, 0xb4, 0xb7, 0x5d, 0x71, 0x08, 0x6d, 0x00, 0x95, 0x29,
-  0x6a, 0xd0, 0x48, 0x1e, 0x24, 0xf8, 0x57, 0x05, 0x9a, 0xf9, 0x65, 0xbd,
-  0xa1, 0xc7, 0xac, 0xd7, 0x68, 0x17, 0x24, 0x34, 0xa0, 0x97, 0x15, 0x16,
-  0x4a, 0x1d, 0x4a, 0x0f, 0xa0, 0xf2, 0x93, 0xa3, 0x40, 0x18, 0xcd, 0xf2,
-  0xd7, 0x91, 0xe3, 0xf0, 0x6f, 0xb6, 0x59, 0xad, 0xcc, 0xb7, 0x4d, 0x64,
-  0x3c, 0xc3, 0xe8, 0xee, 0x52, 0x4f, 0xd8, 0x7c, 0x08, 0x3d, 0xc4, 0x1a,
-  0x90, 0xd9, 0x1b, 0xd8, 0xaa, 0x93, 0x07, 0xe5, 0xe1, 0xd7, 0x16, 0xae,
-  0x58, 0x33, 0xde, 0xf3, 0x60, 0xc9, 0x9c, 0x76, 0xed, 0x8f, 0x1e, 0xe4,
-  0x35, 0x23, 0xbe, 0x54, 0x51, 0xd3, 0x43, 0xaf, 0xbe, 0xa4, 0x0f, 0x05,
-  0x2b, 0xd1, 0x56, 0x85, 0xf2, 0x1b, 0xd7, 0x1b, 0x34, 0xeb, 0x7c, 0x79,
-  0x8e, 0xc2, 0x7a, 0x4c, 0x77, 0x19, 0x44, 0x96, 0xc6, 0xd6, 0xca, 0x94,
-  0x92, 0x02, 0xc0, 0xf4, 0x8d, 0xef, 0xea, 0xa0, 0x29, 0xd8, 0x99, 0x2d,
-  0xc2, 0xe5, 0x95, 0xe4, 0x17, 0x1c, 0x6c, 0xb7, 0x2a, 0xfb, 0x90, 0x3a,
-  0x9b, 0x6d, 0x88, 0x2c, 0x05, 0xb7, 0x0e, 0xdf, 0x14, 0xad, 0x0e, 0x4e,
-  0x70, 0x8e, 0xe6, 0x8b, 0xca, 0x78, 0xa4, 0x7f, 0x48, 0x42, 0x12, 0x37,
-  0xbd, 0x8b, 0x5f, 0x0d, 0xc7, 0x60, 0xe3, 0x18, 0xe4, 0x5b, 0x34, 0x12,
-  0xb5, 0xa1, 0x90, 0x54, 0xeb, 0xce, 0x1d, 0xb8, 0xfb, 0xaa, 0x3c, 0xce,
-  0x3a, 0xb3, 0xe2, 0xb5, 0x28, 0x95, 0x13, 0xe9, 0x3e, 0x8d, 0x0a, 0x89,
-  0xe1, 0x6e, 0x01, 0x69, 0xc0, 0xac, 0x29, 0x83, 0x0d, 0xc7, 0x26, 0x4d,
-  0x75, 0x0d, 0x89, 0x93, 0xde, 0xfc, 0xa4, 0x82, 0x84, 0xf2, 0xa0, 0x7a,
-  0x12, 0x84, 0x8e, 0x89, 0x40, 0xe8, 0x3a, 0x9e, 0xa4, 0x92, 0x5b, 0xc7,
-  0x41, 0x40, 0x14, 0x51, 0x45, 0x00, 0x51, 0x45, 0x14, 0x01, 0x45, 0x14,
-  0x50, 0x08, 0x9c, 0x65, 0xf8, 0x96, 0x2f, 0xfb, 0x55, 0x6c, 0xfb, 0xf1,
-  0x4f, 0x74, 0x89, 0xc6, 0x5f, 0x89, 0x62, 0xff, 0x00, 0xb5, 0x56, 0xcf,
-  0xbf, 0x14, 0xf7, 0x40, 0x79, 0x51, 0xeb, 0x45, 0x64, 0x8d, 0x9e, 0xf3,
-  0x45, 0x0a, 0xb4, 0xf2, 0x66, 0x93, 0x38, 0xe3, 0xf2, 0x3d, 0x97, 0x7d,
-  0x11, 0x23, 0xf8, 0x0d, 0x39, 0xd2, 0x67, 0x1c, 0x7e, 0x47, 0xb2, 0xef,
-  0xa2, 0x24, 0x7f, 0x01, 0xa1, 0x61, 0xbe, 0x37, 0xc5, 0xdb, 0xf9, 0x83,
-  0xec, 0xaf, 0x64, 0xfb, 0x2a, 0x2e, 0xf5, 0x7b, 0xb5, 0xe3, 0xb8, 0xeb,
-  0xd7, 0x9b, 0xd4, 0xe6, 0x60, 0xdb, 0xe2, 0x32, 0x1c, 0x7d, 0xf7, 0x4e,
-  0x92, 0x81, 0xd0, 0x0f, 0x59, 0x24, 0x90, 0x00, 0x1d, 0x49, 0x20, 0x0d,
-  0x93, 0x55, 0xea, 0xa6, 0x71, 0x03, 0x89, 0x40, 0xa2, 0xd6, 0x64, 0x60,
-  0x98, 0xaa, 0xf5, 0xb9, 0x6f, 0x37, 0xfe, 0x98, 0x98, 0x8f, 0x1e, 0xcd,
-  0xb3, 0xd2, 0x32, 0x4f, 0x82, 0x95, 0xb5, 0xeb, 0x44, 0x04, 0xee, 0x80,
-  0x60, 0xce, 0xb8, 0x9d, 0x8d, 0x62, 0x93, 0x5b, 0xb5, 0x28, 0xca, 0xbc,
-  0xdf, 0x9e, 0xd8, 0x62, 0xcb, 0x69, 0x6b, 0xca, 0x66, 0xb9, 0xeb, 0x28,
-  0x07, 0xcc, 0x4f, 0xeb, 0x2c, 0xa4, 0x7a, 0xfa, 0x54, 0x0f, 0xb9, 0x5c,
-  0x5b, 0xcd, 0x00, 0x55, 0xea, 0xf1, 0x13, 0x01, 0xb4, 0x3a, 0x36, 0x61,
-  0x5a, 0x08, 0x93, 0x72, 0x52, 0x4f, 0xe6, 0xb9, 0x21, 0x63, 0x91, 0xa5,
-  0x6b, 0xc5, 0xb4, 0xa8, 0x8d, 0xfc, 0x2a, 0x73, 0xc1, 0xf0, 0xac, 0x5f,
-  0x0c, 0xb7, 0x18, 0x98, 0xe5, 0xa1, 0x88, 0x7d, 0xa7, 0x57, 0xdf, 0xd7,
-  0x33, 0xf2, 0x15, 0xbd, 0x95, 0x3a, 0xe9, 0xda, 0xdc, 0x56, 0xc9, 0xea,
-  0xa2, 0x69, 0x87, 0x42, 0x80, 0x56, 0xc1, 0xb0, 0x0c, 0x4f, 0x0c, 0x69,
-  0xc3, 0x60, 0xb4, 0x32, 0xcc, 0xb7, 0xb6, 0x64, 0x4d, 0x74, 0x97, 0x65,
-  0x48, 0x51, 0xea, 0x4b, 0x8f, 0x2b, 0x6b, 0x56, 0xcf, 0xa4, 0xeb, 0xd0,
-  0x05, 0x77, 0xe5, 0xf9, 0x56, 0x3b, 0x88, 0xda, 0xcd, 0xcf, 0x24, 0xbc,
-  0x44, 0xb6, 0x45, 0xdf, 0x2a, 0x56, 0xf2, 0xf4, 0xa7, 0x15, 0xfa, 0x28,
-  0x48, 0xf3, 0x96, 0xaf, 0xd5, 0x48, 0x24, 0xfa, 0x2b, 0xb2, 0xf0, 0xdd,
-  0xcd, 0xd4, 0x47, 0x4d, 0xae, 0x54, 0x78, 0xea, 0x12, 0x5b, 0x53, 0xe5,
-  0xe6, 0x4b, 0x9c, 0xcc, 0x83, 0xe7, 0xa5, 0x3a, 0x50, 0xd2, 0x88, 0xee,
-  0x27, 0x60, 0x7a, 0x0d, 0x7b, 0x93, 0x6f, 0x81, 0x2e, 0x5c, 0x69, 0x72,
-  0xa0, 0xc6, 0x7a, 0x4c, 0x55, 0x15, 0x47, 0x75, 0xc6, 0x92, 0xa5, 0xb2,
-  0x4f, 0x42, 0x52, 0x48, 0xda, 0x77, 0xea, 0xa0, 0x12, 0x71, 0x9c, 0xdf,
-  0x27, 0xcb, 0x2f, 0xd1, 0x95, 0x63, 0xc3, 0x26, 0x5b, 0xf1, 0x94, 0xa8,
-  0x99, 0x17, 0x4b, 0xde, 0xe3, 0x3b, 0x21, 0x3a, 0xe8, 0x23, 0xc7, 0xf8,
-  0x7d, 0x49, 0x07, 0x99, 0xce, 0x51, 0xaf, 0x0a, 0x71, 0x9b, 0x69, 0x89,
-  0x32, 0xed, 0x6f, 0xbb, 0x3c, 0x5f, 0x12, 0x60, 0x07, 0x7b, 0x00, 0x87,
-  0x96, 0x94, 0x7b, 0xe2, 0x42, 0x54, 0x54, 0x90, 0x74, 0xae, 0x83, 0xa7,
-  0x30, 0x3a, 0xeb, 0x50, 0x39, 0x7f, 0x11, 0x71, 0x1c, 0x5e, 0x4f, 0x90,
-  0x4e, 0xb9, 0xf9, 0x4d, 0xd5, 0x63, 0x6d, 0xdb, 0x20, 0xb6, 0x64, 0xcc,
-  0x70, 0xeb, 0x63, 0x4d, 0x23, 0x6a, 0x03, 0xf5, 0x95, 0xa4, 0xfa, 0xe9,
-  0x32, 0xe3, 0x96, 0x71, 0x13, 0x26, 0xda, 0x2d, 0xb1, 0xa3, 0x61, 0x56,
-  0xe5, 0x7f, 0x4d, 0x24, 0x22, 0x65, 0xc5, 0x43, 0xd4, 0xd8, 0x3d, 0x93,
-  0x47, 0xe7, 0x17, 0x08, 0xf4, 0x78, 0x55, 0xe1, 0x4e, 0x53, 0xf0, 0xa2,
-  0x93, 0xa9, 0x18, 0x78, 0x99, 0x67, 0x64, 0x79, 0x05, 0x8f, 0x1a, 0xb5,
-  0xae, 0xe5, 0x7f, 0xba, 0xc2, 0xb5, 0x42, 0x6f, 0xbd, 0xe9, 0x6f, 0xa5,
-  0xb4, 0x7b, 0x01, 0x27, 0xa9, 0xf5, 0x0e, 0xb5, 0x40, 0x66, 0x9f, 0x85,
-  0x35, 0xad, 0x4d, 0xb8, 0xd6, 0x01, 0x66, 0x55, 0xdf, 0x5c, 0xc9, 0xf7,
-  0x42, 0x66, 0xda, 0x8e, 0x08, 0x3a, 0x25, 0x28, 0x1e, 0x7a, 0x87, 0xb7,
-  0x93, 0xeb, 0x15, 0x3a, 0xce, 0x03, 0x89, 0xcc, 0xf2, 0xa1, 0x94, 0x44,
-  0x93, 0x92, 0xbb, 0x3a, 0x3a, 0xa3, 0xc9, 0x9d, 0x75, 0x78, 0xc8, 0x92,
-  0x94, 0x2b, 0xc5, 0xb5, 0x2b, 0xa3, 0x5a, 0xef, 0x01, 0x01, 0x35, 0xf2,
-  0xb7, 0x10, 0x30, 0xeb, 0xcf, 0xe0, 0xff, 0x00, 0xc4, 0x98, 0xee, 0xa5,
-  0x5e, 0xe9, 0x62, 0xd7, 0x25, 0x15, 0x42, 0x98, 0xa6, 0xd2, 0xa2, 0xe3,
-  0x40, 0x8e, 0x61, 0xd4, 0x69, 0x0f, 0xa0, 0x11, 0xd4, 0x68, 0xf5, 0x04,
-  0x6b, 0x7d, 0x34, 0x9d, 0x19, 0x53, 0x6b, 0x51, 0x48, 0x56, 0x55, 0x13,
-  0xd2, 0x36, 0xe4, 0x57, 0x2c, 0xeb, 0x88, 0x6e, 0x89, 0x19, 0x9d, 0xfe,
-  0x6c, 0x88, 0x0b, 0x21, 0x4d, 0xc0, 0x1e, 0xf1, 0x11, 0x43, 0x7f, 0x9a,
-  0xd2, 0x01, 0x2e, 0xfb, 0x40, 0x77, 0x5e, 0x24, 0x77, 0xd3, 0x9e, 0x26,
-  0xfc, 0xdc, 0x32, 0x74, 0x5c, 0xb6, 0xd7, 0xda, 0x49, 0x55, 0x95, 0xb0,
-  0x6e, 0x6d, 0x34, 0x94, 0xa4, 0x3d, 0x6d, 0xd0, 0x4b, 0x88, 0x3a, 0x51,
-  0x0a, 0x28, 0x00, 0x2d, 0x03, 0x99, 0x44, 0x14, 0x7c, 0x14, 0x6e, 0xba,
-  0x20, 0x45, 0x81, 0x21, 0xbf, 0x2d, 0x66, 0x42, 0x66, 0x25, 0xd4, 0x25,
-  0xe5, 0x3c, 0x09, 0x29, 0x29, 0x50, 0x04, 0x29, 0x44, 0xe8, 0x9e, 0x84,
-  0x69, 0x4b, 0xec, 0xfe, 0x79, 0xa6, 0x2b, 0x25, 0xb8, 0xb8, 0xa6, 0xa4,
-  0x06, 0x10, 0x88, 0xa1, 0xc4, 0xee, 0x43, 0x9c, 0x9c, 0xbd, 0x7f, 0x45,
-  0x4a, 0x1c, 0xbc, 0xde, 0xb4, 0x25, 0x64, 0xef, 0xf2, 0x86, 0xb7, 0x8d,
-  0x14, 0xd6, 0x0e, 0x79, 0x56, 0x79, 0xc9, 0x6c, 0x71, 0x5b, 0x19, 0x6f,
-  0x3f, 0xe1, 0xfb, 0x4e, 0xd8, 0xa6, 0x36, 0x9b, 0xa4, 0x62, 0xdd, 0xdb,
-  0x1f, 0x9e, 0xda, 0xb6, 0x1b, 0x92, 0x81, 0xce, 0xd2, 0xc2, 0xbf, 0x41,
-  0x40, 0xf2, 0x9f, 0x4a, 0x56, 0x6a, 0x53, 0x85, 0x99, 0x6b, 0x19, 0xce,
-  0x05, 0x6b, 0xc9, 0x1a, 0x6b, 0xb0, 0x72, 0x4b, 0x5c, 0xb2, 0xa3, 0x9e,
-  0xf6, 0x24, 0x20, 0x94, 0x3a, 0xd9, 0x1f, 0xaa, 0xb4, 0xa8, 0x75, 0xf0,
-  0xd1, 0xf1, 0xa4, 0xee, 0x09, 0x5c, 0x06, 0x3f, 0x73, 0x9b, 0xc3, 0x49,
-  0x4e, 0x28, 0xb1, 0x15, 0x06, 0x75, 0x85, 0x6b, 0x3d, 0x5c, 0x84, 0xa5,
-  0x79, 0xcc, 0xef, 0xc4, 0xb2, 0xe1, 0xd7, 0x7f, 0xc0, 0x52, 0x3d, 0x15,
-  0xaa, 0x12, 0x87, 0x0d, 0x78, 0xd8, 0xfc, 0x27, 0x13, 0xd9, 0xe3, 0x19,
-  0xe4, 0x8e, 0xda, 0x2a, 0x87, 0xc0, 0x8b, 0x76, 0x08, 0xf7, 0xc4, 0x1f,
-  0x40, 0x7d, 0x29, 0xe6, 0x1f, 0xac, 0x92, 0x3c, 0x6b, 0x8e, 0x51, 0x71,
-  0x78, 0x67, 0x64, 0x64, 0xa4, 0xb2, 0x8b, 0x7c, 0x74, 0x14, 0x56, 0x12,
-  0x76, 0x90, 0x6b, 0x35, 0x52, 0xc1, 0x45, 0x14, 0x50, 0x05, 0x14, 0x51,
-  0x40, 0x1d, 0x68, 0xa2, 0x8a, 0x01, 0x13, 0x8c, 0xbf, 0x12, 0xc5, 0xff,
-  0x00, 0x6a, 0xad, 0x9f, 0x7e, 0x29, 0xee, 0x91, 0x38, 0xcb, 0xf1, 0x2c,
-  0x5f, 0xf6, 0xaa, 0xd9, 0xf7, 0xe2, 0x9e, 0xe8, 0x02, 0x8a, 0xf2, 0xa2,
-  0x41, 0xe8, 0x07, 0xd6, 0x75, 0x45, 0x01, 0xea, 0x93, 0x38, 0xe3, 0xbf,
-  0xc4, 0xfe, 0x5c, 0x3f, 0xf4, 0x89, 0x1a, 0xff, 0x00, 0x90, 0xd3, 0x9d,
-  0x26, 0x71, 0xc7, 0xe4, 0x7b, 0x2e, 0xfa, 0x22, 0x47, 0xf0, 0x1a, 0x02,
-  0xbe, 0x9f, 0x7f, 0x63, 0x27, 0xe2, 0x52, 0xfd, 0xd2, 0x61, 0x4f, 0xdb,
-  0xac, 0x37, 0x37, 0x2d, 0xb6, 0x78, 0xab, 0xd7, 0x66, 0x67, 0x30, 0xca,
-  0x5c, 0x7e, 0x63, 0xa9, 0x3d, 0xe5, 0x1c, 0xe8, 0x43, 0x60, 0xef, 0x44,
-  0x95, 0x0e, 0xa7, 0xa5, 0xdb, 0x05, 0x96, 0xd9, 0x8a, 0x84, 0xa0, 0xa8,
-  0x82, 0x36, 0x54, 0x7b, 0xd4, 0x4f, 0x79, 0x3e, 0xb3, 0x5f, 0x38, 0x71,
-  0x36, 0x1c, 0xcc, 0x3f, 0x8d, 0xb6, 0xf9, 0x69, 0x98, 0xd4, 0x7b, 0x3e,
-  0x50, 0xfa, 0x6e, 0x2c, 0xad, 0xf0, 0x7b, 0x36, 0x67, 0x32, 0xcf, 0x65,
-  0x25, 0xae, 0x80, 0xeb, 0xb6, 0x60, 0x82, 0x0e, 0xba, 0xb8, 0xda, 0x47,
-  0xa6, 0xaf, 0x5c, 0x16, 0xf0, 0xc5, 0xdf, 0x1f, 0x8c, 0xf3, 0x0f, 0x07,
-  0x51, 0xd9, 0x25, 0x6d, 0xab, 0x44, 0x15, 0x36, 0xa1, 0xb4, 0xab, 0x47,
-  0xaf, 0x71, 0xf1, 0xeb, 0x5a, 0xe3, 0x34, 0xf2, 0xba, 0x33, 0x27, 0x2c,
-  0x54, 0xc3, 0xea, 0x86, 0x02, 0x75, 0xe1, 0xd2, 0xbc, 0xb8, 0xe2, 0x5b,
-  0x6d, 0x4b, 0x71, 0x49, 0x42, 0x52, 0x36, 0xa2, 0x4e, 0x80, 0x1e, 0x93,
-  0x54, 0x1f, 0x1c, 0x7f, 0x08, 0x85, 0x61, 0xb9, 0x14, 0x9c, 0x4f, 0x14,
-  0xc5, 0x9f, 0xbe, 0x5e, 0x59, 0x21, 0xb7, 0x64, 0x3c, 0x4a, 0x22, 0xb4,
-  0xb2, 0x90, 0xae, 0x5f, 0x37, 0x6a, 0x70, 0x80, 0x46, 0xc0, 0xe5, 0x03,
-  0x7a, 0xdf, 0x7d, 0x7c, 0x77, 0xc6, 0xee, 0x29, 0x71, 0x47, 0x29, 0xbb,
-  0x48, 0xb4, 0xe6, 0x17, 0xf9, 0x09, 0x8e, 0x9d, 0x1f, 0x20, 0x8b, 0xef,
-  0x51, 0x8a, 0x48, 0xd8, 0xf3, 0x52, 0x7c, 0xee, 0x84, 0x7c, 0x22, 0xa2,
-  0x3b, 0xab, 0x34, 0x8d, 0x32, 0x8f, 0xbe, 0xaf, 0x3c, 0x60, 0xc7, 0x3c,
-  0xb6, 0x45, 0xaf, 0x11, 0x62, 0x46, 0x63, 0x75, 0x60, 0xf2, 0xbc, 0xd5,
-  0xad, 0x49, 0x31, 0xd8, 0x57, 0x87, 0x6b, 0x21, 0x47, 0xb3, 0x47, 0x71,
-  0xe8, 0x0a, 0x95, 0xea, 0xa5, 0x6b, 0xa3, 0xb9, 0xb6, 0x44, 0xdb, 0xb2,
-  0x32, 0xec, 0x95, 0x18, 0xfd, 0xaf, 0xbc, 0xdb, 0xac, 0x8e, 0x96, 0x7c,
-  0xcf, 0x43, 0xd2, 0xd4, 0x03, 0x87, 0xbf, 0x44, 0x36, 0x10, 0x3d, 0xb5,
-  0xf3, 0x77, 0xe0, 0x29, 0x74, 0x4b, 0x79, 0x16, 0x4b, 0x66, 0x5b, 0x89,
-  0xdc, 0x88, 0x8d, 0x49, 0x42, 0x09, 0xe8, 0x7b, 0x35, 0x94, 0x9e, 0x9f,
-  0xff, 0x00, 0x20, 0xfe, 0xea, 0xfa, 0x1b, 0x89, 0x39, 0x26, 0x3f, 0x89,
-  0xdb, 0x5b, 0xbc, 0xde, 0xd2, 0xec, 0xb7, 0xb9, 0xbb, 0x2b, 0x7c, 0x06,
-  0x93, 0xda, 0x3b, 0x25, 0xef, 0x00, 0xdb, 0x7e, 0x2a, 0xfd, 0x63, 0xdd,
-  0xea, 0xf1, 0xee, 0xa1, 0x46, 0x1a, 0x35, 0xb3, 0x8a, 0xbd, 0x59, 0xeb,
-  0xd0, 0x89, 0x1c, 0x42, 0xdd, 0x8e, 0xdb, 0x61, 0x29, 0xac, 0x72, 0xdc,
-  0xcc, 0x46, 0x15, 0xd5, 0x6b, 0x6d, 0x82, 0x92, 0xf1, 0xfd, 0x25, 0x2c,
-  0x8d, 0xb8, 0x77, 0xe2, 0x49, 0xf6, 0xd4, 0xd8, 0xef, 0xdf, 0xd5, 0xeb,
-  0xff, 0x00, 0xdf, 0xfe, 0xfa, 0xd5, 0x28, 0xde, 0x47, 0xc7, 0x4b, 0xc5,
-  0xd1, 0x0b, 0x6e, 0x0e, 0x2f, 0x8c, 0x32, 0xe8, 0xe7, 0x8f, 0x6d, 0x98,
-  0xdb, 0xb3, 0x26, 0x2d, 0x1e, 0x1c, 0xc8, 0x68, 0x29, 0x43, 0xfb, 0x93,
-  0x56, 0x74, 0x1b, 0xe2, 0xd9, 0x87, 0x1e, 0x3d, 0xd1, 0xb7, 0x5c, 0xbd,
-  0xa5, 0x09, 0x12, 0x22, 0xc7, 0x86, 0xeb, 0x6a, 0xe7, 0x00, 0x15, 0x28,
-  0x21, 0xcd, 0x29, 0x0d, 0xf5, 0xd8, 0x52, 0xb4, 0x3c, 0x37, 0xba, 0xea,
-  0x85, 0x58, 0xbd, 0x8e, 0x49, 0xd3, 0x97, 0x2c, 0x52, 0xce, 0xf8, 0x83,
-  0x73, 0x4d, 0xe9, 0x78, 0xa6, 0x05, 0x6f, 0x66, 0xe7, 0x7b, 0x6d, 0xc0,
-  0xdc, 0xb9, 0x92, 0x12, 0x7c, 0x92, 0x0a, 0x94, 0x36, 0x12, 0x79, 0x7c,
-  0xe7, 0x5d, 0xd7, 0x5e, 0xcd, 0x20, 0x91, 0xe3, 0xdc, 0x45, 0x42, 0x71,
-  0x1f, 0x0c, 0xcd, 0xee, 0xdc, 0x10, 0xc9, 0x23, 0x66, 0xf7, 0x0b, 0xcd,
-  0xde, 0x40, 0x69, 0x12, 0xed, 0xe5, 0x56, 0xb6, 0x23, 0xc5, 0x86, 0xf3,
-  0x67, 0x98, 0x94, 0x84, 0x92, 0xf0, 0x0a, 0x4f, 0x32, 0x36, 0xa0, 0x07,
-  0x9d, 0xb2, 0x07, 0x78, 0xb5, 0xb8, 0x67, 0x62, 0xf2, 0x0c, 0x4a, 0xf6,
-  0xee, 0x2b, 0x6b, 0x89, 0x03, 0x23, 0x5d, 0xc5, 0xe6, 0x82, 0xa7, 0x28,
-  0x2c, 0x47, 0x0b, 0x58, 0x57, 0x3a, 0xb4, 0x4f, 0x36, 0xd2, 0xb0, 0xb3,
-  0xa2, 0x79, 0x95, 0xa0, 0x4e, 0x80, 0xd4, 0x8e, 0x2f, 0x8d, 0xdc, 0x71,
-  0xbc, 0x22, 0xf5, 0x74, 0xcf, 0x6e, 0xfe, 0xe8, 0xdd, 0x5d, 0x8c, 0xff,
-  0x00, 0x96, 0x48, 0x12, 0xde, 0x71, 0x92, 0xc9, 0x4f, 0x41, 0xd9, 0xa8,
-  0x84, 0x03, 0xd0, 0x9f, 0x35, 0x09, 0xd7, 0x37, 0x28, 0xf4, 0x9f, 0x3a,
-  0xbd, 0x69, 0x4d, 0xb4, 0xcf, 0x46, 0x85, 0x18, 0xc1, 0x26, 0x8a, 0x43,
-  0xf0, 0x66, 0x4a, 0xae, 0x3c, 0x26, 0xb2, 0xc6, 0x90, 0x1b, 0x66, 0xec,
-  0xd0, 0x71, 0x71, 0x15, 0x29, 0xb5, 0x3a, 0x04, 0x60, 0xe9, 0x48, 0x75,
-  0xa4, 0x28, 0x84, 0x92, 0x0e, 0xd2, 0x48, 0xee, 0x29, 0xeb, 0xd7, 0xa5,
-  0x59, 0x4c, 0xdb, 0x2e, 0x2b, 0x9c, 0x5e, 0x4b, 0x49, 0x0e, 0x21, 0x5a,
-  0x33, 0xae, 0x0b, 0x12, 0x1e, 0x23, 0x7f, 0xd1, 0xb6, 0x9f, 0x31, 0x03,
-  0xbf, 0xd1, 0xf3, 0x69, 0x62, 0xdd, 0x65, 0x5e, 0x15, 0x87, 0x18, 0x32,
-  0x16, 0x96, 0xdd, 0xc7, 0x6e, 0x91, 0xee, 0xb1, 0x47, 0x2f, 0x9c, 0xcc,
-  0x19, 0xea, 0x4a, 0x1f, 0x6b, 0xe6, 0x85, 0xad, 0xcd, 0x81, 0xd3, 0x6d,
-  0x83, 0xe1, 0x56, 0x3a, 0x18, 0x6d, 0xb7, 0x9d, 0x71, 0x3c, 0xdc, 0xee,
-  0x1f, 0x3c, 0x95, 0x13, 0xdd, 0xd3, 0xa0, 0x3d, 0x00, 0xe9, 0xdc, 0x34,
-  0x2b, 0xb6, 0xdd, 0xeb, 0x8f, 0xc0, 0xe3, 0xb8, 0x5a, 0x65, 0xb7, 0x52,
-  0x07, 0x37, 0xb7, 0xdc, 0x9c, 0x89, 0x0a, 0xf9, 0x61, 0xda, 0xaf, 0xf6,
-  0x27, 0xbc, 0xb6, 0x07, 0x5d, 0x76, 0xe4, 0x27, 0x4e, 0xb0, 0xaf, 0xd5,
-  0x75, 0xbe, 0x64, 0x6b, 0xa6, 0x8f, 0x29, 0xf0, 0xa7, 0x3c, 0x9a, 0xdd,
-  0x67, 0xe2, 0xff, 0x00, 0x08, 0x35, 0x06, 0x49, 0x43, 0x57, 0x38, 0xc8,
-  0x97, 0x6e, 0x97, 0xdc, 0xe4, 0x49, 0x29, 0x3c, 0xcd, 0x2f, 0xd2, 0x95,
-  0x21, 0xc4, 0x80, 0x47, 0xa9, 0x42, 0xa3, 0x7c, 0x7f, 0xfd, 0xd4, 0x77,
-  0x0d, 0xa7, 0x7f, 0x24, 0x78, 0x83, 0x2f, 0x16, 0x78, 0xf2, 0xd9, 0xf2,
-  0x45, 0xb9, 0x3e, 0xd4, 0x4f, 0x44, 0xb3, 0x30, 0x0e, 0x69, 0x2c, 0x0f,
-  0x40, 0x58, 0xf7, 0xd4, 0x8e, 0x9d, 0x7b, 0x5a, 0xca, 0xf2, 0x96, 0x7b,
-  0xe8, 0xd2, 0xce, 0xa6, 0x3b, 0x8c, 0x6b, 0xe0, 0xce, 0x62, 0xfe, 0x5f,
-  0x86, 0x21, 0xeb, 0xa2, 0x11, 0x1e, 0xff, 0x00, 0x6d, 0x75, 0x76, 0xfb,
-  0xdc, 0x6d, 0xe8, 0xb1, 0x31, 0xa3, 0xca, 0xe7, 0x41, 0xf9, 0xaa, 0xe8,
-  0xb4, 0xfa, 0x42, 0x85, 0x3b, 0x8e, 0xea, 0xa7, 0xf3, 0x34, 0xa3, 0x86,
-  0xdc, 0x5d, 0x83, 0x9e, 0x35, 0xef, 0x58, 0xf6, 0x50, 0xb6, 0xad, 0x59,
-  0x10, 0x1d, 0x10, 0xc4, 0xae, 0xe8, 0x92, 0xc8, 0xde, 0x86, 0xff, 0x00,
-  0x24, 0xa3, 0xdc, 0x01, 0x49, 0xab, 0x80, 0x77, 0x77, 0x6a, 0xbc, 0xf3,
-  0xd0, 0x0a, 0x28, 0xa2, 0x80, 0x28, 0xa2, 0x8a, 0x00, 0xa2, 0x8a, 0x28,
-  0x04, 0x4e, 0x32, 0xfc, 0x4b, 0x17, 0xfd, 0xaa, 0xb6, 0x7d, 0xf8, 0xa7,
-  0xba, 0x44, 0xe3, 0x2f, 0xc4, 0xb1, 0x7f, 0xda, 0xab, 0x67, 0xdf, 0x8a,
-  0x7b, 0xa0, 0x30, 0x40, 0x3d, 0xe2, 0x8a, 0xcd, 0x15, 0x00, 0x29, 0x33,
-  0x8e, 0x3f, 0x23, 0xd9, 0x77, 0xd1, 0x12, 0x3f, 0x80, 0xd3, 0x9d, 0x26,
-  0x71, 0xc7, 0xe4, 0x7b, 0x2e, 0xfa, 0x22, 0x47, 0xf0, 0x1a, 0x90, 0x47,
-  0x71, 0xcf, 0x06, 0x56, 0x7d, 0xc3, 0x27, 0xed, 0x70, 0xdc, 0x2c, 0x5e,
-  0x22, 0xf6, 0x73, 0xad, 0x12, 0x12, 0x74, 0xa6, 0x65, 0xb5, 0xd5, 0xb2,
-  0x0f, 0x86, 0xfa, 0xa7, 0xfe, 0x2a, 0xae, 0xb8, 0x23, 0xc4, 0xc9, 0x37,
-  0x9b, 0xb3, 0x6f, 0xdd, 0x96, 0xb4, 0xc8, 0xb8, 0xb6, 0xb7, 0x54, 0xd2,
-  0xc6, 0xbb, 0x09, 0x0c, 0xf2, 0xb7, 0x36, 0x31, 0xf4, 0x14, 0x2f, 0x95,
-  0xd4, 0x83, 0xbf, 0x31, 0xe1, 0xd4, 0xf2, 0x93, 0x5f, 0x42, 0xc6, 0x1f,
-  0xcd, 0xdb, 0xf9, 0x83, 0xec, 0xaf, 0x97, 0x38, 0xd5, 0x8d, 0x3b, 0x85,
-  0x71, 0xa2, 0x2d, 0xda, 0xdc, 0x43, 0x16, 0xec, 0xb2, 0x5a, 0x24, 0x44,
-  0x70, 0xab, 0x95, 0xb8, 0xd7, 0xa6, 0xc1, 0x00, 0x2c, 0x9e, 0xe4, 0x48,
-  0x42, 0x94, 0xda, 0xba, 0x8e, 0xae, 0x15, 0x77, 0x23, 0x55, 0x7a, 0x72,
-  0xd2, 0xf7, 0xe0, 0xa5, 0x48, 0x6a, 0x5e, 0xa6, 0x38, 0xf7, 0x89, 0x7b,
-  0x93, 0xc4, 0x77, 0x6e, 0x03, 0xb4, 0x5c, 0x2c, 0x97, 0xdf, 0xe1, 0xba,
-  0x56, 0x02, 0x1a, 0x94, 0x84, 0xfb, 0xf3, 0x2a, 0x3a, 0x27, 0x4a, 0x4a,
-  0x52, 0xea, 0x7b, 0x81, 0xe5, 0x70, 0x78, 0x0a, 0xa0, 0xb8, 0xfb, 0x83,
-  0xad, 0x8b, 0x14, 0x3c, 0xa2, 0x31, 0x71, 0xd5, 0xb6, 0xbe, 0xc2, 0x52,
-  0x95, 0xe6, 0xf3, 0x20, 0x9f, 0x35, 0x69, 0x0a, 0xeb, 0xca, 0x15, 0xe6,
-  0x9e, 0xa7, 0x5d, 0x37, 0xaa, 0xfb, 0x3d, 0xf8, 0x70, 0xb8, 0xa5, 0xc2,
-  0xd5, 0xdb, 0x19, 0x77, 0xb1, 0x93, 0xca, 0x89, 0x76, 0xc7, 0x5d, 0x48,
-  0x2b, 0x8d, 0x21, 0xb5, 0x6d, 0x05, 0x40, 0xef, 0xaa, 0x16, 0x0a, 0x14,
-  0x3d, 0x1c, 0xc2, 0xab, 0xfc, 0x52, 0x20, 0xc9, 0x2c, 0x4f, 0x35, 0x32,
-  0xce, 0xd6, 0xa4, 0x87, 0x21, 0x5e, 0x22, 0x38, 0xb0, 0xdb, 0x4c, 0x3a,
-  0x93, 0xc8, 0xf3, 0x2a, 0x00, 0xa9, 0xd7, 0x14, 0x0f, 0xc1, 0x2a, 0x3a,
-  0xd1, 0x4a, 0x93, 0xaa, 0xe9, 0x8d, 0x3d, 0x59, 0x83, 0x39, 0xe5, 0x53,
-  0x18, 0x99, 0xf1, 0x7f, 0x07, 0xb3, 0x17, 0x70, 0x4e, 0x21, 0x5b, 0x32,
-  0x24, 0x85, 0x29, 0x86, 0x97, 0xc9, 0x29, 0xb1, 0xde, 0xe3, 0x2b, 0x1a,
-  0x58, 0x1e, 0xbd, 0x1d, 0x8f, 0x58, 0x15, 0xf7, 0x8b, 0x96, 0xbb, 0x45,
-  0xeb, 0x29, 0xb3, 0x5f, 0x6d, 0xf2, 0x58, 0x5d, 0xce, 0x74, 0x51, 0x16,
-  0x04, 0xc5, 0xa9, 0x2a, 0x4c, 0x78, 0xaa, 0xdb, 0x8b, 0x75, 0xb4, 0x2b,
-  0xa7, 0x31, 0x1a, 0x1b, 0xf1, 0xe6, 0x48, 0x3b, 0x1b, 0x07, 0xe5, 0xfb,
-  0xcf, 0xe0, 0xd7, 0x73, 0x57, 0x11, 0xe6, 0xe3, 0xf6, 0x9b, 0xf4, 0x36,
-  0x20, 0xf9, 0x11, 0xb8, 0x42, 0x7a, 0x5f, 0x31, 0x51, 0x6f, 0xb4, 0x08,
-  0x2d, 0xab, 0x94, 0x7c, 0x24, 0x92, 0x36, 0x7c, 0x41, 0x07, 0x43, 0x7a,
-  0xab, 0x9f, 0xf0, 0x79, 0xb6, 0x5c, 0x2d, 0xf8, 0x7d, 0xc7, 0x0d, 0xc8,
-  0x63, 0x2a, 0x25, 0xfa, 0xc3, 0x2c, 0x32, 0x64, 0x20, 0xed, 0x4a, 0x68,
-  0xfb, 0xe4, 0x77, 0x1b, 0x59, 0xef, 0x48, 0x3b, 0x09, 0xf6, 0x68, 0x8e,
-  0xfa, 0xbd, 0x18, 0xcd, 0x66, 0x18, 0xe7, 0xea, 0x56, 0xb4, 0xa9, 0xc9,
-  0xa9, 0xa7, 0xc7, 0xd0, 0xb5, 0xaf, 0x37, 0x0b, 0xc6, 0x2f, 0x7d, 0xb6,
-  0x62, 0x98, 0x56, 0x2a, 0xf3, 0x30, 0xe6, 0x48, 0x4b, 0x53, 0xaf, 0xcf,
-  0xc3, 0x5c, 0xb0, 0x1d, 0x52, 0x79, 0xb9, 0x96, 0x94, 0xa9, 0x2a, 0x59,
-  0xf3, 0x81, 0x2e, 0x2d, 0x40, 0x0e, 0xa0, 0x6f, 0x5a, 0x12, 0x7c, 0x40,
-  0x61, 0x4c, 0x5d, 0x31, 0x89, 0x4f, 0xbc, 0xd3, 0xb7, 0x25, 0x97, 0x61,
-  0xc8, 0x5b, 0x4d, 0x72, 0x25, 0xe6, 0xcb, 0x45, 0xc5, 0x2b, 0x94, 0x92,
-  0x40, 0x0b, 0x6d, 0x1a, 0x1b, 0x3a, 0xe7, 0xef, 0xf1, 0xa1, 0x8c, 0xb3,
-  0x29, 0x62, 0x38, 0x61, 0xfb, 0x6d, 0xa6, 0x73, 0xc0, 0x69, 0x32, 0x44,
-  0xa5, 0xb0, 0x17, 0xe8, 0x25, 0xae, 0x45, 0x6b, 0xea, 0x57, 0xf7, 0x77,
-  0x54, 0x59, 0x4c, 0xe9, 0xb7, 0x33, 0x75, 0xbd, 0xcb, 0x6e, 0x54, 0xd0,
-  0xd9, 0x69, 0xb4, 0xb4, 0x8e, 0x46, 0x63, 0x20, 0x9d, 0xa9, 0x2d, 0x8d,
-  0x93, 0xb2, 0x40, 0xda, 0x89, 0x24, 0xe8, 0x77, 0x0e, 0x95, 0x4a, 0x56,
-  0xf5, 0x35, 0xa6, 0xcb, 0x56, 0xaf, 0x4f, 0x46, 0x16, 0xe6, 0xf8, 0x51,
-  0xe7, 0x37, 0x70, 0x5c, 0xcb, 0x2d, 0xc4, 0xc0, 0xb8, 0x3a, 0xda, 0x52,
-  0xb0, 0xa6, 0x43, 0xad, 0x48, 0x09, 0xde, 0x92, 0xa4, 0x6c, 0x1e, 0x61,
-  0xcc, 0x74, 0xa0, 0x47, 0x4e, 0x87, 0x63, 0x40, 0x72, 0x4b, 0x89, 0x2e,
-  0xe6, 0xf3, 0x6f, 0x5f, 0xee, 0x92, 0x6e, 0xaa, 0x69, 0x41, 0x6d, 0xb2,
-  0xb0, 0x1b, 0x8e, 0x85, 0x0e, 0xe2, 0x1a, 0x4f, 0x42, 0x47, 0xeb, 0xf3,
-  0x11, 0x5d, 0x85, 0xc4, 0xb4, 0x0b, 0xcb, 0x58, 0x42, 0x5b, 0x1c, 0xe5,
-  0x65, 0x5d, 0x12, 0x07, 0x5d, 0x93, 0xe0, 0x3a, 0x75, 0xde, 0xbb, 0xaa,
-  0x2f, 0x1a, 0xbb, 0xcb, 0xbf, 0xc6, 0x95, 0x76, 0x90, 0x91, 0xe4, 0xf2,
-  0x26, 0x3a, 0x60, 0xac, 0x34, 0x51, 0xda, 0xc6, 0x07, 0x48, 0x73, 0x5d,
-  0xfe, 0x76, 0x89, 0x07, 0x5d, 0x46, 0x8e, 0xba, 0xd7, 0x67, 0xbb, 0x8f,
-  0xbc, 0xce, 0x39, 0x38, 0x95, 0x49, 0x7b, 0xbc, 0x67, 0x82, 0x03, 0x8d,
-  0xf2, 0x53, 0x12, 0xd0, 0x89, 0xcb, 0x4b, 0x8b, 0x4d, 0xde, 0xc3, 0x3a,
-  0xc8, 0xe6, 0xfa, 0x8e, 0xdd, 0x1a, 0x76, 0x3f, 0xd6, 0x7d, 0xf3, 0x54,
-  0xe9, 0xa2, 0x3a, 0x13, 0xb2, 0x3b, 0xcf, 0xa6, 0x97, 0xf8, 0x98, 0x5a,
-  0x46, 0x04, 0xbb, 0x83, 0xa3, 0x9f, 0xdc, 0x4b, 0xb4, 0x0b, 0x98, 0x04,
-  0x6f, 0xcd, 0x0f, 0x25, 0xb7, 0x3a, 0x1f, 0xd4, 0x5a, 0xa9, 0x85, 0x40,
-  0x85, 0x28, 0x1e, 0xfd, 0x9a, 0xad, 0x18, 0xe9, 0x9c, 0x91, 0x6a, 0xd2,
-  0xd5, 0x18, 0xb3, 0x15, 0x09, 0x9a, 0x59, 0x5d, 0xbd, 0xd8, 0xd4, 0xc4,
-  0x29, 0x02, 0x2d, 0xce, 0x33, 0xc8, 0x97, 0x6d, 0x92, 0x7f, 0xa0, 0x94,
-  0xd1, 0xe6, 0x6d, 0x7e, 0xb1, 0xbe, 0x84, 0x78, 0xa4, 0xa8, 0x78, 0xd4,
-  0xdd, 0x1a, 0xad, 0xe4, 0x93, 0x4d, 0x33, 0x14, 0xda, 0x69, 0xa2, 0x4e,
-  0xda, 0xed, 0xa3, 0x8b, 0xfc, 0x23, 0x91, 0x0e, 0xe9, 0x14, 0xb2, 0xd5,
-  0xce, 0x33, 0x90, 0xae, 0x51, 0x4f, 0x55, 0xc4, 0x92, 0x92, 0x52, 0xe2,
-  0x0f, 0xa1, 0x48, 0x70, 0x6c, 0x1f, 0x52, 0x4d, 0x72, 0x70, 0x13, 0x24,
-  0xb9, 0x5c, 0xb1, 0x99, 0x58, 0xbe, 0x48, 0xe7, 0x3e, 0x51, 0x8b, 0x48,
-  0xf7, 0x32, 0xe6, 0x4f, 0x7b, 0xe1, 0x23, 0xde, 0x64, 0xf5, 0xea, 0x52,
-  0xeb, 0x7c, 0xaa, 0xdf, 0xa7, 0x9b, 0xd1, 0x4b, 0x76, 0x19, 0xa9, 0xc2,
-  0xf8, 0x9e, 0xdc, 0x92, 0xae, 0x4b, 0x1e, 0x58, 0xe2, 0x22, 0xcc, 0x04,
-  0xf9, 0x91, 0xee, 0x21, 0x3a, 0x65, 0xdf, 0x50, 0x75, 0x29, 0xec, 0xcf,
-  0xeb, 0x25, 0xbf, 0x4d, 0x76, 0x71, 0x83, 0x9f, 0x02, 0xcd, 0xac, 0xfc,
-  0x5b, 0x88, 0x85, 0x26, 0xde, 0x90, 0x8b, 0x4e, 0x50, 0x84, 0x0e, 0x8a,
-  0x86, 0xb5, 0x69, 0xa9, 0x07, 0xd2, 0x59, 0x71, 0x43, 0x67, 0xbf, 0x95,
-  0x44, 0x77, 0x0a, 0xf1, 0x6a, 0x41, 0xd3, 0x93, 0x89, 0xec, 0x52, 0x9e,
-  0xb8, 0xa6, 0x5b, 0xe9, 0x24, 0x80, 0x4d, 0x66, 0xbc, 0xb4, 0xb4, 0x38,
-  0xd2, 0x5c, 0x6d, 0x49, 0x5a, 0x16, 0x02, 0x92, 0xa4, 0x9d, 0x82, 0x0f,
-  0x71, 0x15, 0xea, 0xa8, 0x68, 0x14, 0x51, 0x45, 0x00, 0x51, 0x45, 0x14,
-  0x02, 0x27, 0x19, 0x7e, 0x25, 0x8b, 0xfe, 0xd5, 0x5b, 0x3e, 0xfc, 0x53,
-  0xdd, 0x22, 0x71, 0x97, 0xe2, 0x58, 0xbf, 0xed, 0x55, 0xb3, 0xef, 0xc5,
-  0x3d, 0xd0, 0x05, 0x14, 0x51, 0x50, 0x02, 0x93, 0x38, 0xe3, 0xf2, 0x3d,
-  0x97, 0x7d, 0x11, 0x23, 0xf8, 0x0d, 0x39, 0xd2, 0x67, 0x1c, 0x7e, 0x47,
-  0xb2, 0xef, 0xa2, 0x24, 0x7f, 0x01, 0xa9, 0x03, 0x7c, 0x6f, 0x8b, 0xb7,
-  0xf3, 0x07, 0xd9, 0x4a, 0x9c, 0x5f, 0xc2, 0x21, 0x71, 0x0b, 0x01, 0xb9,
-  0xe3, 0x12, 0xc8, 0x69, 0xd7, 0xdb, 0xe7, 0x87, 0x23, 0xf3, 0xa3, 0xc8,
-  0x4f, 0x56, 0xdc, 0x49, 0xef, 0x04, 0x2b, 0xbf, 0x5e, 0x04, 0x8f, 0x1a,
-  0x6b, 0x8d, 0xf1, 0x76, 0xfe, 0x60, 0xfb, 0x2b, 0x66, 0xba, 0xd0, 0x1f,
-  0x30, 0x70, 0x4f, 0x2e, 0xb8, 0x31, 0x3d, 0xbf, 0x75, 0x12, 0x63, 0xce,
-  0x7a, 0x5b, 0xb0, 0xae, 0xb1, 0xd6, 0x75, 0xe4, 0xf7, 0x86, 0x47, 0xbf,
-  0x7b, 0x13, 0x25, 0xb4, 0xf6, 0xc3, 0xd2, 0xb4, 0x3d, 0xaf, 0x0a, 0x70,
-  0xe2, 0x45, 0xa6, 0x35, 0x83, 0x38, 0x87, 0x96, 0xc6, 0x49, 0x66, 0xcd,
-  0x92, 0xad, 0xb8, 0xb3, 0xdc, 0x46, 0x93, 0xe4, 0xb3, 0xb5, 0xca, 0xc4,
-  0x8e, 0xbb, 0xe5, 0xed, 0x13, 0xef, 0x2a, 0x3e, 0x9e, 0xcf, 0xd3, 0x4a,
-  0xff, 0x00, 0x84, 0x36, 0x3a, 0xac, 0x53, 0x89, 0x51, 0xf2, 0xc8, 0x6f,
-  0x26, 0x0d, 0xa3, 0x2c, 0x2c, 0xdb, 0xee, 0x2f, 0x9e, 0x8d, 0xc2, 0xba,
-  0x34, 0x79, 0xa0, 0xcc, 0x57, 0x4e, 0x83, 0x98, 0x04, 0x28, 0xfe, 0x81,
-  0x5f, 0xe9, 0x55, 0x8b, 0x89, 0x49, 0xb6, 0xf1, 0x13, 0x02, 0xb8, 0x63,
-  0x77, 0x98, 0xab, 0x65, 0x32, 0xdb, 0x76, 0x24, 0xc8, 0x8a, 0x50, 0xed,
-  0x21, 0xc8, 0x41, 0xd3, 0x8d, 0xfa, 0x94, 0x85, 0x8e, 0x64, 0x9f, 0x50,
-  0x23, 0xc2, 0xba, 0x21, 0x37, 0xa7, 0x57, 0x58, 0xfd, 0x0e, 0x7a, 0x90,
-  0x5a, 0xb1, 0xd2, 0x5f, 0x51, 0x53, 0x88, 0x96, 0xb9, 0x8a, 0x11, 0x72,
-  0x2b, 0x4c, 0x11, 0x3e, 0x75, 0xb4, 0x38, 0x87, 0xa0, 0x68, 0x1f, 0x2f,
-  0x86, 0xe6, 0xbb, 0x66, 0x3a, 0xf4, 0x2a, 0xf3, 0x52, 0xb4, 0x6f, 0xf3,
-  0x90, 0x07, 0x8d, 0x6b, 0xc1, 0xee, 0xd6, 0xe7, 0x25, 0x88, 0xd6, 0xd9,
-  0xce, 0x4b, 0xb4, 0xce, 0x8a, 0x89, 0x36, 0x97, 0x16, 0x95, 0x29, 0x48,
-  0x4e, 0xd6, 0x1c, 0x60, 0xac, 0xf5, 0xf7, 0xb2, 0x9d, 0xf2, 0x28, 0xf3,
-  0x27, 0x98, 0x8f, 0x01, 0x52, 0x38, 0x3c, 0xeb, 0x8b, 0x90, 0xe4, 0xd9,
-  0x6f, 0xaa, 0xdd, 0xfa, 0xc8, 0xf1, 0x83, 0x71, 0x3d, 0xdd, 0xa9, 0x00,
-  0x16, 0xdf, 0x1f, 0xaa, 0xeb, 0x7c, 0xab, 0x07, 0xd3, 0xcc, 0x2b, 0x92,
-  0xe3, 0x88, 0x3c, 0x8b, 0x9c, 0x9b, 0xae, 0x2d, 0x7e, 0x91, 0x8f, 0x4b,
-  0x98, 0xae, 0x79, 0xad, 0xb7, 0x1d, 0x12, 0x22, 0xc9, 0x5f, 0xf5, 0x8a,
-  0x61, 0x5d, 0x03, 0x9f, 0xac, 0x92, 0x92, 0x7c, 0x77, 0x5e, 0x8a, 0xef,
-  0x62, 0x71, 0x3c, 0xe6, 0xf1, 0xdd, 0x90, 0xd5, 0xcc, 0x90, 0x4a, 0x7d,
-  0x03, 0x7a, 0xf4, 0xd6, 0x36, 0x08, 0x1d, 0x41, 0x1d, 0xfb, 0xdf, 0x4a,
-  0x53, 0xb8, 0x31, 0x79, 0xc7, 0x6d, 0x89, 0xba, 0x19, 0xf3, 0xb2, 0x0e,
-  0xc5, 0x3c, 0xd7, 0x36, 0x94, 0x84, 0x07, 0x1e, 0x46, 0xce, 0xdd, 0x65,
-  0x09, 0x00, 0x25, 0x69, 0xd8, 0xf3, 0x07, 0x45, 0x25, 0x24, 0x7c, 0x2e,
-  0xa6, 0x4e, 0xcd, 0x78, 0xb7, 0x5f, 0x2d, 0x2d, 0xdd, 0xad, 0x13, 0xd9,
-  0x9b, 0x09, 0xf4, 0x85, 0x21, 0xe6, 0x55, 0xb4, 0xe8, 0xf5, 0x3b, 0xf1,
-  0x49, 0xee, 0x1a, 0x20, 0x1a, 0xbe, 0xbd, 0xf0, 0xca, 0x69, 0xd8, 0xd5,
-  0x9b, 0x65, 0x10, 0x31, 0x9b, 0x58, 0x97, 0x35, 0x89, 0x92, 0xbb, 0x55,
-  0x16, 0xd9, 0x62, 0x2c, 0x72, 0xea, 0xdd, 0x57, 0xa3, 0x5d, 0xc9, 0x1e,
-  0x92, 0xa2, 0x07, 0x77, 0xb2, 0xa0, 0x31, 0x5b, 0x86, 0x7d, 0x7e, 0xbe,
-  0xc7, 0x9f, 0x73, 0x85, 0x17, 0x1d, 0xb0, 0x20, 0x29, 0x42, 0x1b, 0x88,
-  0x0b, 0x95, 0x2b, 0xa1, 0x09, 0x04, 0xab, 0xaa, 0x52, 0x0e, 0x89, 0xf3,
-  0x52, 0x7d, 0x1b, 0xef, 0xa7, 0x1e, 0x77, 0x5b, 0x49, 0xf3, 0x94, 0x95,
-  0x12, 0x41, 0x00, 0xf8, 0xfe, 0x77, 0xd5, 0xbe, 0x83, 0x7e, 0x83, 0x5c,
-  0x71, 0x6d, 0xb1, 0x63, 0x4c, 0x7e, 0x4c, 0x66, 0xb9, 0x64, 0x48, 0x57,
-  0xbe, 0xbc, 0x56, 0x56, 0xa5, 0x1d, 0x6c, 0x9d, 0x92, 0x74, 0x94, 0x8e,
-  0xe0, 0x08, 0x03, 0xaf, 0xa2, 0xab, 0x24, 0xdb, 0xce, 0x4b, 0x45, 0xa4,
-  0xb1, 0x83, 0x4f, 0x10, 0xdc, 0x67, 0xf1, 0x6b, 0x9a, 0xa5, 0xc2, 0x39,
-  0x3d, 0xc2, 0x92, 0x4a, 0x89, 0x1a, 0x4a, 0xb5, 0xe6, 0x7f, 0xd4, 0x05,
-  0x78, 0x91, 0x9b, 0x62, 0x50, 0x18, 0x40, 0x9d, 0x93, 0xda, 0x1b, 0x75,
-  0x28, 0x1d, 0xa2, 0x04, 0xa4, 0x29, 0x49, 0x3a, 0xea, 0x08, 0x49, 0x24,
-  0x52, 0xd5, 0xd6, 0xee, 0xde, 0x4f, 0x2a, 0x0d, 0xa2, 0x03, 0x25, 0xdc,
-  0x57, 0xdd, 0x46, 0x99, 0xba, 0xdc, 0x92, 0x90, 0x59, 0x79, 0xf4, 0x92,
-  0xe3, 0x51, 0x1b, 0x27, 0xa2, 0xd0, 0x5c, 0x6d, 0x01, 0x6a, 0x1d, 0x36,
-  0x94, 0x24, 0x1d, 0xa8, 0xd4, 0x9e, 0x4b, 0x17, 0x12, 0xc7, 0x67, 0x22,
-  0xe6, 0xed, 0xe7, 0xf9, 0x3d, 0x71, 0x90, 0xb1, 0xd8, 0xf9, 0x1a, 0x00,
-  0x90, 0xfe, 0xcf, 0xc1, 0x42, 0x5a, 0x48, 0x75, 0x67, 0xd0, 0x3c, 0xf4,
-  0xfa, 0x50, 0x77, 0x58, 0x4a, 0x72, 0x52, 0x94, 0xe2, 0xb2, 0x74, 0x46,
-  0x11, 0x71, 0x8c, 0x24, 0xf0, 0x6d, 0x1c, 0x4e, 0xc0, 0xd5, 0xae, 0x4c,
-  0x8d, 0x85, 0xef, 0xbb, 0x91, 0x87, 0x95, 0xf6, 0x20, 0xd7, 0xa3, 0xc4,
-  0xdc, 0x05, 0x09, 0x2a, 0x7b, 0x27, 0x87, 0x1d, 0x20, 0xeb, 0x9a, 0x42,
-  0x56, 0xc8, 0x27, 0xd0, 0x0a, 0xd2, 0x36, 0x7d, 0x5d, 0xf5, 0x2d, 0x64,
-  0xfc, 0x70, 0x64, 0x6c, 0xa1, 0xa8, 0x52, 0x17, 0x8f, 0xc0, 0x0a, 0x20,
-  0x5d, 0x6f, 0x51, 0x80, 0x9a, 0xea, 0x37, 0xd1, 0x49, 0x86, 0x83, 0xca,
-  0x85, 0x6b, 0xbc, 0xb8, 0x47, 0xa7, 0x90, 0x77, 0x54, 0xef, 0xf2, 0x67,
-  0x06, 0xc3, 0xe5, 0xc6, 0xbc, 0xe5, 0x97, 0x69, 0x37, 0xcb, 0xe6, 0xf5,
-  0x1a, 0x65, 0xe5, 0xf3, 0x2e, 0x49, 0x56, 0xc1, 0xe5, 0x8e, 0xc0, 0x1a,
-  0x49, 0xdf, 0x83, 0x48, 0x07, 0xdb, 0x59, 0x4a, 0xee, 0x4b, 0xc8, 0xd2,
-  0x36, 0x91, 0x7e, 0x68, 0x4c, 0x75, 0xbb, 0x97, 0x12, 0x63, 0x37, 0x67,
-  0xb3, 0x63, 0xb7, 0x01, 0x61, 0x90, 0xfb, 0x2a, 0x97, 0x79, 0x9c, 0x83,
-  0x15, 0xae, 0xc9, 0x2e, 0x25, 0x64, 0xc7, 0x42, 0xbd, 0xf1, 0xc5, 0x1e,
-  0x5d, 0x05, 0x04, 0x84, 0x83, 0xa3, 0xba, 0xbb, 0xef, 0x76, 0xd8, 0x37,
-  0x9b, 0x34, 0xbb, 0x4d, 0xd2, 0x23, 0x72, 0xe1, 0x4c, 0x61, 0x4c, 0x48,
-  0x65, 0xc1, 0xb4, 0xb8, 0x85, 0x0e, 0x55, 0x24, 0x8f, 0x58, 0x26, 0x93,
-  0x66, 0x64, 0x99, 0x35, 0xe1, 0x61, 0x9b, 0x4c, 0x36, 0xb1, 0xf8, 0xca,
-  0xde, 0xa4, 0x4e, 0x6f, 0xb7, 0x98, 0xb1, 0xaf, 0xe8, 0xe3, 0x24, 0xe9,
-  0x1d, 0x47, 0x7b, 0xaa, 0x1e, 0xb4, 0x50, 0x71, 0x3b, 0x84, 0xc0, 0xa7,
-  0x1f, 0xbe, 0xe5, 0x6e, 0x38, 0x76, 0x4b, 0xcb, 0xbb, 0x79, 0x31, 0x3e,
-  0xc6, 0xda, 0x48, 0x40, 0x1e, 0xa2, 0x2b, 0x9e, 0xa3, 0x9d, 0x47, 0xaa,
-  0x47, 0x45, 0x35, 0x0a, 0x6b, 0x4a, 0x22, 0xb8, 0x0b, 0x73, 0x99, 0x67,
-  0x55, 0xdb, 0x85, 0x37, 0xd9, 0x2a, 0x7a, 0xe7, 0x8a, 0xa9, 0x29, 0x84,
-  0xfb, 0xa7, 0xce, 0x99, 0x6d, 0x5e, 0xcc, 0x77, 0x7d, 0x65, 0x23, 0x6d,
-  0xab, 0x5d, 0xc5, 0x03, 0xd3, 0x56, 0xb0, 0xee, 0xaf, 0x9c, 0x38, 0xca,
-  0xbc, 0x8f, 0x87, 0x79, 0x26, 0x3b, 0xc4, 0x19, 0x6e, 0xc9, 0xbb, 0x35,
-  0x69, 0x77, 0xb0, 0x33, 0x4b, 0x68, 0x0f, 0xbd, 0x05, 0xdf, 0xcb, 0x43,
-  0x91, 0xc8, 0x02, 0x54, 0xb4, 0xe9, 0x2e, 0x36, 0xb0, 0x00, 0x25, 0x2a,
-  0x07, 0xa9, 0x05, 0x5f, 0x42, 0xdb, 0x27, 0x45, 0xb9, 0x5b, 0x63, 0x5c,
-  0x60, 0xbe, 0xdc, 0x88, 0x92, 0x99, 0x43, 0xcc, 0x3a, 0x83, 0xb4, 0xad,
-  0x0b, 0x00, 0xa5, 0x43, 0xd4, 0x41, 0x06, 0xb1, 0x36, 0x3a, 0xa8, 0xa2,
-  0x8a, 0x00, 0xa2, 0x8a, 0x28, 0x04, 0x4e, 0x32, 0xfc, 0x4b, 0x17, 0xfd,
-  0xaa, 0xb6, 0x7d, 0xf8, 0xa7, 0xba, 0x44, 0xe3, 0x2f, 0xc4, 0xb1, 0x7f,
-  0xda, 0xab, 0x67, 0xdf, 0x8a, 0x7b, 0xa0, 0x0a, 0x28, 0xa2, 0xa0, 0x05,
-  0x26, 0x71, 0xc7, 0xe4, 0x7b, 0x2e, 0xfa, 0x22, 0x47, 0xf0, 0x1a, 0x73,
-  0xa4, 0xce, 0x38, 0xfc, 0x8f, 0x65, 0xdf, 0x44, 0x48, 0xfe, 0x03, 0x52,
-  0x06, 0xf8, 0xdf, 0x17, 0x6f, 0xe6, 0x0f, 0xb2, 0xb6, 0x56, 0xb8, 0xdf,
-  0x17, 0x6f, 0xe6, 0x0f, 0xb2, 0xb6, 0x50, 0x0b, 0xbc, 0x47, 0xc5, 0x2d,
-  0xd9, 0xc6, 0x15, 0x77, 0xc5, 0xae, 0xa8, 0xdc, 0x5b, 0x8c, 0x72, 0xd7,
-  0x37, 0x79, 0x6d, 0x7d, 0xe8, 0x58, 0xf5, 0xa5, 0x40, 0x28, 0x7b, 0x2b,
-  0xe7, 0x0e, 0x13, 0xe4, 0x57, 0x3b, 0x3e, 0x4a, 0x18, 0xbd, 0x2b, 0xb0,
-  0xbd, 0x46, 0x98, 0x8c, 0x7f, 0x22, 0x04, 0xf4, 0x33, 0x9b, 0x49, 0xf2,
-  0x29, 0x87, 0xd2, 0x99, 0x0d, 0x20, 0xb4, 0x4f, 0x8a, 0x9b, 0x41, 0x3f,
-  0x0b, 0xaf, 0xd6, 0x04, 0x6c, 0xee, 0xbe, 0x75, 0xfc, 0x28, 0x71, 0x88,
-  0x96, 0x4c, 0x92, 0x27, 0x10, 0x9c, 0x4b, 0x8d, 0xd8, 0xee, 0x8c, 0x26,
-  0xc5, 0x95, 0xa9, 0xad, 0xed, 0xa6, 0x56, 0xa0, 0x63, 0xcd, 0x1a, 0xfc,
-  0xe6, 0x5d, 0x08, 0x3b, 0xef, 0xd2, 0x52, 0x3c, 0x4d, 0x5a, 0x12, 0x70,
-  0x92, 0x68, 0xac, 0xe2, 0xa7, 0x1c, 0x31, 0xa3, 0x8b, 0x0d, 0xb5, 0x69,
-  0x97, 0x6e, 0xe2, 0x9c, 0x24, 0x94, 0xc4, 0x6d, 0xa4, 0xc1, 0xc8, 0x50,
-  0x91, 0xbf, 0xe6, 0x85, 0x5e, 0x63, 0xe7, 0xd2, 0x59, 0x70, 0x92, 0x7f,
-  0x51, 0x6b, 0xf4, 0x0a, 0x91, 0xd8, 0x52, 0x76, 0x0a, 0x54, 0x9d, 0x7c,
-  0x20, 0x76, 0x35, 0xe9, 0xad, 0x1c, 0x1d, 0xbf, 0x2e, 0xfd, 0x65, 0x9d,
-  0x8e, 0xe4, 0xad, 0x32, 0xed, 0xc1, 0x85, 0xb9, 0x6e, 0xbb, 0x33, 0xa0,
-  0x5b, 0x71, 0xd0, 0x81, 0xb5, 0x8f, 0x02, 0xdb, 0xcd, 0xa9, 0x2e, 0x27,
-  0xc0, 0x85, 0x74, 0xa4, 0x76, 0xe7, 0x5f, 0x31, 0x0b, 0x83, 0xdc, 0x32,
-  0x85, 0x01, 0xcb, 0xa5, 0xee, 0x17, 0x5b, 0x43, 0xf2, 0x02, 0xbb, 0x03,
-  0x6e, 0x27, 0x4d, 0x3e, 0xfb, 0x80, 0x75, 0x0d, 0x7e, 0x49, 0x40, 0x0e,
-  0x65, 0x29, 0x03, 0x5d, 0xfb, 0x1d, 0xf4, 0x2a, 0x28, 0x37, 0x1e, 0x8f,
-  0x74, 0x70, 0x56, 0xa6, 0xe6, 0xb5, 0x75, 0x5b, 0x32, 0x53, 0x89, 0x79,
-  0x14, 0xab, 0x3c, 0x38, 0xb6, 0xdb, 0x53, 0xed, 0xb1, 0x78, 0xba, 0x2d,
-  0xc4, 0xc7, 0x75, 0x63, 0x98, 0x46, 0x69, 0x09, 0x2a, 0x7a, 0x41, 0x4f,
-  0xe7, 0x72, 0xa0, 0x69, 0x23, 0xc5, 0x45, 0x20, 0xf4, 0xde, 0x97, 0xb1,
-  0xcc, 0x42, 0xd5, 0x6f, 0xc9, 0x67, 0x58, 0x12, 0xbb, 0x94, 0x09, 0x26,
-  0x3a, 0x67, 0xdb, 0xa7, 0xc7, 0x94, 0x5a, 0x94, 0xa6, 0xd4, 0x40, 0x79,
-  0xb7, 0x14, 0x9f, 0x35, 0xc2, 0x97, 0x7a, 0xe9, 0x41, 0x40, 0x07, 0x07,
-  0x80, 0x15, 0x1d, 0x27, 0x14, 0x5c, 0x4e, 0x28, 0xb7, 0x2a, 0x7c, 0xb7,
-  0xae, 0x72, 0x9e, 0xb4, 0x36, 0xb9, 0x97, 0x17, 0xbc, 0xd0, 0x49, 0x9c,
-  0xc8, 0x52, 0x52, 0x37, 0xca, 0xdb, 0x69, 0x6d, 0x04, 0x04, 0xfa, 0x09,
-  0x24, 0x92, 0x49, 0xa6, 0xb7, 0xef, 0x71, 0x32, 0x1b, 0xfc, 0x37, 0x70,
-  0xfb, 0x4c, 0xec, 0xaa, 0xe7, 0x6e, 0x53, 0xa8, 0x4b, 0x90, 0x48, 0x44,
-  0x36, 0xfb, 0x44, 0x72, 0xad, 0x0e, 0xc9, 0x5f, 0xbd, 0x81, 0xd0, 0x1d,
-  0x27, 0x99, 0x5b, 0x48, 0xe9, 0xd2, 0xb5, 0x72, 0x59, 0x72, 0x9e, 0xd8,
-  0x32, 0x51, 0x78, 0x4a, 0x3b, 0xe4, 0xda, 0xac, 0x77, 0x32, 0x6d, 0x7c,
-  0x90, 0xb3, 0xc4, 0xad, 0xa1, 0xa0, 0x8f, 0x2a, 0xb2, 0x32, 0xeb, 0x80,
-  0x0e, 0xef, 0x39, 0x2a, 0x40, 0x3f, 0xf2, 0xee, 0x96, 0xee, 0xb1, 0x6d,
-  0x2f, 0x5c, 0x7d, 0xc8, 0xbe, 0xe4, 0xb7, 0xfc, 0xe6, 0xe6, 0x01, 0xff,
-  0x00, 0x41, 0x5a, 0x99, 0x4a, 0x50, 0xaf, 0xf7, 0xad, 0xb0, 0x12, 0x00,
-  0xf5, 0xba, 0xb0, 0x9f, 0x4d, 0x58, 0x8d, 0xf0, 0xf2, 0xf7, 0x75, 0x8a,
-  0xe4, 0xbe, 0x21, 0xe5, 0x48, 0x83, 0x6e, 0x09, 0xe6, 0x76, 0xd7, 0x65,
-  0x71, 0x51, 0x98, 0x09, 0x1e, 0x0f, 0x49, 0x56, 0x9c, 0x58, 0xd7, 0x7f,
-  0x2f, 0x66, 0x2a, 0x52, 0xd7, 0x7d, 0xb0, 0x58, 0x2d, 0xf1, 0xac, 0x9c,
-  0x35, 0xc5, 0x11, 0x2d, 0x97, 0x5d, 0x0c, 0xb2, 0xb8, 0xe9, 0x4c, 0x68,
-  0x6a, 0x57, 0x5e, 0x65, 0x17, 0x48, 0xdb, 0xba, 0x00, 0x92, 0xa4, 0x25,
-  0x7e, 0x3b, 0x3b, 0xae, 0x6a, 0x97, 0x31, 0xe2, 0x08, 0xea, 0xa7, 0x6b,
-  0x27, 0xbc, 0xc8, 0x3b, 0x4e, 0x0b, 0x9b, 0x5f, 0xed, 0xe9, 0x83, 0x74,
-  0x7e, 0x1e, 0x13, 0x61, 0xd2, 0x12, 0x2d, 0xd6, 0xc0, 0x87, 0xe6, 0x14,
-  0x21, 0x5c, 0xc9, 0x05, 0xd2, 0x3b, 0x26, 0x74, 0x40, 0x23, 0xb3, 0x4a,
-  0x88, 0xf0, 0x50, 0xa9, 0x9b, 0x24, 0x6e, 0x1d, 0x60, 0xb2, 0xe4, 0xb7,
-  0x8d, 0xda, 0x9f, 0xbc, 0x5f, 0xca, 0x7f, 0x9c, 0xae, 0x1a, 0x55, 0x3e,
-  0x7b, 0x87, 0xb8, 0xf6, 0xaf, 0x28, 0x9e, 0x4d, 0x9f, 0x05, 0xa9, 0x23,
-  0xd5, 0x5b, 0x9d, 0xb1, 0x5f, 0x72, 0x85, 0x2c, 0x5e, 0xef, 0x0b, 0x93,
-  0x10, 0x9d, 0x2a, 0x34, 0x5e, 0x68, 0xf0, 0xfd, 0x69, 0xd0, 0x3d, 0xa3,
-  0xa0, 0x1f, 0x15, 0x2b, 0x94, 0xfe, 0x88, 0xae, 0xe6, 0xda, 0xc5, 0x6c,
-  0xcd, 0x1b, 0x70, 0x9a, 0x48, 0x6b, 0x6a, 0x54, 0x6b, 0x73, 0x2a, 0xe4,
-  0x6b, 0x43, 0x64, 0xa9, 0x0c, 0xa4, 0xf2, 0xf4, 0xf1, 0x3a, 0xac, 0x24,
-  0x9b, 0x79, 0x9b, 0x36, 0x86, 0x23, 0xb4, 0x11, 0xc8, 0xc5, 0xd3, 0x2b,
-  0xc9, 0xdd, 0x72, 0x3b, 0x6f, 0x0c, 0x70, 0xa0, 0x02, 0xe4, 0x06, 0xd2,
-  0x0c, 0xe4, 0xa0, 0xec, 0x05, 0x29, 0xc7, 0x13, 0xca, 0x90, 0x7a, 0xe8,
-  0xb6, 0x95, 0xf5, 0xfc, 0xfa, 0x85, 0x98, 0xc4, 0x1c, 0x5a, 0xfb, 0x3d,
-  0xc5, 0xa1, 0x8f, 0x29, 0x66, 0x10, 0x93, 0x21, 0xd9, 0x4b, 0x70, 0x3f,
-  0x3c, 0x12, 0x41, 0x6d, 0x12, 0x16, 0x76, 0xa2, 0x34, 0x8f, 0x37, 0x67,
-  0xaa, 0xc0, 0x09, 0x14, 0xe9, 0x76, 0xb6, 0x48, 0x7a, 0xd6, 0xd5, 0xd2,
-  0xd1, 0x2b, 0xca, 0x67, 0x43, 0x49, 0x91, 0x6d, 0x73, 0x63, 0xdf, 0x50,
-  0x40, 0x25, 0x95, 0x1e, 0xe5, 0x21, 0x60, 0x01, 0xea, 0x3c, 0xa7, 0xc0,
-  0x54, 0xcc, 0x05, 0x5b, 0x2f, 0x50, 0xe0, 0x5d, 0x9a, 0x65, 0xa7, 0xd1,
-  0xc8, 0x1d, 0x8c, 0xb7, 0x10, 0x0a, 0x9a, 0xe6, 0x1d, 0x75, 0xe2, 0x95,
-  0x78, 0x1f, 0x66, 0xaa, 0x9a, 0xb4, 0xec, 0x8b, 0xe9, 0xd5, 0xbb, 0x23,
-  0xaf, 0xb2, 0x11, 0x69, 0xc3, 0xe4, 0xdc, 0xed, 0x4c, 0xa1, 0x9e, 0x46,
-  0x12, 0xe9, 0x51, 0x68, 0x92, 0x86, 0xfa, 0x73, 0x2c, 0xa4, 0xe8, 0x9e,
-  0x54, 0x95, 0x2b, 0x47, 0xd1, 0x48, 0x37, 0x34, 0x4c, 0x91, 0x2a, 0x6b,
-  0xa8, 0x8f, 0xe5, 0x51, 0xa2, 0x2f, 0x4e, 0x4f, 0xba, 0xca, 0x71, 0x29,
-  0x3e, 0x71, 0x1c, 0xfc, 0xfc, 0xe8, 0x42, 0x46, 0x87, 0x37, 0xbd, 0x27,
-  0xa2, 0x4a, 0x0f, 0x52, 0x48, 0x16, 0xeb, 0x8d, 0xa1, 0xd6, 0xd6, 0xdb,
-  0x89, 0x0a, 0x42, 0x81, 0x0a, 0x4a, 0xba, 0x82, 0x0f, 0x81, 0x07, 0xec,
-  0xa5, 0x17, 0x31, 0x1c, 0x26, 0xca, 0x91, 0x71, 0x9e, 0xdb, 0x48, 0x8d,
-  0x0c, 0x73, 0x36, 0x67, 0xcb, 0x52, 0xd8, 0x8c, 0x3d, 0x21, 0x2b, 0x57,
-  0x22, 0x40, 0xf0, 0x3e, 0x15, 0x55, 0xbf, 0x24, 0xf8, 0x78, 0x34, 0x5d,
-  0x2c, 0xf2, 0x32, 0x7e, 0x14, 0x5c, 0xec, 0x93, 0x16, 0xa9, 0x2e, 0xbf,
-  0x19, 0xe6, 0xa2, 0xc8, 0x74, 0xef, 0xb6, 0xe5, 0x24, 0xc7, 0x78, 0xfa,
-  0x49, 0xd3, 0x6a, 0x27, 0xc4, 0xee, 0x90, 0x7f, 0x06, 0x7b, 0xfa, 0xac,
-  0xee, 0x1e, 0x1c, 0x5c, 0x14, 0xa4, 0xb0, 0xa8, 0x2d, 0xde, 0xb1, 0xb5,
-  0xac, 0xec, 0x39, 0x01, 0xf1, 0xcc, 0xa6, 0x01, 0x3d, 0xea, 0x65, 0xc2,
-  0xa4, 0x7c, 0xde, 0x5f, 0x0a, 0x73, 0xb9, 0xe6, 0x17, 0x3c, 0x9a, 0x03,
-  0xf0, 0x78, 0x7d, 0x67, 0x93, 0x30, 0x3c, 0x92, 0xd2, 0x6f, 0x32, 0x47,
-  0x61, 0x09, 0xad, 0x82, 0x39, 0xd0, 0x55, 0xe7, 0xbb, 0xaf, 0xd4, 0x49,
-  0x1e, 0xba, 0x82, 0xe2, 0xa6, 0x0f, 0x2a, 0xd1, 0xc3, 0xfc, 0x76, 0xf3,
-  0x88, 0x23, 0xb7, 0xc8, 0x70, 0x26, 0xd1, 0x22, 0xdf, 0xe6, 0xf2, 0xaa,
-  0x63, 0x0d, 0xa0, 0x26, 0x43, 0x0a, 0xd7, 0xf5, 0x8d, 0x83, 0xd3, 0xf4,
-  0x80, 0xf4, 0xd1, 0xac, 0x12, 0x9e, 0x4b, 0x84, 0x51, 0x50, 0xf8, 0x6e,
-  0x45, 0x6c, 0xca, 0xf1, 0x6b, 0x6e, 0x47, 0x67, 0x7b, 0xb6, 0x81, 0x71,
-  0x8e, 0x99, 0x0c, 0xab, 0x5d, 0x74, 0xa1, 0xdc, 0x47, 0x82, 0x81, 0xe8,
-  0x47, 0x81, 0x06, 0xa6, 0x07, 0x75, 0x41, 0x21, 0x45, 0x14, 0x50, 0x08,
-  0x9c, 0x65, 0xf8, 0x96, 0x2f, 0xfb, 0x55, 0x6c, 0xfb, 0xf1, 0x4f, 0x74,
-  0x89, 0xc6, 0x5f, 0x89, 0x62, 0xff, 0x00, 0xb5, 0x56, 0xcf, 0xbf, 0x14,
-  0xf7, 0x40, 0x1e, 0x26, 0x8a, 0xf2, 0xa4, 0x82, 0x7a, 0xd1, 0x4c, 0x11,
-  0x94, 0x7a, 0xa4, 0xce, 0x38, 0xfc, 0x8f, 0x65, 0xdf, 0x44, 0x48, 0xfe,
-  0x03, 0x4e, 0x74, 0x99, 0xc7, 0x1f, 0x91, 0xec, 0xbb, 0xe8, 0x89, 0x1f,
-  0xc0, 0x68, 0x48, 0xdf, 0x1b, 0xe2, 0xed, 0xfc, 0xc1, 0xf6, 0x56, 0xca,
-  0xd7, 0x1b, 0xe2, 0xed, 0xfc, 0xc1, 0xf6, 0x56, 0xca, 0x00, 0xa8, 0xdc,
-  0xa2, 0xc9, 0x6e, 0xc8, 0xf1, 0xe9, 0xf6, 0x1b, 0xb3, 0x01, 0xf8, 0x37,
-  0x06, 0x17, 0x1d, 0xf6, 0xcf, 0x8a, 0x54, 0x34, 0x75, 0xe8, 0x23, 0xbc,
-  0x1f, 0x02, 0x05, 0x49, 0x50, 0x46, 0xe8, 0x0f, 0x98, 0x78, 0x35, 0x12,
-  0xe5, 0x6a, 0xbf, 0x5c, 0x71, 0xa9, 0x31, 0x5e, 0x93, 0x96, 0xe3, 0x4b,
-  0x6a, 0xd3, 0x3e, 0x40, 0x92, 0x1b, 0x4c, 0x8b, 0x5a, 0x52, 0xb7, 0x21,
-  0x4d, 0xe4, 0x57, 0xe5, 0x54, 0x01, 0x4b, 0x5b, 0x1d, 0x42, 0x4a, 0x7b,
-  0xf5, 0xd2, 0xea, 0xbe, 0x63, 0x16, 0x6c, 0xe6, 0x14, 0x2b, 0x84, 0x97,
-  0x26, 0x41, 0xb9, 0x45, 0x4a, 0x90, 0xc4, 0xe8, 0x2f, 0x76, 0x6f, 0xb4,
-  0x15, 0xae, 0x64, 0x83, 0xd5, 0x2a, 0x42, 0xb4, 0x0f, 0x2a, 0x82, 0x87,
-  0xab, 0x75, 0x5b, 0xfe, 0x14, 0x56, 0x24, 0x58, 0xe6, 0xc0, 0xe2, 0x9c,
-  0x78, 0x4b, 0x95, 0x12, 0x2b, 0x0a, 0xb4, 0xe5, 0x31, 0x5a, 0xe8, 0xa9,
-  0x76, 0xb7, 0xcf, 0x2a, 0x95, 0xd3, 0xbd, 0x4d, 0x28, 0xf3, 0x27, 0xd0,
-  0x48, 0x3e, 0x15, 0xd7, 0xc3, 0xec, 0xe2, 0x4d, 0x9b, 0x1a, 0xbd, 0x43,
-  0x9e, 0xfa, 0x27, 0xdc, 0xed, 0x2c, 0x37, 0xd9, 0xbe, 0x0e, 0xd1, 0x3d,
-  0x0e, 0x24, 0x2a, 0x24, 0x90, 0x7f, 0x45, 0xd4, 0xa9, 0x3c, 0xc7, 0xc1,
-  0x41, 0x60, 0xf7, 0x56, 0xf1, 0x7a, 0xa1, 0x8e, 0xab, 0x74, 0x63, 0x35,
-  0x89, 0xe7, 0xa3, 0xd9, 0x93, 0x33, 0xb8, 0x67, 0x8a, 0x42, 0x3e, 0xeb,
-  0xf1, 0x13, 0x25, 0x95, 0x7e, 0x65, 0xae, 0x8d, 0xb5, 0x73, 0x75, 0xb6,
-  0x22, 0x0d, 0x1d, 0x8d, 0xb0, 0xd8, 0x4a, 0x5d, 0x57, 0x41, 0xf0, 0xf9,
-  0xb6, 0x7b, 0x85, 0x4b, 0xff, 0x00, 0x29, 0x6e, 0x0e, 0x46, 0x6a, 0xdf,
-  0x88, 0x63, 0xed, 0x5b, 0xa1, 0x25, 0x01, 0x2c, 0x3b, 0x35, 0x82, 0xde,
-  0x93, 0xe1, 0xd9, 0xc5, 0x4e, 0x95, 0xad, 0x77, 0x73, 0x96, 0xfd, 0x84,
-  0x57, 0xa4, 0x5a, 0x62, 0xc1, 0x71, 0xe9, 0xf7, 0x29, 0x4d, 0xbd, 0x36,
-  0x1b, 0x7c, 0xf3, 0xaf, 0x52, 0x92, 0x14, 0xe3, 0x67, 0x5b, 0x28, 0x64,
-  0x11, 0xef, 0x69, 0xeb, 0xa0, 0x94, 0xf5, 0xf4, 0xec, 0x9d, 0x9e, 0xaf,
-  0x76, 0xcd, 0xa2, 0x3a, 0x1e, 0x8d, 0x8f, 0xad, 0xa6, 0x1d, 0x58, 0x4b,
-  0x66, 0x64, 0xa4, 0xb3, 0x26, 0x5a, 0xbf, 0x45, 0xa6, 0xc8, 0x25, 0x4a,
-  0xd0, 0xe8, 0x95, 0x14, 0x13, 0xd0, 0x55, 0x5a, 0x4b, 0x79, 0xee, 0xc9,
-  0x59, 0x7b, 0x43, 0x64, 0x29, 0xdd, 0xe2, 0x39, 0xee, 0xaa, 0xff, 0x00,
-  0x94, 0x88, 0xb8, 0xde, 0xa5, 0x44, 0x60, 0xcc, 0x71, 0x52, 0x92, 0x84,
-  0xb0, 0xc3, 0x69, 0x03, 0x65, 0xa6, 0xce, 0x9b, 0x2a, 0xea, 0x35, 0xa0,
-  0xa5, 0x6c, 0xe8, 0xa8, 0x1a, 0x67, 0xca, 0xd9, 0x66, 0xd2, 0x6c, 0x19,
-  0x33, 0x2b, 0x75, 0xd8, 0xd0, 0xa4, 0x28, 0x48, 0x52, 0x94, 0x4e, 0xda,
-  0x7d, 0x01, 0x1c, 0xe7, 0x7d, 0xc0, 0x1e, 0xcf, 0xd8, 0x37, 0x4c, 0xa1,
-  0x9b, 0x2e, 0x45, 0x0a, 0x15, 0xc1, 0x71, 0xa3, 0x4f, 0x8e, 0x42, 0x5f,
-  0x8c, 0xb7, 0x1b, 0xe6, 0xd6, 0xc7, 0x42, 0x37, 0xdd, 0xe1, 0xf5, 0x8f,
-  0x55, 0x73, 0xb1, 0x75, 0xc7, 0xb2, 0x36, 0xa4, 0xda, 0xdb, 0x9b, 0x1a,
-  0x62, 0x56, 0x1c, 0x61, 0xf8, 0xea, 0x24, 0x29, 0x40, 0x12, 0x85, 0x8e,
-  0x53, 0xa3, 0xae, 0xf1, 0xb1, 0xd3, 0xae, 0xf7, 0xdd, 0x51, 0xef, 0x1f,
-  0x1d, 0x0b, 0x7b, 0xb5, 0xf3, 0x35, 0x65, 0xad, 0x16, 0xf1, 0x07, 0xd3,
-  0x05, 0xa7, 0x54, 0xcb, 0x61, 0x0b, 0x5b, 0x4c, 0x13, 0xce, 0xe3, 0x01,
-  0x69, 0x53, 0x89, 0x4e, 0x8e, 0xf6, 0x50, 0x14, 0x06, 0xbb, 0xf7, 0xaa,
-  0x8f, 0x5e, 0x61, 0x8b, 0x5b, 0x61, 0x35, 0x16, 0xcd, 0xd9, 0xca, 0x5b,
-  0x9f, 0x90, 0x87, 0x01, 0xae, 0x65, 0xaf, 0xd8, 0x84, 0x8d, 0x8f, 0x6e,
-  0xb5, 0xe9, 0xae, 0x4c, 0x5a, 0xf6, 0xab, 0x03, 0xea, 0xc5, 0x6f, 0xcf,
-  0xab, 0xb6, 0x8a, 0x79, 0x22, 0xbe, 0xbe, 0x8a, 0x90, 0xcf, 0xe6, 0x2c,
-  0x0f, 0x1e, 0x9d, 0x0e, 0xbb, 0x94, 0x15, 0xe1, 0x5e, 0xae, 0x39, 0xde,
-  0x23, 0x64, 0x9c, 0xb8, 0x16, 0xe6, 0x0c, 0xfb, 0xb3, 0xbe, 0x71, 0x85,
-  0x6c, 0x8d, 0xda, 0x48, 0x70, 0xfa, 0x54, 0x94, 0x8d, 0x8f, 0x6a, 0xb4,
-  0x3d, 0x75, 0x3a, 0x1e, 0x73, 0x8c, 0x94, 0xd6, 0xb1, 0x8c, 0xe0, 0x9b,
-  0xc1, 0x21, 0x4f, 0x83, 0x8f, 0xa1, 0x8b, 0x83, 0x6d, 0xb0, 0xb2, 0xf3,
-  0xae, 0x37, 0x19, 0x27, 0x7d, 0x83, 0x6a, 0x59, 0x52, 0x5b, 0x27, 0xc7,
-  0x40, 0xeb, 0xd5, 0xdd, 0xd7, 0x5b, 0xa5, 0xb7, 0x33, 0x2c, 0x7b, 0x0f,
-  0xba, 0xdf, 0x20, 0x5c, 0x27, 0xb4, 0xdb, 0x1e, 0x54, 0x89, 0x11, 0x9a,
-  0x49, 0x2b, 0x5a, 0x94, 0xf2, 0x76, 0xb4, 0x21, 0x23, 0x65, 0x47, 0x9c,
-  0x29, 0x5a, 0x48, 0x27, 0xcf, 0xee, 0xa0, 0xc3, 0xe2, 0x0e, 0x57, 0xb3,
-  0x3a, 0x43, 0x78, 0x7d, 0xad, 0x47, 0x5d, 0x83, 0x1c, 0x92, 0x27, 0x38,
-  0x9f, 0x5a, 0xba, 0xb6, 0xd7, 0x4d, 0x78, 0x38, 0x7e, 0x6d, 0x6e, 0xb5,
-  0xc1, 0xc1, 0xb0, 0xc7, 0x1f, 0x55, 0xad, 0xa6, 0x27, 0x5f, 0x56, 0xb4,
-  0xb4, 0xe1, 0xf2, 0x84, 0xc8, 0xb8, 0x48, 0x5a, 0xb4, 0x90, 0x95, 0x29,
-  0x67, 0x98, 0x0e, 0x83, 0xa6, 0xc2, 0x40, 0xf0, 0x00, 0x55, 0x70, 0x97,
-  0x25, 0xd3, 0x6c, 0xd6, 0x9b, 0xd6, 0x7f, 0x92, 0x91, 0xee, 0x25, 0x8d,
-  0xbc, 0x76, 0x0a, 0xbb, 0xa6, 0x5e, 0x01, 0xed, 0x88, 0xf1, 0xe5, 0x8e,
-  0x93, 0xcd, 0xbf, 0x9e, 0x51, 0xec, 0xaf, 0x5f, 0xc8, 0x9b, 0x0d, 0xb9,
-  0xa5, 0xdf, 0xf3, 0x4b, 0x8b, 0xd9, 0x0c, 0x98, 0xa9, 0xed, 0x94, 0xfd,
-  0xcf, 0xce, 0x61, 0x92, 0x3c, 0x5b, 0x60, 0x0e, 0x40, 0x7c, 0x07, 0x45,
-  0x2b, 0x7d, 0xc4, 0x9a, 0xdd, 0x94, 0x5c, 0xf2, 0xf8, 0x56, 0xa5, 0x4b,
-  0x92, 0xc5, 0xba, 0x0c, 0x27, 0x56, 0xdb, 0x72, 0x1d, 0x8e, 0xea, 0x96,
-  0xf4, 0x06, 0x94, 0xb4, 0x85, 0x3a, 0x49, 0x01, 0x2b, 0xe5, 0x49, 0x3d,
-  0xc0, 0x68, 0xf5, 0xea, 0x07, 0x5d, 0x13, 0x2c, 0x38, 0xbd, 0xc9, 0x33,
-  0xa0, 0x59, 0xdc, 0x8c, 0x32, 0x0b, 0x7b, 0xe8, 0x70, 0x49, 0x92, 0xb5,
-  0x38, 0xf7, 0x6e, 0x8e, 0x57, 0x00, 0x75, 0x44, 0xf3, 0x29, 0xb3, 0xe6,
-  0xec, 0x77, 0x68, 0xf4, 0xd7, 0x4a, 0x8d, 0x4d, 0xf0, 0x4a, 0x8a, 0x5c,
-  0x9d, 0x97, 0xfc, 0x96, 0xfd, 0x0e, 0xc1, 0x26, 0xe5, 0x0f, 0x18, 0x71,
-  0x88, 0xa8, 0x48, 0x4a, 0x1c, 0x92, 0xf0, 0x0e, 0xb4, 0x0e, 0x87, 0x6a,
-  0xa6, 0x40, 0x3e, 0x62, 0x77, 0xcc, 0x41, 0x50, 0x56, 0x81, 0xe8, 0x3b,
-  0xab, 0x51, 0xb5, 0xc0, 0x98, 0x99, 0x5e, 0x45, 0x92, 0x4c, 0x7a, 0xfb,
-  0x15, 0x40, 0x26, 0x73, 0xb3, 0x09, 0x4a, 0x1e, 0xd0, 0x50, 0x4f, 0x66,
-  0x92, 0x1b, 0xe4, 0x3b, 0x00, 0xa4, 0x24, 0x74, 0x57, 0xac, 0x1a, 0x8f,
-  0xb4, 0x66, 0x37, 0x79, 0xee, 0xbe, 0xb5, 0xda, 0x44, 0xfb, 0x7c, 0xc8,
-  0xe8, 0x7d, 0x88, 0xe1, 0x87, 0x52, 0xe2, 0x02, 0xdb, 0x4e, 0xda, 0x59,
-  0x5a, 0x03, 0x3d, 0x9e, 0xf9, 0x8f, 0x69, 0xcf, 0xd4, 0x1f, 0x83, 0x50,
-  0x36, 0x9b, 0x6d, 0xbe, 0x3a, 0xa2, 0xa6, 0xdf, 0x7f, 0x85, 0x72, 0xbd,
-  0xba, 0xc3, 0x70, 0xd4, 0xd5, 0xa8, 0x36, 0x99, 0x0e, 0x04, 0xa3, 0xb8,
-  0xbe, 0x49, 0xf7, 0xb4, 0x84, 0xeb, 0xb5, 0xe5, 0xe7, 0x00, 0x00, 0x15,
-  0xbd, 0x26, 0xa3, 0x65, 0xc9, 0x3b, 0xbe, 0x0e, 0x1e, 0x0a, 0xdc, 0xc6,
-  0x23, 0x9f, 0xc9, 0xc2, 0xd6, 0xd7, 0x93, 0x58, 0xf2, 0x64, 0xbd, 0x79,
-  0xc7, 0xdb, 0xdf, 0x9b, 0x19, 0xf0, 0xa2, 0x26, 0xc2, 0x1e, 0x1a, 0x4b,
-  0x9b, 0x71, 0x3a, 0xd7, 0x9a, 0xaf, 0xee, 0xbd, 0x53, 0xdc, 0x2a, 0x92,
-  0xe3, 0x1e, 0x31, 0x90, 0xbb, 0x86, 0x5b, 0x1a, 0x81, 0x12, 0xd5, 0x0a,
-  0xe3, 0x68, 0x94, 0x89, 0x58, 0xf3, 0xf0, 0xb9, 0xcf, 0x92, 0x4c, 0x47,
-  0xe4, 0xda, 0x71, 0x4b, 0xea, 0xb4, 0x3c, 0x36, 0xd9, 0x3e, 0x6e, 0xd4,
-  0xb4, 0xec, 0x1d, 0xee, 0xac, 0x6e, 0x16, 0xe6, 0x50, 0x73, 0xcc, 0x12,
-  0xdb, 0x93, 0xc0, 0x41, 0x64, 0x49, 0x6f, 0x4f, 0xc7, 0x51, 0xf3, 0xe3,
-  0xbe, 0x93, 0xca, 0xe3, 0x4a, 0x1e, 0x05, 0x2a, 0x04, 0x75, 0xf0, 0xd1,
-  0xf1, 0xa8, 0x24, 0x68, 0xa2, 0x81, 0xdd, 0x45, 0x00, 0x89, 0xc6, 0x5f,
-  0x89, 0x62, 0xff, 0x00, 0xb5, 0x56, 0xcf, 0xbf, 0x14, 0xf7, 0x48, 0x9c,
-  0x65, 0xf8, 0x96, 0x2f, 0xfb, 0x55, 0x6c, 0xfb, 0xf1, 0x4f, 0x74, 0x07,
-  0x95, 0x10, 0x0f, 0x52, 0x07, 0xb6, 0x8a, 0xc9, 0x1d, 0x68, 0xa8, 0x18,
-  0x46, 0x69, 0x33, 0x8e, 0x3f, 0x23, 0xd9, 0x77, 0xd1, 0x12, 0x3f, 0x80,
-  0xd3, 0x9d, 0x26, 0x71, 0xc7, 0xe4, 0x7b, 0x2e, 0xfa, 0x22, 0x47, 0xf0,
-  0x1a, 0x90, 0x37, 0xc6, 0xf8, 0xbb, 0x7f, 0x30, 0x7d, 0x95, 0xb2, 0xb5,
-  0xc6, 0xf8, 0xbb, 0x7f, 0x30, 0x7d, 0x95, 0xb2, 0x80, 0x28, 0xa2, 0x8a,
-  0x03, 0x96, 0xe9, 0x0a, 0x2d, 0xca, 0xdf, 0x26, 0xdf, 0x39, 0x86, 0xe4,
-  0x45, 0x94, 0xd2, 0x99, 0x7d, 0xa5, 0x8d, 0xa5, 0xc4, 0x28, 0x10, 0xa4,
-  0x91, 0xe8, 0x20, 0x9a, 0xf8, 0xda, 0xe3, 0x06, 0xe1, 0x84, 0xca, 0xbd,
-  0xe2, 0x73, 0x24, 0x2f, 0xb4, 0xc5, 0xd8, 0x54, 0x54, 0xba, 0xb5, 0x12,
-  0x5e, 0xb1, 0x49, 0x73, 0x9e, 0x24, 0x8d, 0xf8, 0xf9, 0x2c, 0x92, 0x02,
-  0xbf, 0x55, 0xc5, 0x78, 0x26, 0xbe, 0xd3, 0xd5, 0x52, 0xff, 0x00, 0x84,
-  0xee, 0x3e, 0xfc, 0x7b, 0x7c, 0x0e, 0x26, 0x5a, 0x20, 0x26, 0x74, 0xfc,
-  0x68, 0x38, 0x9b, 0x8c, 0x32, 0x9e, 0x61, 0x70, 0xb5, 0x3a, 0x39, 0x65,
-  0x30, 0xa1, 0xe3, 0xe6, 0x92, 0xa1, 0xbe, 0xef, 0x38, 0xd4, 0xa7, 0x87,
-  0x92, 0x1a, 0xca, 0xc0, 0xd9, 0x8f, 0x4c, 0x63, 0x39, 0xc0, 0x24, 0xbd,
-  0x09, 0xc1, 0x1d, 0xeb, 0x83, 0x45, 0x44, 0xf7, 0x86, 0x24, 0x00, 0x02,
-  0x90, 0xaf, 0x5a, 0x1c, 0x49, 0x04, 0x7a, 0x3d, 0xbb, 0xa8, 0x35, 0xe3,
-  0xf7, 0x97, 0xef, 0x82, 0x5a, 0xec, 0x97, 0x17, 0xee, 0x4b, 0x5f, 0x94,
-  0x11, 0x2e, 0x7e, 0xed, 0xd1, 0x5d, 0x56, 0x8a, 0x96, 0x00, 0xf3, 0x97,
-  0xa2, 0x94, 0xe9, 0x1d, 0x7a, 0x01, 0xbd, 0x68, 0x6a, 0xbd, 0xe0, 0x62,
-  0xe7, 0x40, 0x99, 0x2e, 0xd9, 0x88, 0xdf, 0x18, 0x2f, 0xc6, 0xec, 0x96,
-  0xc3, 0x53, 0xb9, 0x95, 0x16, 0xef, 0x6f, 0x75, 0x3c, 0xd0, 0xe4, 0x12,
-  0x9f, 0x39, 0xb7, 0x83, 0x7e, 0xf4, 0xa7, 0x12, 0x0f, 0x9c, 0xce, 0x94,
-  0x09, 0xd6, 0xad, 0xe7, 0xa4, 0x71, 0x56, 0x6a, 0xfb, 0x36, 0xad, 0x18,
-  0xa5, 0xa9, 0x24, 0xf5, 0x7d, 0x77, 0x17, 0xa4, 0x94, 0x8f, 0x48, 0x40,
-  0x65, 0x1c, 0xc7, 0xda, 0xa4, 0xee, 0xb4, 0x97, 0x39, 0x7d, 0x4c, 0xa3,
-  0xc6, 0x17, 0x41, 0xaa, 0xdb, 0x1e, 0x2d, 0xa2, 0xd4, 0xdc, 0x65, 0xba,
-  0xda, 0x52, 0x9e, 0x75, 0x2d, 0x4a, 0x3c, 0xa9, 0x2a, 0x51, 0x2a, 0x5a,
-  0xb4, 0x4f, 0x40, 0x4a, 0x94, 0x75, 0xe1, 0xba, 0xae, 0x63, 0xdd, 0xf1,
-  0x96, 0xaf, 0x32, 0x15, 0x83, 0xd8, 0xe6, 0xe5, 0x77, 0x30, 0xf1, 0x2d,
-  0xba, 0xcf, 0x9d, 0x16, 0x0a, 0xb9, 0x74, 0xa4, 0x26, 0x42, 0xf4, 0x96,
-  0xd2, 0x76, 0x49, 0x4a, 0x49, 0x3b, 0x27, 0xa7, 0x85, 0x48, 0xdc, 0xb0,
-  0xfb, 0x5b, 0x4d, 0x0b, 0x8f, 0x10, 0xf2, 0x49, 0x57, 0xd4, 0x95, 0x84,
-  0x88, 0xee, 0x0e, 0xc2, 0x22, 0xd5, 0xde, 0x12, 0x23, 0xb7, 0xb2, 0xe9,
-  0xef, 0xf3, 0x54, 0x57, 0xbf, 0x01, 0x52, 0x3f, 0xca, 0x44, 0xf6, 0xf0,
-  0xf1, 0xbb, 0x05, 0xad, 0xcb, 0x5c, 0x97, 0x50, 0xa5, 0x23, 0xcb, 0x60,
-  0xa9, 0xa6, 0x63, 0xc6, 0x40, 0xf3, 0x9d, 0x08, 0x1a, 0x0a, 0x1b, 0x29,
-  0x48, 0x4e, 0xd2, 0x76, 0xa1, 0xbd, 0x78, 0xd3, 0xba, 0xbd, 0x4d, 0x31,
-  0x26, 0x45, 0x4e, 0xc3, 0x2e, 0xd9, 0x34, 0x65, 0x4a, 0xe2, 0x4d, 0xf6,
-  0x3b, 0x76, 0xe4, 0x12, 0xb3, 0x6c, 0xb7, 0x9e, 0xcd, 0x84, 0x27, 0xd0,
-  0xe4, 0x85, 0x0e, 0xd1, 0x5d, 0x3b, 0xca, 0x7b, 0x31, 0xed, 0xef, 0x3d,
-  0xb6, 0x6b, 0xbe, 0x19, 0x8f, 0x43, 0x62, 0xcb, 0x85, 0xdb, 0x61, 0xf6,
-  0xd2, 0x57, 0xd9, 0xc5, 0x89, 0x15, 0xae, 0xc1, 0x32, 0x08, 0x07, 0x6b,
-  0xed, 0x0a, 0x74, 0xb4, 0xa4, 0x02, 0x54, 0xb1, 0xcc, 0x40, 0x1e, 0x24,
-  0xea, 0x8c, 0x8e, 0xdb, 0x2e, 0x0c, 0xbb, 0x44, 0xeb, 0xcd, 0xdd, 0xfb,
-  0xbd, 0x99, 0x12, 0xd2, 0x27, 0x35, 0x21, 0xa6, 0x92, 0x84, 0x2d, 0x63,
-  0x91, 0xa7, 0x00, 0x4a, 0x53, 0xef, 0x69, 0x5a, 0x86, 0xc1, 0x27, 0x5d,
-  0x0f, 0x81, 0xdf, 0x1e, 0x53, 0x95, 0x44, 0xb8, 0x40, 0x76, 0x33, 0x31,
-  0xa6, 0xb1, 0x90, 0xdb, 0x66, 0x03, 0x09, 0xa5, 0xc7, 0x5b, 0x6e, 0x29,
-  0xe0, 0xa2, 0x11, 0xca, 0x08, 0x1c, 0xe8, 0x71, 0x3c, 0xc0, 0x94, 0xed,
-  0x3c, 0xaa, 0x3d, 0x7c, 0x43, 0x79, 0x0d, 0xa2, 0x75, 0xe5, 0x09, 0xc9,
-  0x9a, 0x89, 0x0d, 0xdb, 0xe4, 0xf8, 0x66, 0xce, 0xf4, 0x94, 0x22, 0xe8,
-  0x88, 0x0d, 0xad, 0xb5, 0xb0, 0xc9, 0xd8, 0x1a, 0x70, 0xaf, 0x6a, 0x6c,
-  0xa8, 0xa4, 0x2c, 0xe9, 0x27, 0x97, 0x64, 0x68, 0x6e, 0xb9, 0xae, 0x93,
-  0x71, 0x69, 0xf8, 0x9c, 0x89, 0xd6, 0x01, 0x12, 0x14, 0x8b, 0x13, 0x8e,
-  0x48, 0x8e, 0x52, 0xc0, 0x40, 0x8a, 0xfb, 0x64, 0x82, 0x85, 0x80, 0x07,
-  0x2f, 0x3e, 0x8a, 0x0a, 0x4f, 0x52, 0x15, 0xd0, 0x6f, 0xbb, 0x86, 0xea,
-  0xac, 0x95, 0x84, 0x5c, 0x2d, 0xd7, 0x69, 0x66, 0x34, 0x2b, 0xa2, 0xdd,
-  0x69, 0x84, 0x3e, 0xda, 0x1d, 0x7d, 0x28, 0x73, 0x7c, 0xe8, 0x69, 0xb6,
-  0x4a, 0x94, 0xf9, 0x01, 0x5e, 0x6a, 0x94, 0x11, 0xcb, 0xd3, 0x98, 0x2a,
-  0xb3, 0x1e, 0x1d, 0xae, 0x45, 0xfb, 0xc8, 0xa0, 0x44, 0x99, 0x6d, 0x7d,
-  0x96, 0xd3, 0x31, 0xf7, 0xef, 0x21, 0x6e, 0x96, 0x93, 0xbe, 0x46, 0xd4,
-  0xd2, 0x16, 0xa2, 0x85, 0x2c, 0xe8, 0x80, 0xb3, 0xcd, 0xc9, 0xa0, 0x35,
-  0xd4, 0x0a, 0x61, 0x2f, 0x52, 0x77, 0x61, 0x75, 0xbc, 0x65, 0x2b, 0x5d,
-  0xd3, 0xca, 0x9b, 0x44, 0x3b, 0x2c, 0xb6, 0x88, 0x6f, 0xdd, 0x56, 0x92,
-  0xc8, 0x8c, 0xb5, 0xa3, 0x45, 0x2a, 0x5f, 0x31, 0xed, 0x53, 0xde, 0x52,
-  0x84, 0x27, 0x98, 0x95, 0x00, 0x48, 0xd1, 0xad, 0x46, 0xd9, 0x69, 0x97,
-  0x39, 0x8b, 0x55, 0xad, 0xe9, 0x97, 0x5b, 0x9b, 0xd1, 0x42, 0x5c, 0x6e,
-  0xe0, 0xc9, 0x88, 0x83, 0x1d, 0xb4, 0x80, 0x16, 0xf2, 0x83, 0x49, 0x79,
-  0xe6, 0xb9, 0x88, 0xd2, 0x0a, 0x94, 0x92, 0x49, 0x04, 0xe8, 0x13, 0x5d,
-  0xf9, 0x63, 0xb3, 0x31, 0x0b, 0x94, 0x4c, 0x8e, 0x52, 0xee, 0x39, 0x2c,
-  0x34, 0x32, 0xb6, 0x63, 0xb6, 0xe2, 0x5a, 0x2e, 0xb0, 0xfa, 0x88, 0x25,
-  0x69, 0xe5, 0x4a, 0x76, 0x14, 0x84, 0xab, 0x43, 0x5b, 0xd8, 0xe5, 0x1f,
-  0x0c, 0x01, 0x9c, 0x9e, 0xe9, 0x6e, 0xca, 0xd8, 0xb6, 0x2b, 0x1e, 0x91,
-  0x2d, 0x37, 0x49, 0x0a, 0x53, 0x29, 0xec, 0x42, 0x98, 0x7d, 0x31, 0x5c,
-  0x1c, 0xae, 0xa9, 0x5b, 0x4e, 0xdb, 0x48, 0xe8, 0xa0, 0xa5, 0x27, 0xe1,
-  0xa1, 0x3a, 0x07, 0xb8, 0xc6, 0xfd, 0x42, 0xc6, 0x76, 0x3d, 0x64, 0xb1,
-  0xe7, 0x5a, 0x97, 0x6b, 0x39, 0x1c, 0x86, 0x6e, 0x78, 0xf2, 0x0a, 0xca,
-  0xe3, 0x46, 0x83, 0xc8, 0x90, 0xf2, 0x53, 0xef, 0x2d, 0xf2, 0x02, 0x79,
-  0x9b, 0x24, 0x10, 0x90, 0x7f, 0x3f, 0x90, 0x75, 0xde, 0x86, 0xcc, 0xc2,
-  0xe3, 0x68, 0xbb, 0xe1, 0xd0, 0x32, 0x4b, 0x1c, 0x94, 0xa2, 0x53, 0x0b,
-  0x47, 0xb9, 0x6e, 0xb2, 0x00, 0x52, 0xcb, 0xba, 0x4a, 0x99, 0x6f, 0xa6,
-  0x94, 0x54, 0x9d, 0x8d, 0x0e, 0xe2, 0x90, 0x7f, 0x36, 0xb8, 0x15, 0xee,
-  0xd0, 0xb6, 0x44, 0xc7, 0xf2, 0x89, 0x6e, 0x2c, 0x95, 0x36, 0xeb, 0xad,
-  0x36, 0x80, 0xf4, 0xd9, 0x49, 0x6d, 0x61, 0x49, 0x09, 0x6d, 0x91, 0xca,
-  0xda, 0x76, 0x9d, 0x15, 0x92, 0x77, 0xa3, 0xd1, 0x35, 0xd7, 0x60, 0xb7,
-  0xc4, 0xb9, 0xde, 0x64, 0x2e, 0xc0, 0xc3, 0xb6, 0x56, 0xe0, 0x14, 0xc7,
-  0x7a, 0x4c, 0xb6, 0xd4, 0xec, 0xd4, 0xb8, 0xa4, 0xf3, 0x29, 0xa6, 0xbb,
-  0x62, 0xa0, 0xd2, 0x42, 0x54, 0x36, 0x40, 0x21, 0x5b, 0xe9, 0xd0, 0x6c,
-  0xb6, 0x5c, 0x05, 0x97, 0xc9, 0xcf, 0x70, 0x99, 0x7b, 0x7b, 0x11, 0x36,
-  0x5c, 0x91, 0xf4, 0xc6, 0x0f, 0x28, 0x33, 0x26, 0xe5, 0x35, 0x86, 0xe3,
-  0x02, 0x90, 0xa1, 0xd1, 0x96, 0x50, 0xe2, 0xd4, 0xb7, 0x48, 0x1b, 0x04,
-  0x10, 0x90, 0x41, 0x23, 0xc0, 0x52, 0xde, 0x39, 0x78, 0xb7, 0xe1, 0x7c,
-  0x74, 0x90, 0xc4, 0x09, 0x04, 0xe2, 0xd9, 0xd3, 0xca, 0x5a, 0x02, 0x90,
-  0xa4, 0x08, 0x77, 0x94, 0x24, 0x17, 0x10, 0x52, 0xad, 0x29, 0x3d, 0xb3,
-  0x7a, 0x5f, 0x51, 0xd5, 0x43, 0xa7, 0x4a, 0x6d, 0x9c, 0x6e, 0x18, 0xbe,
-  0x47, 0x32, 0x53, 0xd1, 0x65, 0xe4, 0xd2, 0x9c, 0x8a, 0x85, 0xda, 0x82,
-  0x8b, 0x61, 0xfe, 0xc5, 0xb5, 0x7f, 0x38, 0x69, 0x04, 0x04, 0x82, 0xe0,
-  0x0b, 0xe7, 0x1d, 0x01, 0x58, 0xd2, 0x76, 0x4a, 0x77, 0x4b, 0xfc, 0x51,
-  0xb1, 0x46, 0xe2, 0x4c, 0x66, 0xad, 0xb6, 0xc4, 0x49, 0xb7, 0xde, 0x25,
-  0xc5, 0x53, 0xea, 0xed, 0x11, 0xca, 0xec, 0x07, 0x99, 0xdb, 0x91, 0x24,
-  0x38, 0x01, 0xf3, 0x16, 0x1c, 0xf3, 0x40, 0xef, 0x52, 0x1d, 0x5f, 0x78,
-  0x1d, 0x0f, 0x7d, 0xc2, 0xc7, 0x05, 0xcc, 0x93, 0xb1, 0xba, 0xcd, 0x23,
-  0xf0, 0x57, 0x34, 0x73, 0x36, 0xc1, 0x63, 0xcf, 0x9e, 0xcf, 0x92, 0xde,
-  0xa1, 0x2d, 0x50, 0x2f, 0x31, 0x08, 0xd2, 0x98, 0x9a, 0xd1, 0xe5, 0x71,
-  0x24, 0x78, 0x02, 0x7c, 0xe1, 0xea, 0x50, 0xf4, 0x53, 0xc0, 0xa8, 0x24,
-  0x44, 0xe3, 0x2f, 0xc4, 0xb1, 0x7f, 0xda, 0xab, 0x67, 0xdf, 0x8a, 0x7b,
-  0xa4, 0x4e, 0x32, 0xfc, 0x4b, 0x17, 0xfd, 0xaa, 0xb6, 0x7d, 0xf8, 0xa7,
-  0xba, 0x00, 0xa2, 0x8a, 0x28, 0x02, 0x93, 0x38, 0xe3, 0xf2, 0x3d, 0x97,
-  0x7d, 0x11, 0x23, 0xf8, 0x0d, 0x39, 0xd2, 0x67, 0x1c, 0x7e, 0x47, 0xb2,
-  0xef, 0xa2, 0x24, 0x7f, 0x01, 0xa0, 0x1b, 0xe3, 0x7c, 0x5d, 0xbf, 0x98,
-  0x3e, 0xca, 0xd9, 0x5a, 0xe3, 0x7c, 0x5d, 0xbf, 0x98, 0x3e, 0xca, 0xd9,
-  0x40, 0x14, 0x51, 0x45, 0x00, 0x56, 0xb9, 0x0d, 0xb4, 0xfb, 0x4e, 0x32,
-  0xf3, 0x68, 0x75, 0xb7, 0x12, 0x52, 0xb4, 0x28, 0x6c, 0x28, 0x11, 0xd4,
-  0x11, 0xe8, 0x22, 0xb6, 0x50, 0x46, 0xe8, 0x0f, 0x8d, 0xe5, 0x43, 0x93,
-  0xc2, 0x6e, 0x21, 0xcb, 0xb4, 0x27, 0xb7, 0xec, 0xf1, 0xc4, 0xae, 0x75,
-  0xb1, 0x5d, 0x49, 0x99, 0x8f, 0xbe, 0xef, 0x33, 0xec, 0x8e, 0xed, 0xae,
-  0x2b, 0xa7, 0xb6, 0x1f, 0xaa, 0x1d, 0xf0, 0xd5, 0x7d, 0x29, 0x22, 0xf4,
-  0xed, 0xd8, 0x5a, 0x62, 0xc4, 0xbb, 0xa2, 0xdf, 0x1e, 0x63, 0x2b, 0x71,
-  0xf9, 0x6d, 0xf2, 0xa9, 0x6a, 0xd1, 0x6d, 0x29, 0x43, 0x65, 0x5b, 0x00,
-  0xab, 0xb4, 0x07, 0x98, 0x82, 0x75, 0xad, 0x75, 0x3b, 0x0b, 0x5f, 0x84,
-  0xc6, 0x29, 0x2e, 0xed, 0x89, 0xc7, 0xcb, 0x2c, 0x31, 0x9b, 0x7b, 0x23,
-  0xc5, 0x5c, 0x55, 0xc2, 0x23, 0x6b, 0x40, 0x50, 0x94, 0xc7, 0x2e, 0xa4,
-  0x46, 0x50, 0xf1, 0x43, 0x8d, 0xf3, 0x02, 0x9f, 0x1d, 0x6b, 0xc6, 0xab,
-  0xbe, 0x0f, 0x3f, 0x65, 0xc8, 0xac, 0xab, 0xc1, 0x9e, 0x90, 0xe2, 0xed,
-  0x6a, 0x8e, 0xdd, 0xc7, 0x1e, 0x92, 0xb5, 0xed, 0xc1, 0x01, 0xd5, 0x1e,
-  0xcd, 0x25, 0x43, 0x47, 0x99, 0x87, 0x02, 0x98, 0x5e, 0x88, 0x20, 0xa1,
-  0x27, 0x7d, 0xc6, 0xb5, 0x87, 0x7a, 0x3a, 0x4c, 0xa7, 0xdd, 0x96, 0xaf,
-  0xcc, 0xb5, 0xf3, 0x08, 0xa7, 0x0b, 0x76, 0x26, 0x59, 0x1d, 0x37, 0x0b,
-  0xac, 0x78, 0xad, 0xad, 0x87, 0xe3, 0x48, 0x96, 0xb7, 0x8a, 0x14, 0xe1,
-  0x48, 0x4b, 0xc8, 0x2e, 0x12, 0x42, 0xb6, 0x02, 0x08, 0x04, 0x0d, 0x2f,
-  0x7a, 0x1a, 0x3b, 0xf5, 0x93, 0xdd, 0x6d, 0x19, 0x44, 0x68, 0x11, 0xec,
-  0xaa, 0x71, 0xfb, 0xa0, 0x79, 0xb5, 0x32, 0x1a, 0x0a, 0x4a, 0x98, 0x69,
-  0x7a, 0x4b, 0xa5, 0xc2, 0x9e, 0xad, 0xa0, 0xb4, 0xa5, 0x8e, 0xba, 0x24,
-  0x81, 0xad, 0x90, 0x35, 0xc9, 0x0a, 0xc9, 0x72, 0x6a, 0x5a, 0x2c, 0xad,
-  0xca, 0x7a, 0xfc, 0x6d, 0xa5, 0x0b, 0x59, 0x94, 0xe2, 0x9a, 0x8a, 0xd3,
-  0x9a, 0xe6, 0x41, 0x74, 0xa8, 0xad, 0xc7, 0xdc, 0xd6, 0x94, 0x13, 0xbe,
-  0x51, 0xb0, 0x4e, 0x8e, 0xb5, 0xee, 0x0a, 0x2d, 0xe6, 0xf5, 0x22, 0xd3,
-  0x96, 0x08, 0x76, 0xce, 0x49, 0x0d, 0x31, 0x0a, 0xd9, 0x11, 0xc2, 0xd4,
-  0x59, 0x5c, 0xe8, 0x2a, 0x0e, 0xe8, 0x04, 0x95, 0x95, 0x14, 0x38, 0x9e,
-  0x53, 0xb0, 0x9e, 0xcc, 0x8e, 0xbb, 0xd9, 0xcf, 0x2b, 0x84, 0x69, 0xbf,
-  0x2c, 0xe7, 0x72, 0xdf, 0x77, 0x65, 0x11, 0xb1, 0xdb, 0xc2, 0x9c, 0xba,
-  0x3e, 0x5b, 0x42, 0x9f, 0x62, 0x22, 0xbb, 0x67, 0xe5, 0x34, 0x95, 0x12,
-  0x90, 0xeb, 0xab, 0x4b, 0x6d, 0xb2, 0xd9, 0x29, 0x00, 0xe8, 0x6d, 0x5a,
-  0x3a, 0x3d, 0xf5, 0xd1, 0x6f, 0x66, 0x12, 0xf2, 0x09, 0x76, 0xf5, 0x5b,
-  0x93, 0x88, 0x88, 0xec, 0xb6, 0xb9, 0x09, 0x8d, 0xd9, 0x87, 0xe5, 0x17,
-  0x56, 0xae, 0x50, 0xdb, 0xa9, 0xea, 0x1a, 0xf3, 0x34, 0x79, 0x79, 0x4f,
-  0x31, 0xd6, 0xc6, 0xba, 0xe9, 0xbf, 0x2d, 0x78, 0x54, 0xe9, 0x0e, 0x63,
-  0x22, 0x0a, 0x18, 0xba, 0x21, 0x12, 0x5a, 0x43, 0xc5, 0x7d, 0x92, 0x0b,
-  0x2b, 0x42, 0x5d, 0x68, 0x29, 0x29, 0x57, 0x66, 0x85, 0x25, 0xcd, 0xa5,
-  0x5a, 0x29, 0x42, 0x81, 0xd8, 0x00, 0xf4, 0x32, 0x26, 0x1a, 0xce, 0x13,
-  0x01, 0xe9, 0x2d, 0xb5, 0x02, 0x23, 0x1c, 0xe1, 0xdb, 0x83, 0xe9, 0x53,
-  0x4d, 0xad, 0x4a, 0xe5, 0x28, 0x6d, 0xad, 0xa9, 0x0a, 0x59, 0x0b, 0x4a,
-  0x55, 0xce, 0x92, 0x91, 0xe6, 0x8e, 0x52, 0x77, 0x53, 0xcf, 0x21, 0x7a,
-  0x1b, 0x72, 0x36, 0x64, 0xe1, 0x73, 0xdd, 0xba, 0x59, 0x48, 0x96, 0x99,
-  0x90, 0xcc, 0x78, 0x88, 0x9f, 0x35, 0x4a, 0x4c, 0x77, 0x9b, 0x25, 0xd5,
-  0x36, 0x97, 0x1c, 0x3d, 0x03, 0x88, 0x0b, 0xd6, 0xce, 0x82, 0xd0, 0x91,
-  0xd0, 0x1e, 0x9a, 0x72, 0x67, 0xd9, 0xcf, 0x1a, 0x83, 0x12, 0x04, 0x1e,
-  0x69, 0x6b, 0x49, 0x4c, 0xa1, 0xdb, 0x10, 0x18, 0x8e, 0xb4, 0x12, 0xa4,
-  0x3c, 0xb4, 0x6c, 0x21, 0x5c, 0xe9, 0x6d, 0x49, 0x48, 0x25, 0x41, 0x48,
-  0x0a, 0xd6, 0x87, 0x5e, 0xeb, 0x5c, 0x2b, 0x8c, 0x9b, 0x82, 0x9e, 0x87,
-  0x1d, 0xab, 0xc1, 0x82, 0xa7, 0x18, 0x44, 0x89, 0x4a, 0xf2, 0x58, 0x2d,
-  0x2f, 0x5c, 0xae, 0x06, 0x9a, 0x48, 0x52, 0x9c, 0x57, 0x52, 0x92, 0xb5,
-  0x6f, 0xf3, 0x82, 0x4f, 0x78, 0xad, 0x56, 0x85, 0xda, 0x2e, 0x4b, 0x2c,
-  0xe4, 0xea, 0x4c, 0x17, 0x55, 0x31, 0xf8, 0x91, 0xec, 0xa8, 0x7f, 0xb3,
-  0x8e, 0xc1, 0x6b, 0x44, 0xec, 0x23, 0x41, 0xc2, 0x52, 0x52, 0xbe, 0x65,
-  0x7e, 0x6a, 0xc6, 0x80, 0xa8, 0xf4, 0x43, 0x18, 0xdd, 0x9e, 0x11, 0x1e,
-  0x43, 0x92, 0x23, 0x59, 0x27, 0x34, 0xe5, 0xe0, 0x5b, 0x56, 0x97, 0x15,
-  0x02, 0x17, 0xbe, 0x6d, 0xc0, 0x9f, 0x35, 0x72, 0xa4, 0x3a, 0x10, 0x92,
-  0xad, 0x1e, 0x60, 0x80, 0x12, 0x49, 0xd1, 0xea, 0x3a, 0x57, 0x45, 0x85,
-  0x16, 0xfb, 0x83, 0xaf, 0xb6, 0xe1, 0x56, 0x35, 0x08, 0x4f, 0x30, 0xda,
-  0xb5, 0x45, 0xe4, 0x88, 0xe3, 0xaf, 0x21, 0x1c, 0xca, 0xed, 0x16, 0xd9,
-  0xd9, 0x24, 0x12, 0x52, 0x10, 0xa0, 0x39, 0x00, 0x3e, 0x76, 0xfa, 0x46,
-  0x48, 0xbb, 0xcb, 0xc2, 0x2e, 0x09, 0xb5, 0xdb, 0x5c, 0x81, 0x22, 0x02,
-  0xe5, 0x19, 0xc9, 0x12, 0xa5, 0x76, 0x6b, 0x7a, 0x3b, 0xdc, 0xc1, 0x49,
-  0xed, 0x57, 0xb1, 0xce, 0xda, 0xd3, 0xd0, 0x28, 0xf9, 0xe8, 0x20, 0x03,
-  0xb4, 0x9a, 0xd3, 0x92, 0xa6, 0xdd, 0x7e, 0x9a, 0xf5, 0xc6, 0xe8, 0x20,
-  0x43, 0xb7, 0x4a, 0x69, 0xa4, 0xa5, 0xb9, 0xb0, 0x9c, 0x71, 0x73, 0x9e,
-  0x6d, 0x4b, 0xe5, 0x75, 0x96, 0x92, 0xa4, 0xbd, 0xb4, 0xa5, 0x5a, 0x0b,
-  0x1a, 0x2a, 0xde, 0x80, 0x29, 0xd1, 0xa9, 0xf5, 0x61, 0x3e, 0x88, 0x90,
-  0x7e, 0x65, 0xc3, 0x0d, 0xbb, 0xdc, 0x59, 0x86, 0xca, 0x2f, 0x0e, 0xca,
-  0x71, 0xb9, 0x6d, 0x2a, 0x54, 0xb0, 0x97, 0xde, 0x8a, 0x90, 0x1b, 0x53,
-  0x08, 0x5a, 0xf4, 0x14, 0xe3, 0x6a, 0x01, 0x40, 0x28, 0xf9, 0xc9, 0x5f,
-  0x53, 0xbe, 0xfe, 0x6b, 0xec, 0x37, 0x33, 0x5b, 0xda, 0x24, 0x58, 0x5b,
-  0x7e, 0x32, 0xd2, 0xca, 0x57, 0x2e, 0x43, 0x72, 0x43, 0x69, 0x6d, 0xf6,
-  0xd6, 0x92, 0xc8, 0x0e, 0xa5, 0x2b, 0x47, 0x6c, 0x02, 0x9d, 0x49, 0xd0,
-  0x58, 0x01, 0x5a, 0x3f, 0x9b, 0xae, 0xeb, 0x65, 0xb6, 0xec, 0x51, 0x22,
-  0x6f, 0xf2, 0x69, 0x37, 0x2e, 0x66, 0x12, 0x82, 0x6e, 0xce, 0xa1, 0x82,
-  0xe3, 0x60, 0xf3, 0x76, 0x4c, 0xb0, 0x94, 0xa8, 0x36, 0x36, 0x01, 0xf3,
-  0xc8, 0x24, 0xeb, 0x98, 0x9d, 0x74, 0xf3, 0x61, 0x56, 0x35, 0x77, 0x66,
-  0xdc, 0x9b, 0xf4, 0xe5, 0xbd, 0x71, 0x9b, 0x0d, 0x52, 0xd9, 0x88, 0x1d,
-  0x5b, 0x4c, 0xc4, 0x6c, 0x1e, 0x55, 0x21, 0xb4, 0x20, 0x84, 0xa4, 0xb6,
-  0x4f, 0x29, 0x3d, 0x55, 0xb4, 0xf7, 0xd1, 0x79, 0x24, 0x1e, 0xdb, 0xb3,
-  0xc3, 0x71, 0xdd, 0xb9, 0xcd, 0xd4, 0xfb, 0x5b, 0x99, 0x2f, 0x90, 0xa5,
-  0x6c, 0x25, 0x86, 0x02, 0x53, 0x15, 0x85, 0x13, 0xa7, 0x09, 0x75, 0xd2,
-  0x0b, 0xce, 0xf4, 0xd7, 0x9a, 0x00, 0x4f, 0x51, 0xa4, 0x9a, 0xdf, 0x89,
-  0x37, 0x6f, 0xbb, 0xc7, 0x42, 0x3c, 0xb1, 0xfb, 0x2b, 0x4f, 0x17, 0x9c,
-  0x62, 0xcf, 0x0b, 0xf9, 0xa2, 0xda, 0x4a, 0x16, 0x5b, 0x2a, 0x78, 0xa7,
-  0xcf, 0x53, 0x9b, 0x1e, 0x77, 0x50, 0x90, 0x7a, 0x10, 0x7b, 0xcc, 0x6d,
-  0xbf, 0x2c, 0x95, 0x88, 0xcf, 0x67, 0x19, 0x7a, 0x33, 0x52, 0x60, 0xc2,
-  0x0b, 0x60, 0xcb, 0x0b, 0xf3, 0xc9, 0x3c, 0xae, 0x34, 0xe2, 0x81, 0xea,
-  0xbd, 0xa1, 0x7a, 0x50, 0x47, 0x32, 0xf9, 0x82, 0x8f, 0x2e, 0x88, 0xae,
-  0x94, 0x61, 0xf2, 0xb2, 0x0b, 0xf3, 0xd9, 0x2a, 0xa1, 0xb1, 0x6c, 0x25,
-  0xd4, 0xb9, 0x19, 0x32, 0x59, 0x74, 0x39, 0xbe, 0x44, 0x87, 0x1c, 0x28,
-  0x6d, 0xd4, 0x68, 0x28, 0xa1, 0x3e, 0xf6, 0xe7, 0x36, 0xf9, 0x41, 0x20,
-  0x12, 0x45, 0x31, 0xd5, 0x8c, 0xf4, 0x42, 0x54, 0x59, 0xb2, 0x78, 0x6b,
-  0xc7, 0x74, 0xcc, 0x9a, 0xe9, 0x5d, 0x9b, 0x27, 0x71, 0x9b, 0x6d, 0xd5,
-  0xfe, 0x81, 0x02, 0x61, 0x49, 0xf2, 0x39, 0x67, 0xb8, 0x02, 0xea, 0x12,
-  0xa6, 0x96, 0x75, 0xd5, 0x6d, 0x95, 0x78, 0x81, 0x5f, 0x42, 0x27, 0xaa,
-  0x77, 0x55, 0xf6, 0x4d, 0x82, 0xda, 0x72, 0x0b, 0x15, 0xdf, 0x11, 0xb9,
-  0xba, 0xec, 0xd7, 0x2f, 0x11, 0xb9, 0xe5, 0xce, 0x70, 0x8e, 0xd5, 0xb7,
-  0x11, 0xae, 0xc9, 0x68, 0x4a, 0x40, 0x08, 0x08, 0x57, 0x54, 0x81, 0xad,
-  0x7a, 0xce, 0xc9, 0xcf, 0x00, 0xb2, 0x4b, 0xae, 0x43, 0xc3, 0xe4, 0x35,
-  0x90, 0x68, 0xdf, 0x6c, 0xb2, 0xdf, 0xb3, 0xdd, 0x17, 0xbd, 0x87, 0x24,
-  0x47, 0x57, 0x21, 0x5e, 0xff, 0x00, 0x58, 0x72, 0xa8, 0xfa, 0xc9, 0xa8,
-  0x69, 0xa0, 0x9a, 0x66, 0xee, 0x32, 0xfc, 0x4b, 0x17, 0xfd, 0xaa, 0xb6,
-  0x7d, 0xf8, 0xa7, 0xba, 0x44, 0xe3, 0x27, 0xc4, 0x71, 0x7f, 0xda, 0xab,
-  0x67, 0xdf, 0x8a, 0x7b, 0xa8, 0x24, 0x28, 0xac, 0x6f, 0x47, 0xa9, 0x14,
-  0x50, 0x19, 0xa4, 0xce, 0x38, 0xfc, 0x8f, 0x65, 0xdf, 0x44, 0x48, 0xfe,
-  0x03, 0x4e, 0x74, 0x99, 0xc7, 0x1f, 0x91, 0xec, 0xbb, 0xe8, 0x89, 0x1f,
-  0xc0, 0x68, 0x06, 0xf8, 0xdf, 0x17, 0x6f, 0xe6, 0x0f, 0xb2, 0xb6, 0x56,
-  0xb8, 0xdf, 0x17, 0x6f, 0xe6, 0x0f, 0xb2, 0xb6, 0x50, 0x05, 0x14, 0x51,
-  0x40, 0x14, 0x51, 0x45, 0x01, 0xe5, 0x40, 0x6f, 0x64, 0x6f, 0xd1, 0x5f,
-  0x22, 0x66, 0x56, 0x29, 0x9c, 0x37, 0xe2, 0x5c, 0xbb, 0x55, 0xa9, 0x82,
-  0x5b, 0x8c, 0xb7, 0xf2, 0x4c, 0x5d, 0xa1, 0xd0, 0x48, 0x8c, 0xa1, 0xfe,
-  0x93, 0xb6, 0xa7, 0xfe, 0x11, 0xdb, 0x20, 0x78, 0x14, 0x0e, 0xf2, 0xaa,
-  0xfa, 0xf7, 0x5d, 0x77, 0x55, 0xa7, 0xe1, 0x11, 0x88, 0x4f, 0xc9, 0xb0,
-  0x74, 0xdc, 0x71, 0xef, 0x33, 0x28, 0xc7, 0xa4, 0x26, 0xeb, 0x65, 0x74,
-  0x0d, 0xab, 0xb6, 0x6f, 0xaa, 0x9b, 0xf5, 0x85, 0xa4, 0x14, 0xeb, 0xb8,
-  0x9d, 0x6e, 0xa5, 0x3c, 0x3c, 0xa2, 0x1a, 0xca, 0xc3, 0x39, 0x58, 0xbc,
-  0x5c, 0x6e, 0xb6, 0x06, 0xb2, 0x1c, 0x4e, 0x63, 0xef, 0xa2, 0x77, 0x93,
-  0xcb, 0x0e, 0x34, 0xc7, 0x6c, 0x95, 0x72, 0xa4, 0x75, 0x5a, 0x01, 0xe6,
-  0x28, 0x71, 0xbd, 0x24, 0x94, 0xed, 0x49, 0x52, 0x47, 0x4e, 0xfa, 0xd3,
-  0x96, 0x47, 0xb7, 0x64, 0x13, 0xe3, 0x9c, 0xae, 0xe2, 0xdd, 0x99, 0xb8,
-  0xcc, 0xa8, 0x30, 0xdb, 0xaa, 0x6f, 0xca, 0x9c, 0x25, 0x6d, 0xac, 0x38,
-  0xe2, 0x13, 0xcc, 0x1a, 0x6d, 0x1d, 0x98, 0xd1, 0xde, 0xf6, 0x49, 0x25,
-  0x3d, 0xc5, 0x03, 0xf0, 0x78, 0xcc, 0xa0, 0xc7, 0xb8, 0xb7, 0x12, 0x22,
-  0x15, 0x12, 0xcd, 0x7a, 0x4b, 0x97, 0x2b, 0x43, 0x24, 0x79, 0xb1, 0xce,
-  0xff, 0x00, 0x9e, 0xc2, 0xf5, 0x16, 0x5e, 0x25, 0x49, 0x4f, 0xe8, 0x2d,
-  0x26, 0xad, 0x7c, 0x66, 0xfd, 0x6a, 0xb2, 0x3b, 0x02, 0xc3, 0x36, 0xdd,
-  0x26, 0x3c, 0xc9, 0xcd, 0x6d, 0xd9, 0x4b, 0x68, 0xac, 0x4b, 0x94, 0x14,
-  0xa0, 0xe2, 0x54, 0xb1, 0xf0, 0x96, 0x48, 0xe6, 0xd1, 0xef, 0x4a, 0x86,
-  0xba, 0x77, 0x6b, 0x35, 0x9c, 0x38, 0xf5, 0x32, 0x83, 0x4b, 0x2a, 0x5d,
-  0x0f, 0x78, 0xcc, 0x5b, 0xbc, 0x80, 0x6f, 0x96, 0x64, 0x44, 0x58, 0x7d,
-  0xae, 0x56, 0x27, 0x5d, 0x54, 0xa7, 0x1e, 0x92, 0xd7, 0x7a, 0x42, 0x10,
-  0xdf, 0x2a, 0x18, 0x69, 0x47, 0x44, 0x72, 0xef, 0x7d, 0x09, 0x4e, 0xc5,
-  0x73, 0xe3, 0x32, 0xb1, 0xb9, 0x8e, 0xc6, 0x56, 0x4d, 0xe4, 0xf2, 0x32,
-  0x19, 0xa2, 0x40, 0x75, 0xb9, 0xa9, 0x0b, 0x0c, 0xa9, 0xa5, 0x00, 0xeb,
-  0x0d, 0x85, 0x0d, 0x24, 0x24, 0x29, 0x3d, 0xc3, 0x6a, 0x1a, 0x51, 0xde,
-  0xf7, 0x51, 0x96, 0xd5, 0x5e, 0xe3, 0xde, 0x55, 0xfc, 0x9a, 0x7e, 0x74,
-  0xcb, 0x04, 0x27, 0x9d, 0x8b, 0x1d, 0x2d, 0x21, 0xa5, 0x32, 0xa6, 0xb9,
-  0x42, 0xf4, 0x87, 0x16, 0xe2, 0x79, 0x3b, 0x35, 0xa9, 0x48, 0xe7, 0xd2,
-  0xd2, 0x52, 0x90, 0x06, 0x94, 0x9e, 0xba, 0xe7, 0x2b, 0x1d, 0x94, 0xd4,
-  0xab, 0xcd, 0xf6, 0x6b, 0xd2, 0xa6, 0x2e, 0x68, 0x7d, 0x84, 0x5b, 0x3b,
-  0x43, 0x19, 0x2f, 0x04, 0x25, 0xb6, 0x9a, 0x43, 0xfc, 0xbc, 0x85, 0xd2,
-  0x12, 0x91, 0xce, 0x0a, 0x4e, 0xce, 0x86, 0x87, 0x4a, 0xc9, 0x63, 0x93,
-  0x5d, 0xfa, 0x1b, 0x99, 0x99, 0x79, 0xc7, 0xee, 0xc6, 0xcf, 0x8c, 0x29,
-  0x32, 0x6d, 0x96, 0xd7, 0xc8, 0xf2, 0x61, 0x15, 0xd7, 0x90, 0x58, 0x7c,
-  0x07, 0x12, 0x9e, 0x66, 0xc2, 0x8a, 0x5d, 0x41, 0xe6, 0xd7, 0x30, 0xe5,
-  0x52, 0x14, 0x01, 0x20, 0xf5, 0x39, 0xbd, 0xc6, 0x6a, 0xeb, 0x75, 0x91,
-  0x26, 0xe6, 0x86, 0xd8, 0x9a, 0xe9, 0x8e, 0xa6, 0x2d, 0x6d, 0xc2, 0x6a,
-  0x74, 0x82, 0xa6, 0x82, 0xf9, 0x5e, 0x71, 0x07, 0x61, 0xa5, 0xf9, 0xe3,
-  0x4a, 0xe6, 0x00, 0x04, 0xf5, 0x27, 0xc2, 0x55, 0xfb, 0x06, 0x4f, 0x1b,
-  0x17, 0x96, 0xcd, 0x9a, 0xe1, 0x02, 0xdf, 0x24, 0x36, 0xa5, 0x26, 0xdb,
-  0x0d, 0x80, 0x5b, 0x20, 0xef, 0x69, 0x53, 0xaa, 0x3c, 0xea, 0x75, 0x49,
-  0xfe, 0x93, 0xcd, 0xf3, 0xba, 0x90, 0x6b, 0x7c, 0x0c, 0xab, 0x1e, 0xb2,
-  0xdb, 0x10, 0xa8, 0x16, 0x0b, 0xb3, 0x76, 0xf7, 0x58, 0x4c, 0x96, 0x5c,
-  0x85, 0x6c, 0x75, 0xf4, 0x39, 0xcc, 0x3c, 0xee, 0x65, 0x36, 0x93, 0xca,
-  0xe0, 0x20, 0x85, 0x73, 0x90, 0x7a, 0x6f, 0x7a, 0xeb, 0x4c, 0x92, 0x92,
-  0x36, 0x58, 0xf1, 0xfb, 0xe8, 0x71, 0xe7, 0xd7, 0x2c, 0x5a, 0xd7, 0x2b,
-  0x97, 0xb7, 0x79, 0x4b, 0x12, 0x67, 0x3a, 0x90, 0x4e, 0x92, 0x56, 0x40,
-  0x69, 0xa0, 0x37, 0xf0, 0x50, 0x82, 0x91, 0xb3, 0xae, 0xbb, 0x35, 0x3f,
-  0x6c, 0xb4, 0xda, 0x2c, 0x85, 0xd7, 0xd9, 0x6c, 0x99, 0x2b, 0x47, 0xbf,
-  0x49, 0x79, 0x6a, 0x75, 0xf7, 0x40, 0xfd, 0x25, 0x2b, 0x6a, 0x23, 0xd5,
-  0xdd, 0xe8, 0x14, 0x82, 0xac, 0xc3, 0x3a, 0xcb, 0xd6, 0x23, 0xe1, 0xf6,
-  0x2f, 0x72, 0x20, 0x13, 0xa5, 0x5c, 0x66, 0x29, 0x0e, 0xb8, 0x47, 0x4f,
-  0x82, 0x06, 0xda, 0x49, 0xf5, 0xed, 0xd2, 0x3c, 0x51, 0xba, 0x9b, 0xc6,
-  0xb8, 0x7e, 0x98, 0xf1, 0x94, 0x6f, 0xf7, 0x17, 0xee, 0x2e, 0x3e, 0x42,
-  0xa4, 0x36, 0x1d, 0x51, 0x4b, 0xe7, 0xfd, 0xaa, 0xcf, 0x9e, 0xe8, 0xfd,
-  0x52, 0x43, 0x7e, 0x84, 0x01, 0xa1, 0x50, 0x49, 0x2e, 0xac, 0xba, 0xd9,
-  0x21, 0x45, 0x8b, 0x33, 0x32, 0xaf, 0x32, 0x47, 0x9a, 0x5a, 0x88, 0xdf,
-  0x44, 0x1f, 0xd7, 0x5a, 0xb4, 0x94, 0x7b, 0x14, 0x77, 0xea, 0xa8, 0x36,
-  0x30, 0x69, 0x97, 0x15, 0x22, 0x7d, 0xd6, 0x44, 0x68, 0x72, 0x7c, 0xbd,
-  0xc9, 0xcd, 0xc7, 0x66, 0x3b, 0x72, 0x04, 0x45, 0x2f, 0x5f, 0x93, 0x71,
-  0xc4, 0xed, 0x2b, 0x3a, 0xda, 0xba, 0x14, 0xec, 0x9e, 0x9e, 0x25, 0xbd,
-  0xd9, 0x16, 0xbb, 0x34, 0x34, 0x30, 0x90, 0xcc, 0x66, 0x90, 0x34, 0xdb,
-  0x2d, 0x20, 0x0d, 0x7a, 0x82, 0x45, 0x25, 0x66, 0xbc, 0x47, 0xb7, 0x59,
-  0x5b, 0x6c, 0x4a, 0x96, 0x88, 0x21, 0xf3, 0xca, 0xc3, 0x41, 0x25, 0xd9,
-  0x2f, 0x9f, 0x43, 0x6d, 0xa7, 0x6a, 0x51, 0xf5, 0x24, 0x13, 0xec, 0xad,
-  0x69, 0xd1, 0x94, 0xf7, 0x5c, 0x79, 0x98, 0xce, 0xb4, 0x61, 0xb7, 0x51,
-  0xb6, 0x0c, 0x6b, 0x46, 0x37, 0x01, 0x4d, 0xa5, 0xd5, 0x24, 0xb8, 0xe1,
-  0x75, 0xd7, 0x1e, 0x70, 0xb8, 0xf3, 0xee, 0x10, 0x01, 0x5a, 0x89, 0xea,
-  0xa5, 0x74, 0x03, 0xd0, 0x00, 0x00, 0x68, 0x00, 0x2a, 0x26, 0xe5, 0x92,
-  0x3c, 0xf7, 0xbd, 0x42, 0x41, 0x65, 0x04, 0xeb, 0x9c, 0x80, 0x54, 0x7d,
-  0x9e, 0x03, 0xed, 0xaa, 0xba, 0xff, 0x00, 0x94, 0x5c, 0xa3, 0x34, 0xdd,
-  0xeb, 0x2c, 0x9f, 0x17, 0x03, 0xc7, 0xcf, 0x9c, 0xa9, 0x17, 0x87, 0x02,
-  0xee, 0x72, 0x87, 0xa1, 0x98, 0xe9, 0x27, 0x93, 0x7d, 0xdb, 0x57, 0x31,
-  0xd7, 0xe6, 0x8a, 0x81, 0xfc, 0x6e, 0x66, 0x19, 0xb3, 0x6e, 0xc3, 0xe0,
-  0x16, 0x07, 0x22, 0x5b, 0x68, 0xf3, 0x1e, 0xc8, 0xaf, 0x49, 0x4b, 0x4c,
-  0xa3, 0xae, 0xbd, 0xed, 0x2a, 0x20, 0x28, 0xf8, 0xf5, 0x3b, 0xfd, 0x4a,
-  0xd5, 0x7b, 0xaa, 0x5b, 0xbe, 0xf3, 0xfd, 0x0c, 0xa4, 0xab, 0x55, 0xf4,
-  0x45, 0xb9, 0x75, 0xc9, 0x2c, 0x7c, 0x3c, 0xc5, 0xa7, 0x65, 0x59, 0x7d,
-  0xc1, 0xb8, 0x2c, 0x84, 0x79, 0x89, 0x71, 0x5e, 0xfa, 0xf1, 0xd7, 0x44,
-  0x21, 0x3d, 0xea, 0x52, 0x8e, 0xb4, 0x3c, 0x3b, 0xfb, 0xb6, 0x6b, 0x9b,
-  0xf0, 0x6f, 0xb3, 0x5c, 0xed, 0xbc, 0x37, 0x17, 0x5b, 0xdb, 0x45, 0x9b,
-  0xae, 0x47, 0x3a, 0x45, 0xf2, 0x63, 0x47, 0xbd, 0xb5, 0x49, 0x5f, 0x3a,
-  0x52, 0x7d, 0x61, 0x1c, 0x80, 0x8f, 0x03, 0xb1, 0x4b, 0xdc, 0x3b, 0xe0,
-  0x44, 0x66, 0xae, 0x4d, 0x65, 0x9c, 0x54, 0xba, 0x39, 0x9c, 0x65, 0x9b,
-  0xe6, 0x4b, 0x93, 0x09, 0x5c, 0x48, 0x7d, 0x76, 0x12, 0xcb, 0x47, 0xcd,
-  0xe9, 0xd3, 0xa9, 0x1a, 0xd8, 0xd8, 0x02, 0xae, 0xc0, 0x3a, 0x77, 0x56,
-  0x15, 0x26, 0xe7, 0x27, 0x26, 0x6f, 0x4e, 0x0a, 0x11, 0xd2, 0x84, 0x5e,
-  0x32, 0x7c, 0x47, 0x17, 0xfd, 0xaa, 0xb6, 0x7d, 0xf8, 0xa7, 0xba, 0x44,
-  0xe3, 0x20, 0xd4, 0x1c, 0x5c, 0x7f, 0xf7, 0x55, 0xb3, 0xef, 0xc5, 0x3d,
-  0xd5, 0x0b, 0x9e, 0x57, 0xdf, 0xd0, 0x91, 0x45, 0x64, 0x8d, 0x9a, 0x28,
-  0x43, 0xc9, 0x9a, 0x4c, 0xe3, 0x8f, 0xc8, 0xf6, 0x5d, 0xf4, 0x44, 0x8f,
-  0xe0, 0x34, 0xe7, 0x50, 0x1c, 0x45, 0xb2, 0xc8, 0xc9, 0x30, 0x5b, 0xe6,
-  0x3f, 0x11, 0xd6, 0xd9, 0x91, 0x70, 0x82, 0xec, 0x66, 0x9c, 0x73, 0x7c,
-  0x89, 0x52, 0xd2, 0x40, 0x2a, 0xd7, 0x5d, 0x6e, 0x84, 0x93, 0x71, 0xbe,
-  0x2e, 0xdf, 0xcc, 0x1f, 0x65, 0x6c, 0xaa, 0xfd, 0xbf, 0xc7, 0x2a, 0x1b,
-  0x4a, 0x03, 0x58, 0x11, 0x09, 0x1a, 0xdf, 0x69, 0x2f, 0xaf, 0xfd, 0x35,
-  0xeb, 0x9b, 0x8c, 0xbf, 0xd4, 0xe0, 0x3f, 0xbd, 0x97, 0xfe, 0x5a, 0x01,
-  0xfa, 0x8a, 0x41, 0xe7, 0xe3, 0x2f, 0xf5, 0x58, 0x0f, 0xef, 0x65, 0xff,
-  0x00, 0x96, 0x8e, 0x6e, 0x32, 0xff, 0x00, 0x53, 0x80, 0xfe, 0xf6, 0x5f,
-  0xf9, 0x68, 0x07, 0xea, 0x29, 0x07, 0x9b, 0x8c, 0xbf, 0xd4, 0xe0, 0x3f,
-  0xbd, 0x97, 0xfe, 0x5a, 0x39, 0xf8, 0xcb, 0xfd, 0x56, 0x03, 0xfb, 0xd9,
-  0x7f, 0xe5, 0xa0, 0x1f, 0xa8, 0x23, 0x74, 0x83, 0xcf, 0xc6, 0x5f, 0xea,
-  0xb0, 0x1f, 0xde, 0x4b, 0xff, 0x00, 0x2d, 0x1c, 0xfc, 0x65, 0xfe, 0xab,
-  0x01, 0xfd, 0xe4, 0xbf, 0xf2, 0xd0, 0x14, 0x97, 0x15, 0x71, 0x49, 0x58,
-  0x87, 0x12, 0xe5, 0x5a, 0xac, 0xc8, 0x4b, 0x31, 0xf2, 0x49, 0x26, 0xfd,
-  0x8b, 0x2f, 0x5a, 0x44, 0x7b, 0xdb, 0x29, 0xf7, 0xf8, 0xbb, 0xee, 0x4a,
-  0x24, 0xb5, 0xb4, 0xf5, 0xe8, 0x49, 0x00, 0x7c, 0x1a, 0xb3, 0x2c, 0x37,
-  0x9b, 0x06, 0x55, 0x83, 0xc5, 0xc8, 0x5a, 0xb7, 0x31, 0x29, 0xf9, 0x4c,
-  0x33, 0xe4, 0xe2, 0x43, 0x8a, 0x42, 0x3c, 0xe5, 0xa5, 0x1c, 0x8f, 0x80,
-  0x47, 0x30, 0x6d, 0x44, 0xec, 0x1f, 0xd1, 0x23, 0xa5, 0x70, 0x71, 0x73,
-  0x0c, 0xe2, 0xb6, 0x77, 0x88, 0xb9, 0x6b, 0x94, 0x30, 0xc8, 0xf2, 0xa3,
-  0x3c, 0xdc, 0xdb, 0x7c, 0x98, 0xae, 0xc9, 0x0f, 0x47, 0x92, 0xd2, 0xb9,
-  0x90, 0xb4, 0x15, 0x27, 0x5b, 0xef, 0x1d, 0x7a, 0x75, 0x35, 0x5f, 0xf0,
-  0xb7, 0x26, 0x8e, 0xbb, 0x82, 0x15, 0x36, 0x30, 0x8d, 0x6b, 0xcb, 0x5f,
-  0x75, 0x46, 0x3a, 0xba, 0x22, 0x05, 0xe9, 0x03, 0x53, 0xa1, 0x11, 0xde,
-  0x8e, 0xd0, 0xe9, 0xe4, 0x0e, 0x9b, 0xe6, 0x20, 0x75, 0xad, 0xa9, 0x62,
-  0x59, 0x83, 0xeb, 0xf5, 0x32, 0xab, 0x98, 0xe2, 0x6b, 0xa7, 0xd0, 0xbb,
-  0xaf, 0xd8, 0xcc, 0xc7, 0xf1, 0xc7, 0x84, 0x6b, 0xf4, 0xab, 0x84, 0x86,
-  0x39, 0x43, 0x90, 0x92, 0x50, 0xd4, 0x57, 0xd0, 0x85, 0x02, 0xa8, 0xdd,
-  0x92, 0x46, 0x90, 0x14, 0x01, 0x47, 0x7f, 0x30, 0xd8, 0xd9, 0x22, 0xb5,
-  0x8c, 0xaa, 0xd7, 0x7a, 0xb5, 0xcf, 0x85, 0x75, 0xb7, 0xaa, 0x1d, 0x95,
-  0xc4, 0x21, 0x31, 0xe5, 0x1f, 0x35, 0x0f, 0x34, 0xb4, 0x05, 0x20, 0xb4,
-  0x40, 0x3b, 0x75, 0x2a, 0xf3, 0x79, 0x13, 0xe7, 0x25, 0x43, 0xbb, 0xbb,
-  0x7a, 0x2d, 0x38, 0xeb, 0x8e, 0x4f, 0x9d, 0x2e, 0x35, 0xf2, 0x34, 0x06,
-  0x27, 0xbc, 0x1f, 0x7c, 0xb4, 0x55, 0xdb, 0x73, 0x84, 0xf2, 0xa9, 0x49,
-  0x42, 0xd4, 0x5b, 0x6d, 0x64, 0x6b, 0x99, 0x41, 0x24, 0x12, 0x37, 0xa0,
-  0x69, 0x86, 0x1c, 0x3c, 0x36, 0xc4, 0x96, 0x97, 0x0a, 0x0d, 0xbd, 0x0f,
-  0x32, 0xd8, 0x6d, 0x0e, 0x34, 0xca, 0x54, 0xe9, 0x00, 0x6b, 0xaa, 0xb5,
-  0xb2, 0x75, 0xe2, 0x4d, 0x46, 0x86, 0x9e, 0x31, 0xb8, 0xf7, 0x89, 0xac,
-  0xb7, 0xb0, 0xaf, 0x8b, 0xd8, 0xf3, 0x56, 0xe7, 0xfb, 0xae, 0x97, 0x0c,
-  0x65, 0xdc, 0x63, 0xb2, 0xf4, 0xc6, 0xe5, 0xc8, 0x05, 0xae, 0xdc, 0x34,
-  0x84, 0x17, 0x0b, 0x49, 0x6c, 0x2c, 0x2f, 0x49, 0x1b, 0x6f, 0x9c, 0x27,
-  0x7b, 0x3b, 0x1b, 0xd5, 0x34, 0xda, 0xb0, 0x7c, 0x7a, 0x24, 0x66, 0x53,
-  0x2e, 0x13, 0x57, 0x09, 0x28, 0xda, 0xdd, 0x7d, 0xf4, 0x03, 0xdb, 0x38,
-  0x54, 0x54, 0xa5, 0xa9, 0x3f, 0x07, 0x7b, 0x51, 0xd7, 0x4e, 0x9d, 0x00,
-  0xee, 0xa2, 0x46, 0x54, 0x80, 0x9d, 0x45, 0x8a, 0x48, 0x00, 0xf9, 0xce,
-  0x2b, 0xa0, 0xf6, 0xeb, 0xff, 0x00, 0x35, 0x5d, 0x5d, 0xb8, 0xb3, 0x06,
-  0xe5, 0x70, 0x55, 0xaa, 0xc2, 0xec, 0xdc, 0xa2, 0xe2, 0x09, 0x06, 0x05,
-  0x81, 0xae, 0xdf, 0x93, 0xc3, 0xdf, 0x1c, 0x04, 0x36, 0xd8, 0xdf, 0x8a,
-  0xd6, 0x2b, 0x4f, 0xb3, 0xcf, 0x99, 0xec, 0x67, 0xf6, 0x88, 0x7e, 0x0d,
-  0xcb, 0x66, 0x7d, 0xe2, 0xdd, 0x01, 0x1d, 0x99, 0x70, 0x2d, 0x69, 0xee,
-  0x6d, 0xbe, 0xba, 0xff, 0x00, 0xb0, 0xa4, 0x1c, 0xd7, 0x89, 0x96, 0xfb,
-  0x4b, 0xad, 0xc4, 0x93, 0x38, 0x31, 0x2a, 0x47, 0x48, 0xf0, 0x22, 0xb6,
-  0xa7, 0xe6, 0x3e, 0x7c, 0x39, 0x5b, 0x40, 0x2b, 0x3f, 0xdc, 0x07, 0xaf,
-  0xc6, 0xa9, 0x0e, 0x23, 0x71, 0x3d, 0x16, 0x82, 0xa8, 0xd9, 0x4e, 0x55,
-  0x1e, 0xc8, 0xe9, 0x25, 0x3e, 0xe0, 0x62, 0xee, 0x22, 0x75, 0xcd, 0x5d,
-  0xfe, 0x63, 0xd2, 0xcf, 0xbd, 0x47, 0x3b, 0xef, 0xe4, 0x05, 0x5d, 0x7a,
-  0x1a, 0xe3, 0xe1, 0xe5, 0x87, 0x8c, 0xb9, 0x84, 0x59, 0x3f, 0x8b, 0xfc,
-  0x5e, 0x17, 0x0a, 0xec, 0x32, 0x92, 0xa5, 0x2a, 0xeb, 0x24, 0x2d, 0xcb,
-  0x8c, 0xde, 0xa3, 0x5d, 0xa3, 0xee, 0x6d, 0xe5, 0x6f, 0x5b, 0xda, 0x42,
-  0x53, 0x4d, 0x54, 0xe9, 0xf8, 0x56, 0x5f, 0x9b, 0x1a, 0x2a, 0x54, 0xf1,
-  0x3c, 0x21, 0xcb, 0x39, 0xce, 0xa5, 0x5b, 0x23, 0x2e, 0x5e, 0x53, 0x7d,
-  0x87, 0xc3, 0xd8, 0x4b, 0x47, 0x3a, 0x1a, 0x92, 0x53, 0x32, 0xfb, 0x21,
-  0x3d, 0x3a, 0xa2, 0x32, 0x49, 0x43, 0x3b, 0xde, 0xb9, 0x96, 0x54, 0x47,
-  0x88, 0x14, 0x85, 0x88, 0x5d, 0xf8, 0x8b, 0x9a, 0xce, 0x77, 0xf1, 0x29,
-  0x83, 0x39, 0x61, 0x8d, 0x23, 0x68, 0x7f, 0x31, 0xbf, 0xab, 0xb7, 0x9c,
-  0xfa, 0x77, 0xa3, 0xa7, 0x9c, 0x05, 0x29, 0x1f, 0xa8, 0xd8, 0x56, 0xb5,
-  0xd3, 0x54, 0xcf, 0x80, 0xfe, 0x0b, 0xd7, 0xcc, 0x76, 0xf0, 0x6f, 0x77,
-  0xa4, 0xe2, 0xb9, 0x75, 0xd7, 0xb5, 0xed, 0x43, 0xd7, 0x79, 0x12, 0x94,
-  0xdf, 0x30, 0x3b, 0x0a, 0x2d, 0x84, 0xe9, 0x67, 0xe7, 0x95, 0x0a, 0xbc,
-  0x59, 0x6f, 0x8c, 0x0c, 0x34, 0x86, 0x99, 0x8d, 0xc3, 0xf6, 0xdb, 0x6d,
-  0x21, 0x28, 0x4a, 0x57, 0x2d, 0x21, 0x29, 0x1d, 0xc0, 0x00, 0x9e, 0x83,
-  0xa7, 0x75, 0x65, 0x3a, 0xb2, 0x9f, 0x2c, 0xda, 0x14, 0xa3, 0x0e, 0x0a,
-  0xfb, 0x02, 0xfc, 0x18, 0xf1, 0xd8, 0xd7, 0x04, 0xe4, 0x1c, 0x4a, 0xbb,
-  0x4e, 0xce, 0xef, 0xeb, 0x57, 0x3b, 0x8b, 0x9c, 0xea, 0x8c, 0x60, 0xae,
-  0x9d, 0x39, 0x09, 0x25, 0x7a, 0x3d, 0x34, 0xa2, 0x53, 0xa1, 0xf0, 0x45,
-  0x5f, 0x70, 0xe1, 0xc5, 0x87, 0x11, 0xa8, 0x90, 0xe3, 0xb5, 0x1a, 0x3b,
-  0x29, 0x08, 0x6d, 0xa6, 0x90, 0x10, 0x94, 0x24, 0x78, 0x00, 0x3a, 0x01,
-  0xec, 0xa4, 0x7d, 0xf1, 0x93, 0xfa, 0xac, 0x07, 0xf7, 0x92, 0xff, 0x00,
-  0xcb, 0x59, 0x0a, 0xe3, 0x2f, 0xf5, 0x38, 0x0f, 0xef, 0x65, 0xff, 0x00,
-  0x96, 0xb3, 0x2e, 0x3e, 0xe8, 0x56, 0x47, 0x4a, 0x41, 0xe7, 0xe3, 0x2f,
-  0xf5, 0x58, 0x0f, 0xef, 0x65, 0xff, 0x00, 0x96, 0x8e, 0x7e, 0x32, 0xff,
-  0x00, 0x55, 0x80, 0xfe, 0xf2, 0x5f, 0xf9, 0x68, 0x0f, 0x7c, 0x65, 0xf8,
-  0x96, 0x2f, 0xfb, 0x55, 0x6c, 0xfb, 0xf1, 0x4f, 0x75, 0x58, 0xdd, 0xac,
-  0x5c, 0x4d, 0xc8, 0x66, 0x59, 0x5a, 0xbe, 0xaf, 0x10, 0x62, 0x04, 0x1b,
-  0xb4, 0x6b, 0x83, 0xa6, 0x12, 0xa4, 0x17, 0x54, 0x19, 0x58, 0x57, 0x2a,
-  0x42, 0xc6, 0xba, 0xea, 0xac, 0xea, 0x00, 0xa2, 0xb0, 0x49, 0xf0, 0xa2,
-  0x80, 0xcd, 0x1a, 0xeb, 0x45, 0x14, 0x01, 0x45, 0x14, 0x50, 0x05, 0x14,
-  0x51, 0x40, 0x14, 0x51, 0x45, 0x00, 0x51, 0x45, 0x14, 0x01, 0x5f, 0x2b,
-  0x7e, 0x11, 0x38, 0x75, 0xcf, 0x0a, 0xc9, 0xef, 0x79, 0x7c, 0x1c, 0x7d,
-  0xeb, 0xf6, 0x09, 0x91, 0x86, 0x9c, 0xc8, 0xe0, 0x43, 0x51, 0x4c, 0xa8,
-  0x12, 0xdb, 0xdf, 0x24, 0xe6, 0x08, 0xf8, 0x0b, 0x1f, 0x0b, 0x98, 0x74,
-  0xdf, 0x30, 0x57, 0x42, 0x0d, 0x7d, 0x53, 0x58, 0x52, 0x42, 0xba, 0x28,
-  0x6c, 0x1e, 0x84, 0x50, 0x1f, 0x19, 0xe3, 0x3c, 0x46, 0xe2, 0x5c, 0x7b,
-  0x12, 0x2e, 0x96, 0x9b, 0x64, 0x1e, 0x28, 0x63, 0xcd, 0x68, 0x79, 0x75,
-  0xad, 0x65, 0xab, 0x93, 0x49, 0xf0, 0x12, 0x23, 0x8d, 0xa9, 0x0e, 0x01,
-  0xde, 0x42, 0x08, 0xdf, 0xe7, 0x10, 0x76, 0x58, 0xec, 0xdc, 0x52, 0xcb,
-  0xb2, 0x08, 0xcb, 0x7e, 0xd5, 0xc3, 0x29, 0x76, 0x88, 0x6d, 0x90, 0x97,
-  0xae, 0x99, 0x1c, 0xe4, 0xdb, 0xe1, 0x32, 0x77, 0xd4, 0xa9, 0x6a, 0x4e,
-  0xd5, 0xeb, 0x09, 0xd9, 0xf5, 0x55, 0x8d, 0xc4, 0x0f, 0xc1, 0xd7, 0x05,
-  0xc8, 0xee, 0xc6, 0xfb, 0x65, 0x72, 0xe3, 0x87, 0xde, 0xf7, 0xbf, 0x2d,
-  0xb1, 0xbd, 0xe4, 0xfc, 0xc7, 0xd2, 0xa4, 0x01, 0xad, 0xf8, 0xec, 0x68,
-  0x93, 0xd4, 0x9a, 0xe6, 0xb4, 0x7e, 0x0d, 0xb8, 0x6a, 0xee, 0xcd, 0xdd,
-  0xf3, 0x4b, 0xce, 0x49, 0x9c, 0xce, 0x6c, 0x0e, 0x53, 0x7c, 0xb8, 0x29,
-  0xd6, 0xc6, 0xbf, 0x50, 0x6b, 0x63, 0xa0, 0xe8, 0x49, 0x1e, 0xaa, 0xdd,
-  0x5c, 0xd4, 0x4b, 0x19, 0x30, 0x76, 0xd4, 0xdb, 0xcb, 0x45, 0x4d, 0x17,
-  0x3f, 0x72, 0x6d, 0xc3, 0xdc, 0xeb, 0x42, 0x2e, 0x9c, 0x5e, 0xc9, 0x04,
-  0x80, 0xf0, 0x62, 0xcc, 0xca, 0xe1, 0x59, 0xa0, 0x10, 0x85, 0x23, 0xb3,
-  0x2b, 0xef, 0x79, 0x1e, 0x79, 0x27, 0x9f, 0xcd, 0x3a, 0x1d, 0xd4, 0xe9,
-  0x03, 0x83, 0xfc, 0x55, 0xcc, 0xed, 0xcd, 0xc3, 0xcd, 0xf2, 0xe8, 0x18,
-  0x56, 0x3c, 0x47, 0xfa, 0xb7, 0x8a, 0x47, 0x0d, 0x23, 0x93, 0xa7, 0x9a,
-  0xb7, 0x3b, 0xbc, 0x07, 0x7f, 0x38, 0xaf, 0xa1, 0x6c, 0xf6, 0x9b, 0x5d,
-  0x9a, 0x0a, 0x60, 0x5a, 0x2d, 0xd1, 0x2d, 0xf1, 0x11, 0xf0, 0x59, 0x8a,
-  0xca, 0x5a, 0x40, 0xf6, 0x25, 0x20, 0x0a, 0xec, 0x00, 0x0a, 0xca, 0x53,
-  0x94, 0xb9, 0x35, 0x8c, 0x23, 0x1e, 0x11, 0x5f, 0x70, 0xe3, 0x82, 0xfc,
-  0x36, 0xc0, 0x43, 0x4e, 0xe3, 0xd8, 0xcc, 0x51, 0x35, 0xb1, 0xf1, 0xe9,
-  0x43, 0xb7, 0x92, 0x4f, 0xa7, 0x9d, 0x7b, 0xe5, 0x3f, 0x37, 0x43, 0xd5,
-  0x56, 0x0f, 0x28, 0xac, 0x81, 0xae, 0xea, 0x2a, 0xa5, 0x8c, 0x68, 0x56,
-  0x68, 0xa2, 0x80, 0x28, 0xa2, 0x8a, 0x00, 0xa2, 0x8a, 0x28, 0x03, 0x42,
-  0x8a, 0x28, 0xa0, 0x30, 0x52, 0x0f, 0x7d, 0x15, 0x9a, 0x28, 0x02, 0x8a,
-  0x28, 0xa0, 0x0a, 0x28, 0xa2, 0x80, 0x28, 0xa2, 0x8a, 0x00, 0xa2, 0x8a,
-  0x28, 0x02, 0x8a, 0x28, 0xa0, 0x0a, 0x28, 0xa2, 0x80, 0x35, 0x45, 0x14,
-  0x50, 0x05, 0x14, 0x51, 0x40, 0x14, 0x51, 0x45, 0x00, 0x51, 0x45, 0x14,
-  0x01, 0x45, 0x14, 0x50, 0x05, 0x14, 0x51, 0x40, 0x14, 0x51, 0x45, 0x00,
-  0x51, 0x45, 0x14, 0x07, 0xff, 0xd9
+  0xff,  0xd8,  0xff,  0xe0,  0x00,  0x10,  0x4a,  0x46,  0x49,  0x46,  0x00,  0x01,
+  0x01,  0x01,  0x00,  0x60,  0x00,  0x60,  0x00,  0x00,  0xff,  0xe1,  0x00,  0x66,
+  0x45,  0x78,  0x69,  0x66,  0x00,  0x00,  0x49,  0x49,  0x2a,  0x00,  0x08,  0x00,
+  0x00,  0x00,  0x04,  0x00,  0x1a,  0x01,  0x05,  0x00,  0x01,  0x00,  0x00,  0x00,
+  0x3e,  0x00,  0x00,  0x00,  0x1b,  0x01,  0x05,  0x00,  0x01,  0x00,  0x00,  0x00,
+  0x46,  0x00,  0x00,  0x00,  0x28,  0x01,  0x03,  0x00,  0x01,  0x00,  0x00,  0x00,
+  0x02,  0x00,  0x00,  0x00,  0x31,  0x01,  0x02,  0x00,  0x10,  0x00,  0x00,  0x00,
+  0x4e,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x60,  0x00,  0x00,  0x00,
+  0x01,  0x00,  0x00,  0x00,  0x60,  0x00,  0x00,  0x00,  0x01,  0x00,  0x00,  0x00,
+  0x50,  0x61,  0x69,  0x6e,  0x74,  0x2e,  0x4e,  0x45,  0x54,  0x20,  0x76,  0x33,
+  0x2e,  0x33,  0x36,  0x00,  0xff,  0xdb,  0x00,  0x43,  0x00,  0x03,  0x02,  0x02,
+  0x03,  0x02,  0x02,  0x03,  0x03,  0x03,  0x03,  0x04,  0x03,  0x03,  0x04,  0x05,
+  0x08,  0x05,  0x05,  0x04,  0x04,  0x05,  0x0a,  0x07,  0x07,  0x06,  0x08,  0x0c,
+  0x0a,  0x0c,  0x0c,  0x0b,  0x0a,  0x0b,  0x0b,  0x0d,  0x0e,  0x12,  0x10,  0x0d,
+  0x0e,  0x11,  0x0e,  0x0b,  0x0b,  0x10,  0x16,  0x10,  0x11,  0x13,  0x14,  0x15,
+  0x15,  0x15,  0x0c,  0x0f,  0x17,  0x18,  0x16,  0x14,  0x18,  0x12,  0x14,  0x15,
+  0x14,  0xff,  0xdb,  0x00,  0x43,  0x01,  0x03,  0x04,  0x04,  0x05,  0x04,  0x05,
+  0x09,  0x05,  0x05,  0x09,  0x14,  0x0d,  0x0b,  0x0d,  0x14,  0x14,  0x14,  0x14,
+  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,
+  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,
+  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,
+  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0xff,  0xc0,
+  0x00,  0x11,  0x08,  0x00,  0xf0,  0x01,  0x40,  0x03,  0x01,  0x22,  0x00,  0x02,
+  0x11,  0x01,  0x03,  0x11,  0x01,  0xff,  0xc4,  0x00,  0x1f,  0x00,  0x00,  0x01,
+  0x05,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x01,  0x02,  0x03,  0x04,  0x05,  0x06,  0x07,  0x08,  0x09,
+  0x0a,  0x0b,  0xff,  0xc4,  0x00,  0xb5,  0x10,  0x00,  0x02,  0x01,  0x03,  0x03,
+  0x02,  0x04,  0x03,  0x05,  0x05,  0x04,  0x04,  0x00,  0x00,  0x01,  0x7d,  0x01,
+  0x02,  0x03,  0x00,  0x04,  0x11,  0x05,  0x12,  0x21,  0x31,  0x41,  0x06,  0x13,
+  0x51,  0x61,  0x07,  0x22,  0x71,  0x14,  0x32,  0x81,  0x91,  0xa1,  0x08,  0x23,
+  0x42,  0xb1,  0xc1,  0x15,  0x52,  0xd1,  0xf0,  0x24,  0x33,  0x62,  0x72,  0x82,
+  0x09,  0x0a,  0x16,  0x17,  0x18,  0x19,  0x1a,  0x25,  0x26,  0x27,  0x28,  0x29,
+  0x2a,  0x34,  0x35,  0x36,  0x37,  0x38,  0x39,  0x3a,  0x43,  0x44,  0x45,  0x46,
+  0x47,  0x48,  0x49,  0x4a,  0x53,  0x54,  0x55,  0x56,  0x57,  0x58,  0x59,  0x5a,
+  0x63,  0x64,  0x65,  0x66,  0x67,  0x68,  0x69,  0x6a,  0x73,  0x74,  0x75,  0x76,
+  0x77,  0x78,  0x79,  0x7a,  0x83,  0x84,  0x85,  0x86,  0x87,  0x88,  0x89,  0x8a,
+  0x92,  0x93,  0x94,  0x95,  0x96,  0x97,  0x98,  0x99,  0x9a,  0xa2,  0xa3,  0xa4,
+  0xa5,  0xa6,  0xa7,  0xa8,  0xa9,  0xaa,  0xb2,  0xb3,  0xb4,  0xb5,  0xb6,  0xb7,
+  0xb8,  0xb9,  0xba,  0xc2,  0xc3,  0xc4,  0xc5,  0xc6,  0xc7,  0xc8,  0xc9,  0xca,
+  0xd2,  0xd3,  0xd4,  0xd5,  0xd6,  0xd7,  0xd8,  0xd9,  0xda,  0xe1,  0xe2,  0xe3,
+  0xe4,  0xe5,  0xe6,  0xe7,  0xe8,  0xe9,  0xea,  0xf1,  0xf2,  0xf3,  0xf4,  0xf5,
+  0xf6,  0xf7,  0xf8,  0xf9,  0xfa,  0xff,  0xc4,  0x00,  0x1f,  0x01,  0x00,  0x03,
+  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x01,  0x02,  0x03,  0x04,  0x05,  0x06,  0x07,  0x08,  0x09,
+  0x0a,  0x0b,  0xff,  0xc4,  0x00,  0xb5,  0x11,  0x00,  0x02,  0x01,  0x02,  0x04,
+  0x04,  0x03,  0x04,  0x07,  0x05,  0x04,  0x04,  0x00,  0x01,  0x02,  0x77,  0x00,
+  0x01,  0x02,  0x03,  0x11,  0x04,  0x05,  0x21,  0x31,  0x06,  0x12,  0x41,  0x51,
+  0x07,  0x61,  0x71,  0x13,  0x22,  0x32,  0x81,  0x08,  0x14,  0x42,  0x91,  0xa1,
+  0xb1,  0xc1,  0x09,  0x23,  0x33,  0x52,  0xf0,  0x15,  0x62,  0x72,  0xd1,  0x0a,
+  0x16,  0x24,  0x34,  0xe1,  0x25,  0xf1,  0x17,  0x18,  0x19,  0x1a,  0x26,  0x27,
+  0x28,  0x29,  0x2a,  0x35,  0x36,  0x37,  0x38,  0x39,  0x3a,  0x43,  0x44,  0x45,
+  0x46,  0x47,  0x48,  0x49,  0x4a,  0x53,  0x54,  0x55,  0x56,  0x57,  0x58,  0x59,
+  0x5a,  0x63,  0x64,  0x65,  0x66,  0x67,  0x68,  0x69,  0x6a,  0x73,  0x74,  0x75,
+  0x76,  0x77,  0x78,  0x79,  0x7a,  0x82,  0x83,  0x84,  0x85,  0x86,  0x87,  0x88,
+  0x89,  0x8a,  0x92,  0x93,  0x94,  0x95,  0x96,  0x97,  0x98,  0x99,  0x9a,  0xa2,
+  0xa3,  0xa4,  0xa5,  0xa6,  0xa7,  0xa8,  0xa9,  0xaa,  0xb2,  0xb3,  0xb4,  0xb5,
+  0xb6,  0xb7,  0xb8,  0xb9,  0xba,  0xc2,  0xc3,  0xc4,  0xc5,  0xc6,  0xc7,  0xc8,
+  0xc9,  0xca,  0xd2,  0xd3,  0xd4,  0xd5,  0xd6,  0xd7,  0xd8,  0xd9,  0xda,  0xe2,
+  0xe3,  0xe4,  0xe5,  0xe6,  0xe7,  0xe8,  0xe9,  0xea,  0xf2,  0xf3,  0xf4,  0xf5,
+  0xf6,  0xf7,  0xf8,  0xf9,  0xfa,  0xff,  0xda,  0x00,  0x0c,  0x03,  0x01,  0x00,
+  0x02,  0x11,  0x03,  0x11,  0x00,  0x3f,  0x00,  0xf9,  0xd2,  0xa3,  0x95,  0xbb,
+  0x54,  0x84,  0xe0,  0x66,  0xa0,  0x27,  0x27,  0x35,  0xed,  0x9e,  0x50,  0x95,
+  0x2c,  0x4b,  0xc6,  0x6a,  0x35,  0x1b,  0x8e,  0x2a,  0x70,  0x30,  0x28,  0x00,
+  0xa8,  0xe5,  0x6e,  0x71,  0x52,  0x31,  0xda,  0x33,  0x50,  0x13,  0x93,  0x40,
+  0x09,  0x52,  0xc6,  0xb8,  0x19,  0xf5,  0xa6,  0x2a,  0xee,  0x6c,  0x54,  0xd4,
+  0x00,  0x54,  0x52,  0x36,  0x5b,  0x1e,  0x95,  0x23,  0xb6,  0xd5,  0xcd,  0x41,
+  0x40,  0x05,  0x4c,  0x8b,  0xb5,  0x7d,  0xea,  0x34,  0x5d,  0xcd,  0xed,  0x53,
+  0x50,  0x01,  0x50,  0xbb,  0x6e,  0x6f,  0x6a,  0x91,  0xdb,  0x6a,  0xfb,  0xd4,
+  0x34,  0x00,  0x54,  0xe8,  0xbb,  0x57,  0x15,  0x1c,  0x6b,  0x96,  0xcf,  0xa5,
+  0x4b,  0x40,  0x05,  0x42,  0xcd,  0xb9,  0xb3,  0x4f,  0x91,  0xb0,  0x31,  0xeb,
+  0x51,  0x50,  0x02,  0x81,  0x93,  0x53,  0xa8,  0xda,  0x31,  0x51,  0xc4,  0xbc,
+  0xe6,  0xa4,  0xa0,  0x00,  0x9c,  0x0a,  0x81,  0x8e,  0xe3,  0x9a,  0x92,  0x56,
+  0xe3,  0x15,  0x15,  0x00,  0x28,  0x19,  0x38,  0xa9,  0xc0,  0xc0,  0xc5,  0x47,
+  0x12,  0xf7,  0xa9,  0x28,  0x00,  0x27,  0x00,  0x9a,  0x80,  0x9c,  0x9c,  0xd3,
+  0xe5,  0x6e,  0xd5,  0x1d,  0x00,  0x2a,  0x8d,  0xc7,  0x15,  0x3d,  0x32,  0x35,
+  0xc0,  0xcf,  0xad,  0x3e,  0x80,  0x11,  0x8e,  0xd1,  0x9a,  0x82,  0x9f,  0x23,
+  0x64,  0xe3,  0xd2,  0x99,  0x40,  0x0e,  0x45,  0xdc,  0xde,  0xd5,  0x35,  0x36,
+  0x35,  0xc2,  0xfb,  0x9a,  0x75,  0x00,  0x35,  0xdb,  0x6a,  0xfb,  0xd4,  0x34,
+  0xe9,  0x1b,  0x73,  0x7b,  0x0a,  0x6d,  0x00,  0x3e,  0x35,  0xcb,  0x7b,  0x0a,
+  0x96,  0x91,  0x17,  0x6a,  0xd2,  0xd0,  0x03,  0x64,  0x6c,  0x2f,  0xb9,  0xa8,
+  0x69,  0xce,  0xdb,  0x9a,  0x9b,  0xd6,  0x80,  0x1f,  0x12,  0xe4,  0xe7,  0xd2,
+  0xa5,  0xa4,  0x51,  0xb4,  0x62,  0x97,  0xa5,  0x00,  0x67,  0xc9,  0xad,  0xd8,
+  0x91,  0x81,  0x72,  0x9f,  0x9d,  0x47,  0xfd,  0xb3,  0x65,  0xff,  0x00,  0x3f,
+  0x29,  0x5f,  0xa0,  0x1f,  0xf0,  0xe9,  0x6f,  0x09,  0x7f,  0xd0,  0xfb,  0xad,
+  0x7f,  0xe0,  0x24,  0x34,  0x7f,  0xc3,  0xa5,  0xbc,  0x25,  0xff,  0x00,  0x43,
+  0xee,  0xb5,  0xff,  0x00,  0x80,  0x90,  0xd7,  0x3f,  0xb7,  0x87,  0x73,  0x6f,
+  0x63,  0x33,  0xe0,  0x28,  0xf5,  0x9b,  0x11,  0xc9,  0xb9,  0x4c,  0xfd,  0x69,
+  0xff,  0x00,  0xdb,  0x96,  0x1f,  0xf3,  0xf5,  0x1f,  0xe7,  0x5f,  0x7d,  0x7f,
+  0xc3,  0xa5,  0xbc,  0x25,  0xff,  0x00,  0x43,  0xee,  0xb5,  0xff,  0x00,  0x80,
+  0x90,  0xd1,  0xff,  0x00,  0x0e,  0x96,  0xf0,  0x97,  0xfd,  0x0f,  0xba,  0xd7,
+  0xfe,  0x02,  0x43,  0x47,  0xb7,  0x87,  0x70,  0xf6,  0x33,  0x3e,  0x02,  0x93,
+  0x5b,  0xb1,  0x3c,  0x0b,  0x94,  0xc7,  0xd6,  0x99,  0xfd,  0xb3,  0x65,  0xff,
+  0x00,  0x3f,  0x29,  0xf9,  0xd7,  0xe8,  0x07,  0xfc,  0x3a,  0x5b,  0xc2,  0x5f,
+  0xf4,  0x3e,  0xeb,  0x5f,  0xf8,  0x09,  0x0d,  0x1f,  0xf0,  0xe9,  0x6f,  0x09,
+  0x7f,  0xd0,  0xfb,  0xad,  0x7f,  0xe0,  0x24,  0x34,  0xbd,  0xbc,  0x03,  0xd8,
+  0xcc,  0xf8,  0x0e,  0x3d,  0x6a,  0xc1,  0x47,  0x37,  0x29,  0x9f,  0xad,  0x3b,
+  0xfb,  0x72,  0xc3,  0xfe,  0x7e,  0xa3,  0xfc,  0xeb,  0xef,  0xaf,  0xf8,  0x74,
+  0xb7,  0x84,  0xbf,  0xe8,  0x7d,  0xd6,  0xbf,  0xf0,  0x12,  0x1a,  0x3f,  0xe1,
+  0xd2,  0xde,  0x12,  0xff,  0x00,  0xa1,  0xf7,  0x5a,  0xff,  0x00,  0xc0,  0x48,
+  0x69,  0xfb,  0x78,  0x77,  0x0f,  0x63,  0x33,  0xe0,  0x19,  0x35,  0xbb,  0x26,
+  0x3c,  0x5c,  0xa6,  0x3e,  0xb4,  0xdf,  0xed,  0x9b,  0x2f,  0xf9,  0xf9,  0x4a,
+  0xfd,  0x00,  0xff,  0x00,  0x87,  0x4b,  0x78,  0x4b,  0xfe,  0x87,  0xdd,  0x6b,
+  0xff,  0x00,  0x01,  0x21,  0xa3,  0xfe,  0x1d,  0x2d,  0xe1,  0x2f,  0xfa,  0x1f,
+  0x75,  0xaf,  0xfc,  0x04,  0x86,  0x97,  0xb7,  0x80,  0x7b,  0x19,  0x9f,  0x01,
+  0xa6,  0xb5,  0x60,  0xab,  0xff,  0x00,  0x1f,  0x51,  0xe7,  0xeb,  0x4e,  0xfe,
+  0xdc,  0xb0,  0xff,  0x00,  0x9f,  0xa8,  0xff,  0x00,  0x3a,  0xfb,  0xeb,  0xfe,
+  0x1d,  0x2d,  0xe1,  0x2f,  0xfa,  0x1f,  0x75,  0xaf,  0xfc,  0x04,  0x86,  0x8f,
+  0xf8,  0x74,  0xb7,  0x84,  0xbf,  0xe8,  0x7d,  0xd6,  0xbf,  0xf0,  0x12,  0x1a,
+  0x3d,  0xbc,  0x03,  0xd8,  0xcc,  0xf8,  0x05,  0xf5,  0xab,  0x26,  0x6f,  0xf8,
+  0xf9,  0x4c,  0x7d,  0x69,  0xbf,  0xdb,  0x36,  0x5f,  0xf3,  0xf2,  0x9f,  0x9d,
+  0x7e,  0x80,  0x7f,  0xc3,  0xa5,  0xbc,  0x25,  0xff,  0x00,  0x43,  0xee,  0xb5,
+  0xff,  0x00,  0x80,  0x90,  0xd1,  0xff,  0x00,  0x0e,  0x96,  0xf0,  0x97,  0xfd,
+  0x0f,  0xba,  0xd7,  0xfe,  0x02,  0x43,  0x47,  0xb7,  0x80,  0x7b,  0x19,  0x9f,
+  0x02,  0x26,  0xb5,  0x60,  0xab,  0x8f,  0xb5,  0x47,  0xf9,  0xd2,  0xff,  0x00,
+  0x6e,  0x58,  0x7f,  0xcf,  0xd4,  0x7f,  0x9d,  0x7d,  0xf5,  0xff,  0x00,  0x0e,
+  0x96,  0xf0,  0x97,  0xfd,  0x0f,  0xba,  0xd7,  0xfe,  0x02,  0x43,  0x47,  0xfc,
+  0x3a,  0x5b,  0xc2,  0x5f,  0xf4,  0x3e,  0xeb,  0x5f,  0xf8,  0x09,  0x0d,  0x1e,
+  0xde,  0x01,  0xec,  0x66,  0x7c,  0x00,  0xda,  0xd5,  0x93,  0x1c,  0xfd,  0xa5,
+  0x3f,  0x3a,  0x4f,  0xed,  0x8b,  0x2f,  0xf9,  0xf9,  0x4f,  0xce,  0xbf,  0x40,
+  0x3f,  0xe1,  0xd2,  0xde,  0x12,  0xff,  0x00,  0xa1,  0xf7,  0x5a,  0xff,  0x00,
+  0xc0,  0x48,  0x68,  0xff,  0x00,  0x87,  0x4b,  0x78,  0x4b,  0xfe,  0x87,  0xdd,
+  0x6b,  0xff,  0x00,  0x01,  0x21,  0xa7,  0xed,  0xe1,  0xdc,  0x3d,  0x8c,  0xcf,
+  0x81,  0x57,  0x5a,  0xb0,  0x51,  0x8f,  0xb5,  0x47,  0xf9,  0xd1,  0xfd,  0xb9,
+  0x61,  0xff,  0x00,  0x3f,  0x49,  0xf9,  0xd7,  0xdf,  0x5f,  0xf0,  0xe9,  0x6f,
+  0x09,  0x7f,  0xd0,  0xfb,  0xad,  0x7f,  0xe0,  0x24,  0x34,  0x7f,  0xc3,  0xa5,
+  0xbc,  0x25,  0xff,  0x00,  0x43,  0xee,  0xb5,  0xff,  0x00,  0x80,  0x90,  0xd2,
+  0xf6,  0xf0,  0x0f,  0x63,  0x33,  0xe0,  0x06,  0xd6,  0xac,  0x98,  0xe7,  0xed,
+  0x29,  0xf9,  0xd2,  0x0d,  0x62,  0xcb,  0xfe,  0x7e,  0x53,  0xf3,  0xaf,  0xd0,
+  0x0f,  0xf8,  0x74,  0xb7,  0x84,  0xbf,  0xe8,  0x7d,  0xd6,  0xbf,  0xf0,  0x12,
+  0x1a,  0x3f,  0xe1,  0xd2,  0xde,  0x12,  0xff,  0x00,  0xa1,  0xf7,  0x5a,  0xff,
+  0x00,  0xc0,  0x48,  0x69,  0xfb,  0x78,  0x77,  0x0f,  0x63,  0x33,  0xe0,  0x51,
+  0xad,  0xd8,  0x01,  0x8f,  0xb5,  0x47,  0xf9,  0xd0,  0x75,  0xcb,  0x0c,  0x7f,
+  0xc7,  0xca,  0x7e,  0x75,  0xf7,  0xd7,  0xfc,  0x3a,  0x5b,  0xc2,  0x5f,  0xf4,
+  0x3e,  0xeb,  0x5f,  0xf8,  0x09,  0x0d,  0x1f,  0xf0,  0xe9,  0x6f,  0x09,  0x7f,
+  0xd0,  0xfb,  0xad,  0x7f,  0xe0,  0x24,  0x34,  0x7b,  0x78,  0x77,  0x0f,  0x63,
+  0x33,  0xf3,  0xfc,  0xeb,  0x36,  0x44,  0xff,  0x00,  0xc7,  0xca,  0x7e,  0x74,
+  0xa3,  0x58,  0xb1,  0x24,  0x66,  0xe5,  0x31,  0xf5,  0xaf,  0xbf,  0xff,  0x00,
+  0xe1,  0xd2,  0xde,  0x12,  0xff,  0x00,  0xa1,  0xf7,  0x5a,  0xff,  0x00,  0xc0,
+  0x48,  0x68,  0xff,  0x00,  0x87,  0x4b,  0x78,  0x4b,  0xfe,  0x87,  0xdd,  0x6b,
+  0xff,  0x00,  0x01,  0x21,  0xa3,  0xdb,  0xc3,  0xb8,  0x7b,  0x19,  0x9f,  0x02,
+  0xff,  0x00,  0x6d,  0xd8,  0x7f,  0xcf,  0xd4,  0x7f,  0x9d,  0x07,  0x5c,  0xb1,
+  0x03,  0x8b,  0x94,  0xcf,  0xd6,  0xbe,  0xfa,  0xff,  0x00,  0x87,  0x4b,  0x78,
+  0x4b,  0xfe,  0x87,  0xdd,  0x6b,  0xff,  0x00,  0x01,  0x21,  0xa3,  0xfe,  0x1d,
+  0x2d,  0xe1,  0x2f,  0xfa,  0x1f,  0x75,  0xaf,  0xfc,  0x04,  0x86,  0x8f,  0x6f,
+  0x0e,  0xe1,  0xec,  0x66,  0x7e,  0x7f,  0xff,  0x00,  0x6c,  0xd9,  0x7f,  0xcf,
+  0xca,  0x7e,  0x74,  0xab,  0xac,  0x58,  0xe7,  0x9b,  0x94,  0xc7,  0xd6,  0xbe,
+  0xff,  0x00,  0xff,  0x00,  0x87,  0x4b,  0x78,  0x4b,  0xfe,  0x87,  0xdd,  0x6b,
+  0xff,  0x00,  0x01,  0x21,  0xa3,  0xfe,  0x1d,  0x2d,  0xe1,  0x2f,  0xfa,  0x1f,
+  0x75,  0xaf,  0xfc,  0x04,  0x86,  0x8f,  0x6f,  0x0e,  0xe1,  0xec,  0x66,  0x7c,
+  0x0b,  0xfd,  0xb9,  0x61,  0xff,  0x00,  0x3f,  0x51,  0xfe,  0x74,  0x8d,  0xae,
+  0x58,  0xed,  0x38,  0xb9,  0x4c,  0xfd,  0x6b,  0xef,  0xbf,  0xf8,  0x74,  0xb7,
+  0x84,  0xbf,  0xe8,  0x7d,  0xd6,  0xbf,  0xf0,  0x12,  0x1a,  0x3f,  0xe1,  0xd2,
+  0xde,  0x12,  0xff,  0x00,  0xa1,  0xf7,  0x5a,  0xff,  0x00,  0xc0,  0x48,  0x68,
+  0xf6,  0xf0,  0xee,  0x1e,  0xc6,  0x67,  0xe7,  0xff,  0x00,  0xf6,  0xc5,  0x97,
+  0xfc,  0xfc,  0xa7,  0xe7,  0x4e,  0x4d,  0x62,  0xc7,  0x77,  0x37,  0x29,  0xf9,
+  0xd7,  0xdf,  0xdf,  0xf0,  0xe9,  0x6f,  0x09,  0x7f,  0xd0,  0xfb,  0xad,  0x7f,
+  0xe0,  0x24,  0x34,  0x7f,  0xc3,  0xa5,  0xbc,  0x25,  0xff,  0x00,  0x43,  0xee,
+  0xb5,  0xff,  0x00,  0x80,  0x90,  0xd1,  0xed,  0xe1,  0xdc,  0x3d,  0x8c,  0xcf,
+  0x81,  0x7f,  0xb7,  0x2c,  0x3f,  0xe7,  0xea,  0x3f,  0xce,  0x91,  0xf5,  0xcb,
+  0x1c,  0x71,  0x72,  0x9f,  0x9d,  0x7d,  0xf7,  0xff,  0x00,  0x0e,  0x96,  0xf0,
+  0x97,  0xfd,  0x0f,  0xba,  0xd7,  0xfe,  0x02,  0x43,  0x47,  0xfc,  0x3a,  0x5b,
+  0xc2,  0x5f,  0xf4,  0x3e,  0xeb,  0x5f,  0xf8,  0x09,  0x0d,  0x1e,  0xde,  0x1d,
+  0xc3,  0xd8,  0xcc,  0xfc,  0xff,  0x00,  0xfe,  0xd9,  0xb2,  0xff,  0x00,  0x9f,
+  0x94,  0xfc,  0xe9,  0xd1,  0xeb,  0x36,  0x20,  0xe4,  0xdc,  0xa7,  0xe7,  0x5f,
+  0x7f,  0x7f,  0xc3,  0xa5,  0xbc,  0x25,  0xff,  0x00,  0x43,  0xee,  0xb5,  0xff,
+  0x00,  0x80,  0x90,  0xd1,  0xff,  0x00,  0x0e,  0x96,  0xf0,  0x97,  0xfd,  0x0f,
+  0xba,  0xd7,  0xfe,  0x02,  0x43,  0x47,  0xb7,  0x87,  0x70,  0xf6,  0x33,  0x3e,
+  0x05,  0xfe,  0xdc,  0xb0,  0xff,  0x00,  0x9f,  0xa8,  0xff,  0x00,  0x3a,  0x6c,
+  0x9a,  0xdd,  0x89,  0x18,  0x17,  0x29,  0xf9,  0xd7,  0xdf,  0x9f,  0xf0,  0xe9,
+  0x6f,  0x09,  0x7f,  0xd0,  0xfb,  0xad,  0x7f,  0xe0,  0x24,  0x34,  0x7f,  0xc3,
+  0xa5,  0xbc,  0x25,  0xff,  0x00,  0x43,  0xee,  0xb5,  0xff,  0x00,  0x80,  0x90,
+  0xd1,  0xed,  0xe1,  0xdc,  0x3d,  0x8c,  0xcf,  0xbc,  0xa8,  0xa2,  0x8a,  0xf3,
+  0x0e,  0xf0,  0xa2,  0x8a,  0x28,  0x00,  0xa2,  0x8a,  0x28,  0x00,  0xa2,  0x8a,
+  0x28,  0x00,  0xa2,  0x8a,  0x28,  0x00,  0xa2,  0x8a,  0x28,  0x00,  0xa2,  0x8a,
+  0x28,  0x00,  0xa2,  0x8a,  0x28,  0x00,  0xa2,  0xa0,  0xbb,  0xbd,  0xb7,  0xb0,
+  0x88,  0x49,  0x73,  0x3c,  0x56,  0xf1,  0x96,  0x0a,  0x1e,  0x57,  0x0a,  0x09,
+  0x3d,  0x06,  0x4f,  0x7a,  0x9e,  0x95,  0xd3,  0x76,  0xea,  0x01,  0x45,  0x14,
+  0x53,  0x00,  0xa2,  0x8a,  0x28,  0x00,  0xa2,  0x8a,  0x82,  0xda,  0xf6,  0xde,
+  0xf0,  0xca,  0x2d,  0xe7,  0x8a,  0x73,  0x13,  0x98,  0xe4,  0xf2,  0xdc,  0x36,
+  0xc6,  0x1d,  0x54,  0xe3,  0xa1,  0xf6,  0xa4,  0xda,  0x4e,  0xcc,  0x09,  0xe8,
+  0xa2,  0x8a,  0x60,  0x14,  0x51,  0x45,  0x00,  0x14,  0x51,  0x45,  0x00,  0x14,
+  0x51,  0x45,  0x00,  0x14,  0x51,  0x45,  0x00,  0x14,  0x51,  0x45,  0x00,  0x14,
+  0x51,  0x45,  0x00,  0x14,  0x51,  0x45,  0x00,  0x14,  0x51,  0x45,  0x02,  0xb8,
+  0x51,  0x45,  0x14,  0x05,  0xc2,  0x8a,  0x28,  0xa0,  0x2e,  0x14,  0x51,  0x45,
+  0x01,  0x70,  0xa2,  0x8a,  0x28,  0x18,  0x51,  0x45,  0x14,  0x0a,  0xe1,  0x45,
+  0x14,  0x50,  0x17,  0x0a,  0x28,  0xa2,  0x80,  0xb9,  0xca,  0xfc,  0x4a,  0xf0,
+  0x52,  0x78,  0xef,  0xc2,  0xb7,  0x1a,  0x76,  0xef,  0x2e,  0xe5,  0x4f,  0x9d,
+  0x6c,  0xe4,  0xe0,  0x09,  0x00,  0x38,  0xcf,  0xb1,  0xc9,  0x1f,  0x8e,  0x7b,
+  0x57,  0x3d,  0xf0,  0x5b,  0xc7,  0x53,  0x6b,  0xba,  0x6c,  0xda,  0x16,  0xaa,
+  0x5a,  0x3d,  0x73,  0x4a,  0xfd,  0xd4,  0x8b,  0x2f,  0xdf,  0x91,  0x01,  0xc0,
+  0x27,  0xdc,  0x1e,  0x0f,  0xe0,  0x7b,  0xd7,  0xa3,  0x5c,  0xdc,  0xc5,  0x67,
+  0x04,  0x93,  0xcf,  0x2a,  0x43,  0x0c,  0x60,  0xb3,  0xc9,  0x23,  0x05,  0x55,
+  0x1e,  0xa4,  0x9e,  0x95,  0xf3,  0x47,  0xc4,  0x8f,  0x1f,  0xe9,  0x36,  0xdf,
+  0x10,  0xed,  0x3c,  0x41,  0xe1,  0x39,  0x99,  0xaf,  0xa1,  0xe2,  0xea,  0x42,
+  0x98,  0x82,  0x72,  0x38,  0xe3,  0x90,  0x4e,  0x46,  0x41,  0xe9,  0x9c,  0x0c,
+  0x7a,  0xd7,  0xc4,  0x67,  0x98,  0x9a,  0x59,  0x3e,  0x26,  0x9e,  0x64,  0xa6,
+  0x93,  0x7e,  0xec,  0xe3,  0x7d,  0x65,  0x1e,  0xe9,  0x77,  0x8b,  0xd7,  0xd3,
+  0x4b,  0x99,  0x4d,  0xa8,  0xbe,  0x63,  0xe9,  0xca,  0x2b,  0xe4,  0x3d,  0x73,
+  0xe3,  0x3f,  0x8b,  0xb5,  0xc6,  0x6d,  0xfa,  0xb4,  0x96,  0x71,  0x9e,  0x91,
+  0x59,  0x0f,  0x28,  0x0f,  0xc4,  0x7c,  0xdf,  0x99,  0xae,  0x56,  0xe7,  0x5a,
+  0xd4,  0x6f,  0x18,  0xb5,  0xc5,  0xfd,  0xd4,  0xec,  0x7b,  0xc9,  0x33,  0x31,
+  0xfd,  0x4d,  0x78,  0x75,  0xf8,  0xfb,  0x0b,  0x07,  0x6a,  0x14,  0x65,  0x25,
+  0xe6,  0xd2,  0xff,  0x00,  0x32,  0x1d,  0x75,  0xd1,  0x1f,  0x73,  0x51,  0x5f,
+  0x0b,  0xdb,  0xea,  0xf7,  0xf6,  0xad,  0xba,  0x0b,  0xdb,  0x88,  0x58,  0x77,
+  0x8e,  0x56,  0x53,  0xfa,  0x1a,  0xe9,  0xf4,  0x5f,  0x8b,  0xfe,  0x2e,  0xd0,
+  0xd9,  0x7c,  0xad,  0x66,  0x7b,  0x84,  0x1f,  0xf2,  0xce,  0xec,  0xf9,  0xc0,
+  0xff,  0x00,  0xdf,  0x59,  0x23,  0xf0,  0x34,  0xa8,  0x71,  0xf6,  0x1a,  0x4e,
+  0xd5,  0xa8,  0x4a,  0x2b,  0xc9,  0xa7,  0xfe,  0x40,  0xab,  0xae,  0xa8,  0xfa,
+  0x13,  0xe2,  0xff,  0x00,  0x8f,  0xcf,  0x82,  0xfc,  0x3e,  0x21,  0xb3,  0x6d,
+  0xda,  0xcd,  0xfe,  0x62,  0xb5,  0x45,  0xe5,  0x97,  0xb1,  0x7c,  0x7b,  0x67,
+  0x8f,  0x72,  0x3d,  0xea,  0x5f,  0x84,  0x7e,  0x05,  0x6f,  0x04,  0x78,  0x60,
+  0x2d,  0xd1,  0x2d,  0xa9,  0xde,  0xb0,  0x9e,  0xe8,  0x93,  0x9d,  0xad,  0x8e,
+  0x17,  0xf0,  0x1d,  0x4f,  0xa9,  0x35,  0xe2,  0x5e,  0x13,  0xf8,  0x89,  0x61,
+  0xac,  0xfc,  0x49,  0x8f,  0xc4,  0x3e,  0x30,  0x76,  0xcc,  0x68,  0x16,  0xd8,
+  0x43,  0x19,  0x68,  0x61,  0x61,  0xd0,  0x91,  0x92,  0x40,  0x1c,  0x9e,  0x33,
+  0xc9,  0xcd,  0x7d,  0x3b,  0x63,  0x7f,  0x6d,  0xaa,  0x5a,  0x45,  0x75,  0x69,
+  0x3c,  0x77,  0x36,  0xd2,  0x8d,  0xc9,  0x2c,  0x4c,  0x19,  0x58,  0x7b,  0x11,
+  0x5e,  0xde,  0x4d,  0x8b,  0xa3,  0x9d,  0xe3,  0x2a,  0x66,  0x1c,  0xe9,  0xf2,
+  0x5e,  0x30,  0x8f,  0x58,  0xae,  0xb2,  0x6b,  0xbc,  0xbf,  0x05,  0xa1,  0x50,
+  0x6a,  0x6f,  0x98,  0xb1,  0x45,  0x14,  0x57,  0xdc,  0x9b,  0x5c,  0x28,  0xa2,
+  0x8a,  0x02,  0xe1,  0x45,  0x14,  0x50,  0x17,  0x0a,  0x28,  0xa2,  0x80,  0xb8,
+  0x51,  0x45,  0x14,  0x05,  0xc2,  0x8a,  0x28,  0xa0,  0x2e,  0x14,  0x51,  0x45,
+  0x01,  0x70,  0xa2,  0x8a,  0x28,  0x0b,  0x8d,  0xcd,  0x19,  0xa6,  0xe4,  0x51,
+  0x91,  0x55,  0x62,  0x47,  0x66,  0x8c,  0xd3,  0x72,  0x28,  0xc8,  0xa2,  0xc0,
+  0x3b,  0x34,  0x66,  0x9b,  0x91,  0x46,  0x45,  0x16,  0x01,  0xd9,  0xa3,  0x34,
+  0xdc,  0x8a,  0x32,  0x28,  0xb0,  0x0e,  0xcd,  0x19,  0xa6,  0xe4,  0x52,  0xe4,
+  0x51,  0x60,  0xb8,  0xb9,  0xa3,  0x34,  0xdc,  0x8a,  0x32,  0x28,  0xb0,  0x0e,
+  0xdd,  0x46,  0x69,  0xb9,  0x14,  0x64,  0x51,  0x60,  0x1d,  0x9a,  0xa7,  0xac,
+  0x6b,  0x16,  0x9a,  0x0e,  0x9b,  0x71,  0xa8,  0x5f,  0x4c,  0x20,  0xb5,  0x81,
+  0x37,  0xbb,  0x9e,  0xc3,  0xd0,  0x7a,  0x93,  0xd0,  0x0a,  0xb5,  0x91,  0x5f,
+  0x39,  0xfe,  0xd1,  0x1e,  0x37,  0x7d,  0x4b,  0x5a,  0x4f,  0x0f,  0x5b,  0x48,
+  0x45,  0xa5,  0x96,  0x1e,  0x70,  0xa7,  0xef,  0xca,  0x46,  0x40,  0x3f,  0xee,
+  0x83,  0xf9,  0x93,  0xe9,  0x5e,  0x06,  0x79,  0x9a,  0xc3,  0x27,  0xc1,  0x4b,
+  0x12,  0xd5,  0xe5,  0xb4,  0x57,  0x76,  0xff,  0x00,  0xab,  0xbf,  0x24,  0x44,
+  0xe5,  0xca,  0xae,  0x72,  0xbf,  0x12,  0xbe,  0x2a,  0xea,  0x3e,  0x3e,  0xbd,
+  0x78,  0xd5,  0x9e,  0xd3,  0x48,  0x46,  0xfd,  0xd5,  0xa2,  0x9f,  0xbd,  0xe8,
+  0xcf,  0xea,  0x7f,  0x41,  0xdb,  0xd4,  0xc3,  0xe0,  0x5f,  0x85,  0x1a,  0xd7,
+  0x8f,  0xed,  0xe6,  0xb9,  0xb1,  0xf2,  0x2d,  0xed,  0x22,  0x6d,  0x86,  0x7b,
+  0x96,  0x21,  0x59,  0xb1,  0x9c,  0x0c,  0x02,  0x4f,  0x51,  0xf9,  0xd7,  0x19,
+  0x5e,  0xcd,  0xf0,  0x73,  0xe3,  0x16,  0x97,  0xe1,  0x0d,  0x06,  0x4d,  0x23,
+  0x57,  0x49,  0x63,  0x44,  0x95,  0xa5,  0x86,  0x78,  0x53,  0x78,  0x21,  0xba,
+  0xab,  0x0e,  0xb9,  0xcf,  0x7f,  0x7f,  0x6a,  0xfc,  0x1b,  0x2e,  0xa9,  0x87,
+  0xcd,  0xb3,  0x2f,  0x69,  0x9c,  0xd5,  0x6a,  0x2e,  0xfa,  0xde,  0xda,  0xf4,
+  0x57,  0xe8,  0xbf,  0xe1,  0x8e,  0x48,  0xda,  0x52,  0xf7,  0x8f,  0x30,  0xf1,
+  0x57,  0x85,  0x75,  0x0f,  0x06,  0xeb,  0x12,  0x69,  0xba,  0x94,  0x42,  0x3b,
+  0x84,  0x01,  0x83,  0x21,  0xca,  0xba,  0x9e,  0x8c,  0xa7,  0xb8,  0xac,  0x8a,
+  0xed,  0x3e,  0x2c,  0xf8,  0xee,  0x1f,  0x1f,  0xf8,  0x9c,  0x5e,  0xda,  0xc2,
+  0xf0,  0xda,  0x41,  0x08,  0x82,  0x2f,  0x33,  0x01,  0xd8,  0x02,  0x49,  0x63,
+  0xe9,  0xc9,  0x3c,  0x57,  0x17,  0x5e,  0x26,  0x3e,  0x9e,  0x1e,  0x96,  0x2a,
+  0xa4,  0x30,  0xb2,  0xe6,  0xa6,  0x9b,  0xb3,  0xee,  0x88,  0x76,  0xbe,  0x81,
+  0x5a,  0x1a,  0x06,  0x83,  0x7b,  0xe2,  0x7d,  0x5e,  0xdf,  0x4d,  0xd3,  0xe2,
+  0xf3,  0xae,  0xa7,  0x38,  0x55,  0xce,  0x00,  0x00,  0x64,  0x92,  0x7b,  0x00,
+  0x39,  0xac,  0xfa,  0xea,  0x3e,  0x1b,  0x78,  0xc1,  0x7c,  0x0d,  0xe2,  0xcb,
+  0x5d,  0x52,  0x58,  0x4c,  0xf6,  0xe1,  0x5a,  0x39,  0x51,  0x3e,  0xf6,  0xd6,
+  0x18,  0x24,  0x7b,  0x8e,  0x0d,  0x67,  0x83,  0x85,  0x1a,  0x98,  0x8a,  0x70,
+  0xc4,  0x4b,  0x96,  0x0d,  0xae,  0x67,  0xd9,  0x5f,  0x50,  0x56,  0xbe,  0xa6,
+  0x97,  0x8d,  0x7e,  0x0e,  0xeb,  0xde,  0x06,  0xd3,  0x17,  0x50,  0xbb,  0x36,
+  0xf7,  0x56,  0x99,  0x0b,  0x24,  0x96,  0xae,  0x4f,  0x96,  0x4f,  0x4d,  0xc0,
+  0x81,  0xc1,  0x3c,  0x66,  0xa9,  0xfc,  0x3e,  0xf8,  0x93,  0xaa,  0x78,  0x03,
+  0x50,  0x0f,  0x6c,  0xe6,  0x7b,  0x07,  0x6f,  0xdf,  0xd9,  0x3b,  0x7c,  0x8e,
+  0x3d,  0x47,  0xa3,  0x7b,  0xfe,  0x79,  0xaf,  0x45,  0xf8,  0xad,  0xf1,  0xb3,
+  0x47,  0xf1,  0x27,  0x85,  0x26,  0xd2,  0x34,  0x84,  0x9a,  0x67,  0xbb,  0x2b,
+  0xe6,  0xcb,  0x34,  0x7b,  0x04,  0x6a,  0x18,  0x36,  0x07,  0xa9,  0xc8,  0x1e,
+  0xd5,  0xe1,  0x95,  0xf4,  0x39,  0xab,  0xc2,  0x65,  0x79,  0x84,  0x67,  0x93,
+  0x55,  0x6d,  0x24,  0x9d,  0xd3,  0xbd,  0x9f,  0x55,  0x7e,  0xaa,  0xd6,  0xbe,
+  0xfb,  0xd8,  0xb9,  0x5a,  0x32,  0xf7,  0x59,  0xf6,  0xef,  0x86,  0xbc,  0x49,
+  0x63,  0xe2,  0xbd,  0x1a,  0xdf,  0x53,  0xd3,  0xe5,  0xf3,  0x2d,  0xe6,  0x1d,
+  0xfe,  0xf2,  0x1e,  0xea,  0xc3,  0xb1,  0x15,  0xa9,  0x9a,  0xf9,  0x7b,  0xe0,
+  0x27,  0x8d,  0xe4,  0xf0,  0xef,  0x8a,  0x53,  0x4a,  0x9e,  0x43,  0xfd,  0x9f,
+  0xa9,  0x30,  0x8f,  0x69,  0x3c,  0x24,  0xdf,  0xc0,  0xc3,  0xeb,  0xf7,  0x7f,
+  0x11,  0xe9,  0x5f,  0x4f,  0xe4,  0x57,  0xee,  0x3c,  0x3f,  0x9b,  0xc7,  0x39,
+  0xc1,  0x2a,  0xed,  0x5a,  0x6b,  0x49,  0x2f,  0x3f,  0xf2,  0x7b,  0xfe,  0x1d,
+  0x0e,  0xb8,  0x4f,  0x99,  0x5c,  0x76,  0x4d,  0x19,  0xa6,  0xe4,  0x51,  0x91,
+  0x5f,  0x4b,  0x62,  0xc7,  0x64,  0xd1,  0x9a,  0x6e,  0x45,  0x19,  0x14,  0x58,
+  0x2e,  0x3b,  0x34,  0x66,  0x9b,  0x91,  0x46,  0x45,  0x16,  0x0b,  0x8e,  0xcd,
+  0x19,  0xa6,  0xe4,  0x51,  0x91,  0x45,  0x80,  0x76,  0x68,  0xcd,  0x37,  0x34,
+  0x64,  0x51,  0x60,  0xb8,  0xec,  0xd1,  0x9a,  0x6e,  0x45,  0x19,  0x14,  0x58,
+  0x07,  0x64,  0xd1,  0x9a,  0x6e,  0x45,  0x19,  0x14,  0x58,  0x06,  0x6e,  0xa3,
+  0x75,  0x37,  0x34,  0x66,  0xae,  0xc4,  0x5c,  0x76,  0xea,  0x37,  0x53,  0x73,
+  0x46,  0x68,  0xb0,  0x5c,  0x76,  0xea,  0x37,  0x53,  0x73,  0x46,  0x68,  0xb0,
+  0x5c,  0x76,  0xea,  0x37,  0x53,  0x72,  0x28,  0xcd,  0x16,  0x0b,  0x8e,  0xdd,
+  0x46,  0xea,  0x6e,  0x68,  0xcd,  0x16,  0x0b,  0x8e,  0xdd,  0x46,  0xea,  0x6e,
+  0x68,  0xcd,  0x16,  0x0b,  0x8e,  0xdd,  0x46,  0xea,  0xc4,  0xf1,  0x57,  0x8c,
+  0x34,  0xaf,  0x06,  0x69,  0xff,  0x00,  0x6b,  0xd5,  0x2e,  0x44,  0x28,  0xc7,
+  0x08,  0x8a,  0x37,  0x3c,  0x87,  0xd1,  0x47,  0x7f,  0xe5,  0x5c,  0x0d,  0x9f,
+  0xed,  0x1f,  0xe1,  0xcb,  0x8b,  0xc1,  0x14,  0xd6,  0x97,  0xf6,  0xb0,  0x93,
+  0x81,  0x3b,  0xa2,  0xb0,  0x1e,  0xe4,  0x06,  0x27,  0xf2,  0xcd,  0x78,  0xf8,
+  0xac,  0xdf,  0x2f,  0xc0,  0xd4,  0x54,  0x71,  0x35,  0xa3,  0x19,  0x3e,  0x8d,
+  0xfe,  0x7d,  0xbe,  0x64,  0xb9,  0x25,  0xb9,  0xeb,  0x05,  0xf6,  0x82,  0x4f,
+  0x41,  0x5f,  0x10,  0xeb,  0x7a,  0x93,  0xeb,  0x3a,  0xcd,  0xf5,  0xfc,  0x84,
+  0x97,  0xb9,  0x9d,  0xe6,  0x39,  0xff,  0x00,  0x69,  0x89,  0xfe,  0xb5,  0xf6,
+  0xad,  0x8e,  0xa1,  0x6b,  0xab,  0x58,  0xc5,  0x75,  0x69,  0x34,  0x77,  0x36,
+  0xb3,  0x2e,  0xe4,  0x91,  0x0e,  0x55,  0x85,  0x78,  0x5f,  0xfc,  0x2d,  0x5f,
+  0x87,  0x3f,  0xf4,  0x25,  0x27,  0xfe,  0x00,  0xdb,  0xff,  0x00,  0x8d,  0x7c,
+  0x67,  0x18,  0xe1,  0xa8,  0x63,  0x61,  0x87,  0x55,  0x31,  0x31,  0xa7,  0x1f,
+  0x79,  0xab,  0xdd,  0xf3,  0x7c,  0x3a,  0xab,  0x76,  0xfd,  0x4c,  0xea,  0x59,
+  0xdb,  0x53,  0xc4,  0x68,  0xaf,  0x6e,  0xff,  0x00,  0x85,  0xab,  0xf0,  0xe7,
+  0xfe,  0x84,  0xa4,  0xff,  0x00,  0xc0,  0x1b,  0x7f,  0xf1,  0xa3,  0xfe,  0x16,
+  0xaf,  0xc3,  0x9f,  0xfa,  0x12,  0x93,  0xff,  0x00,  0x00,  0x6d,  0xff,  0x00,
+  0xc6,  0xbf,  0x33,  0xfe,  0xc5,  0xc0,  0xff,  0x00,  0xd0,  0x7c,  0x3e,  0xe9,
+  0x7f,  0x91,  0x8f,  0x2a,  0xee,  0x78,  0x8d,  0x15,  0xed,  0xdf,  0xf0,  0xb5,
+  0x7e,  0x1c,  0xff,  0x00,  0xd0,  0x94,  0x9f,  0xf8,  0x03,  0x6f,  0xfe,  0x34,
+  0x7f,  0xc2,  0xd5,  0xf8,  0x73,  0xff,  0x00,  0x42,  0x52,  0x7f,  0xe0,  0x0d,
+  0xbf,  0xf8,  0xd1,  0xfd,  0x8b,  0x81,  0xff,  0x00,  0xa0,  0xf8,  0x7d,  0xd2,
+  0xff,  0x00,  0x20,  0xe5,  0x5d,  0xcf,  0x11,  0xa2,  0xbd,  0xbb,  0xfe,  0x16,
+  0xaf,  0xc3,  0x9f,  0xfa,  0x12,  0x93,  0xff,  0x00,  0x00,  0x6d,  0xff,  0x00,
+  0xc6,  0x8f,  0xf8,  0x5a,  0xbf,  0x0e,  0x7f,  0xe8,  0x4a,  0x4f,  0xfc,  0x01,
+  0xb7,  0xff,  0x00,  0x1a,  0x3f,  0xb1,  0x70,  0x3f,  0xf4,  0x1f,  0x0f,  0xba,
+  0x5f,  0xe4,  0x1c,  0xab,  0xb9,  0xe2,  0x34,  0x57,  0xb7,  0x7f,  0xc2,  0xd5,
+  0xf8,  0x73,  0xff,  0x00,  0x42,  0x52,  0x7f,  0xe0,  0x0d,  0xbf,  0xf8,  0xd1,
+  0xff,  0x00,  0x0b,  0x57,  0xe1,  0xcf,  0xfd,  0x09,  0x49,  0xff,  0x00,  0x80,
+  0x36,  0xff,  0x00,  0xe3,  0x47,  0xf6,  0x2e,  0x07,  0xfe,  0x83,  0xe1,  0xf7,
+  0x4b,  0xfc,  0x83,  0x95,  0x77,  0x3c,  0x52,  0x09,  0xde,  0xda,  0x78,  0xe6,
+  0x89,  0x8a,  0x49,  0x1b,  0x07,  0x56,  0x1d,  0x41,  0x07,  0x20,  0xd7,  0xdb,
+  0xfa,  0x5d,  0xf0,  0xd4,  0x74,  0xdb,  0x4b,  0xb0,  0x30,  0x27,  0x85,  0x25,
+  0x03,  0xfd,  0xe5,  0x07,  0xfa,  0xd7,  0x85,  0xff,  0x00,  0xc2,  0xd5,  0xf8,
+  0x73,  0xff,  0x00,  0x42,  0x52,  0x7f,  0xe0,  0x0d,  0xbf,  0xf8,  0xd7,  0xb6,
+  0x69,  0x1a,  0x95,  0xa5,  0xc7,  0x87,  0xec,  0xaf,  0xe1,  0x55,  0xb3,  0xb1,
+  0x7b,  0x54,  0x99,  0x11,  0xf0,  0x82,  0x28,  0xca,  0x02,  0x01,  0xec,  0x30,
+  0x3f,  0x0e,  0x2b,  0xf4,  0x7e,  0x0e,  0xc2,  0xd0,  0xc1,  0xce,  0xbc,  0x69,
+  0x62,  0x63,  0x51,  0x34,  0x9b,  0x4a,  0xfa,  0x5a,  0xfa,  0xeb,  0xea,  0x6d,
+  0x4e,  0xca,  0xfa,  0x9a,  0x5b,  0xa8,  0xdd,  0x5e,  0x57,  0xab,  0xfe,  0xd1,
+  0x3e,  0x1b,  0xd3,  0xaf,  0x1a,  0x0b,  0x68,  0x6e,  0xf5,  0x15,  0x53,  0x83,
+  0x34,  0x28,  0xaa,  0x87,  0xe9,  0xb8,  0x82,  0x7f,  0x2a,  0xeb,  0xbc,  0x1b,
+  0xf1,  0x07,  0x45,  0xf1,  0xcd,  0xbb,  0xbe,  0x99,  0x70,  0x7c,  0xe8,  0xc6,
+  0x64,  0xb6,  0x98,  0x6d,  0x91,  0x07,  0xa9,  0x1d,  0xc7,  0xb8,  0xc8,  0xaf,
+  0xb7,  0xc3,  0xe7,  0x19,  0x76,  0x2a,  0xb7,  0xd5,  0xe8,  0x56,  0x8c,  0xa7,
+  0xd9,  0x3f,  0xcb,  0xbf,  0xc8,  0xd1,  0x49,  0x3d,  0x2e,  0x74,  0xdb,  0xa8,
+  0xcd,  0x37,  0x34,  0x64,  0x57,  0xb2,  0x55,  0xc7,  0x6e,  0xa3,  0x75,  0x37,
+  0x34,  0x66,  0x8b,  0x05,  0xc7,  0x6e,  0xa3,  0x75,  0x37,  0x34,  0x66,  0x8b,
+  0x05,  0xc7,  0x6e,  0xa3,  0x75,  0x37,  0x34,  0x66,  0x8b,  0x05,  0xc7,  0x6e,
+  0xa3,  0x75,  0x37,  0x34,  0x64,  0x51,  0x60,  0xb8,  0xed,  0xd4,  0x6e,  0xa6,
+  0xe4,  0x51,  0x9a,  0x2c,  0x17,  0x1b,  0x9a,  0x33,  0x51,  0xee,  0xa3,  0x75,
+  0x55,  0x88,  0xb9,  0x26,  0x68,  0xcd,  0x47,  0xba,  0x8d,  0xd4,  0x58,  0x2e,
+  0x49,  0x9a,  0x33,  0x51,  0xee,  0xa3,  0x75,  0x16,  0x15,  0xc9,  0x32,  0x28,
+  0xa8,  0xf7,  0x51,  0xba,  0x8b,  0x0e,  0xe4,  0x99,  0xa3,  0x35,  0x1e,  0xea,
+  0x37,  0x51,  0x60,  0xb9,  0x26,  0x68,  0xcd,  0x47,  0xba,  0x8c,  0xd3,  0xb0,
+  0x5c,  0xf9,  0x7b,  0xe3,  0xb6,  0xaf,  0x3e,  0xa5,  0xf1,  0x0e,  0xf2,  0xde,
+  0x47,  0x26,  0x1b,  0x24,  0x48,  0x62,  0x4e,  0xc0,  0x15,  0x0c,  0x4f,  0xe2,
+  0x58,  0xfe,  0x95,  0xe7,  0x95,  0xda,  0x7c,  0x64,  0xff,  0x00,  0x92,  0x97,
+  0xad,  0xff,  0x00,  0xbf,  0x1f,  0xfe,  0x8a,  0x4a,  0xe2,  0xeb,  0xf9,  0x47,
+  0x3a,  0x9c,  0xaa,  0x66,  0x78,  0x99,  0x49,  0xdd,  0xf3,  0xcb,  0xf0,  0x6d,
+  0x23,  0x92,  0x5b,  0x9e,  0xf7,  0xfb,  0x34,  0xeb,  0x13,  0xcd,  0x67,  0xac,
+  0xe9,  0xb2,  0x39,  0x6b,  0x78,  0x1a,  0x39,  0xa2,  0x04,  0xfd,  0xd2,  0xdb,
+  0x83,  0x0f,  0xc7,  0x68,  0xfd,  0x6b,  0xc1,  0x2b,  0xda,  0xff,  0x00,  0x66,
+  0x73,  0x8b,  0xed,  0x7f,  0xfe,  0xb9,  0xc3,  0xfc,  0xde,  0xbc,  0x52,  0xbd,
+  0x8c,  0xd2,  0x72,  0x9e,  0x4b,  0x97,  0x39,  0x3b,  0xdb,  0xda,  0xaf,  0x92,
+  0x92,  0xb1,  0x4f,  0xe1,  0x41,  0x45,  0x14,  0x57,  0xc6,  0x90,  0x14,  0x51,
+  0x45,  0x00,  0x14,  0x51,  0x45,  0x00,  0x14,  0x51,  0x45,  0x00,  0x15,  0xef,
+  0x7f,  0x13,  0xf5,  0x89,  0xf4,  0xef,  0x82,  0xbe,  0x19,  0xb6,  0x81,  0xca,
+  0x0b,  0xc8,  0x2d,  0x62,  0x94,  0x83,  0xd5,  0x04,  0x3b,  0x88,  0xfc,  0x48,
+  0x15,  0xe0,  0x95,  0xed,  0x7f,  0x17,  0x0f,  0xfc,  0x5a,  0x5f,  0x05,  0xff,
+  0x00,  0xd7,  0x38,  0x3f,  0xf4,  0x45,  0x7d,  0x96,  0x47,  0x39,  0x43,  0x03,
+  0x98,  0x4a,  0x2e,  0xcf,  0x91,  0x7e,  0x32,  0xb3,  0xfc,  0x0a,  0x8e,  0xcc,
+  0xf1,  0x4a,  0xe9,  0xbe,  0x1a,  0x6a,  0xf3,  0xe8,  0xbe,  0x3a,  0xd1,  0x67,
+  0x81,  0xca,  0x99,  0x2e,  0x52,  0x07,  0x00,  0xfd,  0xe4,  0x76,  0x0a,  0xc0,
+  0xfe,  0x07,  0xf4,  0xae,  0x66,  0xb6,  0x3c,  0x1b,  0xff,  0x00,  0x23,  0x7e,
+  0x87,  0xff,  0x00,  0x5f,  0xd0,  0x7f,  0xe8,  0xc5,  0xaf,  0x9b,  0xc0,  0xce,
+  0x54,  0xf1,  0x54,  0xa7,  0x07,  0x66,  0xa4,  0xbf,  0x31,  0x2d,  0xcf,  0xb4,
+  0x33,  0x46,  0x6a,  0x3d,  0xd4,  0x6e,  0xaf,  0xeb,  0x9b,  0x1d,  0x57,  0x24,
+  0xcd,  0x19,  0xa8,  0xf7,  0x51,  0xba,  0x8b,  0x0e,  0xe4,  0x99,  0xa3,  0x35,
+  0x1e,  0xea,  0x37,  0x51,  0x60,  0xb9,  0x26,  0x68,  0xcd,  0x47,  0xba,  0x8d,
+  0xd4,  0x58,  0x2e,  0x49,  0x9a,  0x33,  0x51,  0xee,  0xa3,  0x75,  0x16,  0x15,
+  0xc9,  0x33,  0x46,  0x6a,  0x3d,  0xd4,  0x6e,  0xa2,  0xc3,  0xb8,  0xdd,  0xd4,
+  0x9b,  0xa9,  0xbb,  0xa8,  0xdd,  0x5a,  0x19,  0xdc,  0x7e,  0xea,  0x4d,  0xd4,
+  0xdd,  0xd4,  0x6e,  0xa0,  0x57,  0x1f,  0xba,  0x8d,  0xd4,  0xcd,  0xd4,  0x6e,
+  0xa0,  0x77,  0x1f,  0xba,  0x8d,  0xd4,  0xcd,  0xd4,  0x6e,  0xa4,  0x2b,  0x8f,
+  0xdd,  0x49,  0xba,  0x9b,  0xba,  0x8d,  0xd4,  0xc2,  0xe3,  0xb7,  0x52,  0xee,
+  0xa6,  0x6e,  0xa3,  0x75,  0x20,  0xb9,  0xf2,  0x9f,  0xc6,  0x3f,  0xf9,  0x29,
+  0x5a,  0xdf,  0xfb,  0xf1,  0xff,  0x00,  0xe8,  0xb4,  0xae,  0x32,  0xbb,  0x2f,
+  0x8c,  0x5c,  0xfc,  0x49,  0xd6,  0xff,  0x00,  0xdf,  0x8f,  0xff,  0x00,  0x45,
+  0xa5,  0x71,  0xb5,  0xfc,  0x99,  0x9c,  0x7f,  0xc8,  0xcb,  0x13,  0xfe,  0x39,
+  0xff,  0x00,  0xe9,  0x4c,  0xc1,  0xee,  0x7b,  0x57,  0xec,  0xd2,  0x71,  0x7d,
+  0xaf,  0x7f,  0xd7,  0x38,  0x7f,  0x9b,  0xd7,  0x8a,  0xd7,  0xb4,  0x7e,  0xcd,
+  0x67,  0x17,  0xda,  0xf7,  0xfd,  0x73,  0x87,  0xf9,  0xbd,  0x78,  0xbd,  0x7b,
+  0x19,  0x97,  0xfc,  0x89,  0x32,  0xef,  0xfb,  0x8b,  0xff,  0x00,  0xa5,  0x21,
+  0xbd,  0x90,  0x51,  0x45,  0x15,  0xf2,  0x02,  0x0a,  0x28,  0xa2,  0x80,  0x0a,
+  0x28,  0xa2,  0x80,  0x0a,  0x28,  0xa2,  0x80,  0x0a,  0xf6,  0xaf,  0x8b,  0x47,
+  0x3f,  0x09,  0x7c,  0x17,  0xff,  0x00,  0x5c,  0xe0,  0xff,  0x00,  0xd1,  0x15,
+  0xe2,  0xb5,  0xed,  0x1f,  0x16,  0x4f,  0xfc,  0x5a,  0x6f,  0x06,  0x7f,  0xd7,
+  0x38,  0x3f,  0xf4,  0x45,  0x7d,  0x7e,  0x4d,  0xff,  0x00,  0x22,  0xfc,  0xc3,
+  0xfc,  0x11,  0xff,  0x00,  0xd2,  0x90,  0xd6,  0xcc,  0xf1,  0x7a,  0xd8,  0xf0,
+  0x67,  0xfc,  0x8e,  0x1a,  0x17,  0xfd,  0x7f,  0xc1,  0xff,  0x00,  0xa3,  0x16,
+  0xb1,  0xeb,  0x63,  0xc1,  0xdf,  0xf2,  0x37,  0x68,  0x7f,  0xf5,  0xfd,  0x07,
+  0xfe,  0x8c,  0x5a,  0xf9,  0xbc,  0x27,  0xfb,  0xcd,  0x3f,  0xf1,  0x2f,  0xcc,
+  0x48,  0xfb,  0x2b,  0x75,  0x1b,  0xa9,  0x9b,  0xa8,  0xdd,  0x5f,  0xd8,  0x16,
+  0x37,  0xb8,  0xfd,  0xd4,  0x6e,  0xa6,  0x6e,  0xa3,  0x75,  0x20,  0xb8,  0xed,
+  0xd4,  0xbb,  0xa9,  0x9b,  0xa8,  0xdd,  0x4c,  0x2e,  0x3f,  0x75,  0x26,  0xea,
+  0x6e,  0xea,  0x37,  0x52,  0x0b,  0x8f,  0xdd,  0x49,  0xba,  0x9b,  0xba,  0x8d,
+  0xd4,  0xec,  0x3b,  0x8f,  0xdd,  0x49,  0xba,  0x9b,  0xba,  0x8d,  0xd4,  0x0a,
+  0xe4,  0x74,  0x53,  0x33,  0x4b,  0x93,  0x57,  0x63,  0x3b,  0x8e,  0xa2,  0x9b,
+  0x9a,  0x4c,  0xd1,  0x60,  0xb8,  0xfa,  0x29,  0x99,  0xa3,  0x34,  0x58,  0x2e,
+  0x3f,  0x34,  0x53,  0x33,  0x4b,  0x93,  0x45,  0x82,  0xe3,  0xa8,  0xcd,  0x33,
+  0x34,  0x66,  0x8b,  0x05,  0xc7,  0xd1,  0x4d,  0xc9,  0xa3,  0x26,  0x8b,  0x05,
+  0xcf,  0x96,  0x3e,  0x30,  0x7f,  0xc9,  0x48,  0xd6,  0xbf,  0xdf,  0x8f,  0xff,
+  0x00,  0x45,  0xa5,  0x71,  0xb5,  0xdd,  0xfc,  0x6c,  0xd3,  0xa6,  0xb1,  0xf8,
+  0x85,  0x7f,  0x2c,  0x8a,  0x44,  0x77,  0x4b,  0x1c,  0xd1,  0xb7,  0x66,  0x1b,
+  0x02,  0x9f,  0xd5,  0x4d,  0x70,  0x95,  0xfc,  0x97,  0x9d,  0x42,  0x50,  0xcc,
+  0xf1,  0x31,  0x92,  0xb7,  0xbf,  0x2f,  0xfd,  0x29,  0x90,  0x7b,  0x3f,  0xec,
+  0xdb,  0xff,  0x00,  0x1f,  0xba,  0xef,  0xfd,  0x73,  0x87,  0xf9,  0xbd,  0x78,
+  0xc5,  0x7b,  0x87,  0xec,  0xe3,  0xa7,  0x4d,  0x1c,  0x3a,  0xd5,  0xf3,  0x29,
+  0x58,  0x24,  0x31,  0xc2,  0x8d,  0xfd,  0xe2,  0x37,  0x16,  0xfc,  0xb2,  0x3f,
+  0x3a,  0xf0,  0xfa,  0xf6,  0x73,  0x58,  0x4a,  0x19,  0x26,  0x5b,  0xcc,  0xad,
+  0x7f,  0x6a,  0xff,  0x00,  0xf2,  0x64,  0x01,  0x45,  0x14,  0x57,  0xc6,  0x00,
+  0x51,  0x45,  0x14,  0x00,  0x51,  0x45,  0x14,  0x00,  0x51,  0x45,  0x14,  0x00,
+  0x57,  0xb3,  0xfc,  0x57,  0xff,  0x00,  0x92,  0x51,  0xe0,  0xdf,  0xfa,  0xe7,
+  0x07,  0xfe,  0x88,  0xaf,  0x18,  0xaf,  0x70,  0xf8,  0x9b,  0xa7,  0x4d,  0x79,
+  0xf0,  0x77,  0xc3,  0x37,  0x11,  0x29,  0x74,  0xb5,  0x8a,  0xd9,  0xe4,  0xc7,
+  0x65,  0x30,  0xed,  0xcf,  0xe6,  0x40,  0xfc,  0x6b,  0xec,  0xf2,  0x38,  0x4a,
+  0x78,  0x0c,  0xc1,  0x45,  0x5f,  0xdc,  0x5f,  0x84,  0xae,  0xc0,  0xf0,  0xfa,
+  0xd8,  0xf0,  0x6f,  0xfc,  0x8d,  0xfa,  0x1f,  0xfd,  0x7f,  0x41,  0xff,  0x00,
+  0xa3,  0x16,  0xb1,  0xeb,  0xa2,  0xf8,  0x79,  0xa7,  0x4d,  0xaa,  0x78,  0xdf,
+  0x45,  0x86,  0x15,  0x2c,  0xcb,  0x75,  0x1c,  0xad,  0x8e,  0xca,  0x8c,  0x18,
+  0x9f,  0xc8,  0x57,  0xcd,  0x60,  0x61,  0x29,  0xe2,  0xe9,  0x46,  0x2a,  0xed,
+  0xca,  0x3f,  0x9a,  0x03,  0xeb,  0x9c,  0xd1,  0x4c,  0xcd,  0x2e,  0x4d,  0x7f,
+  0x60,  0x58,  0xbb,  0x8e,  0xa2,  0x99,  0x9a,  0x33,  0x45,  0x82,  0xe3,  0xe8,
+  0xa6,  0x66,  0x8c,  0xd1,  0x60,  0xb8,  0xfa,  0x29,  0x99,  0xa5,  0xc9,  0xa2,
+  0xc1,  0x71,  0xd9,  0xa2,  0x9b,  0x93,  0x49,  0x9a,  0x2c,  0x17,  0x1f,  0x45,
+  0x33,  0x34,  0x66,  0x8b,  0x05,  0xc6,  0x6e,  0xa3,  0x75,  0x30,  0x90,  0x3a,
+  0x9c,  0x51,  0x9a,  0xd2,  0xc6,  0x57,  0x1f,  0xba,  0x8d,  0xd4,  0xda,  0x4c,
+  0xd1,  0x60,  0xb8,  0xfd,  0xd4,  0x6e,  0xa6,  0x02,  0x0f,  0x43,  0x9a,  0x37,
+  0x01,  0xdf,  0x14,  0x58,  0x2e,  0x3f,  0x75,  0x1b,  0xa9,  0xb4,  0x94,  0x58,
+  0x2e,  0x3f,  0x75,  0x1b,  0xa9,  0xb4,  0x80,  0x83,  0xd0,  0xe6,  0x8b,  0x05,
+  0xc7,  0xee,  0xa3,  0x75,  0x30,  0x90,  0x3a,  0x9c,  0x51,  0x9a,  0x2c,  0x17,
+  0x31,  0x3c,  0x5d,  0xe0,  0xcd,  0x2f,  0xc6,  0xb6,  0x2b,  0x6f,  0xa8,  0xc4,
+  0x4b,  0x26,  0x4c,  0x53,  0xc6,  0x71,  0x24,  0x64,  0xf5,  0xc1,  0xfe,  0x87,
+  0x8a,  0xe0,  0x6d,  0x3f,  0x67,  0x7d,  0x32,  0x2b,  0xb0,  0xf7,  0x1a,  0xad,
+  0xcc,  0xf6,  0xe0,  0xe7,  0xca,  0x58,  0xd5,  0x09,  0x1e,  0x85,  0xb2,  0x7f,
+  0x95,  0x7a,  0xd5,  0x25,  0x78,  0x38,  0xcc,  0x87,  0x2c,  0xcc,  0x2b,  0x2a,
+  0xf8,  0x9a,  0x2a,  0x52,  0xef,  0xaa,  0xfb,  0xec,  0xd5,  0xfe,  0x77,  0x0b,
+  0x95,  0xf4,  0xad,  0x32,  0xd3,  0x44,  0xb0,  0x86,  0xca,  0xc6,  0x05,  0xb7,
+  0xb6,  0x88,  0x61,  0x23,  0x4e,  0x83,  0xfc,  0x4f,  0xbd,  0x7c,  0x6b,  0x5f,
+  0x69,  0x57,  0xc5,  0xb5,  0xf9,  0x8f,  0x88,  0xb0,  0x8d,  0x38,  0xe0,  0xe1,
+  0x05,  0x64,  0xb9,  0xec,  0x97,  0xfd,  0xb8,  0x34,  0x14,  0x51,  0x45,  0x7e,
+  0x32,  0x30,  0xa2,  0x8a,  0x28,  0x00,  0xa2,  0x8a,  0x28,  0x00,  0xa2,  0x8a,
+  0x28,  0x00,  0xaf,  0xad,  0xfc,  0x2b,  0x04,  0x57,  0x9e,  0x06,  0xd1,  0xad,
+  0xe7,  0x8d,  0x66,  0x86,  0x4d,  0x3a,  0x04,  0x78,  0xdc,  0x65,  0x58,  0x18,
+  0xd7,  0x20,  0x8a,  0xf9,  0x22,  0xbe,  0xba,  0xf0,  0x67,  0xfc,  0x89,  0xfa,
+  0x17,  0xfd,  0x78,  0x41,  0xff,  0x00,  0xa2,  0xd6,  0xbf,  0x5c,  0xf0,  0xee,
+  0x2a,  0x58,  0x9c,  0x42,  0x7b,  0x72,  0xaf,  0xcc,  0x47,  0x05,  0xab,  0x7e,
+  0xcf,  0x7a,  0x4d,  0xdd,  0xdb,  0x4b,  0x65,  0xa8,  0x4f,  0x63,  0x13,  0x1c,
+  0xf9,  0x25,  0x04,  0x80,  0x7b,  0x02,  0x48,  0x3f,  0x9e,  0x6b,  0xaf,  0xf0,
+  0x57,  0xc3,  0xcd,  0x27,  0xc0,  0xd1,  0xb9,  0xb3,  0x47,  0x9a,  0xee,  0x41,
+  0xb6,  0x4b,  0xa9,  0xb0,  0x5c,  0x8f,  0x41,  0xe8,  0x3d,  0x87,  0xe3,  0x5d,
+  0x36,  0x69,  0x6b,  0xf5,  0x7c,  0x37,  0x0f,  0xe5,  0x78,  0x3a,  0xff,  0x00,
+  0x59,  0xa1,  0x41,  0x46,  0x7d,  0xf5,  0xd3,  0xd1,  0x6c,  0xbe,  0x49,  0x0a,
+  0xe3,  0xb7,  0x51,  0xba,  0x99,  0x9a,  0x03,  0x03,  0xde,  0xbd,  0xfb,  0x05,
+  0xc7,  0xee,  0xa3,  0x75,  0x30,  0x90,  0x06,  0x4f,  0x14,  0x51,  0x60,  0xb8,
+  0xfd,  0xd4,  0x6e,  0xa6,  0xd1,  0x45,  0x82,  0xe3,  0xb7,  0x51,  0xba,  0x98,
+  0x08,  0x3d,  0x0e,  0x68,  0x24,  0x0e,  0xf4,  0x58,  0x2e,  0x3f,  0x75,  0x1b,
+  0xa9,  0x94,  0xb4,  0x58,  0x2e,  0x3b,  0x75,  0x1b,  0xa9,  0x99,  0xa0,  0x10,
+  0x7a,  0x1a,  0x2c,  0x17,  0x31,  0x62,  0xbd,  0x91,  0x46,  0xf7,  0x90,  0x3e,
+  0xd3,  0xf7,  0x1b,  0xa9,  0xad,  0x58,  0xa5,  0x13,  0x46,  0xae,  0xbd,  0x08,
+  0xac,  0x3f,  0x38,  0xff,  0x00,  0x71,  0x3f,  0xef,  0x91,  0x56,  0x52,  0xf1,
+  0xe3,  0x48,  0x55,  0x42,  0x80,  0x7a,  0x80,  0x3d,  0xeb,  0xb2,  0x70,  0xbe,
+  0xc7,  0x9d,  0x4e,  0xaf,  0x2e,  0xec,  0xd6,  0xcd,  0x36,  0x59,  0x44,  0x31,
+  0xb3,  0xb7,  0x41,  0x49,  0xba,  0xb3,  0x1e,  0xf2,  0x49,  0x12,  0x65,  0x60,
+  0x08,  0x1d,  0x01,  0x1e,  0xf5,  0x84,  0x61,  0xcc,  0x75,  0x4e,  0xa7,  0x22,
+  0x1b,  0x2d,  0xec,  0x8c,  0x0b,  0xa4,  0x81,  0x37,  0x1f,  0xb8,  0xbd,  0x7e,
+  0xb4,  0xb1,  0x5e,  0xc8,  0xa0,  0x3b,  0xb8,  0x7d,  0xa7,  0xee,  0x37,  0x5f,
+  0xad,  0x57,  0xf3,  0x8f,  0xf7,  0x13,  0xfe,  0xf9,  0x14,  0x79,  0xc7,  0xfb,
+  0x89,  0xff,  0x00,  0x7c,  0x8a,  0xeb,  0xe5,  0x56,  0xb5,  0x8e,  0x0e,  0x77,
+  0x7b,  0xdc,  0xdd,  0x8e,  0x41,  0x2a,  0x2b,  0xaf,  0x42,  0x33,  0x4e,  0xac,
+  0xa8,  0xef,  0x1d,  0x3c,  0x85,  0x00,  0x05,  0x3d,  0x40,  0x1e,  0xe6,  0xb4,
+  0x77,  0x57,  0x24,  0xa3,  0xca,  0x77,  0xc2,  0x7c,  0xe8,  0x74,  0x92,  0x08,
+  0xd1,  0x99,  0x8f,  0x00,  0x66,  0xb2,  0xa5,  0xbd,  0x91,  0x81,  0x74,  0x70,
+  0x99,  0x38,  0xd8,  0x3a,  0xfd,  0x69,  0xd2,  0x5e,  0x3b,  0xf9,  0xea,  0x40,
+  0x2a,  0x3a,  0x02,  0x3d,  0xc5,  0x55,  0xf3,  0x8f,  0xf7,  0x13,  0xfe,  0xf9,
+  0x15,  0xbc,  0x21,  0x6d,  0xce,  0x6a,  0x95,  0x6f,  0xa2,  0x64,  0xf1,  0x5e,
+  0x48,  0xa3,  0x7b,  0x48,  0x1f,  0x69,  0xfb,  0x8d,  0xd4,  0xd6,  0xac,  0x52,
+  0x89,  0xa3,  0x57,  0x5e,  0x86,  0xb0,  0xfc,  0xe3,  0xfd,  0xc4,  0xff,  0x00,
+  0xbe,  0x45,  0x59,  0x4b,  0xc7,  0x8d,  0x61,  0x0a,  0x14,  0x03,  0xd4,  0x01,
+  0xef,  0x44,  0xe1,  0x7d,  0x85,  0x4e,  0xaf,  0x2e,  0xec,  0xd6,  0xcd,  0x15,
+  0x1e,  0xea,  0x5d,  0xd5,  0xcd,  0x63,  0xba,  0xe3,  0xeb,  0xc0,  0xbc,  0x71,
+  0xf0,  0x57,  0x55,  0x83,  0x57,  0x9e,  0xe7,  0x44,  0x85,  0x6f,  0x6c,  0xa6,
+  0x72,  0xe2,  0x25,  0x70,  0xaf,  0x16,  0x4e,  0x76,  0xe0,  0x91,  0x91,  0xe9,
+  0x8a,  0xf7,  0xad,  0xd4,  0x66,  0xbe,  0x7f,  0x39,  0xc8,  0xf0,  0x99,  0xe5,
+  0x18,  0xd2,  0xc4,  0xdd,  0x72,  0xbb,  0xa6,  0xb7,  0x5d,  0xfb,  0xef,  0xe8,
+  0x17,  0xb1,  0xf2,  0xc5,  0xff,  0x00,  0xc3,  0x5f,  0x12,  0xe9,  0x96,  0x53,
+  0x5d,  0xdd,  0x69,  0x52,  0x43,  0x6f,  0x0a,  0x97,  0x92,  0x42,  0xe8,  0x42,
+  0x81,  0xd4,  0xf0,  0x6b,  0x99,  0xaf,  0xaa,  0xfe,  0x21,  0x9c,  0xf8,  0x1f,
+  0x5c,  0xff,  0x00,  0xaf,  0x47,  0xfe,  0x55,  0xf2,  0xa5,  0x7e,  0x01,  0xc5,
+  0x59,  0x1e,  0x1f,  0x22,  0xc4,  0x53,  0xa3,  0x87,  0x93,  0x92,  0x94,  0x6f,
+  0xef,  0x5b,  0xbd,  0xba,  0x24,  0x5a,  0x77,  0x0a,  0xe9,  0xec,  0xbe,  0x19,
+  0xf8,  0x9b,  0x51,  0xb3,  0x86,  0xea,  0xdb,  0x49,  0x92,  0x5b,  0x79,  0x90,
+  0x49,  0x1b,  0x87,  0x40,  0x19,  0x48,  0xc8,  0x3d,  0x6b,  0x98,  0xaf,  0xac,
+  0x3c,  0x08,  0x71,  0xe0,  0xad,  0x0b,  0xfe,  0xbc,  0xa1,  0xff,  0x00,  0xd0,
+  0x05,  0x57,  0x0a,  0xe4,  0x58,  0x7c,  0xf6,  0xbd,  0x5a,  0x58,  0x89,  0x4a,
+  0x2a,  0x2a,  0xfe,  0xed,  0xbb,  0xdb,  0xaa,  0x60,  0xdd,  0x8f,  0x9e,  0xdb,
+  0xe1,  0x4f,  0x8a,  0xd1,  0x4b,  0x1d,  0x1a,  0x50,  0x00,  0xc9,  0x3e,  0x62,
+  0x7f,  0xf1,  0x55,  0xc9,  0xd7,  0xd9,  0x17,  0x4d,  0xfe,  0x8d,  0x37,  0xfb,
+  0x87,  0xf9,  0x57,  0xc6,  0xf5,  0xd1,  0xc5,  0x9c,  0x3d,  0x86,  0xc8,  0x5d,
+  0x05,  0x87,  0x9c,  0xa5,  0xcf,  0xcd,  0x7e,  0x6b,  0x74,  0xb6,  0xd6,  0x4b,
+  0xb8,  0x27,  0x70,  0xae,  0x87,  0x47,  0xf0,  0x07,  0x88,  0x35,  0xfb,  0x04,
+  0xbd,  0xb0,  0xd3,  0x64,  0xb9,  0xb5,  0x72,  0x42,  0xc8,  0xae,  0xa0,  0x12,
+  0x0e,  0x0f,  0x53,  0xeb,  0x5c,  0xf5,  0x7d,  0x27,  0xf0,  0x54,  0xe3,  0xe1,
+  0xed,  0x8f,  0xfd,  0x74,  0x97,  0xff,  0x00,  0x43,  0x35,  0xe7,  0x70,  0xbe,
+  0x4f,  0x43,  0x3c,  0xc6,  0xcb,  0x0d,  0x5e,  0x4d,  0x25,  0x16,  0xf4,  0xb5,
+  0xee,  0x9a,  0x5d,  0x53,  0xee,  0x0d,  0xd8,  0xf3,  0x1f,  0x0d,  0x7c,  0x12,
+  0xd7,  0xb5,  0x3d,  0x42,  0x31,  0xa9,  0x40,  0x34,  0xdb,  0x20,  0xc0,  0xc8,
+  0xee,  0xea,  0xce,  0x47,  0x70,  0xa0,  0x13,  0xcf,  0xb9,  0xe2,  0xbe,  0x87,
+  0xb7,  0x82,  0x3b,  0x4b,  0x78,  0xa0,  0x89,  0x42,  0x45,  0x12,  0x84,  0x45,
+  0x1d,  0x80,  0x18,  0x02,  0x97,  0x34,  0x9b,  0xab,  0xfa,  0x07,  0x25,  0xe1,
+  0xfc,  0x1e,  0x45,  0x09,  0x47,  0x0d,  0x76,  0xe5,  0xbb,  0x7a,  0xbd,  0x36,
+  0x5a,  0x24,  0xad,  0xf2,  0x22,  0xf7,  0x24,  0xcd,  0x19,  0xa8,  0xf7,  0x51,
+  0xba,  0xbe,  0x96,  0xc1,  0x71,  0xd2,  0x48,  0x22,  0x46,  0x76,  0xe0,  0x0e,
+  0x6b,  0x2a,  0x5b,  0xd9,  0x18,  0x17,  0x47,  0x11,  0xe4,  0xe3,  0x60,  0xeb,
+  0xf5,  0xa7,  0x49,  0x78,  0xef,  0xe7,  0xa9,  0x00,  0xa8,  0xe8,  0x08,  0xf7,
+  0x02,  0xaa,  0xf9,  0xc7,  0xfb,  0x89,  0xff,  0x00,  0x7c,  0x8a,  0xe9,  0x84,
+  0x2d,  0xb9,  0xc5,  0x56,  0xaf,  0x36,  0x89,  0x93,  0xc5,  0x7b,  0x22,  0x8d,
+  0xef,  0x20,  0x7d,  0xa7,  0xee,  0x37,  0x53,  0x5a,  0xd1,  0x4a,  0x26,  0x8d,
+  0x5d,  0x7a,  0x1a,  0xc2,  0xf3,  0x8f,  0xf7,  0x13,  0xfe,  0xf9,  0x15,  0x65,
+  0x2f,  0x1e,  0x34,  0x84,  0x28,  0x50,  0x09,  0xe4,  0x01,  0xef,  0x44,  0xe1,
+  0x7d,  0x85,  0x4e,  0xaf,  0x2e,  0xec,  0xd6,  0xa6,  0xcb,  0x28,  0x86,  0x36,
+  0x76,  0xe8,  0x29,  0x37,  0x56,  0x63,  0xde,  0x3c,  0x89,  0x30,  0x60,  0xa4,
+  0x0e,  0x80,  0x8f,  0x7a,  0xc2,  0x30,  0xe6,  0x3a,  0xa7,  0x53,  0x91,  0x0d,
+  0x96,  0xf6,  0x46,  0x05,  0xd2,  0x40,  0x9b,  0x8f,  0xdc,  0x5e,  0xa3,  0xde,
+  0x96,  0x2b,  0xd9,  0x14,  0x07,  0x77,  0x0f,  0xb4,  0xfd,  0xc6,  0xeb,  0xf5,
+  0xaa,  0xfe,  0x71,  0xfe,  0xe2,  0x7f,  0xdf,  0x22,  0x8f,  0x38,  0xff,  0x00,
+  0x71,  0x3f,  0xef,  0x91,  0x5d,  0x7c,  0xaa,  0xd6,  0xb1,  0xc1,  0xce,  0xef,
+  0x7b,  0x9b,  0xb1,  0xc8,  0x25,  0x45,  0x75,  0xe8,  0x46,  0x69,  0xd5,  0x95,
+  0x1d,  0xe3,  0xa0,  0x81,  0x46,  0x02,  0x9e,  0xa0,  0x0f,  0x72,  0x2b,  0x4b,
+  0x35,  0xc9,  0x28,  0xf2,  0x9d,  0xf0,  0xa9,  0xce,  0x85,  0x92,  0x41,  0x1a,
+  0x33,  0xb7,  0x40,  0x32,  0x6b,  0x2a,  0x5b,  0xd9,  0x1c,  0x17,  0x47,  0x09,
+  0x93,  0x8d,  0x83,  0xaf,  0xd6,  0x9d,  0x25,  0xe3,  0xbf,  0x9e,  0xa4,  0x02,
+  0xa3,  0xa0,  0x23,  0xdc,  0x55,  0x5f,  0x38,  0xff,  0x00,  0x71,  0x3f,  0xef,
+  0x91,  0x5b,  0xc2,  0x16,  0xdc,  0xe6,  0xa9,  0x57,  0x9b,  0x44,  0xc8,  0xea,
+  0x70,  0xa4,  0x88,  0x30,  0x09,  0xff,  0x00,  0xf5,  0xd3,  0x4d,  0xbb,  0x09,
+  0x84,  0x59,  0x1b,  0xbd,  0x7b,  0x56,  0x95,  0xb4,  0x66,  0x18,  0x42,  0x13,
+  0x92,  0x3d,  0x2a,  0xe5,  0x2b,  0x23,  0x2a,  0x70,  0x72,  0x6d,  0x32,  0x7a,
+  0xc8,  0x2a,  0x40,  0x9f,  0x20,  0x8f,  0xff,  0x00,  0x5d,  0x6a,  0xe6,  0xa3,
+  0xb9,  0x8c,  0xcf,  0x09,  0x40,  0x40,  0x27,  0xd6,  0xb1,  0x83,  0xe5,  0x3a,
+  0x6a,  0x47,  0x99,  0x5c,  0xc7,  0xa2,  0xa5,  0x5b,  0x76,  0x69,  0x8c,  0x59,
+  0x1b,  0xbf,  0x4a,  0x3e,  0xce,  0xde,  0x7f,  0x95,  0x91,  0xbb,  0xd7,  0xb5,
+  0x74,  0xdd,  0x1c,  0x3c,  0xac,  0x7a,  0xa9,  0x2d,  0x6f,  0x80,  0x7f,  0xcb,
+  0x1a,  0xd6,  0xa8,  0x6d,  0xe3,  0x30,  0xc2,  0xa8,  0x48,  0x24,  0x77,  0x15,
+  0x26,  0x6b,  0x9a,  0x6f,  0x99,  0x9d,  0xf4,  0xe3,  0xca,  0x8c,  0xb6,  0x52,
+  0x1a,  0xe3,  0x20,  0xff,  0x00,  0x96,  0x15,  0x5e,  0xb6,  0x2e,  0x23,  0x33,
+  0x44,  0xc8,  0x08,  0x04,  0xd6,  0x67,  0xd9,  0xdb,  0xcf,  0xf2,  0xb2,  0x37,
+  0x7a,  0xf6,  0xad,  0xa1,  0x24,  0xd1,  0xcb,  0x52,  0x0e,  0x2d,  0x58,  0x8a,
+  0xa7,  0x0a,  0x48,  0x83,  0x00,  0x9f,  0xff,  0x00,  0x5d,  0x34,  0xdb,  0xb2,
+  0xcc,  0x22,  0xc8,  0xdd,  0xeb,  0xda,  0xb4,  0xad,  0xa3,  0x30,  0xc2,  0xaa,
+  0x4e,  0x48,  0xf4,  0xa2,  0x52,  0xb2,  0x0a,  0x70,  0x72,  0x6d,  0x32,  0x7a,
+  0x29,  0xa4,  0xd1,  0x9a,  0xe5,  0xb1,  0xde,  0x3a,  0x8a,  0x6e,  0x73,  0x41,
+  0x34,  0x58,  0x0e,  0x7f,  0xe2,  0x1f,  0xfc,  0x88,  0xfa,  0xe7,  0xfd,  0x7a,
+  0xbf,  0xf2,  0xaf,  0x95,  0xab,  0xeb,  0x2f,  0x18,  0x58,  0x4b,  0xaa,  0xf8,
+  0x57,  0x56,  0xb4,  0x80,  0x6e,  0x9a,  0x6b,  0x69,  0x15,  0x17,  0xd5,  0xb6,
+  0x9c,  0x0f,  0xce,  0xbe,  0x4e,  0x65,  0x2a,  0x48,  0x20,  0x82,  0x38,  0x20,
+  0xf6,  0xaf,  0xc1,  0x7c,  0x46,  0x84,  0x96,  0x32,  0x84,  0xed,  0xa3,  0x8b,
+  0x5f,  0x73,  0xff,  0x00,  0x82,  0x8d,  0x20,  0x25,  0x7d,  0x5d,  0xe0,  0x5f,
+  0xf9,  0x12,  0xf4,  0x2f,  0xfa,  0xf2,  0x87,  0xff,  0x00,  0x40,  0x15,  0xf2,
+  0x9a,  0x23,  0x48,  0xea,  0x88,  0xa5,  0x9d,  0x8e,  0x02,  0x81,  0x92,  0x4d,
+  0x7d,  0x69,  0xe1,  0x8b,  0x19,  0x34,  0xbf,  0x0d,  0xe9,  0x76,  0x73,  0x71,
+  0x2c,  0x16,  0xd1,  0xc6,  0xe3,  0xd0,  0x85,  0x00,  0xd5,  0x78,  0x73,  0x09,
+  0x3c,  0x56,  0x22,  0x76,  0xd1,  0x45,  0x2f,  0xc7,  0xfe,  0x00,  0x4c,  0xd0,
+  0xba,  0xff,  0x00,  0x8f,  0x69,  0xbf,  0xdc,  0x3f,  0xca,  0xbe,  0x39,  0xaf,
+  0xb1,  0xe5,  0x5f,  0x32,  0x27,  0x4c,  0xe3,  0x72,  0x91,  0x9a,  0xf9,  0x03,
+  0x50,  0xb1,  0x9b,  0x4c,  0xbe,  0xb8,  0xb4,  0x9d,  0x0a,  0x4d,  0x04,  0x86,
+  0x37,  0x53,  0xd8,  0x83,  0x8a,  0xed,  0xf1,  0x22,  0x12,  0xff,  0x00,  0x65,
+  0x9d,  0xb4,  0xf7,  0xd7,  0xfe,  0x92,  0x10,  0x2b,  0xd7,  0xd2,  0x5f,  0x05,
+  0xbf,  0xe4,  0x9f,  0x58,  0xff,  0x00,  0xd7,  0x49,  0x7f,  0xf4,  0x33,  0x5f,
+  0x36,  0xd7,  0xd3,  0x9f,  0x0a,  0x74,  0xe9,  0xb4,  0xbf,  0x01,  0xe9,  0x91,
+  0x4e,  0xa5,  0x24,  0x75,  0x69,  0x76,  0x9e,  0xa0,  0x33,  0x12,  0x3f,  0x42,
+  0x2b,  0xc3,  0xf0,  0xf6,  0x12,  0x96,  0x69,  0x52,  0x49,  0x68,  0xa0,  0xff,
+  0x00,  0x19,  0x44,  0x72,  0xd8,  0xeb,  0xe8,  0xa6,  0xe6,  0x8c,  0xd7,  0xf4,
+  0x3d,  0x8c,  0x87,  0x51,  0x4d,  0xcd,  0x19,  0xa2,  0xc0,  0x65,  0xb2,  0x90,
+  0xd7,  0x19,  0x04,  0x7f,  0xfb,  0x42,  0xab,  0xd6,  0xc5,  0xc4,  0x66,  0x68,
+  0x59,  0x07,  0x04,  0xfa,  0xd6,  0x67,  0xd9,  0xdb,  0xcf,  0xf2,  0xb2,  0x37,
+  0x7a,  0xf6,  0xae,  0xa8,  0x4a,  0xe8,  0xe0,  0xa9,  0x07,  0x16,  0xac,  0x45,
+  0x53,  0x85,  0x24,  0x41,  0x80,  0x4f,  0xff,  0x00,  0xae,  0x9a,  0x6d,  0xd9,
+  0x66,  0x11,  0x64,  0x6e,  0xf5,  0xed,  0x5a,  0x76,  0xd1,  0x98,  0x21,  0x0a,
+  0x48,  0x27,  0xda,  0x89,  0x4a,  0xc8,  0x29,  0xc1,  0xc9,  0xb4,  0xc9,  0xab,
+  0x20,  0xa9,  0x02,  0x7c,  0x82,  0x3f,  0xfd,  0x75,  0xab,  0x9a,  0x8a,  0xe6,
+  0x33,  0x34,  0x45,  0x41,  0xc1,  0xf7,  0xac,  0x60,  0xf9,  0x4e,  0x9a,  0x91,
+  0xe6,  0x46,  0x45,  0x15,  0x28,  0xb7,  0x66,  0x98,  0xc5,  0x91,  0xb8,  0x77,
+  0xed,  0x47,  0xd9,  0xdb,  0xcf,  0xf2,  0xb2,  0x37,  0x7a,  0xf6,  0xae,  0x9b,
+  0xa3,  0x87,  0x95,  0x8f,  0x55,  0x25,  0xad,  0xf0,  0x0f,  0xf9,  0x63,  0x5a,
+  0xd5,  0x0d,  0xba,  0x18,  0x61,  0x54,  0x24,  0x12,  0x3d,  0x2a,  0x4c,  0xd7,
+  0x34,  0xdf,  0x33,  0x3b,  0xe9,  0xc7,  0x95,  0x19,  0x6c,  0xa4,  0x35,  0xc6,
+  0x41,  0xff,  0x00,  0x2c,  0x2a,  0xbd,  0x6c,  0x5c,  0x46,  0x66,  0x85,  0x90,
+  0x1c,  0x13,  0xeb,  0x59,  0x9f,  0x67,  0x6f,  0x3f,  0xca,  0xc8,  0xdd,  0xfa,
+  0x56,  0xd0,  0x92,  0x68,  0xe5,  0xa9,  0x06,  0x9a,  0xb1,  0xa0,  0xd6,  0xc1,
+  0xae,  0x04,  0xb9,  0x39,  0x1d,  0xaa,  0x6a,  0x28,  0xae,  0x76,  0xdb,  0x3a,
+  0xd2,  0xb6,  0xc1,  0x45,  0x14,  0x52,  0x19,  0x0a,  0xdb,  0x05,  0xb8,  0x32,
+  0xe4,  0xe4,  0xf6,  0xa3,  0xec,  0xc3,  0xed,  0x1e,  0x6e,  0x4e,  0x7d,  0x2a,
+  0x6a,  0x2a,  0xb9,  0x99,  0x3c,  0xa8,  0x28,  0xa2,  0x8a,  0x92,  0x82,  0xa1,
+  0xfb,  0x30,  0xfb,  0x47,  0x9b,  0x93,  0x9f,  0x4a,  0x9a,  0x8a,  0x69,  0xd8,
+  0x4d,  0x5f,  0x72,  0x16,  0xb6,  0x0d,  0x70,  0x25,  0xc9,  0xc8,  0xed,  0x53,
+  0x51,  0x45,  0x0d,  0xb6,  0x09,  0x5b,  0x60,  0xa2,  0x8a,  0x29,  0x0c,  0x28,
+  0xa2,  0x8a,  0x00,  0x2b,  0x83,  0xf1,  0x57,  0xc1,  0xdd,  0x1b,  0xc4,  0xb7,
+  0xaf,  0x79,  0x1b,  0xcb,  0xa7,  0x5d,  0x48,  0x73,  0x21,  0x80,  0x02,  0x8e,
+  0x7d,  0x4a,  0x9e,  0xff,  0x00,  0x42,  0x2b,  0xbc,  0xa2,  0xbc,  0xfc,  0x76,
+  0x5f,  0x85,  0xcc,  0xa9,  0xfb,  0x1c,  0x5d,  0x35,  0x38,  0xf9,  0xfe,  0x8f,
+  0x75,  0xf2,  0x1a,  0x6d,  0x1c,  0x3f,  0x84,  0xbe,  0x11,  0xe8,  0xde,  0x16,
+  0xbb,  0x4b,  0xc2,  0xd2,  0x5f,  0xde,  0x27,  0x29,  0x24,  0xf8,  0xda,  0x87,
+  0xd5,  0x54,  0x77,  0xf7,  0x39,  0xae,  0xe2,  0x8a,  0x29,  0xe0,  0xb0,  0x18,
+  0x5c,  0xba,  0x97,  0xb1,  0xc2,  0x53,  0x50,  0x8f,  0x97,  0xeb,  0xd5,  0xfc,
+  0xc2,  0xed,  0x85,  0x71,  0xfe,  0x31,  0xf8,  0x5f,  0xa4,  0x78,  0xc6,  0x6f,
+  0xb4,  0xcd,  0xe6,  0x5a,  0x5e,  0xe3,  0x06,  0xe2,  0x0c,  0x65,  0xc7,  0x6d,
+  0xc0,  0xf5,  0xfe,  0x7e,  0xf5,  0xd8,  0x51,  0x55,  0x8c,  0xc1,  0x61,  0xf1,
+  0xf4,  0x9d,  0x0c,  0x54,  0x14,  0xe2,  0xfa,  0x3f,  0xeb,  0x46,  0x17,  0x68,
+  0xf3,  0xbf,  0x0f,  0x7c,  0x11,  0xd1,  0x74,  0x6b,  0xc4,  0xb9,  0xb9,  0x96,
+  0x5d,  0x49,  0xd0,  0xe5,  0x63,  0x94,  0x05,  0x8f,  0x3e,  0xa5,  0x47,  0x5f,
+  0xc4,  0xe3,  0xda,  0xbd,  0x13,  0xa5,  0x14,  0x56,  0x38,  0x1c,  0xb7,  0x07,
+  0x96,  0x41,  0xd3,  0xc1,  0xd3,  0x50,  0x4f,  0x7b,  0x75,  0xf5,  0x7b,  0xb0,
+  0x6d,  0xb0,  0xa2,  0x8a,  0x2b,  0xd3,  0x10,  0x51,  0x45,  0x14,  0x00,  0x54,
+  0x3f,  0x66,  0x1f,  0x68,  0xf3,  0x72,  0x73,  0xe9,  0x53,  0x51,  0x4d,  0x3b,
+  0x09,  0xab,  0xee,  0x42,  0xd6,  0xc1,  0xae,  0x04,  0xb9,  0x39,  0x1d,  0xaa,
+  0x6a,  0x28,  0xa1,  0xb6,  0xc1,  0x2b,  0x6c,  0x14,  0x51,  0x45,  0x21,  0x90,
+  0xad,  0xb0,  0x5b,  0x83,  0x2e,  0x4e,  0x4f,  0x6a,  0x3e,  0xcc,  0x3e,  0xd1,
+  0xe6,  0xe4,  0xe7,  0xd2,  0xa6,  0xa2,  0xab,  0x99,  0x93,  0xca,  0x82,  0x8a,
+  0x28,  0xa9,  0x28,  0x2a,  0x1f,  0xb3,  0x0f,  0xb4,  0x79,  0xb9,  0x39,  0xf4,
+  0xa9,  0xa8,  0xa6,  0x9d,  0x84,  0xd5,  0xf7,  0x3e,  0x20,  0xff,  0x00,  0x87,
+  0xa6,  0xf8,  0x5b,  0xfe,  0x84,  0x7d,  0x63,  0xff,  0x00,  0x02,  0xa2,  0xa3,
+  0xfe,  0x1e,  0x9b,  0xe1,  0x6f,  0xfa,  0x11,  0xf5,  0x8f,  0xfc,  0x0a,  0x8a,
+  0xbe,  0x17,  0xfe,  0xc6,  0xb2,  0xff,  0x00,  0x9f,  0x64,  0xa7,  0x47,  0xa2,
+  0x59,  0x31,  0xe6,  0xd9,  0x31,  0x45,  0x8e,  0x9e,  0x44,  0x7d,  0xcd,  0xff,
+  0x00,  0x0f,  0x4d,  0xf0,  0xb7,  0xfd,  0x08,  0xfa,  0xc7,  0xfe,  0x05,  0x45,
+  0x47,  0xfc,  0x3d,  0x37,  0xc2,  0xdf,  0xf4,  0x23,  0xeb,  0x1f,  0xf8,  0x15,
+  0x15,  0x7c,  0x3b,  0xfd,  0x87,  0x61,  0xff,  0x00,  0x3e,  0xb1,  0xfe,  0x54,
+  0xd9,  0x34,  0x6b,  0x05,  0x1c,  0x5b,  0x47,  0x9f,  0xa5,  0x16,  0x0e,  0x44,
+  0x7d,  0xc9,  0xff,  0x00,  0x0f,  0x4d,  0xf0,  0xb7,  0xfd,  0x08,  0xfa,  0xc7,
+  0xfe,  0x05,  0x45,  0x47,  0xfc,  0x3d,  0x37,  0xc2,  0xdf,  0xf4,  0x23,  0xeb,
+  0x1f,  0xf8,  0x15,  0x15,  0x7c,  0x2f,  0xfd,  0x8d,  0x65,  0xff,  0x00,  0x3e,
+  0xc9,  0xf9,  0x53,  0xe3,  0xd1,  0x2c,  0x4f,  0x26,  0xd9,  0x31,  0xf4,  0xa2,
+  0xc1,  0xc8,  0x8f,  0xb9,  0x7f,  0xe1,  0xe9,  0xbe,  0x16,  0xff,  0x00,  0xa1,
+  0x1f,  0x58,  0xff,  0x00,  0xc0,  0xa8,  0xa8,  0xff,  0x00,  0x87,  0xa6,  0xf8,
+  0x5b,  0xfe,  0x84,  0x7d,  0x63,  0xff,  0x00,  0x02,  0xa2,  0xaf,  0x87,  0x7f,
+  0xb0,  0xec,  0x3f,  0xe7,  0xd6,  0x3f,  0xca,  0x99,  0x26,  0x8d,  0x62,  0x38,
+  0x16,  0xc9,  0x9a,  0x2c,  0x1c,  0x88,  0xfb,  0x97,  0xfe,  0x1e,  0x9b,  0xe1,
+  0x6f,  0xfa,  0x11,  0xf5,  0x8f,  0xfc,  0x0a,  0x8a,  0x8f,  0xf8,  0x7a,  0x6f,
+  0x85,  0xbf,  0xe8,  0x47,  0xd6,  0x3f,  0xf0,  0x2a,  0x2a,  0xf8,  0x5f,  0xfb,
+  0x1a,  0xcb,  0xfe,  0x7d,  0x93,  0xf2,  0xa9,  0x23,  0xd1,  0x2c,  0x48,  0xc9,
+  0xb6,  0x4f,  0xca,  0x8b,  0x07,  0x22,  0x3e,  0xe4,  0xff,  0x00,  0x87,  0xa6,
+  0xf8,  0x5b,  0xfe,  0x84,  0x7d,  0x63,  0xff,  0x00,  0x02,  0xa2,  0xa3,  0xfe,
+  0x1e,  0x9b,  0xe1,  0x6f,  0xfa,  0x11,  0xf5,  0x8f,  0xfc,  0x0a,  0x8a,  0xbe,
+  0x1d,  0xfe,  0xc3,  0xb0,  0xff,  0x00,  0x9f,  0x58,  0xff,  0x00,  0x2a,  0x64,
+  0x9a,  0x35,  0x88,  0x38,  0x16,  0xc9,  0xf9,  0x51,  0x60,  0xe4,  0x47,  0xdc,
+  0xbf,  0xf0,  0xf4,  0xdf,  0x0b,  0x7f,  0xd0,  0x8f,  0xac,  0x7f,  0xe0,  0x54,
+  0x54,  0x7f,  0xc3,  0xd3,  0x7c,  0x2d,  0xff,  0x00,  0x42,  0x3e,  0xb1,  0xff,
+  0x00,  0x81,  0x51,  0x57,  0xc2,  0xff,  0x00,  0xd8,  0xd6,  0x5f,  0xf3,  0xec,
+  0x9f,  0x95,  0x48,  0x9a,  0x1d,  0x89,  0x19,  0x36,  0xc9,  0xf9,  0x51,  0x60,
+  0xe4,  0x47,  0xdc,  0x9f,  0xf0,  0xf4,  0xdf,  0x0b,  0x7f,  0xd0,  0x8f,  0xac,
+  0x7f,  0xe0,  0x54,  0x54,  0x7f,  0xc3,  0xd3,  0x7c,  0x2d,  0xff,  0x00,  0x42,
+  0x3e,  0xb1,  0xff,  0x00,  0x81,  0x51,  0x57,  0xc3,  0xbf,  0xd8,  0x76,  0x1f,
+  0xf3,  0xeb,  0x1f,  0xe5,  0x51,  0xbe,  0x8d,  0x63,  0x9c,  0x0b,  0x64,  0xfc,
+  0xa8,  0xb0,  0x72,  0x23,  0xee,  0x6f,  0xf8,  0x7a,  0x6f,  0x85,  0xbf,  0xe8,
+  0x47,  0xd6,  0x3f,  0xf0,  0x2a,  0x2a,  0x3f,  0xe1,  0xe9,  0xbe,  0x16,  0xff,
+  0x00,  0xa1,  0x1f,  0x58,  0xff,  0x00,  0xc0,  0xa8,  0xab,  0xe1,  0x7f,  0xec,
+  0x7b,  0x2f,  0xf9,  0xf6,  0x4f,  0xca,  0x9b,  0x2e,  0x9d,  0xa7,  0xdb,  0xed,
+  0x53,  0x67,  0xe6,  0xc8,  0xc0,  0x90,  0xb1,  0xae,  0x4e,  0x3d,  0x68,  0xb0,
+  0x72,  0x23,  0xee,  0xaf,  0xf8,  0x7a,  0x6f,  0x85,  0xbf,  0xe8,  0x47,  0xd6,
+  0x3f,  0xf0,  0x2a,  0x2a,  0x3f,  0xe1,  0xe9,  0xbe,  0x16,  0xff,  0x00,  0xa1,
+  0x1f,  0x58,  0xff,  0x00,  0xc0,  0xa8,  0xab,  0xe1,  0x1f,  0x23,  0x4b,  0xd8,
+  0x1b,  0xec,  0x44,  0x8d,  0xbb,  0x9b,  0x09,  0xf7,  0x06,  0x48,  0xc9,  0xe7,
+  0xd8,  0xfe,  0x54,  0x3d,  0x9e,  0x9e,  0x2e,  0x04,  0x66,  0xcb,  0x60,  0x27,
+  0x68,  0x72,  0xbf,  0x29,  0x3f,  0x5c,  0xd1,  0x60,  0xe4,  0x47,  0xdd,  0xdf,
+  0xf0,  0xf4,  0xdf,  0x0b,  0x7f,  0xd0,  0x8f,  0xac,  0x7f,  0xe0,  0x54,  0x54,
+  0x7f,  0xc3,  0xd3,  0x7c,  0x2d,  0xff,  0x00,  0x42,  0x3e,  0xb1,  0xff,  0x00,
+  0x81,  0x51,  0x57,  0xc1,  0x82,  0xdf,  0x4e,  0x1b,  0xb7,  0xd9,  0x98,  0x88,
+  0x19,  0xda,  0xeb,  0xc9,  0xe7,  0x1c,  0x73,  0xea,  0x45,  0x4d,  0x1d,  0x9e,
+  0x9a,  0x46,  0x0d,  0x91,  0x12,  0x02,  0x41,  0x8c,  0xaf,  0xcd,  0x9c,  0x67,
+  0xd7,  0xd2,  0x8b,  0x07,  0x22,  0x3e,  0xed,  0xff,  0x00,  0x87,  0xa6,  0xf8,
+  0x5b,  0xfe,  0x84,  0x7d,  0x63,  0xff,  0x00,  0x02,  0xa2,  0xa3,  0xfe,  0x1e,
+  0x9b,  0xe1,  0x6f,  0xfa,  0x11,  0xf5,  0x8f,  0xfc,  0x0a,  0x8a,  0xbe,  0x16,
+  0xb7,  0xd3,  0xf4,  0xeb,  0x86,  0x65,  0xfb,  0x1f,  0x96,  0xea,  0x01,  0x2b,
+  0x22,  0xe0,  0xe0,  0xf7,  0xa7,  0x36,  0x8f,  0x62,  0x49,  0xc5,  0xb2,  0x62,
+  0x8b,  0x07,  0x22,  0x3e,  0xe7,  0xff,  0x00,  0x87,  0xa6,  0xf8,  0x5b,  0xfe,
+  0x84,  0x7d,  0x63,  0xff,  0x00,  0x02,  0xa2,  0xa3,  0xfe,  0x1e,  0x9b,  0xe1,
+  0x6f,  0xfa,  0x11,  0xf5,  0x8f,  0xfc,  0x0a,  0x8a,  0xbe,  0x17,  0xfe,  0xc6,
+  0xb2,  0x3f,  0xf2,  0xec,  0x95,  0x30,  0xd0,  0xec,  0x40,  0xff,  0x00,  0x8f,
+  0x64,  0xa2,  0xc1,  0xc8,  0x8f,  0xb8,  0xbf,  0xe1,  0xe9,  0xbe,  0x16,  0xff,
+  0x00,  0xa1,  0x1f,  0x58,  0xff,  0x00,  0xc0,  0xa8,  0xa8,  0xff,  0x00,  0x87,
+  0xa6,  0xf8,  0x5b,  0xfe,  0x84,  0x7d,  0x63,  0xff,  0x00,  0x02,  0xa2,  0xaf,
+  0x87,  0x7f,  0xb1,  0x2c,  0x07,  0xfc,  0xba,  0xc7,  0xf9,  0x54,  0x27,  0x47,
+  0xb2,  0x27,  0xfe,  0x3d,  0x92,  0x8b,  0x07,  0x22,  0x3e,  0xe8,  0xff,  0x00,
+  0x87,  0xa6,  0xf8,  0x5b,  0xfe,  0x84,  0x7d,  0x63,  0xff,  0x00,  0x02,  0xa2,
+  0xa3,  0xfe,  0x1e,  0x9b,  0xe1,  0x6f,  0xfa,  0x11,  0xf5,  0x8f,  0xfc,  0x0a,
+  0x8a,  0xbe,  0x17,  0x1a,  0x2d,  0x91,  0x38,  0xfb,  0x32,  0x54,  0xdf,  0xd8,
+  0x76,  0x1f,  0xf3,  0xea,  0x9f,  0x95,  0x16,  0x0e,  0x44,  0x7d,  0xc5,  0xff,
+  0x00,  0x0f,  0x4d,  0xf0,  0xb7,  0xfd,  0x08,  0xfa,  0xc7,  0xfe,  0x05,  0x45,
+  0x47,  0xfc,  0x3d,  0x37,  0xc2,  0xdf,  0xf4,  0x23,  0xeb,  0x1f,  0xf8,  0x15,
+  0x15,  0x7c,  0x3a,  0x74,  0x4b,  0x00,  0x33,  0xf6,  0x58,  0xff,  0x00,  0x2a,
+  0x84,  0xe8,  0xd6,  0x5f,  0xf3,  0xec,  0x94,  0x58,  0x39,  0x11,  0xf7,  0x47,
+  0xfc,  0x3d,  0x37,  0xc2,  0xdf,  0xf4,  0x23,  0xeb,  0x1f,  0xf8,  0x15,  0x15,
+  0x1f,  0xf0,  0xf4,  0xdf,  0x0b,  0x7f,  0xd0,  0x8f,  0xac,  0x7f,  0xe0,  0x54,
+  0x55,  0xf0,  0xc2,  0xe8,  0xb6,  0x4c,  0x40,  0xfb,  0x32,  0x54,  0xbf,  0xd8,
+  0x76,  0x1f,  0xf3,  0xea,  0x94,  0x58,  0x39,  0x11,  0xf7,  0x17,  0xfc,  0x3d,
+  0x37,  0xc2,  0xdf,  0xf4,  0x23,  0xeb,  0x1f,  0xf8,  0x15,  0x15,  0x1f,  0xf0,
+  0xf4,  0xdf,  0x0b,  0x7f,  0xd0,  0x8f,  0xac,  0x7f,  0xe0,  0x54,  0x55,  0xf0,
+  0xe3,  0x68,  0xb6,  0x0a,  0x09,  0xfb,  0x2c,  0x7f,  0x95,  0x45,  0xfd,  0x8d,
+  0x65,  0xff,  0x00,  0x3e,  0xc9,  0x45,  0x83,  0x91,  0x1f,  0x74,  0x7f,  0xc3,
+  0xd3,  0x7c,  0x2d,  0xff,  0x00,  0x42,  0x3e,  0xb1,  0xff,  0x00,  0x81,  0x51,
+  0x51,  0xff,  0x00,  0x0f,  0x4d,  0xf0,  0xb7,  0xfd,  0x08,  0xfa,  0xc7,  0xfe,
+  0x05,  0x45,  0x5f,  0x0c,  0x26,  0x89,  0x64,  0xcd,  0xff,  0x00,  0x1e,  0xc9,
+  0x52,  0xff,  0x00,  0x61,  0xd8,  0x7f,  0xcf,  0xac,  0x7f,  0x95,  0x16,  0x0e,
+  0x44,  0x7d,  0xc5,  0xff,  0x00,  0x0f,  0x4d,  0xf0,  0xb7,  0xfd,  0x08,  0xfa,
+  0xc7,  0xfe,  0x05,  0x45,  0x47,  0xfc,  0x3d,  0x37,  0xc2,  0xdf,  0xf4,  0x23,
+  0xeb,  0x1f,  0xf8,  0x15,  0x15,  0x7c,  0x38,  0xfa,  0x2d,  0x82,  0xaf,  0xfc,
+  0x7a,  0xc7,  0xf9,  0x54,  0x5f,  0xd8,  0xd6,  0x5f,  0xf3,  0xec,  0x94,  0x58,
+  0x39,  0x11,  0x72,  0xa7,  0x45,  0xda,  0xb8,  0xa8,  0xe3,  0x5c,  0xb6,  0x7d,
+  0x2a,  0x5a,  0xa2,  0xc2,  0xa1,  0x66,  0xdc,  0xd9,  0xa7,  0xc8,  0xd8,  0x18,
+  0xf5,  0xa8,  0xa8,  0x01,  0x40,  0xc9,  0xa9,  0xd4,  0x6d,  0x18,  0xa8,  0xe2,
+  0x5e,  0x73,  0x52,  0x50,  0x00,  0x4e,  0x05,  0x40,  0xc7,  0x71,  0xcd,  0x49,
+  0x2b,  0x71,  0x8a,  0x8a,  0x80,  0x14,  0x0c,  0x9c,  0x54,  0xe0,  0x60,  0x62,
+  0xa3,  0x89,  0x7b,  0xd4,  0x94,  0x00,  0x13,  0x80,  0x4d,  0x40,  0x4e,  0x4e,
+  0x69,  0xf2,  0xb7,  0x6a,  0x8e,  0x80,  0x15,  0x46,  0xe3,  0x8a,  0x9e,  0x99,
+  0x1a,  0xe0,  0x67,  0xd6,  0x9f,  0x40,  0x08,  0xc7,  0x68,  0xcd,  0x41,  0x4f,
+  0x91,  0xb2,  0x71,  0xe9,  0x4c,  0xa0,  0x07,  0x22,  0xee,  0x6f,  0x6a,  0x27,
+  0xb5,  0x59,  0xa4,  0x49,  0x37,  0xbc,  0x6e,  0xbc,  0x06,  0x43,  0x8c,  0x8f,
+  0x43,  0xed,  0x52,  0x46,  0xb8,  0x5f,  0x73,  0x4e,  0xa0,  0x0a,  0xa6,  0xca,
+  0x38,  0xa2,  0x95,  0x41,  0x6f,  0xde,  0x2e,  0xc3,  0xcf,  0x6c,  0x93,  0xff,
+  0x00,  0xb3,  0x1a,  0x87,  0xec,  0x60,  0xca,  0xae,  0xd2,  0x48,  0xe1,  0x4e,
+  0x42,  0x12,  0x36,  0x83,  0xf9,  0x55,  0xa9,  0x1b,  0x73,  0x7b,  0x0a,  0x6d,
+  0x00,  0x57,  0x8b,  0x49,  0xb7,  0x0c,  0xfb,  0x53,  0xcb,  0x0c,  0x00,  0x21,
+  0x38,  0xe8,  0x72,  0x0f,  0xd6,  0xa6,  0x5d,  0x39,  0x17,  0x90,  0xf2,  0x79,
+  0x99,  0x2c,  0x64,  0x27,  0x2c,  0x4e,  0xdc,  0x7e,  0x82,  0xac,  0xa2,  0xed,
+  0x5a,  0x5a,  0x00,  0xad,  0x1d,  0xaa,  0xdb,  0x16,  0x6f,  0x31,  0xe5,  0x91,
+  0xc0,  0x05,  0xe4,  0x39,  0x38,  0x1d,  0xbf,  0x5a,  0x5a,  0x73,  0xb6,  0xe6,
+  0xa6,  0xf5,  0xa0,  0x07,  0xc4,  0xb9,  0x39,  0xf4,  0xa9,  0x69,  0x14,  0x6d,
+  0x18,  0xa5,  0xe9,  0x40,  0x0c,  0x95,  0xb0,  0x31,  0x51,  0x52,  0xb1,  0xdc,
+  0x49,  0xa0,  0x0c,  0x9c,  0x50,  0x03,  0xe2,  0x5e,  0xf5,  0x25,  0x00,  0x60,
+  0x62,  0x82,  0x70,  0x33,  0x40,  0x11,  0xca,  0xdd,  0xaa,  0x3a,  0x52,  0x72,
+  0x73,  0x42,  0x8d,  0xc4,  0x0a,  0x00,  0x92,  0x25,  0xc0,  0xcd,  0x3e,  0x8e,
+  0x94,  0x8c,  0x76,  0x82,  0x68,  0x02,  0x39,  0x5b,  0x27,  0x1e,  0x94,  0xca,
+  0x3a,  0xd3,  0x91,  0x77,  0x35,  0x00,  0x49,  0x1a,  0xe1,  0x7d,  0xcd,  0x3a,
+  0x8a,  0x47,  0x6d,  0xab,  0x40,  0x11,  0xc8,  0xd9,  0x6f,  0x61,  0x4c,  0xa2,
+  0x9d,  0x1a,  0xee,  0x6f,  0x61,  0x40,  0x1f,  0xff,  0xd9
 };
diff --git a/camera/tests/CameraServiceTest/Android.mk b/camera/tests/CameraServiceTest/Android.mk
new file mode 100644
index 0000000..8da7c1f
--- /dev/null
+++ b/camera/tests/CameraServiceTest/Android.mk
@@ -0,0 +1,22 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= CameraServiceTest.cpp
+
+LOCAL_MODULE:= CameraServiceTest
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_C_INCLUDES += \
+                frameworks/base/libs
+
+LOCAL_CFLAGS :=
+
+LOCAL_SHARED_LIBRARIES += \
+		libbinder \
+                libcutils \
+                libutils \
+                libui
+
+include $(BUILD_EXECUTABLE)
diff --git a/camera/tests/CameraServiceTest/CameraServiceTest.cpp b/camera/tests/CameraServiceTest/CameraServiceTest.cpp
new file mode 100644
index 0000000..f89d9d3
--- /dev/null
+++ b/camera/tests/CameraServiceTest/CameraServiceTest.cpp
@@ -0,0 +1,849 @@
+#define LOG_TAG "CameraServiceTest"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <ui/ISurface.h>
+#include <ui/Camera.h>
+#include <ui/CameraParameters.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/ICamera.h>
+#include <ui/ICameraClient.h>
+#include <ui/ICameraService.h>
+#include <ui/Overlay.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <utils/KeyedVector.h>
+#include <utils/Log.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+using namespace android;
+
+//
+//  Assertion and Logging utilities
+//
+#define INFO(...) \
+    do { \
+        printf(__VA_ARGS__); \
+        printf("\n"); \
+        LOGD(__VA_ARGS__); \
+    } while(0)
+
+void assert_fail(const char *file, int line, const char *func, const char *expr) {
+    INFO("assertion failed at file %s, line %d, function %s:",
+            file, line, func);
+    INFO("%s", expr);
+    exit(1);
+}
+
+void assert_eq_fail(const char *file, int line, const char *func,
+        const char *expr, int actual) {
+    INFO("assertion failed at file %s, line %d, function %s:",
+            file, line, func);
+    INFO("(expected) %s != (actual) %d", expr, actual);
+    exit(1);
+}
+
+#define ASSERT(e) \
+    do { \
+        if (!(e)) \
+            assert_fail(__FILE__, __LINE__, __func__, #e); \
+    } while(0)
+
+#define ASSERT_EQ(expected, actual) \
+    do { \
+        int _x = (actual); \
+        if (_x != (expected)) \
+            assert_eq_fail(__FILE__, __LINE__, __func__, #expected, _x); \
+    } while(0)
+
+//
+//  Holder service for pass objects between processes.
+//
+class IHolder : public IInterface {
+protected:
+    enum {
+        HOLDER_PUT = IBinder::FIRST_CALL_TRANSACTION,
+        HOLDER_GET,
+        HOLDER_CLEAR
+    };
+public:
+    DECLARE_META_INTERFACE(Holder);
+
+    virtual void put(sp<IBinder> obj) = 0;
+    virtual sp<IBinder> get() = 0;
+    virtual void clear() = 0;
+};
+
+class BnHolder : public BnInterface<IHolder> {
+    virtual status_t onTransact(uint32_t code,
+                                const Parcel& data,
+                                Parcel* reply,
+                                uint32_t flags = 0);
+};
+
+class BpHolder : public BpInterface<IHolder> {
+public:
+    BpHolder(const sp<IBinder>& impl)
+        : BpInterface<IHolder>(impl) {
+    }
+
+    virtual void put(sp<IBinder> obj) {
+        Parcel data, reply;
+        data.writeStrongBinder(obj);
+        remote()->transact(HOLDER_PUT, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual sp<IBinder> get() {
+        Parcel data, reply;
+        remote()->transact(HOLDER_GET, data, &reply);
+        return reply.readStrongBinder();
+    }
+
+    virtual void clear() {
+        Parcel data, reply;
+        remote()->transact(HOLDER_CLEAR, data, &reply);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(Holder, "CameraServiceTest.Holder");
+
+status_t BnHolder::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+    switch(code) {
+        case HOLDER_PUT: {
+            put(data.readStrongBinder());
+            return NO_ERROR;
+        } break;
+        case HOLDER_GET: {
+            reply->writeStrongBinder(get());
+            return NO_ERROR;
+        } break;
+        case HOLDER_CLEAR: {
+            clear();
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+class HolderService : public BnHolder {
+    virtual void put(sp<IBinder> obj) {
+        mObj = obj;
+    }
+    virtual sp<IBinder> get() {
+        return mObj;
+    }
+    virtual void clear() {
+        mObj.clear();
+    }
+private:
+    sp<IBinder> mObj;
+};
+
+//
+//  A mock CameraClient
+//
+class MCameraClient : public BnCameraClient {
+public:
+    virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2);
+    virtual void dataCallback(int32_t msgType, const sp<IMemory>& data);
+    virtual void dataCallbackTimestamp(nsecs_t timestamp,
+            int32_t msgType, const sp<IMemory>& data) {}
+
+    // new functions
+    void clearStat();
+    enum OP { EQ, GE, LE, GT, LT };
+    void assertNotify(int32_t msgType, OP op, int count);
+    void assertData(int32_t msgType, OP op, int count);
+    void waitNotify(int32_t msgType, OP op, int count);
+    void waitData(int32_t msgType, OP op, int count);
+    void assertDataSize(int32_t msgType, OP op, int dataSize);
+
+    void setReleaser(ICamera *releaser) {
+        mReleaser = releaser;
+    }
+private:
+    Mutex mLock;
+    Condition mCond;
+    DefaultKeyedVector<int32_t, int> mNotifyCount;
+    DefaultKeyedVector<int32_t, int> mDataCount;
+    DefaultKeyedVector<int32_t, int> mDataSize;
+    bool test(OP op, int v1, int v2);
+
+    ICamera *mReleaser;
+};
+
+void MCameraClient::clearStat() {
+    Mutex::Autolock _l(mLock);
+    mNotifyCount.clear();
+    mDataCount.clear();
+    mDataSize.clear();
+}
+
+bool MCameraClient::test(OP op, int v1, int v2) {
+    switch (op) {
+        case EQ: return v1 == v2;
+        case GT: return v1 > v2;
+        case LT: return v1 < v2;
+        case GE: return v1 >= v2;
+        case LE: return v1 <= v2;
+        default: ASSERT(0); break;
+    }
+    return false;
+}
+
+void MCameraClient::assertNotify(int32_t msgType, OP op, int count) {
+    Mutex::Autolock _l(mLock);
+    int v = mNotifyCount.valueFor(msgType);
+    ASSERT(test(op, v, count));
+}
+
+void MCameraClient::assertData(int32_t msgType, OP op, int count) {
+    Mutex::Autolock _l(mLock);
+    int v = mDataCount.valueFor(msgType);
+    ASSERT(test(op, v, count));
+}
+
+void MCameraClient::assertDataSize(int32_t msgType, OP op, int dataSize) {
+    Mutex::Autolock _l(mLock);
+    int v = mDataSize.valueFor(msgType);
+    ASSERT(test(op, v, dataSize));
+}
+
+void MCameraClient::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
+    INFO(__func__);
+    Mutex::Autolock _l(mLock);
+    ssize_t i = mNotifyCount.indexOfKey(msgType);
+    if (i < 0) {
+        mNotifyCount.add(msgType, 1);
+    } else {
+        ++mNotifyCount.editValueAt(i);
+    }
+    mCond.signal();
+}
+
+void MCameraClient::dataCallback(int32_t msgType, const sp<IMemory>& data) {
+    INFO(__func__);
+    int dataSize = data->size();
+    INFO("data type = %d, size = %d", msgType, dataSize);
+    Mutex::Autolock _l(mLock);
+    ssize_t i = mDataCount.indexOfKey(msgType);
+    if (i < 0) {
+        mDataCount.add(msgType, 1);
+        mDataSize.add(msgType, dataSize);
+    } else {
+        ++mDataCount.editValueAt(i);
+        mDataSize.editValueAt(i) = dataSize;
+    }
+    mCond.signal();
+
+    if (msgType == CAMERA_MSG_VIDEO_FRAME) {
+        ASSERT(mReleaser != NULL);
+        mReleaser->releaseRecordingFrame(data);
+    }
+}
+
+void MCameraClient::waitNotify(int32_t msgType, OP op, int count) {
+    INFO("waitNotify: %d, %d, %d", msgType, op, count);
+    Mutex::Autolock _l(mLock);
+    while (true) {
+        int v = mNotifyCount.valueFor(msgType);
+        if (test(op, v, count)) {
+            break;
+        }
+        mCond.wait(mLock);
+    }
+}
+
+void MCameraClient::waitData(int32_t msgType, OP op, int count) {
+    INFO("waitData: %d, %d, %d", msgType, op, count);
+    Mutex::Autolock _l(mLock);
+    while (true) {
+        int v = mDataCount.valueFor(msgType);
+        if (test(op, v, count)) {
+            break;
+        }
+        mCond.wait(mLock);
+    }
+}
+
+//
+//  A mock Surface
+//
+class MSurface : public BnSurface {
+public:
+    virtual status_t registerBuffers(const BufferHeap& buffers);
+    virtual void postBuffer(ssize_t offset);
+    virtual void unregisterBuffers();
+    virtual sp<OverlayRef> createOverlay(
+            uint32_t w, uint32_t h, int32_t format, int32_t orientation);
+    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage);
+
+    // new functions
+    void clearStat();
+    void waitUntil(int c0, int c1, int c2);
+
+private:
+    // check callback count
+    Condition mCond;
+    Mutex mLock;
+    int registerBuffersCount;
+    int postBufferCount;
+    int unregisterBuffersCount;
+};
+
+status_t MSurface::registerBuffers(const BufferHeap& buffers) {
+    INFO(__func__);
+    Mutex::Autolock _l(mLock);
+    ++registerBuffersCount;
+    mCond.signal();
+    return NO_ERROR;
+}
+
+void MSurface::postBuffer(ssize_t offset) {
+    // INFO(__func__);
+    Mutex::Autolock _l(mLock);
+    ++postBufferCount;
+    mCond.signal();
+}
+
+void MSurface::unregisterBuffers() {
+    INFO(__func__);
+    Mutex::Autolock _l(mLock);
+    ++unregisterBuffersCount;
+    mCond.signal();
+}
+
+sp<GraphicBuffer> MSurface::requestBuffer(int bufferIdx, int usage) {
+    INFO(__func__);
+    return NULL;
+}
+
+void MSurface::clearStat() {
+    Mutex::Autolock _l(mLock);
+    registerBuffersCount = 0;
+    postBufferCount = 0;
+    unregisterBuffersCount = 0;
+}
+
+void MSurface::waitUntil(int c0, int c1, int c2) {
+    INFO("waitUntil: %d %d %d", c0, c1, c2);
+    Mutex::Autolock _l(mLock);
+    while (true) {
+        if (registerBuffersCount >= c0 &&
+            postBufferCount >= c1 &&
+            unregisterBuffersCount >= c2) {
+            break;
+        }
+        mCond.wait(mLock);
+    }
+}
+
+sp<OverlayRef> MSurface::createOverlay(uint32_t w, uint32_t h, int32_t format,
+        int32_t orientation) {
+    // We don't expect this to be called in current hardware.
+    ASSERT(0);
+    sp<OverlayRef> dummy;
+    return dummy;
+}
+
+//
+//  Utilities to use the Holder service
+//
+sp<IHolder> getHolder() {
+    sp<IServiceManager> sm = defaultServiceManager();
+    ASSERT(sm != 0);
+    sp<IBinder> binder = sm->getService(String16("CameraServiceTest.Holder"));
+    ASSERT(binder != 0);
+    sp<IHolder> holder = interface_cast<IHolder>(binder);
+    ASSERT(holder != 0);
+    return holder;
+}
+
+void putTempObject(sp<IBinder> obj) {
+    INFO(__func__);
+    getHolder()->put(obj);
+}
+
+sp<IBinder> getTempObject() {
+    INFO(__func__);
+    return getHolder()->get();
+}
+
+void clearTempObject() {
+    INFO(__func__);
+    getHolder()->clear();
+}
+
+//
+//  Get a Camera Service
+//
+sp<ICameraService> getCameraService() {
+    sp<IServiceManager> sm = defaultServiceManager();
+    ASSERT(sm != 0);
+    sp<IBinder> binder = sm->getService(String16("media.camera"));
+    ASSERT(binder != 0);
+    sp<ICameraService> cs = interface_cast<ICameraService>(binder);
+    ASSERT(cs != 0);
+    return cs;
+}
+
+//
+// Various Connect Tests
+//
+void testConnect() {
+    INFO(__func__);
+    sp<ICameraService> cs = getCameraService();
+    sp<MCameraClient> cc = new MCameraClient();
+    sp<ICamera> c = cs->connect(cc);
+    ASSERT(c != 0);
+    c->disconnect();
+}
+
+void testAllowConnectOnceOnly() {
+    INFO(__func__);
+    sp<ICameraService> cs = getCameraService();
+    // Connect the first client.
+    sp<MCameraClient> cc = new MCameraClient();
+    sp<ICamera> c = cs->connect(cc);
+    ASSERT(c != 0);
+    // Same client -- ok.
+    ASSERT(cs->connect(cc) != 0);
+    // Different client -- not ok.
+    sp<MCameraClient> cc2 = new MCameraClient();
+    ASSERT(cs->connect(cc2) == 0);
+    c->disconnect();
+}
+
+void testReconnectFailed() {
+    INFO(__func__);
+    sp<ICamera> c = interface_cast<ICamera>(getTempObject());
+    sp<MCameraClient> cc2 = new MCameraClient();
+    ASSERT(c->connect(cc2) != NO_ERROR);
+}
+
+void testReconnectSuccess() {
+    INFO(__func__);
+    sp<ICamera> c = interface_cast<ICamera>(getTempObject());
+    sp<MCameraClient> cc = new MCameraClient();
+    ASSERT(c->connect(cc) == NO_ERROR);
+}
+
+void testLockFailed() {
+    INFO(__func__);
+    sp<ICamera> c = interface_cast<ICamera>(getTempObject());
+    ASSERT(c->lock() != NO_ERROR);
+}
+
+void testLockUnlockSuccess() {
+    INFO(__func__);
+    sp<ICamera> c = interface_cast<ICamera>(getTempObject());
+    ASSERT(c->lock() == NO_ERROR);
+    ASSERT(c->unlock() == NO_ERROR);
+}
+
+void testLockSuccess() {
+    INFO(__func__);
+    sp<ICamera> c = interface_cast<ICamera>(getTempObject());
+    ASSERT(c->lock() == NO_ERROR);
+}
+
+//
+// Run the connect tests in another process.
+//
+const char *gExecutable;
+
+struct FunctionTableEntry {
+    const char *name;
+    void (*func)();
+};
+
+FunctionTableEntry function_table[] = {
+#define ENTRY(x) {#x, &x}
+    ENTRY(testReconnectFailed),
+    ENTRY(testReconnectSuccess),
+    ENTRY(testLockUnlockSuccess),
+    ENTRY(testLockFailed),
+    ENTRY(testLockSuccess),
+#undef ENTRY
+};
+
+void runFunction(const char *tag) {
+    INFO("runFunction: %s", tag);
+    int entries = sizeof(function_table) / sizeof(function_table[0]);
+    for (int i = 0; i < entries; i++) {
+        if (strcmp(function_table[i].name, tag) == 0) {
+            (*function_table[i].func)();
+            return;
+        }
+    }
+    ASSERT(0);
+}
+
+void runInAnotherProcess(const char *tag) {
+    pid_t pid = fork();
+    if (pid == 0) {
+        execlp(gExecutable, gExecutable, tag, NULL);
+        ASSERT(0);
+    } else {
+        int status;
+        ASSERT_EQ(pid, wait(&status));
+        ASSERT_EQ(0, status);
+    }
+}
+
+void testReconnect() {
+    INFO(__func__);
+    sp<ICameraService> cs = getCameraService();
+    sp<MCameraClient> cc = new MCameraClient();
+    sp<ICamera> c = cs->connect(cc);
+    ASSERT(c != 0);
+    // Reconnect to the same client -- ok.
+    ASSERT(c->connect(cc) == NO_ERROR);
+    // Reconnect to a different client (but the same pid) -- ok.
+    sp<MCameraClient> cc2 = new MCameraClient();
+    ASSERT(c->connect(cc2) == NO_ERROR);
+    c->disconnect();
+    cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+}
+
+void testLockUnlock() {
+    sp<ICameraService> cs = getCameraService();
+    sp<MCameraClient> cc = new MCameraClient();
+    sp<ICamera> c = cs->connect(cc);
+    ASSERT(c != 0);
+    // We can lock as many times as we want.
+    ASSERT(c->lock() == NO_ERROR);
+    ASSERT(c->lock() == NO_ERROR);
+    // Lock from a different process -- not ok.
+    putTempObject(c->asBinder());
+    runInAnotherProcess("testLockFailed");
+    // Unlock then lock from a different process -- ok.
+    ASSERT(c->unlock() == NO_ERROR);
+    runInAnotherProcess("testLockUnlockSuccess");
+    // Unlock then lock from a different process -- ok.
+    runInAnotherProcess("testLockSuccess");
+    c->disconnect();
+    clearTempObject();
+}
+
+void testReconnectFromAnotherProcess() {
+    INFO(__func__);
+
+    sp<ICameraService> cs = getCameraService();
+    sp<MCameraClient> cc = new MCameraClient();
+    sp<ICamera> c = cs->connect(cc);
+    ASSERT(c != 0);
+    // Reconnect from a different process -- not ok.
+    putTempObject(c->asBinder());
+    runInAnotherProcess("testReconnectFailed");
+    // Unlock then reconnect from a different process -- ok.
+    ASSERT(c->unlock() == NO_ERROR);
+    runInAnotherProcess("testReconnectSuccess");
+    c->disconnect();
+    clearTempObject();
+}
+
+// We need to flush the command buffer after the reference
+// to ICamera is gone. The sleep is for the server to run
+// the destructor for it.
+static void flushCommands() {
+    IPCThreadState::self()->flushCommands();
+    usleep(200000);  // 200ms
+}
+
+// Run a test case
+#define RUN(class_name) do { \
+    { \
+        INFO(#class_name); \
+        class_name instance; \
+        instance.run(); \
+    } \
+    flushCommands(); \
+} while(0)
+
+// Base test case after the the camera is connected.
+class AfterConnect {
+protected:
+    sp<ICameraService> cs;
+    sp<MCameraClient> cc;
+    sp<ICamera> c;
+
+    AfterConnect() {
+        cs = getCameraService();
+        cc = new MCameraClient();
+        c = cs->connect(cc);
+        ASSERT(c != 0);
+    }
+
+    ~AfterConnect() {
+        c.clear();
+        cc.clear();
+        cs.clear();
+    }
+};
+
+class TestSetPreviewDisplay : public AfterConnect {
+public:
+    void run() {
+        sp<MSurface> surface = new MSurface();
+        ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
+        c->disconnect();
+        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+    }
+};
+
+class TestStartPreview : public AfterConnect {
+public:
+    void run() {
+        sp<MSurface> surface = new MSurface();
+        ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
+
+        ASSERT(c->startPreview() == NO_ERROR);
+        ASSERT(c->previewEnabled() == true);
+
+        surface->waitUntil(1, 10, 0); // needs 1 registerBuffers and 10 postBuffer
+        surface->clearStat();
+
+        c->disconnect();
+        // TODO: CameraService crashes for this. Fix it.
+#if 0
+        sp<MSurface> another_surface = new MSurface();
+        c->setPreviewDisplay(another_surface);  // just to make sure unregisterBuffers
+                                                // is called.
+        surface->waitUntil(0, 0, 1);  // needs unregisterBuffers
+#endif
+        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+    }
+};
+
+class TestStartPreviewWithoutDisplay : AfterConnect {
+public:
+    void run() {
+        ASSERT(c->startPreview() == NO_ERROR);
+        ASSERT(c->previewEnabled() == true);
+        c->disconnect();
+        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+    }
+};
+
+// Base test case after the the camera is connected and the preview is started.
+class AfterStartPreview : public AfterConnect {
+protected:
+    sp<MSurface> surface;
+
+    AfterStartPreview() {
+        surface = new MSurface();
+        ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
+        ASSERT(c->startPreview() == NO_ERROR);
+    }
+
+    ~AfterStartPreview() {
+        surface.clear();
+    }
+};
+
+class TestAutoFocus : public AfterStartPreview {
+public:
+    void run() {
+        cc->assertNotify(CAMERA_MSG_FOCUS, MCameraClient::EQ, 0);
+        c->autoFocus();
+        cc->waitNotify(CAMERA_MSG_FOCUS, MCameraClient::EQ, 1);
+        c->disconnect();
+        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+    }
+};
+
+class TestStopPreview : public AfterStartPreview {
+public:
+    void run() {
+        ASSERT(c->previewEnabled() == true);
+        c->stopPreview();
+        ASSERT(c->previewEnabled() == false);
+        c->disconnect();
+        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+    }
+};
+
+class TestTakePicture: public AfterStartPreview {
+public:
+    void run() {
+        ASSERT(c->takePicture() == NO_ERROR);
+        cc->waitNotify(CAMERA_MSG_SHUTTER, MCameraClient::EQ, 1);
+        cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
+        cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
+        c->stopPreview();
+#if 1  // TODO: It crashes if we don't have this. Fix it.
+        usleep(100000);
+#endif
+        c->disconnect();
+        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+    }
+};
+
+class TestTakeMultiplePictures: public AfterStartPreview {
+public:
+    void run() {
+        for (int i = 0; i < 10; i++) {
+            cc->clearStat();
+            ASSERT(c->takePicture() == NO_ERROR);
+            cc->waitNotify(CAMERA_MSG_SHUTTER, MCameraClient::EQ, 1);
+            cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
+            cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
+            usleep(100000);  // 100ms
+        }
+        c->disconnect();
+        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+    }
+};
+
+class TestGetParameters: public AfterStartPreview {
+public:
+    void run() {
+        String8 param_str = c->getParameters();
+        INFO(param_str);
+    }
+};
+
+class TestPictureSize : public AfterStartPreview {
+public:
+    void checkOnePicture(int w, int h) {
+        const float rate = 0.5;  // byte per pixel limit
+        int pixels = w * h;
+
+        CameraParameters param(c->getParameters());
+        param.setPictureSize(w, h);
+        c->setParameters(param.flatten());
+
+        cc->clearStat();
+        ASSERT(c->takePicture() == NO_ERROR);
+        cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
+        cc->assertDataSize(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, pixels*3/2);
+        cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
+        cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::LT,
+                int(pixels * rate));
+        cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::GT, 0);
+        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+        usleep(100000);  // 100ms
+    }
+
+    void run() {
+        checkOnePicture(2048, 1536);
+        checkOnePicture(1600, 1200);
+        checkOnePicture(1024, 768);
+    }
+};
+
+class TestPreviewCallbackFlag : public AfterConnect {
+public:
+    void run() {
+        sp<MSurface> surface = new MSurface();
+        ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
+
+        // Try all flag combinations.
+        for (int v = 0; v < 8; v++) {
+            cc->clearStat();
+            c->setPreviewCallbackFlag(v);
+            ASSERT(c->previewEnabled() == false);
+            ASSERT(c->startPreview() == NO_ERROR);
+            ASSERT(c->previewEnabled() == true);
+            sleep(2);
+            c->stopPreview();
+            if ((v & FRAME_CALLBACK_FLAG_ENABLE_MASK) == 0) {
+                cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 0);
+            } else {
+                if ((v & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) == 0) {
+                    cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::GE, 10);
+                } else {
+                    cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 1);
+                }
+            }
+        }
+    }
+};
+
+class TestRecording : public AfterConnect {
+public:
+    void run() {
+        ASSERT(c->recordingEnabled() == false);
+        sp<MSurface> surface = new MSurface();
+        ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
+        c->setPreviewCallbackFlag(FRAME_CALLBACK_FLAG_ENABLE_MASK);
+        cc->setReleaser(c.get());
+        c->startRecording();
+        ASSERT(c->recordingEnabled() == true);
+        sleep(2);
+        c->stopRecording();
+        cc->setReleaser(NULL);
+        cc->assertData(CAMERA_MSG_VIDEO_FRAME, MCameraClient::GE, 10);
+    }
+};
+
+class TestPreviewSize : public AfterStartPreview {
+public:
+    void checkOnePicture(int w, int h) {
+        int size = w*h*3/2;  // should read from parameters
+
+        c->stopPreview();
+
+        CameraParameters param(c->getParameters());
+        param.setPreviewSize(w, h);
+        c->setPreviewCallbackFlag(FRAME_CALLBACK_FLAG_ENABLE_MASK);
+        c->setParameters(param.flatten());
+
+        c->startPreview();
+
+        cc->clearStat();
+        cc->waitData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::GE, 1);
+        cc->assertDataSize(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, size);
+    }
+
+    void run() {
+        checkOnePicture(480, 320);
+        checkOnePicture(352, 288);
+        checkOnePicture(176, 144);
+    }
+};
+
+void runHolderService() {
+    defaultServiceManager()->addService(
+            String16("CameraServiceTest.Holder"), new HolderService());
+    ProcessState::self()->startThreadPool();
+}
+
+int main(int argc, char **argv)
+{
+    if (argc != 1) {
+        runFunction(argv[1]);
+        return 0;
+    }
+    INFO("CameraServiceTest start");
+    gExecutable = argv[0];
+    runHolderService();
+
+    testConnect();                              flushCommands();
+    testAllowConnectOnceOnly();                 flushCommands();
+    testReconnect();                            flushCommands();
+    testLockUnlock();                           flushCommands();
+    testReconnectFromAnotherProcess();          flushCommands();
+
+    RUN(TestSetPreviewDisplay);
+    RUN(TestStartPreview);
+    RUN(TestStartPreviewWithoutDisplay);
+    RUN(TestAutoFocus);
+    RUN(TestStopPreview);
+    RUN(TestTakePicture);
+    RUN(TestTakeMultiplePictures);
+    RUN(TestGetParameters);
+    RUN(TestPictureSize);
+    RUN(TestPreviewCallbackFlag);
+    RUN(TestRecording);
+    RUN(TestPreviewSize);
+}
diff --git a/cleanspec.mk b/cleanspec.mk
new file mode 100644
index 0000000..683e303
--- /dev/null
+++ b/cleanspec.mk
@@ -0,0 +1 @@
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/os/IDropBoxService.java)
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c
index ba74c78..4426874 100644
--- a/cmds/keystore/keystore.c
+++ b/cmds/keystore/keystore.c
@@ -163,19 +163,19 @@
 static int8_t encrypt_blob(char *name, AES_KEY *aes_key)
 {
     uint8_t vector[AES_BLOCK_SIZE];
-    int length = blob.length;
+    int length;
     int fd;
 
     if (read(the_entropy, vector, AES_BLOCK_SIZE) != AES_BLOCK_SIZE) {
         return SYSTEM_ERROR;
     }
 
-    length += blob.value - blob.digested;
-    blob.length = htonl(blob.length);
-    MD5(blob.digested, length, blob.digest);
-
-    length += blob.digested - blob.encrypted;
+    length = blob.length + blob.value - blob.encrypted;
     length = (length + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE * AES_BLOCK_SIZE;
+
+    blob.length = htonl(blob.length);
+    MD5(blob.digested, length - (blob.digested - blob.encrypted), blob.digest);
+
     memcpy(vector, blob.vector, AES_BLOCK_SIZE);
     AES_cbc_encrypt(blob.encrypted, blob.encrypted, length, aes_key, vector,
                     AES_ENCRYPT);
@@ -184,11 +184,9 @@
     length += blob.encrypted - (uint8_t *)&blob;
 
     fd = open(".tmp", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
-    if (fd == -1 || write(fd, &blob, length) != length) {
-        return SYSTEM_ERROR;
-    }
+    length -= write(fd, &blob, length);
     close(fd);
-    return rename(".tmp", name) ? SYSTEM_ERROR : NO_ERROR;
+    return (length || rename(".tmp", name)) ? SYSTEM_ERROR : NO_ERROR;
 }
 
 static int8_t decrypt_blob(char *name, AES_KEY *aes_key)
@@ -210,14 +208,15 @@
     AES_cbc_encrypt(blob.encrypted, blob.encrypted, length, aes_key,
                     blob.vector, AES_DECRYPT);
     length -= blob.digested - blob.encrypted;
-    if (!memcmp(blob.digest, MD5(blob.digested, length, NULL),
-                MD5_DIGEST_LENGTH)) {
+    if (memcmp(blob.digest, MD5(blob.digested, length, NULL),
+               MD5_DIGEST_LENGTH)) {
         return VALUE_CORRUPTED;
     }
 
     length -= blob.value - blob.digested;
     blob.length = ntohl(blob.length);
-    return (length < blob.length) ? VALUE_CORRUPTED : NO_ERROR;
+    return (blob.length < 0 || blob.length > length) ? VALUE_CORRUPTED :
+           NO_ERROR;
 }
 
 /* Here are the actions. Each of them is a function without arguments. All
diff --git a/common/Android.mk b/common/Android.mk
new file mode 100644
index 0000000..76091eb
--- /dev/null
+++ b/common/Android.mk
@@ -0,0 +1,29 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+# Note: the source code is in java/, not src/, because this code is also part of
+# the framework library, and build/core/pathmap.mk expects a java/ subdirectory.
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-common
+LOCAL_SRC_FILES := $(call all-java-files-under, java)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Include this library in the build server's output directory
+$(call dist-for-goals, droid, $(LOCAL_BUILT_MODULE):android-common.jar)
+
+# Build the test package
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/common/java/com/android/common/AndroidHttpClient.java b/common/java/com/android/common/AndroidHttpClient.java
new file mode 100644
index 0000000..99faf6e
--- /dev/null
+++ b/common/java/com/android/common/AndroidHttpClient.java
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpResponse;
+import org.apache.http.entity.AbstractHttpEntity;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.protocol.ClientContext;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.params.HttpClientParams;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.client.RequestWrapper;
+import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpProtocolParams;
+import org.apache.http.protocol.BasicHttpProcessor;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+import java.net.URI;
+import java.security.KeyManagementException;
+
+import android.content.ContentResolver;
+import android.os.Looper;
+import android.os.SystemProperties;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * Subclass of the Apache {@link DefaultHttpClient} that is configured with
+ * reasonable default settings and registered schemes for Android, and
+ * also lets the user add {@link HttpRequestInterceptor} classes.
+ * Don't create this directly, use the {@link #newInstance} factory method.
+ *
+ * <p>This client processes cookies but does not retain them by default.
+ * To retain cookies, simply add a cookie store to the HttpContext:</p>
+ *
+ * <pre>context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);</pre>
+ * 
+ * {@hide}
+ */
+public final class AndroidHttpClient implements HttpClient {
+        
+    // Gzip of data shorter than this probably won't be worthwhile
+    public static long DEFAULT_SYNC_MIN_GZIP_BYTES = 256;
+
+    private static final String TAG = "AndroidHttpClient";
+
+
+    /** Interceptor throws an exception if the executing thread is blocked */
+    private static final HttpRequestInterceptor sThreadCheckInterceptor =
+            new HttpRequestInterceptor() {
+        public void process(HttpRequest request, HttpContext context) {
+            // Prevent the HttpRequest from being sent on the main thread
+            if (Looper.myLooper() != null && Looper.myLooper() == Looper.getMainLooper() ) {
+                throw new RuntimeException("This thread forbids HTTP requests");
+            }
+        }
+    };
+
+    /**
+     * Create a new HttpClient with reasonable defaults (which you can update).
+     *
+     * @param userAgent to report in your HTTP requests.
+     * @param sessionCache persistent session cache
+     * @return AndroidHttpClient for you to use for all your requests.
+     */
+    public static AndroidHttpClient newInstance(String userAgent,
+            SSLClientSessionCache sessionCache) {
+        HttpParams params = new BasicHttpParams();
+
+        // Turn off stale checking.  Our connections break all the time anyway,
+        // and it's not worth it to pay the penalty of checking every time.
+        HttpConnectionParams.setStaleCheckingEnabled(params, false);
+
+        // Default connection and socket timeout of 20 seconds.  Tweak to taste.
+        HttpConnectionParams.setConnectionTimeout(params, 20 * 1000);
+        HttpConnectionParams.setSoTimeout(params, 20 * 1000);
+        HttpConnectionParams.setSocketBufferSize(params, 8192);
+
+        // Don't handle redirects -- return them to the caller.  Our code
+        // often wants to re-POST after a redirect, which we must do ourselves.
+        HttpClientParams.setRedirecting(params, false);
+
+        // Set the specified user agent and register standard protocols.
+        HttpProtocolParams.setUserAgent(params, userAgent);
+        SchemeRegistry schemeRegistry = new SchemeRegistry();
+        schemeRegistry.register(new Scheme("http",
+                PlainSocketFactory.getSocketFactory(), 80));
+        schemeRegistry.register(new Scheme("https",
+                socketFactoryWithCache(sessionCache), 443));
+
+        ClientConnectionManager manager =
+                new ThreadSafeClientConnManager(params, schemeRegistry);
+
+        // We use a factory method to modify superclass initialization
+        // parameters without the funny call-a-static-method dance.
+        return new AndroidHttpClient(manager, params);
+    }
+
+    /**
+     * Returns a socket factory backed by the given persistent session cache.
+     *
+     * @param sessionCache to retrieve sessions from, null for no cache
+     */
+    private static SSLSocketFactory socketFactoryWithCache(
+            SSLClientSessionCache sessionCache) {
+        if (sessionCache == null) {
+            // Use the default factory which doesn't support persistent
+            // caching.
+            return SSLSocketFactory.getSocketFactory();
+        }
+
+        // Create a new SSL context backed by the cache.
+        // TODO: Keep a weak *identity* hash map of caches to engines. In the
+        // mean time, if we have two engines for the same cache, they'll still
+        // share sessions but will have to do so through the persistent cache.
+        SSLContextImpl sslContext = new SSLContextImpl();
+        try {
+            sslContext.engineInit(null, null, null, sessionCache, null);
+        } catch (KeyManagementException e) {
+            throw new AssertionError(e);
+        }
+        return new SSLSocketFactory(sslContext.engineGetSocketFactory());
+    }
+
+    /**
+     * Create a new HttpClient with reasonable defaults (which you can update).
+     * @param userAgent to report in your HTTP requests.
+     * @return AndroidHttpClient for you to use for all your requests.
+     */
+    public static AndroidHttpClient newInstance(String userAgent) {
+        return newInstance(userAgent, null /* session cache */);
+    }
+
+    private final HttpClient delegate;
+
+    private RuntimeException mLeakedException = new IllegalStateException(
+            "AndroidHttpClient created and never closed");
+
+    private AndroidHttpClient(ClientConnectionManager ccm, HttpParams params) {
+        this.delegate = new DefaultHttpClient(ccm, params) {
+            @Override
+            protected BasicHttpProcessor createHttpProcessor() {
+                // Add interceptor to prevent making requests from main thread.
+                BasicHttpProcessor processor = super.createHttpProcessor();
+                processor.addRequestInterceptor(sThreadCheckInterceptor);
+                processor.addRequestInterceptor(new CurlLogger());
+
+                return processor;
+            }
+
+            @Override
+            protected HttpContext createHttpContext() {
+                // Same as DefaultHttpClient.createHttpContext() minus the
+                // cookie store.
+                HttpContext context = new BasicHttpContext();
+                context.setAttribute(
+                        ClientContext.AUTHSCHEME_REGISTRY,
+                        getAuthSchemes());
+                context.setAttribute(
+                        ClientContext.COOKIESPEC_REGISTRY,
+                        getCookieSpecs());
+                context.setAttribute(
+                        ClientContext.CREDS_PROVIDER,
+                        getCredentialsProvider());
+                return context;
+            }
+        };
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        super.finalize();
+        if (mLeakedException != null) {
+            Log.e(TAG, "Leak found", mLeakedException);
+            mLeakedException = null;
+        }
+    }
+
+    /**
+     * Modifies a request to indicate to the server that we would like a
+     * gzipped response.  (Uses the "Accept-Encoding" HTTP header.)
+     * @param request the request to modify
+     * @see #getUngzippedContent
+     */
+    public static void modifyRequestToAcceptGzipResponse(HttpRequest request) {
+        request.addHeader("Accept-Encoding", "gzip");
+    }
+
+    /**
+     * Gets the input stream from a response entity.  If the entity is gzipped
+     * then this will get a stream over the uncompressed data.
+     *
+     * @param entity the entity whose content should be read
+     * @return the input stream to read from
+     * @throws IOException
+     */
+    public static InputStream getUngzippedContent(HttpEntity entity)
+            throws IOException {
+        InputStream responseStream = entity.getContent();
+        if (responseStream == null) return responseStream;
+        Header header = entity.getContentEncoding();
+        if (header == null) return responseStream;
+        String contentEncoding = header.getValue();
+        if (contentEncoding == null) return responseStream;
+        if (contentEncoding.contains("gzip")) responseStream
+                = new GZIPInputStream(responseStream);
+        return responseStream;
+    }
+
+    /**
+     * Release resources associated with this client.  You must call this,
+     * or significant resources (sockets and memory) may be leaked.
+     */
+    public void close() {
+        if (mLeakedException != null) {
+            getConnectionManager().shutdown();
+            mLeakedException = null;
+        }
+    }
+
+    public HttpParams getParams() {
+        return delegate.getParams();
+    }
+
+    public ClientConnectionManager getConnectionManager() {
+        return delegate.getConnectionManager();
+    }
+
+    public HttpResponse execute(HttpUriRequest request) throws IOException {
+        return delegate.execute(request);
+    }
+
+    public HttpResponse execute(HttpUriRequest request, HttpContext context)
+            throws IOException {
+        return delegate.execute(request, context);
+    }
+
+    public HttpResponse execute(HttpHost target, HttpRequest request)
+            throws IOException {
+        return delegate.execute(target, request);
+    }
+
+    public HttpResponse execute(HttpHost target, HttpRequest request,
+            HttpContext context) throws IOException {
+        return delegate.execute(target, request, context);
+    }
+
+    public <T> T execute(HttpUriRequest request, 
+            ResponseHandler<? extends T> responseHandler)
+            throws IOException, ClientProtocolException {
+        return delegate.execute(request, responseHandler);
+    }
+
+    public <T> T execute(HttpUriRequest request,
+            ResponseHandler<? extends T> responseHandler, HttpContext context)
+            throws IOException, ClientProtocolException {
+        return delegate.execute(request, responseHandler, context);
+    }
+
+    public <T> T execute(HttpHost target, HttpRequest request,
+            ResponseHandler<? extends T> responseHandler) throws IOException,
+            ClientProtocolException {
+        return delegate.execute(target, request, responseHandler);
+    }
+
+    public <T> T execute(HttpHost target, HttpRequest request,
+            ResponseHandler<? extends T> responseHandler, HttpContext context)
+            throws IOException, ClientProtocolException {
+        return delegate.execute(target, request, responseHandler, context);
+    }
+
+    /**
+     * Compress data to send to server.
+     * Creates a Http Entity holding the gzipped data.
+     * The data will not be compressed if it is too short.
+     * @param data The bytes to compress
+     * @return Entity holding the data
+     */
+    public static AbstractHttpEntity getCompressedEntity(byte data[], ContentResolver resolver)
+            throws IOException {
+        AbstractHttpEntity entity;
+        if (data.length < getMinGzipSize(resolver)) {
+            entity = new ByteArrayEntity(data);
+        } else {
+            ByteArrayOutputStream arr = new ByteArrayOutputStream();
+            OutputStream zipper = new GZIPOutputStream(arr);
+            zipper.write(data);
+            zipper.close();
+            entity = new ByteArrayEntity(arr.toByteArray());
+            entity.setContentEncoding("gzip");
+        }
+        return entity;
+    }
+
+    /**
+     * Retrieves the minimum size for compressing data.
+     * Shorter data will not be compressed.
+     */
+    public static long getMinGzipSize(ContentResolver resolver) {
+        return Settings.Secure.getLong(resolver,
+                                       Settings.Secure.SYNC_MIN_GZIP_BYTES,
+                                       DEFAULT_SYNC_MIN_GZIP_BYTES);
+    }
+
+    /* cURL logging support. */
+
+    /**
+     * Logging tag and level.
+     */
+    private static class LoggingConfiguration {
+
+        private final String tag;
+        private final int level;
+
+        private LoggingConfiguration(String tag, int level) {
+            this.tag = tag;
+            this.level = level;
+        }
+
+        /**
+         * Returns true if logging is turned on for this configuration.
+         */
+        private boolean isLoggable() {
+            return Log.isLoggable(tag, level);
+        }
+
+        /**
+         * Returns true if auth logging is turned on for this configuration.  Can only be set on
+         * insecure devices.
+         */
+        private boolean isAuthLoggable() {
+            String secure = SystemProperties.get("ro.secure");
+            return "0".equals(secure) && Log.isLoggable(tag + "-auth", level);
+        }
+
+        /**
+         * Prints a message using this configuration.
+         */
+        private void println(String message) {
+            Log.println(level, tag, message);
+        }
+    }
+
+    /** cURL logging configuration. */
+    private volatile LoggingConfiguration curlConfiguration;
+
+    /**
+     * Enables cURL request logging for this client.
+     *
+     * @param name to log messages with
+     * @param level at which to log messages (see {@link android.util.Log})
+     */
+    public void enableCurlLogging(String name, int level) {
+        if (name == null) {
+            throw new NullPointerException("name");
+        }
+        if (level < Log.VERBOSE || level > Log.ASSERT) {
+            throw new IllegalArgumentException("Level is out of range ["
+                + Log.VERBOSE + ".." + Log.ASSERT + "]");    
+        }
+
+        curlConfiguration = new LoggingConfiguration(name, level);
+    }
+
+    /**
+     * Disables cURL logging for this client.
+     */
+    public void disableCurlLogging() {
+        curlConfiguration = null;
+    }
+
+    /**
+     * Logs cURL commands equivalent to requests.
+     */
+    private class CurlLogger implements HttpRequestInterceptor {
+        public void process(HttpRequest request, HttpContext context)
+                throws HttpException, IOException {
+            LoggingConfiguration configuration = curlConfiguration;
+            if (configuration != null
+                    && configuration.isLoggable()
+                    && request instanceof HttpUriRequest) {
+                configuration.println(toCurl((HttpUriRequest) request,
+                        configuration.isAuthLoggable()));
+            }
+        }
+    }
+
+    /**
+     * Generates a cURL command equivalent to the given request.
+     */
+    private static String toCurl(HttpUriRequest request, boolean logAuthToken) throws IOException {
+        StringBuilder builder = new StringBuilder();
+
+        builder.append("curl ");
+
+        for (Header header: request.getAllHeaders()) {
+            if (!logAuthToken
+                    && (header.getName().equals("Authorization") ||
+                        header.getName().equals("Cookie"))) {
+                continue;
+            }
+            builder.append("--header \"");
+            builder.append(header.toString().trim());
+            builder.append("\" ");
+        }
+
+        URI uri = request.getURI();
+
+        // If this is a wrapped request, use the URI from the original
+        // request instead. getURI() on the wrapper seems to return a
+        // relative URI. We want an absolute URI.
+        if (request instanceof RequestWrapper) {
+            HttpRequest original = ((RequestWrapper) request).getOriginal();
+            if (original instanceof HttpUriRequest) {
+                uri = ((HttpUriRequest) original).getURI();
+            }
+        }
+
+        builder.append("\"");
+        builder.append(uri);
+        builder.append("\"");
+
+        if (request instanceof HttpEntityEnclosingRequest) {
+            HttpEntityEnclosingRequest entityRequest =
+                    (HttpEntityEnclosingRequest) request;
+            HttpEntity entity = entityRequest.getEntity();
+            if (entity != null && entity.isRepeatable()) {
+                if (entity.getContentLength() < 1024) {
+                    ByteArrayOutputStream stream = new ByteArrayOutputStream();
+                    entity.writeTo(stream);
+                    String entityString = stream.toString();
+
+                    // TODO: Check the content type, too.
+                    builder.append(" --data-ascii \"")
+                            .append(entityString)
+                            .append("\"");
+                } else {
+                    builder.append(" [TOO MUCH DATA TO INCLUDE]");
+                }
+            }
+        }
+
+        return builder.toString();
+    }
+}
diff --git a/common/java/com/android/common/ArrayListCursor.java b/common/java/com/android/common/ArrayListCursor.java
new file mode 100644
index 0000000..cc1fe27
--- /dev/null
+++ b/common/java/com/android/common/ArrayListCursor.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+import android.database.AbstractCursor;
+import android.database.CursorWindow;
+
+import java.lang.System;
+import java.util.ArrayList;
+
+/**
+ * A convenience class that presents a two-dimensional ArrayList
+ * as a Cursor.
+ * @deprecated This is has been replaced by MatrixCursor.
+*/
+public class ArrayListCursor extends AbstractCursor {
+    private String[] mColumnNames;
+    private ArrayList<Object>[] mRows;
+
+    @SuppressWarnings({"unchecked"})
+    public ArrayListCursor(String[] columnNames, ArrayList<ArrayList> rows) {
+        int colCount = columnNames.length;
+        boolean foundID = false;
+        // Add an _id column if not in columnNames
+        for (int i = 0; i < colCount; ++i) {
+            if (columnNames[i].compareToIgnoreCase("_id") == 0) {
+                mColumnNames = columnNames;
+                foundID = true;
+                break;
+            }
+        }
+
+        if (!foundID) {
+            mColumnNames = new String[colCount + 1];
+            System.arraycopy(columnNames, 0, mColumnNames, 0, columnNames.length);
+            mColumnNames[colCount] = "_id";
+        }
+
+        int rowCount = rows.size();
+        mRows = new ArrayList[rowCount];
+
+        for (int i = 0; i < rowCount; ++i) {
+            mRows[i] = rows.get(i);
+            if (!foundID) {
+                mRows[i].add(i);
+            }
+        }
+    }
+
+    @Override
+    public void fillWindow(int position, CursorWindow window) {
+        if (position < 0 || position > getCount()) {
+            return;
+        }
+
+        window.acquireReference();
+        try {
+            int oldpos = mPos;
+            mPos = position - 1;
+            window.clear();
+            window.setStartPosition(position);
+            int columnNum = getColumnCount();
+            window.setNumColumns(columnNum);
+            while (moveToNext() && window.allocRow()) {
+                for (int i = 0; i < columnNum; i++) {
+                    final Object data = mRows[mPos].get(i);
+                    if (data != null) {
+                        if (data instanceof byte[]) {
+                            byte[] field = (byte[]) data;
+                            if (!window.putBlob(field, mPos, i)) {
+                                window.freeLastRow();
+                                break;
+                            }
+                        } else {
+                            String field = data.toString();
+                            if (!window.putString(field, mPos, i)) {
+                                window.freeLastRow();
+                                break;
+                            }
+                        }
+                    } else {
+                        if (!window.putNull(mPos, i)) {
+                            window.freeLastRow();
+                            break;
+                        }
+                    }
+                }
+            }
+
+            mPos = oldpos;
+        } catch (IllegalStateException e){
+            // simply ignore it
+        } finally {
+            window.releaseReference();
+        }
+    }
+
+    @Override
+    public int getCount() {
+        return mRows.length;
+    }
+
+    @Override
+    public boolean deleteRow() {
+        return false;
+    }
+
+    @Override
+    public String[] getColumnNames() {
+        return mColumnNames;
+    }
+
+    @Override
+    public byte[] getBlob(int columnIndex) {
+        return (byte[]) mRows[mPos].get(columnIndex);
+    }
+
+    @Override
+    public String getString(int columnIndex) {
+        Object cell = mRows[mPos].get(columnIndex);
+        return (cell == null) ? null : cell.toString();
+    }
+
+    @Override
+    public short getShort(int columnIndex) {
+        Number num = (Number) mRows[mPos].get(columnIndex);
+        return num.shortValue();
+    }
+
+    @Override
+    public int getInt(int columnIndex) {
+        Number num = (Number) mRows[mPos].get(columnIndex);
+        return num.intValue();
+    }
+
+    @Override
+    public long getLong(int columnIndex) {
+        Number num = (Number) mRows[mPos].get(columnIndex);
+        return num.longValue();
+    }
+
+    @Override
+    public float getFloat(int columnIndex) {
+        Number num = (Number) mRows[mPos].get(columnIndex);
+        return num.floatValue();
+    }
+
+    @Override
+    public double getDouble(int columnIndex) {
+        Number num = (Number) mRows[mPos].get(columnIndex);
+        return num.doubleValue();
+    }
+
+    @Override
+    public boolean isNull(int columnIndex) {
+        return mRows[mPos].get(columnIndex) == null;
+    }
+}
diff --git a/common/java/com/android/common/DNParser.java b/common/java/com/android/common/DNParser.java
new file mode 100644
index 0000000..32d57c0
--- /dev/null
+++ b/common/java/com/android/common/DNParser.java
@@ -0,0 +1,447 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package com.android.common;
+
+import android.util.Log;
+
+import java.io.IOException;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * A simple distinguished name(DN) parser.
+ *
+ * <p>This class is based on org.apache.harmony.security.x509.DNParser.  It's customized to remove
+ * external references which are unnecessary for our requirements.
+ *
+ * <p>This class is only meant for extracting a string value from a DN.  e.g. it doesn't support
+ * values in the hex-string style.
+ *
+ * <p>This class is used by {@link DomainNameValidator} only.  However, in order to make this
+ * class visible from unit tests, it's made public.
+ */
+public final class DNParser {
+    private static final String TAG = "DNParser";
+
+    /** DN to be parsed. */
+    private final String dn;
+
+    // length of distinguished name string
+    private final int length;
+
+    private int pos, beg, end;
+
+    // tmp vars to store positions of the currently parsed item
+    private int cur;
+
+    // distinguished name chars
+    private char[] chars;
+
+    /**
+     * Exception message thrown when we failed to parse DN, which shouldn't happen because we
+     * only handle DNs that {@link X500Principal#getName} returns, which shouldn't be malformed.
+     */
+    private static final String ERROR_PARSE_ERROR = "Failed to parse DN";
+
+    /**
+     * Constructor.
+     *
+     * @param principal - {@link X500Principal} to be parsed
+     */
+    public DNParser(X500Principal principal) {
+        this.dn = principal.getName(X500Principal.RFC2253);
+        this.length = dn.length();
+    }
+
+    // gets next attribute type: (ALPHA 1*keychar) / oid
+    private String nextAT() throws IOException {
+
+        // skip preceding space chars, they can present after
+        // comma or semicolon (compatibility with RFC 1779)
+        for (; pos < length && chars[pos] == ' '; pos++) {
+        }
+        if (pos == length) {
+            return null; // reached the end of DN
+        }
+
+        // mark the beginning of attribute type
+        beg = pos;
+
+        // attribute type chars
+        pos++;
+        for (; pos < length && chars[pos] != '=' && chars[pos] != ' '; pos++) {
+            // we don't follow exact BNF syntax here:
+            // accept any char except space and '='
+        }
+        if (pos >= length) {
+            // unexpected end of DN
+            throw new IOException(ERROR_PARSE_ERROR);
+        }
+
+        // mark the end of attribute type
+        end = pos;
+
+        // skip trailing space chars between attribute type and '='
+        // (compatibility with RFC 1779)
+        if (chars[pos] == ' ') {
+            for (; pos < length && chars[pos] != '=' && chars[pos] == ' '; pos++) {
+            }
+
+            if (chars[pos] != '=' || pos == length) {
+                // unexpected end of DN
+                throw new IOException(ERROR_PARSE_ERROR);
+            }
+        }
+
+        pos++; //skip '=' char
+
+        // skip space chars between '=' and attribute value
+        // (compatibility with RFC 1779)
+        for (; pos < length && chars[pos] == ' '; pos++) {
+        }
+
+        // in case of oid attribute type skip its prefix: "oid." or "OID."
+        // (compatibility with RFC 1779)
+        if ((end - beg > 4) && (chars[beg + 3] == '.')
+                && (chars[beg] == 'O' || chars[beg] == 'o')
+                && (chars[beg + 1] == 'I' || chars[beg + 1] == 'i')
+                && (chars[beg + 2] == 'D' || chars[beg + 2] == 'd')) {
+            beg += 4;
+        }
+
+        return new String(chars, beg, end - beg);
+    }
+
+    // gets quoted attribute value: QUOTATION *( quotechar / pair ) QUOTATION
+    private String quotedAV() throws IOException {
+
+        pos++;
+        beg = pos;
+        end = beg;
+        while (true) {
+
+            if (pos == length) {
+                // unexpected end of DN
+                throw new IOException(ERROR_PARSE_ERROR);
+            }
+
+            if (chars[pos] == '"') {
+                // enclosing quotation was found
+                pos++;
+                break;
+            } else if (chars[pos] == '\\') {
+                chars[end] = getEscaped();
+            } else {
+                // shift char: required for string with escaped chars
+                chars[end] = chars[pos];
+            }
+            pos++;
+            end++;
+        }
+
+        // skip trailing space chars before comma or semicolon.
+        // (compatibility with RFC 1779)
+        for (; pos < length && chars[pos] == ' '; pos++) {
+        }
+
+        return new String(chars, beg, end - beg);
+    }
+
+    // gets hex string attribute value: "#" hexstring
+    private String hexAV() throws IOException {
+
+        if (pos + 4 >= length) {
+            // encoded byte array  must be not less then 4 c
+            throw new IOException(ERROR_PARSE_ERROR);
+        }
+
+        beg = pos; // store '#' position
+        pos++;
+        while (true) {
+
+            // check for end of attribute value
+            // looks for space and component separators
+            if (pos == length || chars[pos] == '+' || chars[pos] == ','
+                    || chars[pos] == ';') {
+                end = pos;
+                break;
+            }
+
+            if (chars[pos] == ' ') {
+                end = pos;
+                pos++;
+                // skip trailing space chars before comma or semicolon.
+                // (compatibility with RFC 1779)
+                for (; pos < length && chars[pos] == ' '; pos++) {
+                }
+                break;
+            } else if (chars[pos] >= 'A' && chars[pos] <= 'F') {
+                chars[pos] += 32; //to low case
+            }
+
+            pos++;
+        }
+
+        // verify length of hex string
+        // encoded byte array  must be not less then 4 and must be even number
+        int hexLen = end - beg; // skip first '#' char
+        if (hexLen < 5 || (hexLen & 1) == 0) {
+            throw new IOException(ERROR_PARSE_ERROR);
+        }
+
+        // get byte encoding from string representation
+        byte[] encoded = new byte[hexLen / 2];
+        for (int i = 0, p = beg + 1; i < encoded.length; p += 2, i++) {
+            encoded[i] = (byte) getByte(p);
+        }
+
+        return new String(chars, beg, hexLen);
+    }
+
+    // gets string attribute value: *( stringchar / pair )
+    private String escapedAV() throws IOException {
+
+        beg = pos;
+        end = pos;
+        while (true) {
+
+            if (pos >= length) {
+                // the end of DN has been found
+                return new String(chars, beg, end - beg);
+            }
+
+            switch (chars[pos]) {
+            case '+':
+            case ',':
+            case ';':
+                // separator char has beed found
+                return new String(chars, beg, end - beg);
+            case '\\':
+                // escaped char
+                chars[end++] = getEscaped();
+                pos++;
+                break;
+            case ' ':
+                // need to figure out whether space defines
+                // the end of attribute value or not
+                cur = end;
+
+                pos++;
+                chars[end++] = ' ';
+
+                for (; pos < length && chars[pos] == ' '; pos++) {
+                    chars[end++] = ' ';
+                }
+                if (pos == length || chars[pos] == ',' || chars[pos] == '+'
+                        || chars[pos] == ';') {
+                    // separator char or the end of DN has beed found
+                    return new String(chars, beg, cur - beg);
+                }
+                break;
+            default:
+                chars[end++] = chars[pos];
+                pos++;
+            }
+        }
+    }
+
+    // returns escaped char
+    private char getEscaped() throws IOException {
+
+        pos++;
+        if (pos == length) {
+            throw new IOException(ERROR_PARSE_ERROR);
+        }
+
+        switch (chars[pos]) {
+        case '"':
+        case '\\':
+        case ',':
+        case '=':
+        case '+':
+        case '<':
+        case '>':
+        case '#':
+        case ';':
+        case ' ':
+        case '*':
+        case '%':
+        case '_':
+            //FIXME: escaping is allowed only for leading or trailing space char
+            return chars[pos];
+        default:
+            // RFC doesn't explicitly say that escaped hex pair is
+            // interpreted as UTF-8 char. It only contains an example of such DN.
+            return getUTF8();
+        }
+    }
+
+    // decodes UTF-8 char
+    // see http://www.unicode.org for UTF-8 bit distribution table
+    private char getUTF8() throws IOException {
+
+        int res = getByte(pos);
+        pos++; //FIXME tmp
+
+        if (res < 128) { // one byte: 0-7F
+            return (char) res;
+        } else if (res >= 192 && res <= 247) {
+
+            int count;
+            if (res <= 223) { // two bytes: C0-DF
+                count = 1;
+                res = res & 0x1F;
+            } else if (res <= 239) { // three bytes: E0-EF
+                count = 2;
+                res = res & 0x0F;
+            } else { // four bytes: F0-F7
+                count = 3;
+                res = res & 0x07;
+            }
+
+            int b;
+            for (int i = 0; i < count; i++) {
+                pos++;
+                if (pos == length || chars[pos] != '\\') {
+                    return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
+                }
+                pos++;
+
+                b = getByte(pos);
+                pos++; //FIXME tmp
+                if ((b & 0xC0) != 0x80) {
+                    return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
+                }
+
+                res = (res << 6) + (b & 0x3F);
+            }
+            return (char) res;
+        } else {
+            return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
+        }
+    }
+
+    // Returns byte representation of a char pair
+    // The char pair is composed of DN char in
+    // specified 'position' and the next char
+    // According to BNF syntax:
+    // hexchar    = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
+    //                    / "a" / "b" / "c" / "d" / "e" / "f"
+    private int getByte(int position) throws IOException {
+
+        if ((position + 1) >= length) {
+            // to avoid ArrayIndexOutOfBoundsException
+            throw new IOException(ERROR_PARSE_ERROR);
+        }
+
+        int b1, b2;
+
+        b1 = chars[position];
+        if (b1 >= '0' && b1 <= '9') {
+            b1 = b1 - '0';
+        } else if (b1 >= 'a' && b1 <= 'f') {
+            b1 = b1 - 87; // 87 = 'a' - 10
+        } else if (b1 >= 'A' && b1 <= 'F') {
+            b1 = b1 - 55; // 55 = 'A' - 10
+        } else {
+            throw new IOException(ERROR_PARSE_ERROR);
+        }
+
+        b2 = chars[position + 1];
+        if (b2 >= '0' && b2 <= '9') {
+            b2 = b2 - '0';
+        } else if (b2 >= 'a' && b2 <= 'f') {
+            b2 = b2 - 87; // 87 = 'a' - 10
+        } else if (b2 >= 'A' && b2 <= 'F') {
+            b2 = b2 - 55; // 55 = 'A' - 10
+        } else {
+            throw new IOException(ERROR_PARSE_ERROR);
+        }
+
+        return (b1 << 4) + b2;
+    }
+
+    /**
+     * Parses the DN and returns the attribute value for an attribute type.
+     *
+     * @param attributeType attribute type to look for (e.g. "ca")
+     * @return value of the attribute that first found, or null if none found
+     */
+    public String find(String attributeType) {
+        try {
+            // Initialize internal state.
+            pos = 0;
+            beg = 0;
+            end = 0;
+            cur = 0;
+            chars = dn.toCharArray();
+
+            String attType = nextAT();
+            if (attType == null) {
+                return null;
+            }
+            while (true) {
+                String attValue = "";
+
+                if (pos == length) {
+                    return null;
+                }
+
+                switch (chars[pos]) {
+                case '"':
+                    attValue = quotedAV();
+                    break;
+                case '#':
+                    attValue = hexAV();
+                    break;
+                case '+':
+                case ',':
+                case ';': // compatibility with RFC 1779: semicolon can separate RDNs
+                    //empty attribute value
+                    break;
+                default:
+                    attValue = escapedAV();
+                }
+
+                if (attributeType.equalsIgnoreCase(attType)) {
+                    return attValue;
+                }
+
+                if (pos >= length) {
+                    return null;
+                }
+
+                if (chars[pos] == ',' || chars[pos] == ';') {
+                } else if (chars[pos] != '+') {
+                    throw new IOException(ERROR_PARSE_ERROR);
+                }
+
+                pos++;
+                attType = nextAT();
+                if (attType == null) {
+                    throw new IOException(ERROR_PARSE_ERROR);
+                }
+            }
+        } catch (IOException e) {
+            // Parse error shouldn't happen, because we only handle DNs that
+            // X500Principal.getName() returns, which shouldn't be malformed.
+            Log.e(TAG, "Failed to parse DN: " + dn);
+            return null;
+        }
+    }
+}
diff --git a/common/java/com/android/common/DomainNameValidator.java b/common/java/com/android/common/DomainNameValidator.java
new file mode 100644
index 0000000..25dc007
--- /dev/null
+++ b/common/java/com/android/common/DomainNameValidator.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.common;
+
+import android.util.Config;
+import android.util.Log;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import javax.security.auth.x500.X500Principal;
+
+public class DomainNameValidator {
+    private final static String TAG = "DomainNameValidator";
+
+    private static final boolean DEBUG = false;
+    private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
+
+    private static Pattern QUICK_IP_PATTERN;
+    static {
+        try {
+            QUICK_IP_PATTERN = Pattern.compile("^[a-f0-9\\.:]+$");
+        } catch (PatternSyntaxException e) {}
+    }
+
+    private static final int ALT_DNS_NAME = 2;
+    private static final int ALT_IPA_NAME = 7;
+
+    /**
+     * Checks the site certificate against the domain name of the site being visited
+     * @param certificate The certificate to check
+     * @param thisDomain The domain name of the site being visited
+     * @return True iff if there is a domain match as specified by RFC2818
+     */
+    public static boolean match(X509Certificate certificate, String thisDomain) {
+        if (certificate == null || thisDomain == null || thisDomain.length() == 0) {
+            return false;
+        }
+
+        thisDomain = thisDomain.toLowerCase();
+        if (!isIpAddress(thisDomain)) {
+            return matchDns(certificate, thisDomain);
+        } else {
+            return matchIpAddress(certificate, thisDomain);
+        }
+    }
+
+    /**
+     * @return True iff the domain name is specified as an IP address
+     */
+    private static boolean isIpAddress(String domain) {
+        boolean rval = (domain != null && domain.length() != 0);
+        if (rval) {
+            try {
+                // do a quick-dirty IP match first to avoid DNS lookup
+                rval = QUICK_IP_PATTERN.matcher(domain).matches();
+                if (rval) {
+                    rval = domain.equals(
+                        InetAddress.getByName(domain).getHostAddress());
+                }
+            } catch (UnknownHostException e) {
+                String errorMessage = e.getMessage();
+                if (errorMessage == null) {
+                  errorMessage = "unknown host exception";
+                }
+
+                if (LOG_ENABLED) {
+                    Log.v(TAG, "DomainNameValidator.isIpAddress(): " + errorMessage);
+                }
+
+                rval = false;
+            }
+        }
+
+        return rval;
+    }
+
+    /**
+     * Checks the site certificate against the IP domain name of the site being visited
+     * @param certificate The certificate to check
+     * @param thisDomain The DNS domain name of the site being visited
+     * @return True iff if there is a domain match as specified by RFC2818
+     */
+    private static boolean matchIpAddress(X509Certificate certificate, String thisDomain) {
+        if (LOG_ENABLED) {
+            Log.v(TAG, "DomainNameValidator.matchIpAddress(): this domain: " + thisDomain);
+        }
+
+        try {
+            Collection subjectAltNames = certificate.getSubjectAlternativeNames();
+            if (subjectAltNames != null) {
+                Iterator i = subjectAltNames.iterator();
+                while (i.hasNext()) {
+                    List altNameEntry = (List)(i.next());
+                    if (altNameEntry != null && 2 <= altNameEntry.size()) {
+                        Integer altNameType = (Integer)(altNameEntry.get(0));
+                        if (altNameType != null) {
+                            if (altNameType.intValue() == ALT_IPA_NAME) {
+                                String altName = (String)(altNameEntry.get(1));
+                                if (altName != null) {
+                                    if (LOG_ENABLED) {
+                                        Log.v(TAG, "alternative IP: " + altName);
+                                    }
+                                    if (thisDomain.equalsIgnoreCase(altName)) {
+                                        return true;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (CertificateParsingException e) {}
+
+        return false;
+    }
+
+    /**
+     * Checks the site certificate against the DNS domain name of the site being visited
+     * @param certificate The certificate to check
+     * @param thisDomain The DNS domain name of the site being visited
+     * @return True iff if there is a domain match as specified by RFC2818
+     */
+    private static boolean matchDns(X509Certificate certificate, String thisDomain) {
+        boolean hasDns = false;
+        try {
+            Collection subjectAltNames = certificate.getSubjectAlternativeNames();
+            if (subjectAltNames != null) {
+                Iterator i = subjectAltNames.iterator();
+                while (i.hasNext()) {
+                    List altNameEntry = (List)(i.next());
+                    if (altNameEntry != null && 2 <= altNameEntry.size()) {
+                        Integer altNameType = (Integer)(altNameEntry.get(0));
+                        if (altNameType != null) {
+                            if (altNameType.intValue() == ALT_DNS_NAME) {
+                                hasDns = true;
+                                String altName = (String)(altNameEntry.get(1));
+                                if (altName != null) {
+                                    if (matchDns(thisDomain, altName)) {
+                                        return true;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (CertificateParsingException e) {
+            String errorMessage = e.getMessage();
+            if (errorMessage == null) {
+                errorMessage = "failed to parse certificate";
+            }
+
+            Log.w(TAG, "DomainNameValidator.matchDns(): " + errorMessage);
+            return false;
+        }
+
+        if (!hasDns) {
+            final String cn = new DNParser(certificate.getSubjectX500Principal())
+                    .find("cn");
+            if (LOG_ENABLED) {
+                Log.v(TAG, "Validating subject: DN:"
+                        + certificate.getSubjectX500Principal().getName(X500Principal.CANONICAL)
+                        + "  CN:" + cn);
+            }
+            if (cn != null) {
+                return matchDns(thisDomain, cn);
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * @param thisDomain The domain name of the site being visited
+     * @param thatDomain The domain name from the certificate
+     * @return True iff thisDomain matches thatDomain as specified by RFC2818
+     */
+    // not private for testing
+    public static boolean matchDns(String thisDomain, String thatDomain) {
+        if (LOG_ENABLED) {
+            Log.v(TAG, "DomainNameValidator.matchDns():" +
+                      " this domain: " + thisDomain +
+                      " that domain: " + thatDomain);
+        }
+
+        if (thisDomain == null || thisDomain.length() == 0 ||
+            thatDomain == null || thatDomain.length() == 0) {
+            return false;
+        }
+
+        thatDomain = thatDomain.toLowerCase();
+
+        // (a) domain name strings are equal, ignoring case: X matches X
+        boolean rval = thisDomain.equals(thatDomain);
+        if (!rval) {
+            String[] thisDomainTokens = thisDomain.split("\\.");
+            String[] thatDomainTokens = thatDomain.split("\\.");
+
+            int thisDomainTokensNum = thisDomainTokens.length;
+            int thatDomainTokensNum = thatDomainTokens.length;
+
+            // (b) OR thatHost is a '.'-suffix of thisHost: Z.Y.X matches X
+            if (thisDomainTokensNum >= thatDomainTokensNum) {
+                for (int i = thatDomainTokensNum - 1; i >= 0; --i) {
+                    rval = thisDomainTokens[i].equals(thatDomainTokens[i]);
+                    if (!rval) {
+                        // (c) OR we have a special *-match:
+                        // *.Y.X matches Z.Y.X but *.X doesn't match Z.Y.X
+                        rval = (i == 0 && thisDomainTokensNum == thatDomainTokensNum);
+                        if (rval) {
+                            rval = thatDomainTokens[0].equals("*");
+                            if (!rval) {
+                                // (d) OR we have a *-component match:
+                                // f*.com matches foo.com but not bar.com
+                                rval = domainTokenMatch(
+                                    thisDomainTokens[0], thatDomainTokens[0]);
+                            }
+                        }
+                        break;
+                    }
+                }
+            } else {
+              // (e) OR thatHost has a '*.'-prefix of thisHost:
+              // *.Y.X matches Y.X
+              rval = thatDomain.equals("*." + thisDomain);
+            }
+        }
+
+        return rval;
+    }
+
+    /**
+     * @param thisDomainToken The domain token from the current domain name
+     * @param thatDomainToken The domain token from the certificate
+     * @return True iff thisDomainToken matches thatDomainToken, using the
+     * wildcard match as specified by RFC2818-3.1. For example, f*.com must
+     * match foo.com but not bar.com
+     */
+    private static boolean domainTokenMatch(String thisDomainToken, String thatDomainToken) {
+        if (thisDomainToken != null && thatDomainToken != null) {
+            int starIndex = thatDomainToken.indexOf('*');
+            if (starIndex >= 0) {
+                if (thatDomainToken.length() - 1 <= thisDomainToken.length()) {
+                    String prefix = thatDomainToken.substring(0,  starIndex);
+                    String suffix = thatDomainToken.substring(starIndex + 1);
+
+                    return thisDomainToken.startsWith(prefix) && thisDomainToken.endsWith(suffix);
+                }
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/common/java/com/android/common/FastXmlSerializer.java b/common/java/com/android/common/FastXmlSerializer.java
new file mode 100644
index 0000000..0d33941
--- /dev/null
+++ b/common/java/com/android/common/FastXmlSerializer.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+
+/**
+ * This is a quick and dirty implementation of XmlSerializer that isn't horribly
+ * painfully slow like the normal one.  It only does what is needed for the
+ * specific XML files being written with it.
+ */
+public class FastXmlSerializer implements XmlSerializer {
+    private static final String ESCAPE_TABLE[] = new String[] {
+        null,     null,     null,     null,     null,     null,     null,     null,  // 0-7
+        null,     null,     null,     null,     null,     null,     null,     null,  // 8-15
+        null,     null,     null,     null,     null,     null,     null,     null,  // 16-23
+        null,     null,     null,     null,     null,     null,     null,     null,  // 24-31
+        null,     null,     "&quot;", null,     null,     null,     "&amp;",  null,  // 32-39
+        null,     null,     null,     null,     null,     null,     null,     null,  // 40-47
+        null,     null,     null,     null,     null,     null,     null,     null,  // 48-55
+        null,     null,     null,     null,     "&lt;",   null,     "&gt;",   null,  // 56-63
+    };
+
+    private static final int BUFFER_LEN = 8192;
+
+    private final char[] mText = new char[BUFFER_LEN];
+    private int mPos;
+
+    private Writer mWriter;
+
+    private OutputStream mOutputStream;
+    private CharsetEncoder mCharset;
+    private ByteBuffer mBytes = ByteBuffer.allocate(BUFFER_LEN);
+
+    private boolean mInTag;
+
+    private void append(char c) throws IOException {
+        int pos = mPos;
+        if (pos >= (BUFFER_LEN-1)) {
+            flush();
+            pos = mPos;
+        }
+        mText[pos] = c;
+        mPos = pos+1;
+    }
+
+    private void append(String str, int i, final int length) throws IOException {
+        if (length > BUFFER_LEN) {
+            final int end = i + length;
+            while (i < end) {
+                int next = i + BUFFER_LEN;
+                append(str, i, next<end ? BUFFER_LEN : (end-i));
+                i = next;
+            }
+            return;
+        }
+        int pos = mPos;
+        if ((pos+length) > BUFFER_LEN) {
+            flush();
+            pos = mPos;
+        }
+        str.getChars(i, i+length, mText, pos);
+        mPos = pos + length;
+    }
+
+    private void append(char[] buf, int i, final int length) throws IOException {
+        if (length > BUFFER_LEN) {
+            final int end = i + length;
+            while (i < end) {
+                int next = i + BUFFER_LEN;
+                append(buf, i, next<end ? BUFFER_LEN : (end-i));
+                i = next;
+            }
+            return;
+        }
+        int pos = mPos;
+        if ((pos+length) > BUFFER_LEN) {
+            flush();
+            pos = mPos;
+        }
+        System.arraycopy(buf, i, mText, pos, length);
+        mPos = pos + length;
+    }
+
+    private void append(String str) throws IOException {
+        append(str, 0, str.length());
+    }
+
+    private void escapeAndAppendString(final String string) throws IOException {
+        final int N = string.length();
+        final char NE = (char)ESCAPE_TABLE.length;
+        final String[] escapes = ESCAPE_TABLE;
+        int lastPos = 0;
+        int pos;
+        for (pos=0; pos<N; pos++) {
+            char c = string.charAt(pos);
+            if (c >= NE) continue;
+            String escape = escapes[c];
+            if (escape == null) continue;
+            if (lastPos < pos) append(string, lastPos, pos-lastPos);
+            lastPos = pos + 1;
+            append(escape);
+        }
+        if (lastPos < pos) append(string, lastPos, pos-lastPos);
+    }
+
+    private void escapeAndAppendString(char[] buf, int start, int len) throws IOException {
+        final char NE = (char)ESCAPE_TABLE.length;
+        final String[] escapes = ESCAPE_TABLE;
+        int end = start+len;
+        int lastPos = start;
+        int pos;
+        for (pos=start; pos<end; pos++) {
+            char c = buf[pos];
+            if (c >= NE) continue;
+            String escape = escapes[c];
+            if (escape == null) continue;
+            if (lastPos < pos) append(buf, lastPos, pos-lastPos);
+            lastPos = pos + 1;
+            append(escape);
+        }
+        if (lastPos < pos) append(buf, lastPos, pos-lastPos);
+    }
+
+    public XmlSerializer attribute(String namespace, String name, String value) throws IOException,
+            IllegalArgumentException, IllegalStateException {
+        append(' ');
+        if (namespace != null) {
+            append(namespace);
+            append(':');
+        }
+        append(name);
+        append("=\"");
+
+        escapeAndAppendString(value);
+        append('"');
+        return this;
+    }
+
+    public void cdsect(String text) throws IOException, IllegalArgumentException,
+            IllegalStateException {
+        throw new UnsupportedOperationException();
+    }
+
+    public void comment(String text) throws IOException, IllegalArgumentException,
+            IllegalStateException {
+        throw new UnsupportedOperationException();
+    }
+
+    public void docdecl(String text) throws IOException, IllegalArgumentException,
+            IllegalStateException {
+        throw new UnsupportedOperationException();
+    }
+
+    public void endDocument() throws IOException, IllegalArgumentException, IllegalStateException {
+        flush();
+    }
+
+    public XmlSerializer endTag(String namespace, String name) throws IOException,
+            IllegalArgumentException, IllegalStateException {
+        if (mInTag) {
+            append(" />\n");
+        } else {
+            append("</");
+            if (namespace != null) {
+                append(namespace);
+                append(':');
+            }
+            append(name);
+            append(">\n");
+        }
+        mInTag = false;
+        return this;
+    }
+
+    public void entityRef(String text) throws IOException, IllegalArgumentException,
+            IllegalStateException {
+        throw new UnsupportedOperationException();
+    }
+
+    private void flushBytes() throws IOException {
+        int position;
+        if ((position = mBytes.position()) > 0) {
+            mBytes.flip();
+            mOutputStream.write(mBytes.array(), 0, position);
+            mBytes.clear();
+        }
+    }
+
+    public void flush() throws IOException {
+        //Log.i("PackageManager", "flush mPos=" + mPos);
+        if (mPos > 0) {
+            if (mOutputStream != null) {
+                CharBuffer charBuffer = CharBuffer.wrap(mText, 0, mPos);
+                CoderResult result = mCharset.encode(charBuffer, mBytes, true);
+                while (true) {
+                    if (result.isError()) {
+                        throw new IOException(result.toString());
+                    } else if (result.isOverflow()) {
+                        flushBytes();
+                        result = mCharset.encode(charBuffer, mBytes, true);
+                        continue;
+                    }
+                    break;
+                }
+                flushBytes();
+                mOutputStream.flush();
+            } else {
+                mWriter.write(mText, 0, mPos);
+                mWriter.flush();
+            }
+            mPos = 0;
+        }
+    }
+
+    public int getDepth() {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean getFeature(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    public String getName() {
+        throw new UnsupportedOperationException();
+    }
+
+    public String getNamespace() {
+        throw new UnsupportedOperationException();
+    }
+
+    public String getPrefix(String namespace, boolean generatePrefix)
+            throws IllegalArgumentException {
+        throw new UnsupportedOperationException();
+    }
+
+    public Object getProperty(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    public void ignorableWhitespace(String text) throws IOException, IllegalArgumentException,
+            IllegalStateException {
+        throw new UnsupportedOperationException();
+    }
+
+    public void processingInstruction(String text) throws IOException, IllegalArgumentException,
+            IllegalStateException {
+        throw new UnsupportedOperationException();
+    }
+
+    public void setFeature(String name, boolean state) throws IllegalArgumentException,
+            IllegalStateException {
+        if (name.equals("http://xmlpull.org/v1/doc/features.html#indent-output")) {
+            return;
+        }
+        throw new UnsupportedOperationException();
+    }
+
+    public void setOutput(OutputStream os, String encoding) throws IOException,
+            IllegalArgumentException, IllegalStateException {
+        if (os == null)
+            throw new IllegalArgumentException();
+        if (true) {
+            try {
+                mCharset = Charset.forName(encoding).newEncoder();
+            } catch (IllegalCharsetNameException e) {
+                throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
+                        encoding).initCause(e));
+            } catch (UnsupportedCharsetException e) {
+                throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
+                        encoding).initCause(e));
+            }
+            mOutputStream = os;
+        } else {
+            setOutput(
+                encoding == null
+                    ? new OutputStreamWriter(os)
+                    : new OutputStreamWriter(os, encoding));
+        }
+    }
+
+    public void setOutput(Writer writer) throws IOException, IllegalArgumentException,
+            IllegalStateException {
+        mWriter = writer;
+    }
+
+    public void setPrefix(String prefix, String namespace) throws IOException,
+            IllegalArgumentException, IllegalStateException {
+        throw new UnsupportedOperationException();
+    }
+
+    public void setProperty(String name, Object value) throws IllegalArgumentException,
+            IllegalStateException {
+        throw new UnsupportedOperationException();
+    }
+
+    public void startDocument(String encoding, Boolean standalone) throws IOException,
+            IllegalArgumentException, IllegalStateException {
+        append("<?xml version='1.0' encoding='utf-8' standalone='"
+                + (standalone ? "yes" : "no") + "' ?>\n");
+    }
+
+    public XmlSerializer startTag(String namespace, String name) throws IOException,
+            IllegalArgumentException, IllegalStateException {
+        if (mInTag) {
+            append(">\n");
+        }
+        append('<');
+        if (namespace != null) {
+            append(namespace);
+            append(':');
+        }
+        append(name);
+        mInTag = true;
+        return this;
+    }
+
+    public XmlSerializer text(char[] buf, int start, int len) throws IOException,
+            IllegalArgumentException, IllegalStateException {
+        if (mInTag) {
+            append(">");
+            mInTag = false;
+        }
+        escapeAndAppendString(buf, start, len);
+        return this;
+    }
+
+    public XmlSerializer text(String text) throws IOException, IllegalArgumentException,
+            IllegalStateException {
+        if (mInTag) {
+            append(">");
+            mInTag = false;
+        }
+        escapeAndAppendString(text);
+        return this;
+    }
+
+}
diff --git a/common/java/com/android/common/NetworkConnectivityListener.java b/common/java/com/android/common/NetworkConnectivityListener.java
new file mode 100644
index 0000000..b49b80d
--- /dev/null
+++ b/common/java/com/android/common/NetworkConnectivityListener.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * A wrapper for a broadcast receiver that provides network connectivity
+ * state information, independent of network type (mobile, Wi-Fi, etc.).
+ * @deprecated Code tempted to use this class should simply listen for connectivity intents
+ * (or poll ConnectivityManager) directly.
+ * {@hide}
+ */
+public class NetworkConnectivityListener {
+    private static final String TAG = "NetworkConnectivityListener";
+    private static final boolean DBG = false;
+
+    private Context mContext;
+    private HashMap<Handler, Integer> mHandlers = new HashMap<Handler, Integer>();
+    private State mState;
+    private boolean mListening;
+    private String mReason;
+    private boolean mIsFailover;
+
+    /** Network connectivity information */
+    private NetworkInfo mNetworkInfo;
+
+    /**
+     * In case of a Disconnect, the connectivity manager may have
+     * already established, or may be attempting to establish, connectivity
+     * with another network. If so, {@code mOtherNetworkInfo} will be non-null.
+     */
+    private NetworkInfo mOtherNetworkInfo;
+
+    private ConnectivityBroadcastReceiver mReceiver;
+
+    private class ConnectivityBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+
+            if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
+                mListening == false) {
+                Log.w(TAG, "onReceived() called with " + mState.toString() + " and " + intent);
+                return;
+            }
+
+            boolean noConnectivity =
+                intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
+
+            if (noConnectivity) {
+                mState = State.NOT_CONNECTED;
+            } else {
+                mState = State.CONNECTED;
+            }
+
+            mNetworkInfo = (NetworkInfo)
+                intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
+            mOtherNetworkInfo = (NetworkInfo)
+                intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
+
+            mReason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);
+            mIsFailover =
+                intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false);
+
+            if (DBG) {
+                Log.d(TAG, "onReceive(): mNetworkInfo=" + mNetworkInfo +  " mOtherNetworkInfo = "
+                        + (mOtherNetworkInfo == null ? "[none]" : mOtherNetworkInfo +
+                        " noConn=" + noConnectivity) + " mState=" + mState.toString());
+            }
+
+            // Notifiy any handlers.
+            Iterator<Handler> it = mHandlers.keySet().iterator();
+            while (it.hasNext()) {
+                Handler target = it.next();
+                Message message = Message.obtain(target, mHandlers.get(target));
+                target.sendMessage(message);
+            }
+        }
+    };
+
+    public enum State {
+        UNKNOWN,
+
+        /** This state is returned if there is connectivity to any network **/
+        CONNECTED,
+        /**
+         * This state is returned if there is no connectivity to any network. This is set
+         * to true under two circumstances:
+         * <ul>
+         * <li>When connectivity is lost to one network, and there is no other available
+         * network to attempt to switch to.</li>
+         * <li>When connectivity is lost to one network, and the attempt to switch to
+         * another network fails.</li>
+         */
+        NOT_CONNECTED
+    }
+
+    /**
+     * Create a new NetworkConnectivityListener.
+     */
+    public NetworkConnectivityListener() {
+        mState = State.UNKNOWN;
+        mReceiver = new ConnectivityBroadcastReceiver();
+    }
+
+    /**
+     * This method starts listening for network connectivity state changes.
+     * @param context
+     */
+    public synchronized void startListening(Context context) {
+        if (!mListening) {
+            mContext = context;
+
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+            context.registerReceiver(mReceiver, filter);
+            mListening = true;
+        }
+    }
+
+    /**
+     * This method stops this class from listening for network changes.
+     */
+    public synchronized void stopListening() {
+        if (mListening) {
+            mContext.unregisterReceiver(mReceiver);
+            mContext = null;
+            mNetworkInfo = null;
+            mOtherNetworkInfo = null;
+            mIsFailover = false;
+            mReason = null;
+            mListening = false;
+        }
+    }
+
+    /**
+     * This methods registers a Handler to be called back onto with the specified what code when
+     * the network connectivity state changes.
+     *
+     * @param target The target handler.
+     * @param what The what code to be used when posting a message to the handler.
+     */
+    public void registerHandler(Handler target, int what) {
+        mHandlers.put(target, what);
+    }
+
+    /**
+     * This methods unregisters the specified Handler.
+     * @param target
+     */
+    public void unregisterHandler(Handler target) {
+        mHandlers.remove(target);
+    }
+
+    public State getState() {
+        return mState;
+    }
+
+    /**
+     * Return the NetworkInfo associated with the most recent connectivity event.
+     * @return {@code NetworkInfo} for the network that had the most recent connectivity event.
+     */
+    public NetworkInfo getNetworkInfo() {
+        return mNetworkInfo;
+    }
+
+    /**
+     * If the most recent connectivity event was a DISCONNECT, return
+     * any information supplied in the broadcast about an alternate
+     * network that might be available. If this returns a non-null
+     * value, then another broadcast should follow shortly indicating
+     * whether connection to the other network succeeded.
+     *
+     * @return NetworkInfo
+     */
+    public NetworkInfo getOtherNetworkInfo() {
+        return mOtherNetworkInfo;
+    }
+
+    /**
+     * Returns true if the most recent event was for an attempt to switch over to
+     * a new network following loss of connectivity on another network.
+     * @return {@code true} if this was a failover attempt, {@code false} otherwise.
+     */
+    public boolean isFailover() {
+        return mIsFailover;
+    }
+
+    /**
+     * An optional reason for the connectivity state change may have been supplied.
+     * This returns it.
+     * @return the reason for the state change, if available, or {@code null}
+     * otherwise.
+     */
+    public String getReason() {
+        return mReason;
+    }
+}
diff --git a/common/java/com/android/common/OperationScheduler.java b/common/java/com/android/common/OperationScheduler.java
new file mode 100644
index 0000000..71b22ce
--- /dev/null
+++ b/common/java/com/android/common/OperationScheduler.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+import android.content.SharedPreferences;
+import android.text.format.Time;
+
+import java.util.Map;
+import java.util.TreeSet;
+
+/**
+ * Tracks the success/failure history of a particular network operation in
+ * persistent storage and computes retry strategy accordingly.  Handles
+ * exponential backoff, periodic rescheduling, event-driven triggering,
+ * retry-after moratorium intervals, etc. based on caller-specified parameters.
+ *
+ * <p>This class does not directly perform or invoke any operations,
+ * it only keeps track of the schedule.  Somebody else needs to call
+ * {@link #getNextTimeMillis()} as appropriate and do the actual work.
+ */
+public class OperationScheduler {
+    /** Tunable parameter options for {@link #getNextTimeMillis}. */
+    public static class Options {
+        /** Wait this long after every error before retrying. */
+        public long backoffFixedMillis = 0;
+
+        /** Wait this long times the number of consecutive errors so far before retrying. */
+        public long backoffIncrementalMillis = 5000;
+
+        /** Maximum duration of moratorium to honor.  Mostly an issue for clock rollbacks. */
+        public long maxMoratoriumMillis = 24 * 3600 * 1000;
+
+        /** Minimum duration after success to wait before allowing another trigger. */
+        public long minTriggerMillis = 0;
+
+        /** Automatically trigger this long after the last success. */
+        public long periodicIntervalMillis = 0;
+
+        @Override
+        public String toString() {
+            return String.format(
+                    "OperationScheduler.Options[backoff=%.1f+%.1f max=%.1f min=%.1f period=%.1f]",
+                    backoffFixedMillis / 1000.0, backoffIncrementalMillis / 1000.0,
+                    maxMoratoriumMillis / 1000.0, minTriggerMillis / 1000.0,
+                    periodicIntervalMillis / 1000.0);
+        }
+    }
+
+    private static final String PREFIX = "OperationScheduler_";
+    private final SharedPreferences mStorage;
+
+    /**
+     * Initialize the scheduler state.
+     * @param storage to use for recording the state of operations across restarts/reboots
+     */
+    public OperationScheduler(SharedPreferences storage) {
+        mStorage = storage;
+    }
+
+    /**
+     * Parse scheduler options supplied in this string form:
+     *
+     * <pre>
+     * backoff=(fixed)+(incremental) max=(maxmoratorium) min=(mintrigger) [period=](interval)
+     * </pre>
+     *
+     * All values are times in (possibly fractional) <em>seconds</em> (not milliseconds).
+     * Omitted settings are left at whatever existing default value was passed in.
+     *
+     * <p>
+     * The default options: <code>backoff=0+5 max=86400 min=0 period=0</code><br>
+     * Fractions are OK: <code>backoff=+2.5 period=10.0</code><br>
+     * The "period=" can be omitted: <code>3600</code><br>
+     *
+     * @param spec describing some or all scheduler options.
+     * @param options to update with parsed values.
+     * @return the options passed in (for convenience)
+     * @throws IllegalArgumentException if the syntax is invalid
+     */
+    public static Options parseOptions(String spec, Options options)
+            throws IllegalArgumentException {
+        for (String param : spec.split(" +")) {
+            if (param.length() == 0) continue;
+            if (param.startsWith("backoff=")) {
+                int plus = param.indexOf('+', 8);
+                if (plus < 0) {
+                    options.backoffFixedMillis = parseSeconds(param.substring(8));
+                } else {
+                    if (plus > 8) {
+                        options.backoffFixedMillis = parseSeconds(param.substring(8, plus));
+                    }
+                    options.backoffIncrementalMillis = parseSeconds(param.substring(plus + 1));
+                }
+            } else if (param.startsWith("max=")) {
+                options.maxMoratoriumMillis = parseSeconds(param.substring(4));
+            } else if (param.startsWith("min=")) {
+                options.minTriggerMillis = parseSeconds(param.substring(4));
+            } else if (param.startsWith("period=")) {
+                options.periodicIntervalMillis = parseSeconds(param.substring(7));
+            } else {
+                options.periodicIntervalMillis = parseSeconds(param);
+            }
+        }
+        return options;
+    }
+
+    private static long parseSeconds(String param) throws NumberFormatException {
+        return (long) (Float.parseFloat(param) * 1000);
+    }
+
+    /**
+     * Compute the time of the next operation.  Does not modify any state.
+     *
+     * @param options to use for this computation.
+     * @return the wall clock time ({@link System#currentTimeMillis()}) when the
+     * next operation should be attempted -- immediately, if the return value is
+     * before the current time.
+     */
+    public long getNextTimeMillis(Options options) {
+        boolean enabledState = mStorage.getBoolean(PREFIX + "enabledState", true);
+        if (!enabledState) return Long.MAX_VALUE;
+
+        boolean permanentError = mStorage.getBoolean(PREFIX + "permanentError", false);
+        if (permanentError) return Long.MAX_VALUE;
+
+        // We do quite a bit of limiting to prevent a clock rollback from totally
+        // hosing the scheduler.  Times which are supposed to be in the past are
+        // clipped to the current time so we don't languish forever.
+
+        int errorCount = mStorage.getInt(PREFIX + "errorCount", 0);
+        long now = System.currentTimeMillis();
+        long lastSuccessTimeMillis = getTimeBefore(PREFIX + "lastSuccessTimeMillis", now);
+        long lastErrorTimeMillis = getTimeBefore(PREFIX + "lastErrorTimeMillis", now);
+        long triggerTimeMillis = mStorage.getLong(PREFIX + "triggerTimeMillis", Long.MAX_VALUE);
+        long moratoriumSetMillis = mStorage.getLong(PREFIX + "moratoriumSetTimeMillis", 0);
+        long moratoriumTimeMillis = getTimeBefore(PREFIX + "moratoriumTimeMillis",
+                moratoriumSetMillis + options.maxMoratoriumMillis);
+
+        long time = triggerTimeMillis;
+        if (options.periodicIntervalMillis > 0) {
+            time = Math.min(time, lastSuccessTimeMillis + options.periodicIntervalMillis);
+        }
+        if (time >= moratoriumTimeMillis - options.maxMoratoriumMillis) {
+            time = Math.max(time, moratoriumTimeMillis);
+        }
+        time = Math.max(time, lastSuccessTimeMillis + options.minTriggerMillis);
+        time = Math.max(time, lastErrorTimeMillis + options.backoffFixedMillis +
+                options.backoffIncrementalMillis * errorCount);
+        return time;
+    }
+
+    /**
+     * Fetch a {@link SharedPreferences} property, but force it to be before
+     * a certain time, updating the value if necessary.  This is to recover
+     * gracefully from clock rollbacks which could otherwise strand our timers.
+     *
+     * @param name of SharedPreferences key
+     * @param max time to allow in result
+     * @return current value attached to key (default 0), limited by max
+     */
+    private long getTimeBefore(String name, long max) {
+        long time = mStorage.getLong(name, 0);
+        if (time > max) mStorage.edit().putLong(name, (time = max)).commit();
+        return time;
+    }
+
+    /**
+     * Request an operation to be performed at a certain time.  The actual
+     * scheduled time may be affected by error backoff logic and defined
+     * minimum intervals.
+     *
+     * @param millis wall clock time ({@link System#currentTimeMillis()}) to
+     * trigger another operation; 0 to trigger immediately
+     */
+    public void setTriggerTimeMillis(long millis) {
+        mStorage.edit().putLong(PREFIX + "triggerTimeMillis", millis).commit();
+    }
+
+    /**
+     * Forbid any operations until after a certain (absolute) time.
+     * Commonly used when a server returns a "Retry-After:" type directive.
+     * Limited by {@link #Options.maxMoratoriumMillis}.
+     *
+     * @param millis wall clock time ({@link System#currentTimeMillis()}) to
+     * wait before attempting any more operations; 0 to remove moratorium
+     */
+    public void setMoratoriumTimeMillis(long millis) {
+        mStorage.edit()
+                .putLong(PREFIX + "moratoriumTimeMillis", millis)
+                .putLong(PREFIX + "moratoriumSetTimeMillis", System.currentTimeMillis())
+                .commit();
+    }
+
+    /**
+     * Enable or disable all operations.  When disabled, all calls to
+     * {@link #getNextTimeMillis()} return {@link Long#MAX_VALUE}.
+     * Commonly used when data network availability goes up and down.
+     *
+     * @param enabled if operations can be performed
+     */
+    public void setEnabledState(boolean enabled) {
+        mStorage.edit().putBoolean(PREFIX + "enabledState", enabled).commit();
+    }
+
+    /**
+     * Report successful completion of an operation.  Resets all error
+     * counters, clears any trigger directives, and records the success.
+     */
+    public void onSuccess() {
+        resetTransientError();
+        resetPermanentError();
+        long now = System.currentTimeMillis();
+        mStorage.edit()
+                .remove(PREFIX + "errorCount")
+                .remove(PREFIX + "lastErrorTimeMillis")
+                .remove(PREFIX + "permanentError")
+                .remove(PREFIX + "triggerTimeMillis")
+                .putLong(PREFIX + "lastSuccessTimeMillis", now).commit();
+    }
+
+    /**
+     * Report a transient error (usually a network failure).  Increments
+     * the error count and records the time of the latest error for backoff
+     * purposes.
+     */
+    public void onTransientError() {
+        long now = System.currentTimeMillis();
+        mStorage.edit().putLong(PREFIX + "lastErrorTimeMillis", now).commit();
+        mStorage.edit().putInt(PREFIX + "errorCount",
+                mStorage.getInt(PREFIX + "errorCount", 0) + 1).commit();
+    }
+
+    /**
+     * Reset all transient error counts, allowing the next operation to proceed
+     * immediately without backoff.  Commonly used on network state changes, when
+     * partial progress occurs (some data received), and in other circumstances
+     * where there is reason to hope things might start working better.
+     */
+    public void resetTransientError() {
+        mStorage.edit()
+                .remove(PREFIX + "lastErrorTimeMillis")
+                .remove(PREFIX + "errorCount").commit();
+    }
+
+    /**
+     * Report a permanent error that will not go away until further notice.
+     * No operation will be scheduled until {@link #resetPermanentError()}
+     * is called.  Commonly used for authentication failures (which are reset
+     * when the accounts database is updated).
+     */
+    public void onPermanentError() {
+        mStorage.edit().putBoolean(PREFIX + "permanentError", true).commit();
+    }
+
+    /**
+     * Reset any permanent error status set by {@link #onPermanentError},
+     * allowing operations to be scheduled as normal.
+     */
+    public void resetPermanentError() {
+        mStorage.edit().remove(PREFIX + "permanentError").commit();
+    }
+
+    /**
+     * Return a string description of the scheduler state for debugging.
+     */
+    public String toString() {
+        StringBuilder out = new StringBuilder("[OperationScheduler:");
+        for (String key : new TreeSet<String>(mStorage.getAll().keySet())) {  // Sort keys
+            if (key.startsWith(PREFIX)) {
+                if (key.endsWith("TimeMillis")) {
+                    Time time = new Time();
+                    time.set(mStorage.getLong(key, 0));
+                    out.append(" ").append(key.substring(PREFIX.length(), key.length() - 10));
+                    out.append("=").append(time.format("%Y-%m-%d/%H:%M:%S"));
+                } else {
+                    out.append(" ").append(key.substring(PREFIX.length()));
+                    out.append("=").append(mStorage.getAll().get(key).toString());
+                }
+            }
+        }
+        return out.append("]").toString();
+    }
+}
diff --git a/common/java/com/android/common/Patterns.java b/common/java/com/android/common/Patterns.java
new file mode 100644
index 0000000..24a18c0
--- /dev/null
+++ b/common/java/com/android/common/Patterns.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Commonly used regular expression patterns.
+ */
+public class Patterns {
+    /**
+     *  Regular expression pattern to match all IANA top-level domains.
+     *  List accurate as of 2007/06/15.  List taken from:
+     *  http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+     *  This pattern is auto-generated by //device/tools/make-iana-tld-pattern.py
+     */
+    public static final Pattern TOP_LEVEL_DOMAIN
+        = Pattern.compile(
+                "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
+                + "|(biz|b[abdefghijmnorstvwyz])"
+                + "|(cat|com|coop|c[acdfghiklmnoruvxyz])"
+                + "|d[ejkmoz]"
+                + "|(edu|e[cegrstu])"
+                + "|f[ijkmor]"
+                + "|(gov|g[abdefghilmnpqrstuwy])"
+                + "|h[kmnrtu]"
+                + "|(info|int|i[delmnoqrst])"
+                + "|(jobs|j[emop])"
+                + "|k[eghimnrwyz]"
+                + "|l[abcikrstuvy]"
+                + "|(mil|mobi|museum|m[acdghklmnopqrstuvwxyz])"
+                + "|(name|net|n[acefgilopruz])"
+                + "|(org|om)"
+                + "|(pro|p[aefghklmnrstwy])"
+                + "|qa"
+                + "|r[eouw]"
+                + "|s[abcdeghijklmnortuvyz]"
+                + "|(tel|travel|t[cdfghjklmnoprtvwz])"
+                + "|u[agkmsyz]"
+                + "|v[aceginu]"
+                + "|w[fs]"
+                + "|y[etu]"
+                + "|z[amw])");
+
+    /**
+     *  Regular expression pattern to match RFC 1738 URLs
+     *  List accurate as of 2007/06/15.  List taken from:
+     *  http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+     *  This pattern is auto-generated by //device/tools/make-iana-tld-pattern.py
+     */
+    public static final Pattern WEB_URL
+        = Pattern.compile(
+            "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+            + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
+            + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
+            + "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+"   // named host
+            + "(?:"   // plus top level domain
+            + "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
+            + "|(?:biz|b[abdefghijmnorstvwyz])"
+            + "|(?:cat|com|coop|c[acdfghiklmnoruvxyz])"
+            + "|d[ejkmoz]"
+            + "|(?:edu|e[cegrstu])"
+            + "|f[ijkmor]"
+            + "|(?:gov|g[abdefghilmnpqrstuwy])"
+            + "|h[kmnrtu]"
+            + "|(?:info|int|i[delmnoqrst])"
+            + "|(?:jobs|j[emop])"
+            + "|k[eghimnrwyz]"
+            + "|l[abcikrstuvy]"
+            + "|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz])"
+            + "|(?:name|net|n[acefgilopruz])"
+            + "|(?:org|om)"
+            + "|(?:pro|p[aefghklmnrstwy])"
+            + "|qa"
+            + "|r[eouw]"
+            + "|s[abcdeghijklmnortuvyz]"
+            + "|(?:tel|travel|t[cdfghjklmnoprtvwz])"
+            + "|u[agkmsyz]"
+            + "|v[aceginu]"
+            + "|w[fs]"
+            + "|y[etu]"
+            + "|z[amw]))"
+            + "|(?:(?:25[0-5]|2[0-4]" // or ip address
+            + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]"
+            + "|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]"
+            + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
+            + "|[1-9][0-9]|[0-9])))"
+            + "(?:\\:\\d{1,5})?)" // plus option port number
+            + "(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~"  // plus option query params
+            + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
+            + "(?:\\b|$)"); // and finally, a word boundary or end of
+                            // input.  This is to stop foo.sure from
+                            // matching as foo.su
+
+    public static final Pattern IP_ADDRESS
+        = Pattern.compile(
+            "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]"
+            + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]"
+            + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
+            + "|[1-9][0-9]|[0-9]))");
+
+    public static final Pattern DOMAIN_NAME
+        = Pattern.compile(
+            "(((([a-zA-Z0-9][a-zA-Z0-9\\-]*)*[a-zA-Z0-9]\\.)+"
+            + TOP_LEVEL_DOMAIN + ")|"
+            + IP_ADDRESS + ")");
+
+    public static final Pattern EMAIL_ADDRESS
+        = Pattern.compile(
+            "[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}" +
+            "\\@" +
+            "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" +
+            "(" +
+                "\\." +
+                "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25}" +
+            ")+"
+        );
+
+    /**
+     * This pattern is intended for searching for things that look like they
+     * might be phone numbers in arbitrary text, not for validating whether
+     * something is in fact a phone number.  It will miss many things that
+     * are legitimate phone numbers.
+     * 
+     * <p> The pattern matches the following:
+     * <ul>
+     * <li>Optionally, a + sign followed immediately by one or more digits. Spaces, dots, or dashes
+     * may follow.
+     * <li>Optionally, sets of digits in parentheses, separated by spaces, dots, or dashes.
+     * <li>A string starting and ending with a digit, containing digits, spaces, dots, and/or dashes.
+     * </ul>
+     */
+    public static final Pattern PHONE
+        = Pattern.compile(                                  // sdd = space, dot, or dash
+                "(\\+[0-9]+[\\- \\.]*)?"                    // +<digits><sdd>*
+                + "(\\([0-9]+\\)[\\- \\.]*)?"               // (<digits>)<sdd>*
+                + "([0-9][0-9\\- \\.][0-9\\- \\.]+[0-9])"); // <digit><digit|sdd>+<digit> 
+
+    /**
+     *  Convenience method to take all of the non-null matching groups in a
+     *  regex Matcher and return them as a concatenated string.
+     *
+     *  @param matcher      The Matcher object from which grouped text will
+     *                      be extracted
+     *
+     *  @return             A String comprising all of the non-null matched
+     *                      groups concatenated together
+     */
+    public static final String concatGroups(Matcher matcher) {
+        StringBuilder b = new StringBuilder();
+        final int numGroups = matcher.groupCount();
+
+        for (int i = 1; i <= numGroups; i++) {
+            String s = matcher.group(i);
+
+            System.err.println("Group(" + i + ") : " + s);
+
+            if (s != null) {
+                b.append(s);
+            }
+        }
+
+        return b.toString();
+    }
+
+    /**
+     * Convenience method to return only the digits and plus signs
+     * in the matching string.
+     *
+     * @param matcher      The Matcher object from which digits and plus will
+     *                     be extracted
+     *
+     * @return             A String comprising all of the digits and plus in
+     *                     the match
+     */
+    public static final String digitsAndPlusOnly(Matcher matcher) {
+        StringBuilder buffer = new StringBuilder();
+        String matchingRegion = matcher.group();
+
+        for (int i = 0, size = matchingRegion.length(); i < size; i++) {
+            char character = matchingRegion.charAt(i);
+
+            if (character == '+' || Character.isDigit(character)) {
+                buffer.append(character);
+            }
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Do not create this static utility class.
+     */
+    private Patterns() {}
+}
diff --git a/common/java/com/android/common/Rfc822InputFilter.java b/common/java/com/android/common/Rfc822InputFilter.java
new file mode 100644
index 0000000..6dfdc7b
--- /dev/null
+++ b/common/java/com/android/common/Rfc822InputFilter.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+import android.text.InputFilter;
+import android.text.Spanned;
+import android.text.SpannableStringBuilder;
+
+/**
+ * Implements special address cleanup rules:
+ * The first space key entry following an "@" symbol that is followed by any combination
+ * of letters and symbols, including one+ dots and zero commas, should insert an extra
+ * comma (followed by the space).
+ *
+ * @hide
+ */
+public class Rfc822InputFilter implements InputFilter {
+
+    public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
+        int dstart, int dend) {
+
+        // quick check - did they enter a single space?
+        if (end-start != 1 || source.charAt(start) != ' ') {
+            return null;
+        }
+
+        // determine if the characters before the new space fit the pattern
+        // follow backwards and see if we find a comma, dot, or @
+        int scanBack = dstart;
+        boolean dotFound = false;
+        while (scanBack > 0) {
+            char c = dest.charAt(--scanBack);
+            switch (c) {
+                case '.':
+                    dotFound = true;    // one or more dots are req'd
+                    break;
+                case ',':
+                    return null;
+                case '@':
+                    if (!dotFound) {
+                        return null;
+                    }
+                    // we have found a comma-insert case.  now just do it
+                    // in the least expensive way we can.
+                    if (source instanceof Spanned) {
+                        SpannableStringBuilder sb = new SpannableStringBuilder(",");
+                        sb.append(source);
+                        return sb;
+                    } else {
+                        return ", ";
+                    }
+                default:
+                    // just keep going
+            }
+        }
+
+        // no termination cases were found, so don't edit the input
+        return null;
+    }
+}
diff --git a/common/java/com/android/common/Rfc822Validator.java b/common/java/com/android/common/Rfc822Validator.java
new file mode 100644
index 0000000..087e425
--- /dev/null
+++ b/common/java/com/android/common/Rfc822Validator.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+import android.text.TextUtils;
+import android.text.util.Rfc822Token;
+import android.text.util.Rfc822Tokenizer;
+import android.widget.AutoCompleteTextView;
+
+import java.util.regex.Pattern;
+
+/**
+ * This class works as a Validator for AutoCompleteTextView for
+ * email addresses.  If a token does not appear to be a valid address,
+ * it is trimmed of characters that cannot legitimately appear in one
+ * and has the specified domain name added.  It is meant for use with
+ * {@link Rfc822Token} and {@link Rfc822Tokenizer}.
+ *
+ * @deprecated In the future make sure we don't quietly alter the user's
+ *             text in ways they did not intend.  Meanwhile, hide this
+ *             class from the public API because it does not even have
+ *             a full understanding of the syntax it claims to correct.
+ * @hide
+ */
+public class Rfc822Validator implements AutoCompleteTextView.Validator {
+    /*
+     * Regex.EMAIL_ADDRESS_PATTERN hardcodes the TLD that we accept, but we
+     * want to make sure we will keep accepting email addresses with TLD's
+     * that don't exist at the time of this writing, so this regexp relaxes
+     * that constraint by accepting any kind of top level domain, not just
+     * ".com", ".fr", etc...
+     */
+    private static final Pattern EMAIL_ADDRESS_PATTERN =
+            Pattern.compile("[^\\s@]+@[^\\s@]+\\.[a-zA-z][a-zA-Z][a-zA-Z]*");
+
+    private String mDomain;
+
+    /**
+     * Constructs a new validator that uses the specified domain name as
+     * the default when none is specified.
+     */
+    public Rfc822Validator(String domain) {
+        mDomain = domain;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValid(CharSequence text) {
+        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(text);
+
+        return tokens.length == 1 &&
+               EMAIL_ADDRESS_PATTERN.
+                   matcher(tokens[0].getAddress()).matches();
+    }
+
+    /**
+     * @return a string in which all the characters that are illegal for the username
+     * or the domain name part of the email address have been removed.
+     */
+    private String removeIllegalCharacters(String s) {
+        StringBuilder result = new StringBuilder();
+        int length = s.length();
+        for (int i = 0; i < length; i++) {
+            char c = s.charAt(i);
+
+            /*
+             * An RFC822 atom can contain any ASCII printing character
+             * except for periods and any of the following punctuation.
+             * A local-part can contain multiple atoms, concatenated by
+             * periods, so do allow periods here.
+             */
+
+            if (c <= ' ' || c > '~') {
+                continue;
+            }
+
+            if (c == '(' || c == ')' || c == '<' || c == '>' ||
+                c == '@' || c == ',' || c == ';' || c == ':' ||
+                c == '\\' || c == '"' || c == '[' || c == ']') {
+                continue;
+            }
+
+            result.append(c);
+        }
+        return result.toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public CharSequence fixText(CharSequence cs) {
+        // Return an empty string if the email address only contains spaces, \n or \t
+        if (TextUtils.getTrimmedLength(cs) == 0) return "";
+
+        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(cs);
+        StringBuilder sb = new StringBuilder();
+
+        for (int i = 0; i < tokens.length; i++) {
+            String text = tokens[i].getAddress();
+            int index = text.indexOf('@');
+            if (index < 0) {
+                // If there is no @, just append the domain of the account
+                tokens[i].setAddress(removeIllegalCharacters(text) + "@" + mDomain);
+            } else {
+                // Otherwise, remove the illegal characters on both sides of the '@'
+                String fix = removeIllegalCharacters(text.substring(0, index));
+                String domain = removeIllegalCharacters(text.substring(index + 1));
+                tokens[i].setAddress(fix + "@" + (domain.length() != 0 ? domain : mDomain));
+            }
+
+            sb.append(tokens[i].toString());
+            if (i + 1 < tokens.length) {
+                sb.append(", ");
+            }
+        }
+
+        return sb;
+    }
+}
diff --git a/common/java/com/android/common/XmlUtils.java b/common/java/com/android/common/XmlUtils.java
new file mode 100644
index 0000000..dd57e49
--- /dev/null
+++ b/common/java/com/android/common/XmlUtils.java
@@ -0,0 +1,796 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import android.util.Xml;
+
+/** {@hide} */
+public class XmlUtils
+{
+
+    public static void skipCurrentTag(XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+               && (type != XmlPullParser.END_TAG
+                       || parser.getDepth() > outerDepth)) {
+        }
+    }
+
+    public static final int
+    convertValueToList(CharSequence value, String[] options, int defaultValue)
+    {
+        if (null != value) {
+            for (int i = 0; i < options.length; i++) {
+                if (value.equals(options[i]))
+                    return i;
+            }
+        }
+
+        return defaultValue;
+    }
+
+    public static final boolean
+    convertValueToBoolean(CharSequence value, boolean defaultValue)
+    {
+        boolean result = false;
+
+        if (null == value)
+            return defaultValue;
+
+        if (value.equals("1")
+        ||  value.equals("true")
+        ||  value.equals("TRUE"))
+            result = true;
+
+        return result;
+    }
+
+    public static final int
+    convertValueToInt(CharSequence charSeq, int defaultValue)
+    {
+        if (null == charSeq)
+            return defaultValue;
+
+        String nm = charSeq.toString();
+
+        // XXX This code is copied from Integer.decode() so we don't
+        // have to instantiate an Integer!
+
+        int value;
+        int sign = 1;
+        int index = 0;
+        int len = nm.length();
+        int base = 10;
+
+        if ('-' == nm.charAt(0)) {
+            sign = -1;
+            index++;
+        }
+
+        if ('0' == nm.charAt(index)) {
+            //  Quick check for a zero by itself
+            if (index == (len - 1))
+                return 0;
+
+            char    c = nm.charAt(index + 1);
+
+            if ('x' == c || 'X' == c) {
+                index += 2;
+                base = 16;
+            } else {
+                index++;
+                base = 8;
+            }
+        }
+        else if ('#' == nm.charAt(index))
+        {
+            index++;
+            base = 16;
+        }
+
+        return Integer.parseInt(nm.substring(index), base) * sign;
+    }
+
+    public static final int
+    convertValueToUnsignedInt(String value, int defaultValue)
+    {
+        if (null == value)
+            return defaultValue;
+
+        return parseUnsignedIntAttribute(value);
+    }
+
+    public static final int
+    parseUnsignedIntAttribute(CharSequence charSeq)
+    {
+        String  value = charSeq.toString();
+
+        long    bits;
+        int     index = 0;
+        int     len = value.length();
+        int     base = 10;
+
+        if ('0' == value.charAt(index)) {
+            //  Quick check for zero by itself
+            if (index == (len - 1))
+                return 0;
+
+            char    c = value.charAt(index + 1);
+
+            if ('x' == c || 'X' == c) {     //  check for hex
+                index += 2;
+                base = 16;
+            } else {                        //  check for octal
+                index++;
+                base = 8;
+            }
+        } else if ('#' == value.charAt(index)) {
+            index++;
+            base = 16;
+        }
+
+        return (int) Long.parseLong(value.substring(index), base);
+    }
+
+    /**
+     * Flatten a Map into an output stream as XML.  The map can later be
+     * read back with readMapXml().
+     *
+     * @param val The map to be flattened.
+     * @param out Where to write the XML data.
+     *
+     * @see #writeMapXml(Map, String, XmlSerializer)
+     * @see #writeListXml
+     * @see #writeValueXml
+     * @see #readMapXml
+     */
+    public static final void writeMapXml(Map val, OutputStream out)
+            throws XmlPullParserException, java.io.IOException {
+        XmlSerializer serializer = new FastXmlSerializer();
+        serializer.setOutput(out, "utf-8");
+        serializer.startDocument(null, true);
+        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+        writeMapXml(val, null, serializer);
+        serializer.endDocument();
+    }
+
+    /**
+     * Flatten a List into an output stream as XML.  The list can later be
+     * read back with readListXml().
+     *
+     * @param val The list to be flattened.
+     * @param out Where to write the XML data.
+     *
+     * @see #writeListXml(List, String, XmlSerializer)
+     * @see #writeMapXml
+     * @see #writeValueXml
+     * @see #readListXml
+     */
+    public static final void writeListXml(List val, OutputStream out)
+    throws XmlPullParserException, java.io.IOException
+    {
+        XmlSerializer serializer = Xml.newSerializer();
+        serializer.setOutput(out, "utf-8");
+        serializer.startDocument(null, true);
+        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+        writeListXml(val, null, serializer);
+        serializer.endDocument();
+    }
+
+    /**
+     * Flatten a Map into an XmlSerializer.  The map can later be read back
+     * with readThisMapXml().
+     *
+     * @param val The map to be flattened.
+     * @param name Name attribute to include with this list's tag, or null for
+     *             none.
+     * @param out XmlSerializer to write the map into.
+     *
+     * @see #writeMapXml(Map, OutputStream)
+     * @see #writeListXml
+     * @see #writeValueXml
+     * @see #readMapXml
+     */
+    public static final void writeMapXml(Map val, String name, XmlSerializer out)
+    throws XmlPullParserException, java.io.IOException
+    {
+        if (val == null) {
+            out.startTag(null, "null");
+            out.endTag(null, "null");
+            return;
+        }
+
+        Set s = val.entrySet();
+        Iterator i = s.iterator();
+
+        out.startTag(null, "map");
+        if (name != null) {
+            out.attribute(null, "name", name);
+        }
+
+        while (i.hasNext()) {
+            Map.Entry e = (Map.Entry)i.next();
+            writeValueXml(e.getValue(), (String)e.getKey(), out);
+        }
+
+        out.endTag(null, "map");
+    }
+
+    /**
+     * Flatten a List into an XmlSerializer.  The list can later be read back
+     * with readThisListXml().
+     *
+     * @param val The list to be flattened.
+     * @param name Name attribute to include with this list's tag, or null for
+     *             none.
+     * @param out XmlSerializer to write the list into.
+     *
+     * @see #writeListXml(List, OutputStream)
+     * @see #writeMapXml
+     * @see #writeValueXml
+     * @see #readListXml
+     */
+    public static final void writeListXml(List val, String name, XmlSerializer out)
+    throws XmlPullParserException, java.io.IOException
+    {
+        if (val == null) {
+            out.startTag(null, "null");
+            out.endTag(null, "null");
+            return;
+        }
+
+        out.startTag(null, "list");
+        if (name != null) {
+            out.attribute(null, "name", name);
+        }
+
+        int N = val.size();
+        int i=0;
+        while (i < N) {
+            writeValueXml(val.get(i), null, out);
+            i++;
+        }
+
+        out.endTag(null, "list");
+    }
+
+    /**
+     * Flatten a byte[] into an XmlSerializer.  The list can later be read back
+     * with readThisByteArrayXml().
+     *
+     * @param val The byte array to be flattened.
+     * @param name Name attribute to include with this array's tag, or null for
+     *             none.
+     * @param out XmlSerializer to write the array into.
+     *
+     * @see #writeMapXml
+     * @see #writeValueXml
+     */
+    public static final void writeByteArrayXml(byte[] val, String name,
+            XmlSerializer out)
+            throws XmlPullParserException, java.io.IOException {
+
+        if (val == null) {
+            out.startTag(null, "null");
+            out.endTag(null, "null");
+            return;
+        }
+
+        out.startTag(null, "byte-array");
+        if (name != null) {
+            out.attribute(null, "name", name);
+        }
+
+        final int N = val.length;
+        out.attribute(null, "num", Integer.toString(N));
+
+        StringBuilder sb = new StringBuilder(val.length*2);
+        for (int i=0; i<N; i++) {
+            int b = val[i];
+            int h = b>>4;
+            sb.append(h >= 10 ? ('a'+h-10) : ('0'+h));
+            h = b&0xff;
+            sb.append(h >= 10 ? ('a'+h-10) : ('0'+h));
+        }
+
+        out.text(sb.toString());
+
+        out.endTag(null, "byte-array");
+    }
+
+    /**
+     * Flatten an int[] into an XmlSerializer.  The list can later be read back
+     * with readThisIntArrayXml().
+     *
+     * @param val The int array to be flattened.
+     * @param name Name attribute to include with this array's tag, or null for
+     *             none.
+     * @param out XmlSerializer to write the array into.
+     *
+     * @see #writeMapXml
+     * @see #writeValueXml
+     * @see #readThisIntArrayXml
+     */
+    public static final void writeIntArrayXml(int[] val, String name,
+            XmlSerializer out)
+            throws XmlPullParserException, java.io.IOException {
+
+        if (val == null) {
+            out.startTag(null, "null");
+            out.endTag(null, "null");
+            return;
+        }
+
+        out.startTag(null, "int-array");
+        if (name != null) {
+            out.attribute(null, "name", name);
+        }
+
+        final int N = val.length;
+        out.attribute(null, "num", Integer.toString(N));
+
+        for (int i=0; i<N; i++) {
+            out.startTag(null, "item");
+            out.attribute(null, "value", Integer.toString(val[i]));
+            out.endTag(null, "item");
+        }
+
+        out.endTag(null, "int-array");
+    }
+
+    /**
+     * Flatten an object's value into an XmlSerializer.  The value can later
+     * be read back with readThisValueXml().
+     *
+     * Currently supported value types are: null, String, Integer, Long,
+     * Float, Double Boolean, Map, List.
+     *
+     * @param v The object to be flattened.
+     * @param name Name attribute to include with this value's tag, or null
+     *             for none.
+     * @param out XmlSerializer to write the object into.
+     *
+     * @see #writeMapXml
+     * @see #writeListXml
+     * @see #readValueXml
+     */
+    public static final void writeValueXml(Object v, String name, XmlSerializer out)
+    throws XmlPullParserException, java.io.IOException
+    {
+        String typeStr;
+        if (v == null) {
+            out.startTag(null, "null");
+            if (name != null) {
+                out.attribute(null, "name", name);
+            }
+            out.endTag(null, "null");
+            return;
+        } else if (v instanceof String) {
+            out.startTag(null, "string");
+            if (name != null) {
+                out.attribute(null, "name", name);
+            }
+            out.text(v.toString());
+            out.endTag(null, "string");
+            return;
+        } else if (v instanceof Integer) {
+            typeStr = "int";
+        } else if (v instanceof Long) {
+            typeStr = "long";
+        } else if (v instanceof Float) {
+            typeStr = "float";
+        } else if (v instanceof Double) {
+            typeStr = "double";
+        } else if (v instanceof Boolean) {
+            typeStr = "boolean";
+        } else if (v instanceof byte[]) {
+            writeByteArrayXml((byte[])v, name, out);
+            return;
+        } else if (v instanceof int[]) {
+            writeIntArrayXml((int[])v, name, out);
+            return;
+        } else if (v instanceof Map) {
+            writeMapXml((Map)v, name, out);
+            return;
+        } else if (v instanceof List) {
+            writeListXml((List)v, name, out);
+            return;
+        } else if (v instanceof CharSequence) {
+            // XXX This is to allow us to at least write something if
+            // we encounter styled text...  but it means we will drop all
+            // of the styling information. :(
+            out.startTag(null, "string");
+            if (name != null) {
+                out.attribute(null, "name", name);
+            }
+            out.text(v.toString());
+            out.endTag(null, "string");
+            return;
+        } else {
+            throw new RuntimeException("writeValueXml: unable to write value " + v);
+        }
+
+        out.startTag(null, typeStr);
+        if (name != null) {
+            out.attribute(null, "name", name);
+        }
+        out.attribute(null, "value", v.toString());
+        out.endTag(null, typeStr);
+    }
+
+    /**
+     * Read a HashMap from an InputStream containing XML.  The stream can
+     * previously have been written by writeMapXml().
+     *
+     * @param in The InputStream from which to read.
+     *
+     * @return HashMap The resulting map.
+     *
+     * @see #readListXml
+     * @see #readValueXml
+     * @see #readThisMapXml
+     * #see #writeMapXml
+     */
+    public static final HashMap readMapXml(InputStream in)
+    throws XmlPullParserException, java.io.IOException
+    {
+        XmlPullParser   parser = Xml.newPullParser();
+        parser.setInput(in, null);
+        return (HashMap)readValueXml(parser, new String[1]);
+    }
+
+    /**
+     * Read an ArrayList from an InputStream containing XML.  The stream can
+     * previously have been written by writeListXml().
+     *
+     * @param in The InputStream from which to read.
+     *
+     * @return HashMap The resulting list.
+     *
+     * @see #readMapXml
+     * @see #readValueXml
+     * @see #readThisListXml
+     * @see #writeListXml
+     */
+    public static final ArrayList readListXml(InputStream in)
+    throws XmlPullParserException, java.io.IOException
+    {
+        XmlPullParser   parser = Xml.newPullParser();
+        parser.setInput(in, null);
+        return (ArrayList)readValueXml(parser, new String[1]);
+    }
+
+    /**
+     * Read a HashMap object from an XmlPullParser.  The XML data could
+     * previously have been generated by writeMapXml().  The XmlPullParser
+     * must be positioned <em>after</em> the tag that begins the map.
+     *
+     * @param parser The XmlPullParser from which to read the map data.
+     * @param endTag Name of the tag that will end the map, usually "map".
+     * @param name An array of one string, used to return the name attribute
+     *             of the map's tag.
+     *
+     * @return HashMap The newly generated map.
+     *
+     * @see #readMapXml
+     */
+    public static final HashMap readThisMapXml(XmlPullParser parser, String endTag, String[] name)
+    throws XmlPullParserException, java.io.IOException
+    {
+        HashMap map = new HashMap();
+
+        int eventType = parser.getEventType();
+        do {
+            if (eventType == parser.START_TAG) {
+                Object val = readThisValueXml(parser, name);
+                if (name[0] != null) {
+                    //System.out.println("Adding to map: " + name + " -> " + val);
+                    map.put(name[0], val);
+                } else {
+                    throw new XmlPullParserException(
+                        "Map value without name attribute: " + parser.getName());
+                }
+            } else if (eventType == parser.END_TAG) {
+                if (parser.getName().equals(endTag)) {
+                    return map;
+                }
+                throw new XmlPullParserException(
+                    "Expected " + endTag + " end tag at: " + parser.getName());
+            }
+            eventType = parser.next();
+        } while (eventType != parser.END_DOCUMENT);
+
+        throw new XmlPullParserException(
+            "Document ended before " + endTag + " end tag");
+    }
+
+    /**
+     * Read an ArrayList object from an XmlPullParser.  The XML data could
+     * previously have been generated by writeListXml().  The XmlPullParser
+     * must be positioned <em>after</em> the tag that begins the list.
+     *
+     * @param parser The XmlPullParser from which to read the list data.
+     * @param endTag Name of the tag that will end the list, usually "list".
+     * @param name An array of one string, used to return the name attribute
+     *             of the list's tag.
+     *
+     * @return HashMap The newly generated list.
+     *
+     * @see #readListXml
+     */
+    public static final ArrayList readThisListXml(XmlPullParser parser, String endTag, String[] name)
+    throws XmlPullParserException, java.io.IOException
+    {
+        ArrayList list = new ArrayList();
+
+        int eventType = parser.getEventType();
+        do {
+            if (eventType == parser.START_TAG) {
+                Object val = readThisValueXml(parser, name);
+                list.add(val);
+                //System.out.println("Adding to list: " + val);
+            } else if (eventType == parser.END_TAG) {
+                if (parser.getName().equals(endTag)) {
+                    return list;
+                }
+                throw new XmlPullParserException(
+                    "Expected " + endTag + " end tag at: " + parser.getName());
+            }
+            eventType = parser.next();
+        } while (eventType != parser.END_DOCUMENT);
+
+        throw new XmlPullParserException(
+            "Document ended before " + endTag + " end tag");
+    }
+
+    /**
+     * Read an int[] object from an XmlPullParser.  The XML data could
+     * previously have been generated by writeIntArrayXml().  The XmlPullParser
+     * must be positioned <em>after</em> the tag that begins the list.
+     *
+     * @param parser The XmlPullParser from which to read the list data.
+     * @param endTag Name of the tag that will end the list, usually "list".
+     * @param name An array of one string, used to return the name attribute
+     *             of the list's tag.
+     *
+     * @return Returns a newly generated int[].
+     *
+     * @see #readListXml
+     */
+    public static final int[] readThisIntArrayXml(XmlPullParser parser,
+            String endTag, String[] name)
+            throws XmlPullParserException, java.io.IOException {
+
+        int num;
+        try {
+            num = Integer.parseInt(parser.getAttributeValue(null, "num"));
+        } catch (NullPointerException e) {
+            throw new XmlPullParserException(
+                    "Need num attribute in byte-array");
+        } catch (NumberFormatException e) {
+            throw new XmlPullParserException(
+                    "Not a number in num attribute in byte-array");
+        }
+
+        int[] array = new int[num];
+        int i = 0;
+
+        int eventType = parser.getEventType();
+        do {
+            if (eventType == parser.START_TAG) {
+                if (parser.getName().equals("item")) {
+                    try {
+                        array[i] = Integer.parseInt(
+                                parser.getAttributeValue(null, "value"));
+                    } catch (NullPointerException e) {
+                        throw new XmlPullParserException(
+                                "Need value attribute in item");
+                    } catch (NumberFormatException e) {
+                        throw new XmlPullParserException(
+                                "Not a number in value attribute in item");
+                    }
+                } else {
+                    throw new XmlPullParserException(
+                            "Expected item tag at: " + parser.getName());
+                }
+            } else if (eventType == parser.END_TAG) {
+                if (parser.getName().equals(endTag)) {
+                    return array;
+                } else if (parser.getName().equals("item")) {
+                    i++;
+                } else {
+                    throw new XmlPullParserException(
+                        "Expected " + endTag + " end tag at: "
+                        + parser.getName());
+                }
+            }
+            eventType = parser.next();
+        } while (eventType != parser.END_DOCUMENT);
+
+        throw new XmlPullParserException(
+            "Document ended before " + endTag + " end tag");
+    }
+
+    /**
+     * Read a flattened object from an XmlPullParser.  The XML data could
+     * previously have been written with writeMapXml(), writeListXml(), or
+     * writeValueXml().  The XmlPullParser must be positioned <em>at</em> the
+     * tag that defines the value.
+     *
+     * @param parser The XmlPullParser from which to read the object.
+     * @param name An array of one string, used to return the name attribute
+     *             of the value's tag.
+     *
+     * @return Object The newly generated value object.
+     *
+     * @see #readMapXml
+     * @see #readListXml
+     * @see #writeValueXml
+     */
+    public static final Object readValueXml(XmlPullParser parser, String[] name)
+    throws XmlPullParserException, java.io.IOException
+    {
+        int eventType = parser.getEventType();
+        do {
+            if (eventType == parser.START_TAG) {
+                return readThisValueXml(parser, name);
+            } else if (eventType == parser.END_TAG) {
+                throw new XmlPullParserException(
+                    "Unexpected end tag at: " + parser.getName());
+            } else if (eventType == parser.TEXT) {
+                throw new XmlPullParserException(
+                    "Unexpected text: " + parser.getText());
+            }
+            eventType = parser.next();
+        } while (eventType != parser.END_DOCUMENT);
+
+        throw new XmlPullParserException(
+            "Unexpected end of document");
+    }
+
+    private static final Object readThisValueXml(XmlPullParser parser, String[] name)
+    throws XmlPullParserException, java.io.IOException
+    {
+        final String valueName = parser.getAttributeValue(null, "name");
+        final String tagName = parser.getName();
+
+        //System.out.println("Reading this value tag: " + tagName + ", name=" + valueName);
+
+        Object res;
+
+        if (tagName.equals("null")) {
+            res = null;
+        } else if (tagName.equals("string")) {
+            String value = "";
+            int eventType;
+            while ((eventType = parser.next()) != parser.END_DOCUMENT) {
+                if (eventType == parser.END_TAG) {
+                    if (parser.getName().equals("string")) {
+                        name[0] = valueName;
+                        //System.out.println("Returning value for " + valueName + ": " + value);
+                        return value;
+                    }
+                    throw new XmlPullParserException(
+                        "Unexpected end tag in <string>: " + parser.getName());
+                } else if (eventType == parser.TEXT) {
+                    value += parser.getText();
+                } else if (eventType == parser.START_TAG) {
+                    throw new XmlPullParserException(
+                        "Unexpected start tag in <string>: " + parser.getName());
+                }
+            }
+            throw new XmlPullParserException(
+                "Unexpected end of document in <string>");
+        } else if (tagName.equals("int")) {
+            res = Integer.parseInt(parser.getAttributeValue(null, "value"));
+        } else if (tagName.equals("long")) {
+            res = Long.valueOf(parser.getAttributeValue(null, "value"));
+        } else if (tagName.equals("float")) {
+            res = new Float(parser.getAttributeValue(null, "value"));
+        } else if (tagName.equals("double")) {
+            res = new Double(parser.getAttributeValue(null, "value"));
+        } else if (tagName.equals("boolean")) {
+            res = Boolean.valueOf(parser.getAttributeValue(null, "value"));
+        } else if (tagName.equals("int-array")) {
+            parser.next();
+            res = readThisIntArrayXml(parser, "int-array", name);
+            name[0] = valueName;
+            //System.out.println("Returning value for " + valueName + ": " + res);
+            return res;
+        } else if (tagName.equals("map")) {
+            parser.next();
+            res = readThisMapXml(parser, "map", name);
+            name[0] = valueName;
+            //System.out.println("Returning value for " + valueName + ": " + res);
+            return res;
+        } else if (tagName.equals("list")) {
+            parser.next();
+            res = readThisListXml(parser, "list", name);
+            name[0] = valueName;
+            //System.out.println("Returning value for " + valueName + ": " + res);
+            return res;
+        } else {
+            throw new XmlPullParserException(
+                "Unknown tag: " + tagName);
+        }
+
+        // Skip through to end tag.
+        int eventType;
+        while ((eventType = parser.next()) != parser.END_DOCUMENT) {
+            if (eventType == parser.END_TAG) {
+                if (parser.getName().equals(tagName)) {
+                    name[0] = valueName;
+                    //System.out.println("Returning value for " + valueName + ": " + res);
+                    return res;
+                }
+                throw new XmlPullParserException(
+                    "Unexpected end tag in <" + tagName + ">: " + parser.getName());
+            } else if (eventType == parser.TEXT) {
+                throw new XmlPullParserException(
+                "Unexpected text in <" + tagName + ">: " + parser.getName());
+            } else if (eventType == parser.START_TAG) {
+                throw new XmlPullParserException(
+                    "Unexpected start tag in <" + tagName + ">: " + parser.getName());
+            }
+        }
+        throw new XmlPullParserException(
+            "Unexpected end of document in <" + tagName + ">");
+    }
+
+    public static final void beginDocument(XmlPullParser parser, String firstElementName) throws XmlPullParserException, IOException
+    {
+        int type;
+        while ((type=parser.next()) != parser.START_TAG
+                   && type != parser.END_DOCUMENT) {
+            ;
+        }
+
+        if (type != parser.START_TAG) {
+            throw new XmlPullParserException("No start tag found");
+        }
+
+        if (!parser.getName().equals(firstElementName)) {
+            throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
+                    ", expected " + firstElementName);
+        }
+    }
+
+    public static final void nextElement(XmlPullParser parser) throws XmlPullParserException, IOException
+    {
+        int type;
+        while ((type=parser.next()) != parser.START_TAG
+                   && type != parser.END_DOCUMENT) {
+            ;
+        }
+    }
+}
diff --git a/common/tests/Android.mk b/common/tests/Android.mk
new file mode 100644
index 0000000..0f2c3e4
--- /dev/null
+++ b/common/tests/Android.mk
@@ -0,0 +1,26 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_CERTIFICATE := platform
+LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := AndroidCommonTests
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_STATIC_JAVA_LIBRARIES := android-common
+
+include $(BUILD_PACKAGE)
diff --git a/common/tests/AndroidManifest.xml b/common/tests/AndroidManifest.xml
new file mode 100644
index 0000000..151ec20
--- /dev/null
+++ b/common/tests/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.common.tests"
+        android:sharedUserId="com.android.uid.test">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <!-- Run tests with "runtest common" -->
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+            android:targetPackage="com.android.common.tests"
+            android:label="Android Common Library Tests" />
+
+</manifest>
diff --git a/common/tests/res/raw/alt_ip_only.crt b/common/tests/res/raw/alt_ip_only.crt
new file mode 100644
index 0000000..3ac9f5a
--- /dev/null
+++ b/common/tests/res/raw/alt_ip_only.crt
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICsjCCAZqgAwIBAgIJALrC37YAXFIeMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV
+BAYTAkpQMCAXDTEwMDExMjIxMzk0NloYDzIwNjQxMDE1MjEzOTQ2WjANMQswCQYD
+VQQGEwJKUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALr8s/4Abpby
+IYks5YCJE2nbWH7kj6XbwnRzsVP9RVC33bPoQ1M+2ZY24HqkigjQS/HEXR0s0bYh
+dewNUnTj1uGyGs6cYzsbu7x114vmVYqjxUo3hKjwfYiPeF6f3IE1vpLI7I2G32gq
+Zwm9c1/vXNHIdWQxCpFcuPA8P3YGfoApFX4pQPFplBUNAQqnjdmA68cbxxMC+1F3
+mX42D7iIEVwyVpah5HjyxjIZQlf3X7QBj0bCmkL+ibIHTALrkNNwNM6i4xzYLz/5
+14GkN9ncHY87eSOk6r53ptER6mQMhCe9qPRjSHnpWTTyj6IXTaYe+dDQw657B80w
+cSHL7Ed25zUCAwEAAaMTMBEwDwYDVR0RBAgwBocEwKgKATANBgkqhkiG9w0BAQUF
+AAOCAQEAgrwrtOWZT3fbi1AafpGaAiOBWSJqYqRhtQy0AfiZBxv1U0XaYqmZmpnq
+DVAqr0NkljowD28NBrxIFO5gBNum2ZOPDl2/5vjFn+IirUCJ9u9wS7zYkTCW2lQR
+xE7Ic3mfWv7wUbKDfjlWqP1IDHUxwkrBTAl+HnwOPiaKKk1ttwcrgS8AHlqASe03
+mlwnvJ+Stk54IneRaegL0L93sNAy63RZqnPCTxGz7eHcFwX8Jdr4sbxTxQqV6pIc
+WPjHQcWfpkFzAF5wyOq0kveVfx0g5xPhOVDd+U+q7WastbXICpCoHp9FxISmZVik
+sAyifp8agkYdzaSh55fFmKXlFnRsQw==
+-----END CERTIFICATE-----
diff --git a/common/tests/res/raw/subject_alt_only.crt b/common/tests/res/raw/subject_alt_only.crt
new file mode 100644
index 0000000..d5808fb
--- /dev/null
+++ b/common/tests/res/raw/subject_alt_only.crt
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICvTCCAaWgAwIBAgIJALbA0TZk2YmNMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV
+BAYTAkpQMCAXDTEwMDExMjIwNTg1NFoYDzIwNjQxMDE1MjA1ODU0WjANMQswCQYD
+VQQGEwJKUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMEg6acVC9V4
+xNGoLNVLPbqBc8IvMvcsc88dF6MW3d9VagX3aeWU8c79tI/KOV/1AOakH7WYxw/w
+yD8aOX7+9BK1Hu0qKKKbSM+ycqaMthXd6xytrNDsIx5WiGUz8zTko0Gk3orIR7p7
+rPcNzB/zwtESkscqPv85aEn7S/yClNkzLfEzm3CtaYOc0tfhBMyzi/ipXzGMxUmx
+PvOLr3v/Oz5pZEQw7Kxlm4+tAtn7bJlHziQ1UW4WPIy+T3hySBEpODFiqZi7Ok3X
+Zjxdii62fgo5B2Ee7q5Amo0mUIwcQTDjJ2CLAqzYnSh3tpiPJGjEIjmRyCoMQ1bx
+7D+y7nSPIq8CAwEAAaMeMBwwGgYDVR0RBBMwEYIPd3d3LmV4YW1wbGUuY29tMA0G
+CSqGSIb3DQEBBQUAA4IBAQBsGEh+nHc0l9FJTzWqvG3qs7i6XoJZdtThCDx4HjKJ
+8GMrJtreNN4JvIxn7KC+alVbnILjzCRO+c3rsnpxKBi5cp2imjuw5Kf/x2Seimb9
+UvZbaJvBVOzy4Q1IGef9bLy3wZzy2/WfBFyvPTAkgkRaX7LN2jnYOYVhNoNFrwqe
+EWxkA6fzrpyseUEFeGFFjGxRSRCDcQ25Eq6d9rkC1x21zNtt4QwZBO0wHrTy155M
+JPRynf9244Pn0Sr/wsnmdsTRFIFYynrc51hQ7DkwbUxpcaewkZzilru/SwZ3+pPT
+9JSqm5hJ1pg5WDlPkW7c/1VA0/141N52Q8MIU+2ZpuOj
+-----END CERTIFICATE-----
diff --git a/common/tests/res/raw/subject_only.crt b/common/tests/res/raw/subject_only.crt
new file mode 100644
index 0000000..11b34e7
--- /dev/null
+++ b/common/tests/res/raw/subject_only.crt
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0TCCAbmgAwIBAgIJANCQbJPPw31SMA0GCSqGSIb3DQEBBQUAMCcxCzAJBgNV
+BAYTAkpQMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wIBcNMTAwMTEyMjA1ODE4
+WhgPMjA2NDEwMTUyMDU4MThaMCcxCzAJBgNVBAYTAkpQMRgwFgYDVQQDEw93d3cu
+ZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDsdUJk
+4KxADA3vlDHxNbyC27Ozw4yiSVzPTHUct471YmdDRW3orO2P5a5hRnUGV70gjH9X
+MU4oeOdWYAgXB9pxfLyr6621k1+uNrmaZtzp0ECH9twcwxNJJFDZsN7o9vt7V6Ej
+NN9weeqDr/aeQXo07a12vyVfR6jWO8jHB0e4aemwZNoYjNvM69fivQTse2ZoRVfj
+eSHhjRTX6I8ry4a31Hwt+fT1QiWWNN6o7+WOtpJAhX3eg4smhSD1svi2kOT8tdUe
+NS4hWlmXmumU9G4tI8PBurcLNTm7PB2lUlbn/IV18WavqKE/Uy/1WgAx+a1EJNdp
+i07AG1PsqaONKkf1AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAJrNsuL7fZZNC8gL
+BdePJ7DYW2e7mXANU3bCBe2BZqmXKQxKwibZnEsqA+yMLqcSd8uxISlyHY2tw9wT
+4wB9KPIttfNLbwn/rk+MbOTHpvyF60d9WhJJVUkPBl8D4VuPSl+VnlA54kU9dtZN
++ZYdxYbNtSsI/Flz9SCoOV79W9GhN+uYJhv6RwyIMIHeMpZpyX1xSUVx5dZlmerQ
+WAUvghDH3fFRt2ZdnA4OXoKkTAaM3Pv7PUMsnah8bux6MQi0AuLMWFWOI1H34koH
+rs2oQLwOLnuifH52ey9+tJguabo+brlYYigAuWWFEzJfBzikDkIwnE/L7wlrypIk
+taXDWI4=
+-----END CERTIFICATE-----
diff --git a/common/tests/res/raw/subject_with_alt_names.crt b/common/tests/res/raw/subject_with_alt_names.crt
new file mode 100644
index 0000000..6963c7e
--- /dev/null
+++ b/common/tests/res/raw/subject_with_alt_names.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDBDCCAeygAwIBAgIJALv14qjcuhw9MA0GCSqGSIb3DQEBBQUAMCcxCzAJBgNV
+BAYTAkpQMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wIBcNMTAwMTEyMjA1OTM4
+WhgPMjA2NDEwMTUyMDU5MzhaMCcxCzAJBgNVBAYTAkpQMRgwFgYDVQQDEw93d3cu
+ZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCiTVgU
+kBO9KNYZZLmiPR0eBrk8u61CLnm35BGKW8EFpDaINLbbIFIQvqOMekURON/N+xFY
+D8roo7aFZVuHWAUqFcOJ4e6NmviK5qocLihtzAexsw4f4AzZxM3A8kcLlWLyAt7e
+EVLxhcMHogY7GaF6q+33Z8p+zp6x3tj07mwyPrriCLse2PeRsRunZl/fp/VvRlr6
+YbC7CbRrhnIv5nqohs8BsbBiiFpxQftsMQmiXhY2LUzqY2RXUIOw24fHjoQkHTL2
+4z5nUM3b6ueQe+CBnobUS6fzK/36Nct4dRpev9i/ORdRLuIDKJ+QR16G1V/BJYBR
+dAK+3iXvg6z8vP1XAgMBAAGjMTAvMC0GA1UdEQQmMCSCEHd3dzIuZXhhbXBsZS5j
+b22CEHd3dzMuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEFBQADggEBAJQNf38uXm3h
+0vsF+Yd6/HqM48Su7tWnTDAfTXnQZZkzjzITq3JXzquMXICktAVN2cLnT9zPfRAE
+8V8A3BNO5zXiR5W3o/mJP5HQ3/WxpzBGM2N+YmDCJyBoQrIVaAZaXAZUaBBvn5A+
+kEVfGWquwIFuvA67xegbJOCRLD4eUzRdNsn5+NFiakWO1tkFqEzqyQ0PNPviRjgu
+z9NxdPvd1JQOhydkucsPKJzlEBbGyL5QL/Jkot3Qy+FOeuNzgQUfAGtQgzRrsZDK
+hrTVypLSoRXuTB2aWilu4p6aNh84xTdyqo2avtNr2MiQMZIcdamBq8LdBIAShFXI
+h5G2eVGXH/Y=
+-----END CERTIFICATE-----
diff --git a/common/tests/res/raw/subject_with_wild_alt_name.crt b/common/tests/res/raw/subject_with_wild_alt_name.crt
new file mode 100644
index 0000000..19b1174
--- /dev/null
+++ b/common/tests/res/raw/subject_with_wild_alt_name.crt
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC8DCCAdigAwIBAgIJAL/oWJ64VAdXMA0GCSqGSIb3DQEBBQUAMCcxCzAJBgNV
+BAYTAkpQMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wIBcNMTAwMTEyMjEwMDAx
+WhgPMjA2NDEwMTUyMTAwMDFaMCcxCzAJBgNVBAYTAkpQMRgwFgYDVQQDEw93d3cu
+ZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbx1QB
+92iea7VybLYICA4MX4LWipYrRsgXUXQrcIQ3YLTQ9rH0VwScrHL4O4JDxgXCQnR+
+4VOzD42q1KXHJAqzqGUYCNPyvZEzkGCnQ4FBIUEmxZd5SNEefJVH3Z6GizYJomTh
+p78yDcoqymD9umxRC2cWFu8GscfFGMVyhsqLlOofu7UWOs22mkXPo43jDx+VOAoV
+n48YP3P57a2Eo0gcd4zVL00y62VegqBO/1LW38aTS7teiCBFc1TkNYa5I40yN9lP
+rB9ICHYQWyzf/7OxU9iauEK2w6DmSsQoLs9JzEhgeNZddkcc77ciSUCo2Hx0VpOJ
+BFyf2rbryJeAk+FDAgMBAAGjHTAbMBkGA1UdEQQSMBCCDiouZXhhbXBsZTIuY29t
+MA0GCSqGSIb3DQEBBQUAA4IBAQA2a14pRL+4laJ8sscQlucaDB/oSdb0cwhk4IkE
+kKl/ZKr6rKwPZ81sJRgzvI4imLbUAKt4AJHdpI9cIQUq1gw9bzil7LKwmFtFSPmC
+MYb1iadaYrvp7RE4yXrWCcSbU0hup9JQLHTrHLlqLtRuU48NHMvWYThBcS9Q/hQp
+nJ/JxYy3am99MHALWLAfuRxQXhE4C5utDmBwI2KD6A8SA30s+CnuegmkYScuSqBu
+Y3R0HZvKzNIU3pwAm69HCJoG+/9MZEIDJb0WJc5UygxDT45XE9zQMQe4dBOTaNXT
++ntgaB62kE10HzrzpqXAgoAWxWK4RzFcUpBWw9qYq9xOCewJ
+-----END CERTIFICATE-----
diff --git a/common/tests/res/raw/wild_alt_name_only.crt b/common/tests/res/raw/wild_alt_name_only.crt
new file mode 100644
index 0000000..fafdebf
--- /dev/null
+++ b/common/tests/res/raw/wild_alt_name_only.crt
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICuzCCAaOgAwIBAgIJAP82tgcvmAGxMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV
+BAYTAkpQMCAXDTEwMDExMjIxMDAyN1oYDzIwNjQxMDE1MjEwMDI3WjANMQswCQYD
+VQQGEwJKUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALs528EQbcB1
+x4BwxthQBZrgDJzoO7KPV3dhGYoeP8EnRjapZm+T/sj9P/O4HvfxjnB+fsjYSdmE
+WWUtnFrP7wtG9DUC748Ea2PMV8WFhOG58dqBNIko5XzkHB7SxkNZD5S/0KQYMGLr
+rchDsDlmsEf2Qb6qiqpNEU70aSkExZJcH+B9nWdeBpsVFu7wtezwSWEc2NUa2bhW
+gcXQ/aafwHZ4o2PyGwy0sgS/UifqO9tEllC2tPleSNJOmYsVudv5Bz4Q0GG38BSz
+Pc0IcOoln0ZWpXbGr03V2vlXWCwzaFAl3I1T3O7YVqDiaSWoP+d0tHZzmw8aJLXd
+B+KaUUGxRPsCAwEAAaMcMBowGAYDVR0RBBEwD4INKi5leGFtcGxlLmNvbTANBgkq
+hkiG9w0BAQUFAAOCAQEAJbVan4QgJ0cvpJnK9UWIVJNC+UbP87RC5go2fQiTnmGv
+prOrIuMqz1+vGcpIheLTLctJRHPoadXq0+UbQEIaU3pQbY6C4nNdfl+hcvmJeqrt
+kOCcvmIamO68iNvTSeszuHuu4O38PefrW2Xd0nn7bjFZrzBzHFhTudmnqNliP3ue
+KKQpqkUt5lCytnH8V/u/UCWdvVx5LnUa2XFGVLi3ongBIojW5fvF+yxn9ADqxdrI
+va++ow5r1VxQXFJc0ZPzsDo+6TlktoDHaRQJGMqQomqHWT4i7F5UZgf6BHGfEUPU
+qep+GsF3QRHSBtpObWkVDZNFvky3a1iZ2q25+hFIqQ==
+-----END CERTIFICATE-----
diff --git a/common/tests/src/com/android/common/DNParserTest.java b/common/tests/src/com/android/common/DNParserTest.java
new file mode 100644
index 0000000..34b140a
--- /dev/null
+++ b/common/tests/src/com/android/common/DNParserTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.common;
+
+import javax.security.auth.x500.X500Principal;
+
+import junit.framework.TestCase;
+
+public class DNParserTest extends TestCase {
+    public void testFind() {
+        checkFind("", "cn", null);
+        checkFind("ou=xxx", "cn", null);
+        checkFind("ou=xxx,cn=xxx", "cn", "xxx");
+        checkFind("ou=xxx+cn=yyy,cn=zzz+cn=abc", "cn", "yyy");
+        checkFind("2.5.4.3=a,ou=xxx", "cn", "a"); // OID
+        checkFind("cn=a,cn=b", "cn", "a");
+        checkFind("ou=Cc,ou=Bb,ou=Aa", "ou", "Cc");
+        checkFind("cn=imap.gmail.com", "cn", "imap.gmail.com");
+
+        // Quoted string (see http://www.ietf.org/rfc/rfc2253.txt)
+        checkFind("o=\"\\\" a ,=<>#;\"", "o", "\" a ,=<>#;");
+        checkFind("o=abc\\,def", "o", "abc,def");
+
+        // UTF-8 (example in rfc 2253)
+        checkFind("cn=Lu\\C4\\8Di\\C4\\87", "cn", "\u004c\u0075\u010d\u0069\u0107");
+
+        // whitespaces
+        checkFind("ou=a, o=  a  b  ,cn=x", "o", "a  b");
+        checkFind("o=\"  a  b  \" ,cn=x", "o", "  a  b  ");
+    }
+
+    private void checkFind(String dn, String attrType, String expected) {
+        String actual = new DNParser(new X500Principal(dn)).find(attrType);
+        assertEquals("dn:" + dn + "  attr:" + attrType, expected, actual);
+    }
+}
diff --git a/common/tests/src/com/android/common/DomainNameValidatorTest.java b/common/tests/src/com/android/common/DomainNameValidatorTest.java
new file mode 100644
index 0000000..b825be4
--- /dev/null
+++ b/common/tests/src/com/android/common/DomainNameValidatorTest.java
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.common;
+
+import com.android.common.tests.R;
+
+import android.test.AndroidTestCase;
+
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+public class DomainNameValidatorTest extends AndroidTestCase {
+    private static final int ALT_UNKNOWN = 0;
+    private static final int ALT_DNS_NAME = 2;
+    private static final int ALT_IPA_NAME = 7;
+
+    /**
+     * Tests {@link DomainNameValidator#match}, using a simple {@link X509Certificate}
+     * implementation.
+     */
+    public void testMatch() {
+        checkMatch("11", new StubX509Certificate("cn=imap.g.com"), "imap.g.com", true);
+        checkMatch("12", new StubX509Certificate("cn=imap2.g.com"), "imap.g.com", false);
+        checkMatch("13", new StubX509Certificate("cn=sub.imap.g.com"), "imap.g.com", false);
+
+        // If a subjectAltName extension of type dNSName is present, that MUST
+        // be used as the identity
+        checkMatch("21", new StubX509Certificate("")
+                .addSubjectAlternativeName(ALT_DNS_NAME, "a.y.com")
+                , "imap.g.com", false);
+        checkMatch("22", new StubX509Certificate("cn=imap.g.com") // This cn should be ignored
+                .addSubjectAlternativeName(ALT_DNS_NAME, "a.y.com")
+                , "imap.g.com", false);
+        checkMatch("23", new StubX509Certificate("")
+                .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")
+                , "imap.g.com", true);
+
+        // With wildcards
+        checkMatch("24", new StubX509Certificate("")
+                .addSubjectAlternativeName(ALT_DNS_NAME, "*.g.com")
+                , "imap.g.com", true);
+
+        // host name is ip address
+        checkMatch("31", new StubX509Certificate("")
+                .addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4")
+                , "1.2.3.4", true);
+        checkMatch("32", new StubX509Certificate("")
+                .addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4")
+                , "1.2.3.5", false);
+        checkMatch("32", new StubX509Certificate("")
+                .addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4")
+                .addSubjectAlternativeName(ALT_IPA_NAME, "192.168.100.1")
+                , "192.168.100.1", true);
+
+        // Has unknown subject alternative names
+        checkMatch("41", new StubX509Certificate("")
+                .addSubjectAlternativeName(ALT_UNKNOWN, "random string 1")
+                .addSubjectAlternativeName(ALT_UNKNOWN,  "random string 2")
+                .addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d")
+                .addSubjectAlternativeName(ALT_DNS_NAME, "*.google.com")
+                .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")
+                .addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55")
+                .addSubjectAlternativeName(ALT_UNKNOWN, "random string 3")
+                , "imap.g.com", true);
+
+        checkMatch("42", new StubX509Certificate("")
+                .addSubjectAlternativeName(ALT_UNKNOWN, "random string 1")
+                .addSubjectAlternativeName(ALT_UNKNOWN, "random string 2")
+                .addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d")
+                .addSubjectAlternativeName(ALT_DNS_NAME, "*.google.com")
+                .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")
+                .addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55")
+                .addSubjectAlternativeName(ALT_UNKNOWN, "random string 3")
+                , "2.33.44.55", true);
+
+        checkMatch("43", new StubX509Certificate("")
+                .addSubjectAlternativeName(ALT_UNKNOWN, "random string 1")
+                .addSubjectAlternativeName(ALT_UNKNOWN, "random string 2")
+                .addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d")
+                .addSubjectAlternativeName(ALT_DNS_NAME, "*.google.com")
+                .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")
+                .addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55")
+                .addSubjectAlternativeName(ALT_UNKNOWN, "random string 3")
+                , "g.com", false);
+
+        checkMatch("44", new StubX509Certificate("")
+                .addSubjectAlternativeName(ALT_UNKNOWN, "random string 1")
+                .addSubjectAlternativeName(ALT_UNKNOWN, "random string 2")
+                .addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d")
+                .addSubjectAlternativeName(ALT_DNS_NAME, "*.google.com")
+                .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")
+                .addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55")
+                .addSubjectAlternativeName(ALT_UNKNOWN, "random string 3")
+                , "2.33.44.1", false);
+    }
+
+    private void checkMatch(String message, X509Certificate certificate, String thisDomain,
+            boolean expected) {
+        Boolean actual = DomainNameValidator.match(certificate, thisDomain);
+        assertEquals(message, (Object) expected, (Object) actual);
+    }
+
+    /**
+     * Tests {@link DomainNameValidator#matchDns}
+     */
+    public void testMatchDns() {
+        checkMatchDns("11", "a.b.c.d", "a.b.c.d", true);
+        checkMatchDns("12", "a.b.c.d", "*.b.c.d", true);
+        checkMatchDns("13", "b.c.d", "*.b.c.d", true);
+        checkMatchDns("14", "b.c.d", "b*.c.d", true);
+
+        checkMatchDns("15", "a.b.c.d", "*.*.c.d", false);
+        checkMatchDns("16", "a.b.c.d", "*.c.d", false);
+
+        checkMatchDns("21", "imap.google.com", "imap.google.com", true);
+        checkMatchDns("22", "imap2.google.com", "imap.google.com", false);
+        checkMatchDns("23", "imap.google.com", "*.google.com", true);
+        checkMatchDns("24", "imap2.google.com", "*.google.com", true);
+        checkMatchDns("25", "imap.google.com", "*.googl.com", false);
+        checkMatchDns("26", "imap2.google2.com", "*.google3.com", false);
+        checkMatchDns("27", "imap.google.com", "ima*.google.com", true);
+        checkMatchDns("28", "imap.google.com", "imap*.google.com", true);
+        checkMatchDns("29", "imap.google.com", "*.imap.google.com", true);
+
+        checkMatchDns("41", "imap.google.com", "a*.google.com", false);
+        checkMatchDns("42", "imap.google.com", "ix*.google.com", false);
+
+        checkMatchDns("51", "imap.google.com", "iMap.Google.Com", true);
+    }
+
+    private void checkMatchDns(String message, String thisDomain, String thatDomain,
+            boolean expected) {
+        boolean actual = DomainNameValidator.matchDns(thisDomain, thatDomain);
+        assertEquals(message, expected, actual);
+    }
+
+    /**
+     * Test {@link DomainNameValidator#match} with actual certificates.
+     */
+    public void testWithActualCert() throws Exception {
+        // subject_only
+        //
+        // subject: C=JP, CN=www.example.com
+        // subject alt names: n/a
+        checkWithActualCert("11", R.raw.subject_only, "www.example.com", true);
+        checkWithActualCert("12", R.raw.subject_only, "www2.example.com", false);
+
+        // subject_alt_only
+        //
+        // subject: C=JP (no CN)
+        // subject alt names: DNS:www.example.com
+        checkWithActualCert("21", R.raw.subject_alt_only, "www.example.com", true);
+        checkWithActualCert("22", R.raw.subject_alt_only, "www2.example.com", false);
+
+        // subject_with_alt_names
+        //
+        // subject: C=JP, CN=www.example.com
+        // subject alt names: DNS:www2.example.com, DNS:www3.example.com
+        // * Subject should be ignored, because it has subject alt names.
+        checkWithActualCert("31", R.raw.subject_with_alt_names, "www.example.com", false);
+        checkWithActualCert("32", R.raw.subject_with_alt_names, "www2.example.com", true);
+        checkWithActualCert("33", R.raw.subject_with_alt_names, "www3.example.com", true);
+        checkWithActualCert("34", R.raw.subject_with_alt_names, "www4.example.com", false);
+
+        // subject_with_wild_alt_name
+        //
+        // subject: C=JP, CN=www.example.com
+        // subject alt names: DNS:*.example2.com
+        // * Subject should be ignored, because it has subject alt names.
+        checkWithActualCert("41", R.raw.subject_with_wild_alt_name, "www.example.com", false);
+        checkWithActualCert("42", R.raw.subject_with_wild_alt_name, "www2.example.com", false);
+        checkWithActualCert("43", R.raw.subject_with_wild_alt_name, "www.example2.com", true);
+        checkWithActualCert("44", R.raw.subject_with_wild_alt_name, "abc.example2.com", true);
+        checkWithActualCert("45", R.raw.subject_with_wild_alt_name, "www.example3.com", false);
+
+        // wild_alt_name_only
+        //
+        // subject: C=JP
+        // subject alt names: DNS:*.example.com
+        checkWithActualCert("51", R.raw.wild_alt_name_only, "www.example.com", true);
+        checkWithActualCert("52", R.raw.wild_alt_name_only, "www2.example.com", true);
+        checkWithActualCert("53", R.raw.wild_alt_name_only, "www.example2.com", false);
+
+        // wild_alt_name_only
+        //
+        // subject: C=JP
+        // subject alt names: IP Address:192.168.10.1
+        checkWithActualCert("61", R.raw.alt_ip_only, "192.168.10.1", true);
+        checkWithActualCert("61", R.raw.alt_ip_only, "192.168.10.2", false);
+    }
+
+    private void checkWithActualCert(String message, int resId, String domain,
+            boolean expected) throws Exception {
+        CertificateFactory factory = CertificateFactory.getInstance("X509");
+        InputStream certStream = getContext().getResources().openRawResource(resId);
+        X509Certificate certificate = (X509Certificate) factory.generateCertificate(certStream);
+
+        checkMatch(message, certificate, domain, expected);
+    }
+
+    /**
+     * Minimal {@link X509Certificate} implementation for {@link DomainNameValidator}.
+     */
+    private static class StubX509Certificate extends X509Certificate {
+        private final X500Principal subjectX500Principal;
+        private Collection<List<?>> subjectAlternativeNames;
+
+        public StubX509Certificate(String subjectDn) {
+            subjectX500Principal = new X500Principal(subjectDn);
+            subjectAlternativeNames = null;
+        }
+
+        public StubX509Certificate addSubjectAlternativeName(int type, String name) {
+            if (subjectAlternativeNames == null) {
+                subjectAlternativeNames = new ArrayList<List<?>>();
+            }
+            LinkedList<Object> entry = new LinkedList<Object>();
+            entry.add(type);
+            entry.add(name);
+            subjectAlternativeNames.add(entry);
+            return this;
+        }
+
+        @Override
+        public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException {
+            return subjectAlternativeNames;
+        }
+
+        @Override
+        public X500Principal getSubjectX500Principal() {
+            return subjectX500Principal;
+        }
+
+        @Override
+        public void checkValidity() throws CertificateExpiredException,
+                CertificateNotYetValidException {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public void checkValidity(Date date) throws CertificateExpiredException,
+                CertificateNotYetValidException {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public int getBasicConstraints() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public Principal getIssuerDN() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public boolean[] getIssuerUniqueID() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public boolean[] getKeyUsage() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public Date getNotAfter() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public Date getNotBefore() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public BigInteger getSerialNumber() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public String getSigAlgName() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public String getSigAlgOID() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public byte[] getSigAlgParams() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public byte[] getSignature() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public Principal getSubjectDN() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public boolean[] getSubjectUniqueID() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public byte[] getTBSCertificate() throws CertificateEncodingException {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public int getVersion() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public byte[] getEncoded() throws CertificateEncodingException {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public PublicKey getPublicKey() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public String toString() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException,
+                InvalidKeyException, NoSuchProviderException, SignatureException {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        @Override
+        public void verify(PublicKey key, String sigProvider) throws CertificateException,
+                NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
+                SignatureException {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        public Set<String> getCriticalExtensionOIDs() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        public byte[] getExtensionValue(String oid) {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        public Set<String> getNonCriticalExtensionOIDs() {
+            throw new RuntimeException("Method not implemented");
+        }
+
+        public boolean hasUnsupportedCriticalExtension() {
+            throw new RuntimeException("Method not implemented");
+        }
+    }
+}
diff --git a/common/tests/src/com/android/common/OperationSchedulerTest.java b/common/tests/src/com/android/common/OperationSchedulerTest.java
new file mode 100644
index 0000000..13f710d
--- /dev/null
+++ b/common/tests/src/com/android/common/OperationSchedulerTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+import android.content.SharedPreferences;
+import android.test.AndroidTestCase;
+
+public class OperationSchedulerTest extends AndroidTestCase {
+    public void testScheduler() throws Exception {
+        String name = "OperationSchedulerTest.testScheduler";
+        SharedPreferences storage = getContext().getSharedPreferences(name, 0);
+        storage.edit().clear().commit();
+
+        OperationScheduler scheduler = new OperationScheduler(storage);
+        OperationScheduler.Options options = new OperationScheduler.Options();
+        assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
+
+        long beforeTrigger = System.currentTimeMillis();
+        scheduler.setTriggerTimeMillis(beforeTrigger + 1000000);
+        assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
+
+        // It will schedule for the later of the trigger and the moratorium...
+        scheduler.setMoratoriumTimeMillis(beforeTrigger + 500000);
+        assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
+        scheduler.setMoratoriumTimeMillis(beforeTrigger + 1500000);
+        assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
+
+        // Test enable/disable toggle
+        scheduler.setEnabledState(false);
+        assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
+        scheduler.setEnabledState(true);
+        assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
+
+        // Backoff interval after an error
+        long beforeError = System.currentTimeMillis();
+        scheduler.onTransientError();
+        long afterError = System.currentTimeMillis();
+        assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
+        options.backoffFixedMillis = 1000000;
+        options.backoffIncrementalMillis = 500000;
+        assertTrue(beforeError + 1500000 <= scheduler.getNextTimeMillis(options));
+        assertTrue(afterError + 1500000 >= scheduler.getNextTimeMillis(options));
+
+        // Two errors: backoff interval increases
+        beforeError = System.currentTimeMillis();
+        scheduler.onTransientError();
+        afterError = System.currentTimeMillis();
+        assertTrue(beforeError + 2000000 <= scheduler.getNextTimeMillis(options));
+        assertTrue(afterError + 2000000 >= scheduler.getNextTimeMillis(options));
+
+        // Permanent error holds true even if transient errors are reset
+        // However, we remember that the transient error was reset...
+        scheduler.onPermanentError();
+        assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
+        scheduler.resetTransientError();
+        assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
+        scheduler.resetPermanentError();
+        assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
+
+        // Success resets the trigger
+        long beforeSuccess = System.currentTimeMillis();
+        scheduler.onSuccess();
+        long afterSuccess = System.currentTimeMillis();
+        assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
+
+        // The moratorium is not reset by success!
+        scheduler.setTriggerTimeMillis(beforeSuccess + 500000);
+        assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
+        scheduler.setMoratoriumTimeMillis(0);
+        assertEquals(beforeSuccess + 500000, scheduler.getNextTimeMillis(options));
+
+        // Periodic interval after success
+        options.periodicIntervalMillis = 250000;
+        assertTrue(beforeSuccess + 250000 <= scheduler.getNextTimeMillis(options));
+        assertTrue(afterSuccess + 250000 >= scheduler.getNextTimeMillis(options));
+
+        // Trigger minimum is also since the last success
+        options.minTriggerMillis = 1000000;
+        assertTrue(beforeSuccess + 1000000 <= scheduler.getNextTimeMillis(options));
+        assertTrue(afterSuccess + 1000000 >= scheduler.getNextTimeMillis(options));
+    }
+
+    public void testParseOptions() throws Exception {
+         OperationScheduler.Options options = new OperationScheduler.Options();
+         assertEquals(
+                 "OperationScheduler.Options[backoff=0.0+5.0 max=86400.0 min=0.0 period=3600.0]",
+                 OperationScheduler.parseOptions("3600", options).toString());
+
+         assertEquals(
+                 "OperationScheduler.Options[backoff=0.0+2.5 max=86400.0 min=0.0 period=3700.0]",
+                 OperationScheduler.parseOptions("backoff=+2.5 3700", options).toString());
+
+         assertEquals(
+                 "OperationScheduler.Options[backoff=10.0+2.5 max=12345.6 min=7.0 period=3800.0]",
+                 OperationScheduler.parseOptions("max=12345.6 min=7 backoff=10 period=3800",
+                         options).toString());
+
+         assertEquals(
+                "OperationScheduler.Options[backoff=10.0+2.5 max=12345.6 min=7.0 period=3800.0]",
+                 OperationScheduler.parseOptions("", options).toString());
+    }
+}
diff --git a/common/tests/src/com/android/common/PatternsTest.java b/common/tests/src/com/android/common/PatternsTest.java
new file mode 100644
index 0000000..7fabe5e
--- /dev/null
+++ b/common/tests/src/com/android/common/PatternsTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class PatternsTest extends TestCase {
+
+    @SmallTest
+    public void testTldPattern() throws Exception {
+        boolean t;
+
+        t = Patterns.TOP_LEVEL_DOMAIN.matcher("com").matches();
+        assertTrue("Missed valid TLD", t);
+
+        t = Patterns.TOP_LEVEL_DOMAIN.matcher("xer").matches();
+        assertFalse("Matched invalid TLD!", t);
+    }
+
+    @SmallTest
+    public void testUrlPattern() throws Exception {
+        boolean t;
+
+        t = Patterns.WEB_URL.matcher("http://www.google.com").matches();
+        assertTrue("Valid URL", t);
+
+        t = Patterns.WEB_URL.matcher("ftp://www.example.com").matches();
+        assertFalse("Matched invalid protocol", t);
+
+        t = Patterns.WEB_URL.matcher("http://www.example.com:8080").matches();
+        assertTrue("Didn't match valid URL with port", t);
+
+        t = Patterns.WEB_URL.matcher("http://www.example.com:8080/?foo=bar").matches();
+        assertTrue("Didn't match valid URL with port and query args", t);
+
+        t = Patterns.WEB_URL.matcher("http://www.example.com:8080/~user/?foo=bar").matches();
+        assertTrue("Didn't match valid URL with ~", t);
+    }
+
+    @SmallTest
+    public void testIpPattern() throws Exception {
+        boolean t;
+
+        t = Patterns.IP_ADDRESS.matcher("172.29.86.3").matches();
+        assertTrue("Valid IP", t);
+
+        t = Patterns.IP_ADDRESS.matcher("1234.4321.9.9").matches();
+        assertFalse("Invalid IP", t);
+    }
+
+    @SmallTest
+    public void testDomainPattern() throws Exception {
+        boolean t;
+
+        t = Patterns.DOMAIN_NAME.matcher("mail.example.com").matches();
+        assertTrue("Valid domain", t);
+
+        t = Patterns.DOMAIN_NAME.matcher("__+&42.xer").matches();
+        assertFalse("Invalid domain", t);
+    }
+
+    @SmallTest
+    public void testPhonePattern() throws Exception {
+        boolean t;
+
+        t = Patterns.PHONE.matcher("(919) 555-1212").matches();
+        assertTrue("Valid phone", t);
+
+        t = Patterns.PHONE.matcher("2334 9323/54321").matches();
+        assertFalse("Invalid phone", t);
+
+        String[] tests = {
+                "Me: 16505551212 this\n",
+                "Me: 6505551212 this\n",
+                "Me: 5551212 this\n",
+
+                "Me: 1-650-555-1212 this\n",
+                "Me: (650) 555-1212 this\n",
+                "Me: +1 (650) 555-1212 this\n",
+                "Me: +1-650-555-1212 this\n",
+                "Me: 650-555-1212 this\n",
+                "Me: 555-1212 this\n",
+
+                "Me: 1.650.555.1212 this\n",
+                "Me: (650) 555.1212 this\n",
+                "Me: +1 (650) 555.1212 this\n",
+                "Me: +1.650.555.1212 this\n",
+                "Me: 650.555.1212 this\n",
+                "Me: 555.1212 this\n",
+
+                "Me: 1 650 555 1212 this\n",
+                "Me: (650) 555 1212 this\n",
+                "Me: +1 (650) 555 1212 this\n",
+                "Me: +1 650 555 1212 this\n",
+                "Me: 650 555 1212 this\n",
+                "Me: 555 1212 this\n",
+        };
+
+        for (String test : tests) {
+            Matcher m = Patterns.PHONE.matcher(test);
+
+            assertTrue("Valid phone " + test, m.find());
+        }
+    }
+}
diff --git a/include/binder/IBinder.h b/include/binder/IBinder.h
index 884b5c1..749a977 100644
--- a/include/binder/IBinder.h
+++ b/include/binder/IBinder.h
@@ -52,7 +52,7 @@
         DUMP_TRANSACTION        = B_PACK_CHARS('_','D','M','P'),
         INTERFACE_TRANSACTION   = B_PACK_CHARS('_', 'N', 'T', 'F'),
 
-        // Corresponds to tfOneWay -- an asynchronous call.
+        // Corresponds to TF_ONE_WAY -- an asynchronous call.
         FLAG_ONEWAY             = 0x00000001
     };
 
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
index 78306b2..3ab985d 100644
--- a/include/binder/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -68,6 +68,13 @@
 
     static  void                shutdown();
     
+    // Call this to disable switching threads to background scheduling when
+    // receiving incoming IPC calls.  This is specifically here for the
+    // Android system process, since it expects to have background apps calling
+    // in to it but doesn't want to acquire locks in its services while in
+    // the background.
+    static  void                disableBackgroundScheduling(bool disable);
+    
 private:
                                 IPCThreadState();
                                 ~IPCThreadState();
@@ -93,9 +100,10 @@
                                            void* cookie);
     
     const   sp<ProcessState>    mProcess;
+    const   pid_t               mMyThreadId;
             Vector<BBinder*>    mPendingStrongDerefs;
             Vector<RefBase::weakref_type*> mPendingWeakDerefs;
-                                
+            
             Parcel              mIn;
             Parcel              mOut;
             status_t            mLastError;
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index 5219772..c506fb8 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -82,6 +82,7 @@
 enum {
     CAMERA_CMD_START_SMOOTH_ZOOM     = 1,
     CAMERA_CMD_STOP_SMOOTH_ZOOM      = 2,
+    CAMERA_CMD_SET_DISPLAY_ORIENTATION = 3,
 };
 
 // camera fatal errors
@@ -209,4 +210,3 @@
 }; // namespace android
 
 #endif
-
diff --git a/include/ui/CameraParameters.h b/include/ui/CameraParameters.h
index 9e4e140..cae0676 100644
--- a/include/ui/CameraParameters.h
+++ b/include/ui/CameraParameters.h
@@ -29,12 +29,6 @@
     CameraParameters(const String8 &params) { unflatten(params); }
     ~CameraParameters();
 
-    enum {
-        CAMERA_ORIENTATION_UNKNOWN = 0,
-        CAMERA_ORIENTATION_PORTRAIT = 1,
-        CAMERA_ORIENTATION_LANDSCAPE = 2,
-    };
-
     String8 flatten() const;
     void unflatten(const String8 &params);
 
@@ -63,9 +57,6 @@
     void setPictureFormat(const char *format);
     const char *getPictureFormat() const;
 
-    int getOrientation() const;
-    void setOrientation(int orientation);
-
     void dump() const;
     status_t dump(int fd, const Vector<String16>& args) const;
 
@@ -109,9 +100,10 @@
     // The height (in pixels) of EXIF thumbnail in Jpeg picture.
     // Example value: "384". Read/write.
     static const char KEY_JPEG_THUMBNAIL_HEIGHT[];
-    // Supported EXIF thumbnail sizes (width x height).
-    // Example value: "512x384,320x240". Read only.
-    static const char KEY_SUPPORTED_THUMBNAIL_SIZES[];
+    // Supported EXIF thumbnail sizes (width x height). 0x0 means not thumbnail
+    // in EXIF.
+    // Example value: "512x384,320x240,0x0". Read only.
+    static const char KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES[];
     // The quality of the EXIF thumbnail in Jpeg picture. The range is 1 to 100,
     // with 100 being the best.
     // Example value: "90". Read/write.
diff --git a/include/ui/ISurface.h b/include/ui/ISurface.h
index 2ca0026..c7f181c 100644
--- a/include/ui/ISurface.h
+++ b/include/ui/ISurface.h
@@ -55,8 +55,11 @@
     class BufferHeap {
     public:
         enum {
-            /* rotate source image 90 degrees */
+            /* rotate source image */
+            ROT_0     = 0,
             ROT_90    = HAL_TRANSFORM_ROT_90,
+            ROT_180   = HAL_TRANSFORM_ROT_180,
+            ROT_270   = HAL_TRANSFORM_ROT_270,
         };
         BufferHeap();
         
@@ -86,7 +89,7 @@
     virtual void unregisterBuffers() = 0;
     
     virtual sp<OverlayRef> createOverlay(
-            uint32_t w, uint32_t h, int32_t format) = 0;
+            uint32_t w, uint32_t h, int32_t format, int32_t orientation) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 49145e8..6090f60 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -393,7 +393,10 @@
     enum {
         // If set, the string index is sorted by the string values (based
         // on strcmp16()).
-        SORTED_FLAG = 1<<0
+        SORTED_FLAG = 1<<0,
+
+        // String pool is encoded in UTF-8
+        UTF8_FLAG = 1<<8
     };
     uint32_t flags;
 
@@ -451,14 +454,20 @@
 
     size_t size() const;
 
+#ifndef HAVE_ANDROID_OS
+    bool isUTF8() const;
+#endif
+
 private:
     status_t                    mError;
     void*                       mOwnedData;
     const ResStringPool_header* mHeader;
     size_t                      mSize;
+    mutable Mutex               mDecodeLock;
     const uint32_t*             mEntries;
     const uint32_t*             mEntryStyles;
-    const char16_t*             mStrings;
+    const void*                 mStrings;
+    char16_t**                  mCache;
     uint32_t                    mStringPoolSize;    // number of uint16_t
     const uint32_t*             mStyles;
     uint32_t                    mStylePoolSize;    // number of uint32_t
diff --git a/include/utils/String16.h b/include/utils/String16.h
index a2d22ee..07a0c11 100644
--- a/include/utils/String16.h
+++ b/include/utils/String16.h
@@ -49,12 +49,17 @@
 // Version of strzcmp16 for comparing strings in different endianness.
 int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2);
 
+// Convert UTF-8 to UTF-16 including surrogate pairs
+void utf8_to_utf16(const uint8_t *src, size_t srcLen, char16_t* dst, const size_t dstLen);
+
 }
 
 // ---------------------------------------------------------------------------
 
 namespace android {
 
+// ---------------------------------------------------------------------------
+
 class String8;
 class TextOutput;
 
diff --git a/include/utils/String8.h b/include/utils/String8.h
index ecc5774..c4b18a4 100644
--- a/include/utils/String8.h
+++ b/include/utils/String8.h
@@ -60,6 +60,11 @@
 /*
  * Returns the UTF-8 length of "src".
  */
+size_t utf8_length_from_utf16(const char16_t *src, size_t src_len);
+
+/*
+ * Returns the UTF-8 length of "src".
+ */
 size_t utf8_length_from_utf32(const char32_t *src, size_t src_len);
 
 /*
@@ -120,6 +125,9 @@
 size_t utf32_to_utf8(const char32_t* src, size_t src_len,
                      char* dst, size_t dst_len);
 
+size_t utf16_to_utf8(const char16_t* src, size_t src_len,
+                     char* dst, size_t dst_len);
+
 }
 
 // ---------------------------------------------------------------------------
diff --git a/include/utils/threads.h b/include/utils/threads.h
index 0fc533f..130d83c 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -124,6 +124,24 @@
 
 extern void androidSetCreateThreadFunc(android_create_thread_fn func);
 
+// ------------------------------------------------------------------
+// Extra functions working with raw pids.
+
+// Get pid for the current thread.
+extern pid_t androidGetTid();
+
+// Change the scheduling group of a particular thread.  The group
+// should be one of the ANDROID_TGROUP constants.  Returns BAD_VALUE if
+// grp is out of range, else another non-zero value with errno set if
+// the operation failed.
+extern int androidSetThreadSchedulingGroup(pid_t tid, int grp);
+
+// Change the priority AND scheduling group of a particular thread.  The priority
+// should be one of the ANDROID_PRIORITY constants.  Returns INVALID_OPERATION
+// if the priority set failed, else another value if just the group set failed;
+// in either case errno is set.
+extern int androidSetThreadPriority(pid_t tid, int prio);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp
index 351815b..747d0e4 100644
--- a/libs/audioflinger/A2dpAudioInterface.cpp
+++ b/libs/audioflinger/A2dpAudioInterface.cpp
@@ -185,7 +185,9 @@
     String8 keyValuePairs  = a2dpParam.toString();
 
     if (param.size()) {
-        keyValuePairs += ";";
+        if (keyValuePairs != "") {
+            keyValuePairs += ";";
+        }
         keyValuePairs += mHardwareInterface->getParameters(param.toString());
     }
 
@@ -455,4 +457,10 @@
     return NO_ERROR;
 }
 
+status_t A2dpAudioInterface::A2dpAudioStreamOut::getRenderPosition(uint32_t *driverFrames)
+{
+    //TODO: enable when supported by driver
+    return INVALID_OPERATION;
+}
+
 }; // namespace android
diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h
index 530e432..48154f9 100644
--- a/libs/audioflinger/A2dpAudioInterface.h
+++ b/libs/audioflinger/A2dpAudioInterface.h
@@ -93,6 +93,7 @@
         virtual status_t    dump(int fd, const Vector<String16>& args);
         virtual status_t    setParameters(const String8& keyValuePairs);
         virtual String8     getParameters(const String8& keys);
+        virtual status_t    getRenderPosition(uint32_t *dspFrames);
 
     private:
         friend class A2dpAudioInterface;
diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk
index f5c03bb..b68bfc1 100644
--- a/libs/audioflinger/Android.mk
+++ b/libs/audioflinger/Android.mk
@@ -47,7 +47,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=               \
-    AudioPolicyManagerGeneric.cpp
+    AudioPolicyManagerBase.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
@@ -60,7 +60,7 @@
  LOCAL_SHARED_LIBRARIES += libdl
 endif
 
-LOCAL_MODULE:= libaudiopolicygeneric
+LOCAL_MODULE:= libaudiopolicybase
 
 ifeq ($(BOARD_HAVE_BLUETOOTH),true)
   LOCAL_CFLAGS += -DWITH_A2DP
@@ -70,7 +70,7 @@
   LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
 endif
 
-include $(BUILD_SHARED_LIBRARY)
+include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
 
@@ -87,11 +87,10 @@
     libutils \
 	libbinder \
     libmedia \
-    libhardware_legacy \
-    libaudiopolicygeneric
+    libhardware_legacy
 
 ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
-  LOCAL_STATIC_LIBRARIES += libaudiointerface
+  LOCAL_STATIC_LIBRARIES += libaudiointerface libaudiopolicybase
   LOCAL_CFLAGS += -DGENERIC_AUDIO
 else
   LOCAL_SHARED_LIBRARIES += libaudio libaudiopolicy
diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp
index 858e5aa..30e2bc9 100644
--- a/libs/audioflinger/AudioDumpInterface.cpp
+++ b/libs/audioflinger/AudioDumpInterface.cpp
@@ -379,6 +379,12 @@
     }
 }
 
+status_t AudioStreamOutDump::getRenderPosition(uint32_t *dspFrames)
+{
+    if (mFinalStream != 0 ) return mFinalStream->getRenderPosition(dspFrames);
+    return INVALID_OPERATION;
+}
+
 // ----------------------------------------------------------------------------
 
 AudioStreamInDump::AudioStreamInDump(AudioDumpInterface *interface,
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
index 1136ce1..5b9a6b1 100644
--- a/libs/audioflinger/AudioDumpInterface.h
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -56,8 +56,9 @@
     void                Close(void);
     AudioStreamOut*     finalStream() { return mFinalStream; }
     uint32_t            device() { return mDevice; }
-
     int                 getId()  { return mId; }
+    virtual status_t    getRenderPosition(uint32_t *dspFrames);
+
 private:
     AudioDumpInterface *mInterface;
     int                  mId;
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index ecfe1e0..cad420a 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -544,11 +544,11 @@
     return mStreamTypes[stream].mute;
 }
 
-bool AudioFlinger::isMusicActive() const
+bool AudioFlinger::isStreamActive(int stream) const
 {
     Mutex::Autolock _l(mLock);
     for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) {
-        if (mPlaybackThreads.valueAt(i)->isMusicActive()) {
+        if (mPlaybackThreads.valueAt(i)->isStreamActive(stream)) {
             return true;
         }
     }
@@ -633,6 +633,20 @@
     return ret;
 }
 
+status_t AudioFlinger::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output)
+{
+    status_t status;
+
+    Mutex::Autolock _l(mLock);
+
+    PlaybackThread *playbackThread = checkPlaybackThread_l(output);
+    if (playbackThread != NULL) {
+        return playbackThread->getRenderPosition(halFrames, dspFrames);
+    }
+
+    return BAD_VALUE;
+}
+
 void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
 {
 
@@ -1071,7 +1085,7 @@
     return mStreamTypes[stream].mute;
 }
 
-bool AudioFlinger::PlaybackThread::isMusicActive() const
+bool AudioFlinger::PlaybackThread::isStreamActive(int stream) const
 {
     Mutex::Autolock _l(mLock);
     size_t count = mActiveTracks.size();
@@ -1079,7 +1093,7 @@
         sp<Track> t = mActiveTracks[i].promote();
         if (t == 0) continue;
         Track* const track = t.get();
-        if (t->type() == AudioSystem::MUSIC)
+        if (t->type() == stream)
             return true;
     }
     return false;
@@ -1166,6 +1180,19 @@
     memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
 }
 
+status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames)
+{
+    if (halFrames == 0 || dspFrames == 0) {
+        return BAD_VALUE;
+    }
+    if (mOutput == 0) {
+        return INVALID_OPERATION;
+    }
+    *halFrames = mBytesWritten/mOutput->frameSize();
+
+    return mOutput->getRenderPosition(dspFrames);
+}
+
 // ----------------------------------------------------------------------------
 
 AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id)
@@ -1290,8 +1317,9 @@
         if (sleepTime == 0) {
             mLastWriteTime = systemTime();
             mInWrite = true;
+            mBytesWritten += mixBufferSize;
             int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize);
-            if (bytesWritten > 0) mBytesWritten += bytesWritten;
+            if (bytesWritten < 0) mBytesWritten -= mixBufferSize;
             mNumWrites++;
             mInWrite = false;
             nsecs_t now = systemTime();
@@ -1812,8 +1840,9 @@
         if (sleepTime == 0) {
             mLastWriteTime = systemTime();
             mInWrite = true;
+            mBytesWritten += mixBufferSize;
             int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize);
-            if (bytesWritten) mBytesWritten += bytesWritten;
+            if (bytesWritten < 0) mBytesWritten -= mixBufferSize;
             mNumWrites++;
             mInWrite = false;
             mStandby = false;
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 12c90eb..44da9ed 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -100,7 +100,7 @@
     virtual     status_t    setMicMute(bool state);
     virtual     bool        getMicMute() const;
 
-    virtual     bool        isMusicActive() const;
+    virtual     bool        isStreamActive(int stream) const;
 
     virtual     status_t    setParameters(int ioHandle, const String8& keyValuePairs);
     virtual     String8     getParameters(int ioHandle, const String8& keys);
@@ -136,6 +136,8 @@
 
     virtual status_t setVoiceVolume(float volume);
 
+    virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output);
+
     // IBinder::DeathRecipient
     virtual     void        binderDied(const wp<IBinder>& who);
 
@@ -506,7 +508,7 @@
         virtual     float       streamVolume(int stream) const;
         virtual     bool        streamMute(int stream) const;
 
-                    bool        isMusicActive() const;
+                    bool        isStreamActive(int stream) const;
 
                     sp<Track>   createTrack_l(
                                     const sp<AudioFlinger::Client>& client,
@@ -526,6 +528,7 @@
                     bool        isSuspended() { return (mSuspended != 0); }
         virtual     String8     getParameters(const String8& keys);
         virtual     void        audioConfigChanged(int event, int param = 0);
+        virtual     status_t    getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
 
         struct  stream_type_t {
             stream_type_t()
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp
index 57874f3..d63c031 100644
--- a/libs/audioflinger/AudioHardwareGeneric.cpp
+++ b/libs/audioflinger/AudioHardwareGeneric.cpp
@@ -298,6 +298,11 @@
     return param.toString();
 }
 
+status_t AudioStreamOutGeneric::getRenderPosition(uint32_t *dspFrames)
+{
+    return INVALID_OPERATION;
+}
+
 // ----------------------------------------------------------------------------
 
 // record functions
@@ -310,9 +315,8 @@
         uint32_t *pRate,
         AudioSystem::audio_in_acoustics acoustics)
 {
-    // FIXME: remove logging
     if (pFormat == 0 || pChannels == 0 || pRate == 0) return BAD_VALUE;
-    LOGD("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, *pFormat, *pChannels, *pRate);
+    LOGV("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, *pFormat, *pChannels, *pRate);
     // check values
     if ((*pFormat != format()) ||
         (*pChannels != channels()) ||
@@ -332,14 +336,10 @@
 
 AudioStreamInGeneric::~AudioStreamInGeneric()
 {
-    // FIXME: remove logging
-    LOGD("AudioStreamInGeneric destructor");
 }
 
 ssize_t AudioStreamInGeneric::read(void* buffer, ssize_t bytes)
 {
-    // FIXME: remove logging
-    LOGD("AudioStreamInGeneric::read(%p, %d) from fd %d", buffer, (int)bytes, mFd);
     AutoMutex lock(mLock);
     if (mFd < 0) {
         LOGE("Attempt to read from unopened device");
diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h
index 42da413..95c7ea3 100644
--- a/libs/audioflinger/AudioHardwareGeneric.h
+++ b/libs/audioflinger/AudioHardwareGeneric.h
@@ -55,6 +55,7 @@
     virtual status_t    dump(int fd, const Vector<String16>& args);
     virtual status_t    setParameters(const String8& keyValuePairs);
     virtual String8     getParameters(const String8& keys);
+    virtual status_t    getRenderPosition(uint32_t *dspFrames);
 
 private:
     AudioHardwareGeneric *mAudioHardware;
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
index ae391ee..ae215d1 100644
--- a/libs/audioflinger/AudioHardwareStub.cpp
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -158,6 +158,11 @@
     return param.toString();
 }
 
+status_t AudioStreamOutStub::getRenderPosition(uint32_t *dspFrames)
+{
+    return INVALID_OPERATION;
+}
+
 // ----------------------------------------------------------------------------
 
 status_t AudioStreamInStub::set(int *pFormat, uint32_t *pChannels, uint32_t *pRate,
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
index 583f852..769ae3f 100644
--- a/libs/audioflinger/AudioHardwareStub.h
+++ b/libs/audioflinger/AudioHardwareStub.h
@@ -41,6 +41,7 @@
     virtual status_t    dump(int fd, const Vector<String16>& args);
     virtual status_t    setParameters(const String8& keyValuePairs) { return NO_ERROR;}
     virtual String8     getParameters(const String8& keys);
+    virtual status_t    getRenderPosition(uint32_t *dspFrames);
 };
 
 class AudioStreamInStub : public AudioStreamIn {
diff --git a/libs/audioflinger/AudioPolicyManagerBase.cpp b/libs/audioflinger/AudioPolicyManagerBase.cpp
new file mode 100644
index 0000000..096aa73
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyManagerBase.cpp
@@ -0,0 +1,1924 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioPolicyManagerBase"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+#include <hardware_legacy/AudioPolicyManagerBase.h>
+#include <media/mediarecorder.h>
+
+namespace android {
+
+
+// ----------------------------------------------------------------------------
+// AudioPolicyInterface implementation
+// ----------------------------------------------------------------------------
+
+
+status_t AudioPolicyManagerBase::setDeviceConnectionState(AudioSystem::audio_devices device,
+                                                  AudioSystem::device_connection_state state,
+                                                  const char *device_address)
+{
+
+    LOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);
+
+    // connect/disconnect only 1 device at a time
+    if (AudioSystem::popCount(device) != 1) return BAD_VALUE;
+
+    if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
+        LOGE("setDeviceConnectionState() invalid address: %s", device_address);
+        return BAD_VALUE;
+    }
+
+    // handle output devices
+    if (AudioSystem::isOutputDevice(device)) {
+
+#ifndef WITH_A2DP
+        if (AudioSystem::isA2dpDevice(device)) {
+            LOGE("setDeviceConnectionState() invalid device: %x", device);
+            return BAD_VALUE;
+        }
+#endif
+
+        switch (state)
+        {
+        // handle output device connection
+        case AudioSystem::DEVICE_STATE_AVAILABLE:
+            if (mAvailableOutputDevices & device) {
+                LOGW("setDeviceConnectionState() device already connected: %x", device);
+                return INVALID_OPERATION;
+            }
+            LOGV("setDeviceConnectionState() connecting device %x", device);
+
+            // register new device as available
+            mAvailableOutputDevices |= device;
+
+#ifdef WITH_A2DP
+            // handle A2DP device connection
+            if (AudioSystem::isA2dpDevice(device)) {
+                status_t status = handleA2dpConnection(device, device_address);
+                if (status != NO_ERROR) {
+                    mAvailableOutputDevices &= ~device;
+                    return status;
+                }
+            } else
+#endif
+            {
+                if (AudioSystem::isBluetoothScoDevice(device)) {
+                    LOGV("setDeviceConnectionState() BT SCO  device, address %s", device_address);
+                    // keep track of SCO device address
+                    mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+#ifdef WITH_A2DP
+                    if ((mA2dpDeviceAddress == mScoDeviceAddress) &&
+                        (mPhoneState != AudioSystem::MODE_NORMAL)) {
+                        mpClientInterface->suspendOutput(mA2dpOutput);
+                    }
+#endif
+                }
+            }
+            break;
+        // handle output device disconnection
+        case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+            if (!(mAvailableOutputDevices & device)) {
+                LOGW("setDeviceConnectionState() device not connected: %x", device);
+                return INVALID_OPERATION;
+            }
+
+
+            LOGV("setDeviceConnectionState() disconnecting device %x", device);
+            // remove device from available output devices
+            mAvailableOutputDevices &= ~device;
+
+#ifdef WITH_A2DP
+            // handle A2DP device disconnection
+            if (AudioSystem::isA2dpDevice(device)) {
+                status_t status = handleA2dpDisconnection(device, device_address);
+                if (status != NO_ERROR) {
+                    mAvailableOutputDevices |= device;
+                    return status;
+                }
+            } else
+#endif
+            {
+                if (AudioSystem::isBluetoothScoDevice(device)) {
+                    mScoDeviceAddress = "";
+#ifdef WITH_A2DP
+                    if ((mA2dpDeviceAddress == mScoDeviceAddress) &&
+                        (mPhoneState != AudioSystem::MODE_NORMAL)) {
+                        mpClientInterface->restoreOutput(mA2dpOutput);
+                    }
+#endif
+                }
+            }
+            } break;
+
+        default:
+            LOGE("setDeviceConnectionState() invalid state: %x", state);
+            return BAD_VALUE;
+        }
+
+        // request routing change if necessary
+        uint32_t newDevice = getNewDevice(mHardwareOutput, false);
+#ifdef WITH_A2DP
+        checkOutputForAllStrategies(newDevice);
+        // A2DP outputs must be closed after checkOutputForAllStrategies() is executed
+        if (state == AudioSystem::DEVICE_STATE_UNAVAILABLE && AudioSystem::isA2dpDevice(device)) {
+            closeA2dpOutputs();
+        }
+#endif
+        updateDeviceForStrategy();
+        setOutputDevice(mHardwareOutput, newDevice);
+
+        if (device == AudioSystem::DEVICE_OUT_WIRED_HEADSET) {
+            device = AudioSystem::DEVICE_IN_WIRED_HEADSET;
+        } else if (device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO ||
+                   device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
+                   device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
+            device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+        } else {
+            return NO_ERROR;
+        }
+    }
+    // handle input devices
+    if (AudioSystem::isInputDevice(device)) {
+
+        switch (state)
+        {
+        // handle input device connection
+        case AudioSystem::DEVICE_STATE_AVAILABLE: {
+            if (mAvailableInputDevices & device) {
+                LOGW("setDeviceConnectionState() device already connected: %d", device);
+                return INVALID_OPERATION;
+            }
+            mAvailableInputDevices |= device;
+            }
+            break;
+
+        // handle input device disconnection
+        case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+            if (!(mAvailableInputDevices & device)) {
+                LOGW("setDeviceConnectionState() device not connected: %d", device);
+                return INVALID_OPERATION;
+            }
+            mAvailableInputDevices &= ~device;
+            } break;
+
+        default:
+            LOGE("setDeviceConnectionState() invalid state: %x", state);
+            return BAD_VALUE;
+        }
+
+        audio_io_handle_t activeInput = getActiveInput();
+        if (activeInput != 0) {
+            AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
+            uint32_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+            if (newDevice != inputDesc->mDevice) {
+                LOGV("setDeviceConnectionState() changing device from %x to %x for input %d",
+                        inputDesc->mDevice, newDevice, activeInput);
+                inputDesc->mDevice = newDevice;
+                AudioParameter param = AudioParameter();
+                param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+                mpClientInterface->setParameters(activeInput, param.toString());
+            }
+        }
+
+        return NO_ERROR;
+    }
+
+    LOGW("setDeviceConnectionState() invalid device: %x", device);
+    return BAD_VALUE;
+}
+
+AudioSystem::device_connection_state AudioPolicyManagerBase::getDeviceConnectionState(AudioSystem::audio_devices device,
+                                                  const char *device_address)
+{
+    AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE;
+    String8 address = String8(device_address);
+    if (AudioSystem::isOutputDevice(device)) {
+        if (device & mAvailableOutputDevices) {
+#ifdef WITH_A2DP
+            if (AudioSystem::isA2dpDevice(device) &&
+                address != "" && mA2dpDeviceAddress != address) {
+                return state;
+            }
+#endif
+            if (AudioSystem::isBluetoothScoDevice(device) &&
+                address != "" && mScoDeviceAddress != address) {
+                return state;
+            }
+            state = AudioSystem::DEVICE_STATE_AVAILABLE;
+        }
+    } else if (AudioSystem::isInputDevice(device)) {
+        if (device & mAvailableInputDevices) {
+            state = AudioSystem::DEVICE_STATE_AVAILABLE;
+        }
+    }
+
+    return state;
+}
+
+void AudioPolicyManagerBase::setPhoneState(int state)
+{
+    LOGV("setPhoneState() state %d", state);
+    uint32_t newDevice = 0;
+    if (state < 0 || state >= AudioSystem::NUM_MODES) {
+        LOGW("setPhoneState() invalid state %d", state);
+        return;
+    }
+
+    if (state == mPhoneState ) {
+        LOGW("setPhoneState() setting same state %d", state);
+        return;
+    }
+
+    // if leaving call state, handle special case of active streams
+    // pertaining to sonification strategy see handleIncallSonification()
+    if (mPhoneState == AudioSystem::MODE_IN_CALL) {
+        LOGV("setPhoneState() in call state management: new state is %d", state);
+        for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+            handleIncallSonification(stream, false, true);
+        }
+    }
+
+    // store previous phone state for management of sonification strategy below
+    int oldState = mPhoneState;
+    mPhoneState = state;
+    bool force = false;
+
+    // are we entering or starting a call
+    if ((oldState != AudioSystem::MODE_IN_CALL) && (state == AudioSystem::MODE_IN_CALL)) {
+        LOGV("  Entering call in setPhoneState()");
+        // force routing command to audio hardware when starting a call
+        // even if no device change is needed
+        force = true;
+    } else if ((oldState == AudioSystem::MODE_IN_CALL) && (state != AudioSystem::MODE_IN_CALL)) {
+        LOGV("  Exiting call in setPhoneState()");
+        // force routing command to audio hardware when exiting a call
+        // even if no device change is needed
+        force = true;
+    }
+
+    // check for device and output changes triggered by new phone state
+    newDevice = getNewDevice(mHardwareOutput, false);
+#ifdef WITH_A2DP
+    checkOutputForAllStrategies(newDevice);
+    // suspend A2DP output if SCO device address is the same as A2DP device address.
+    // no need to check that a SCO device is actually connected as mScoDeviceAddress == ""
+    // if none is connected and the test below will fail.
+    if (mA2dpDeviceAddress == mScoDeviceAddress) {
+        if (oldState == AudioSystem::MODE_NORMAL) {
+            mpClientInterface->suspendOutput(mA2dpOutput);
+        } else if (state == AudioSystem::MODE_NORMAL) {
+            mpClientInterface->restoreOutput(mA2dpOutput);
+        }
+    }
+#endif
+    updateDeviceForStrategy();
+
+    AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput);
+
+    // force routing command to audio hardware when ending call
+    // even if no device change is needed
+    if (oldState == AudioSystem::MODE_IN_CALL && newDevice == 0) {
+        newDevice = hwOutputDesc->device();
+    }
+    // change routing is necessary
+    setOutputDevice(mHardwareOutput, newDevice, force);
+
+    // if entering in call state, handle special case of active streams
+    // pertaining to sonification strategy see handleIncallSonification()
+    if (state == AudioSystem::MODE_IN_CALL) {
+        LOGV("setPhoneState() in call state management: new state is %d", state);
+        for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+            handleIncallSonification(stream, true, true);
+        }
+    }
+
+    // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE
+    if (state == AudioSystem::MODE_RINGTONE &&
+        (hwOutputDesc->mRefCount[AudioSystem::MUSIC] ||
+        (systemTime() - mMusicStopTime) < seconds(SONIFICATION_HEADSET_MUSIC_DELAY))) {
+        mLimitRingtoneVolume = true;
+    } else {
+        mLimitRingtoneVolume = false;
+    }
+}
+
+void AudioPolicyManagerBase::setRingerMode(uint32_t mode, uint32_t mask)
+{
+    LOGV("setRingerMode() mode %x, mask %x", mode, mask);
+
+    mRingerMode = mode;
+}
+
+void AudioPolicyManagerBase::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+{
+    LOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState);
+
+    switch(usage) {
+    case AudioSystem::FOR_COMMUNICATION:
+        if (config != AudioSystem::FORCE_SPEAKER && config != AudioSystem::FORCE_BT_SCO &&
+            config != AudioSystem::FORCE_NONE) {
+            LOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config);
+            return;
+        }
+        mForceUse[usage] = config;
+        break;
+    case AudioSystem::FOR_MEDIA:
+        if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP &&
+            config != AudioSystem::FORCE_WIRED_ACCESSORY && config != AudioSystem::FORCE_NONE) {
+            LOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
+            return;
+        }
+        mForceUse[usage] = config;
+        break;
+    case AudioSystem::FOR_RECORD:
+        if (config != AudioSystem::FORCE_BT_SCO && config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+            config != AudioSystem::FORCE_NONE) {
+            LOGW("setForceUse() invalid config %d for FOR_RECORD", config);
+            return;
+        }
+        mForceUse[usage] = config;
+        break;
+    case AudioSystem::FOR_DOCK:
+        if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK &&
+            config != AudioSystem::FORCE_BT_DESK_DOCK && config != AudioSystem::FORCE_WIRED_ACCESSORY) {
+            LOGW("setForceUse() invalid config %d for FOR_DOCK", config);
+        }
+        mForceUse[usage] = config;
+        break;
+    default:
+        LOGW("setForceUse() invalid usage %d", usage);
+        break;
+    }
+
+    // check for device and output changes triggered by new phone state
+    uint32_t newDevice = getNewDevice(mHardwareOutput, false);
+#ifdef WITH_A2DP
+    checkOutputForAllStrategies(newDevice);
+#endif
+    updateDeviceForStrategy();
+    setOutputDevice(mHardwareOutput, newDevice);
+}
+
+AudioSystem::forced_config AudioPolicyManagerBase::getForceUse(AudioSystem::force_use usage)
+{
+    return mForceUse[usage];
+}
+
+void AudioPolicyManagerBase::setSystemProperty(const char* property, const char* value)
+{
+    LOGV("setSystemProperty() property %s, value %s", property, value);
+    if (strcmp(property, "ro.camera.sound.forced") == 0) {
+        if (atoi(value)) {
+            LOGV("ENFORCED_AUDIBLE cannot be muted");
+            mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = false;
+        } else {
+            LOGV("ENFORCED_AUDIBLE can be muted");
+            mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = true;
+        }
+    }
+}
+
+audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type stream,
+                                    uint32_t samplingRate,
+                                    uint32_t format,
+                                    uint32_t channels,
+                                    AudioSystem::output_flags flags)
+{
+    audio_io_handle_t output = 0;
+    uint32_t latency = 0;
+    routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream);
+    uint32_t device = getDeviceForStrategy(strategy);
+    LOGV("getOutput() stream %d, samplingRate %d, format %d, channels %x, flags %x", stream, samplingRate, format, channels, flags);
+
+#ifdef AUDIO_POLICY_TEST
+    if (mCurOutput != 0) {
+        LOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channels %x, mDirectOutput %d",
+                mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, mDirectOutput);
+
+        if (mTestOutputs[mCurOutput] == 0) {
+            LOGV("getOutput() opening test output");
+            AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
+            outputDesc->mDevice = mTestDevice;
+            outputDesc->mSamplingRate = mTestSamplingRate;
+            outputDesc->mFormat = mTestFormat;
+            outputDesc->mChannels = mTestChannels;
+            outputDesc->mLatency = mTestLatencyMs;
+            outputDesc->mFlags = (AudioSystem::output_flags)(mDirectOutput ? AudioSystem::OUTPUT_FLAG_DIRECT : 0);
+            outputDesc->mRefCount[stream] = 0;
+            mTestOutputs[mCurOutput] = mpClientInterface->openOutput(&outputDesc->mDevice,
+                                            &outputDesc->mSamplingRate,
+                                            &outputDesc->mFormat,
+                                            &outputDesc->mChannels,
+                                            &outputDesc->mLatency,
+                                            outputDesc->mFlags);
+            if (mTestOutputs[mCurOutput]) {
+                AudioParameter outputCmd = AudioParameter();
+                outputCmd.addInt(String8("set_id"),mCurOutput);
+                mpClientInterface->setParameters(mTestOutputs[mCurOutput],outputCmd.toString());
+                addOutput(mTestOutputs[mCurOutput], outputDesc);
+            }
+        }
+        return mTestOutputs[mCurOutput];
+    }
+#endif //AUDIO_POLICY_TEST
+
+    // open a direct output if:
+    // 1 a direct output is explicitely requested
+    // 2 the audio format is compressed
+    if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
+         (format !=0 && !AudioSystem::isLinearPCM(format))) {
+
+        LOGV("getOutput() opening direct output device %x", device);
+        AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
+        outputDesc->mDevice = device;
+        outputDesc->mSamplingRate = samplingRate;
+        outputDesc->mFormat = format;
+        outputDesc->mChannels = channels;
+        outputDesc->mLatency = 0;
+        outputDesc->mFlags = (AudioSystem::output_flags)(flags | AudioSystem::OUTPUT_FLAG_DIRECT);
+        outputDesc->mRefCount[stream] = 1;
+        output = mpClientInterface->openOutput(&outputDesc->mDevice,
+                                        &outputDesc->mSamplingRate,
+                                        &outputDesc->mFormat,
+                                        &outputDesc->mChannels,
+                                        &outputDesc->mLatency,
+                                        outputDesc->mFlags);
+
+        // only accept an output with the requeted parameters
+        if (output == 0 ||
+            (samplingRate != 0 && samplingRate != outputDesc->mSamplingRate) ||
+            (format != 0 && format != outputDesc->mFormat) ||
+            (channels != 0 && channels != outputDesc->mChannels)) {
+            LOGV("getOutput() failed opening direct output: samplingRate %d, format %d, channels %d",
+                    samplingRate, format, channels);
+            if (output != 0) {
+                mpClientInterface->closeOutput(output);
+            }
+            delete outputDesc;
+            return 0;
+        }
+        addOutput(output, outputDesc);
+        return output;
+    }
+
+    if (channels != 0 && channels != AudioSystem::CHANNEL_OUT_MONO &&
+        channels != AudioSystem::CHANNEL_OUT_STEREO) {
+        return 0;
+    }
+    // open a non direct output
+
+    // get which output is suitable for the specified stream. The actual routing change will happen
+    // when startOutput() will be called
+    uint32_t a2dpDevice = device & AudioSystem::DEVICE_OUT_ALL_A2DP;
+    if (AudioSystem::popCount((AudioSystem::audio_devices)device) == 2) {
+#ifdef WITH_A2DP
+        if (a2dpUsedForSonification() && a2dpDevice != 0) {
+            // if playing on 2 devices among which one is A2DP, use duplicated output
+            LOGV("getOutput() using duplicated output");
+            LOGW_IF((mA2dpOutput == 0), "getOutput() A2DP device in multiple %x selected but A2DP output not opened", device);
+            output = mDuplicatedOutput;
+        } else
+#endif
+        {
+            // if playing on 2 devices among which none is A2DP, use hardware output
+            output = mHardwareOutput;
+        }
+        LOGV("getOutput() using output %d for 2 devices %x", output, device);
+    } else {
+#ifdef WITH_A2DP
+        if (a2dpDevice != 0) {
+            // if playing on A2DP device, use a2dp output
+            LOGW_IF((mA2dpOutput == 0), "getOutput() A2DP device %x selected but A2DP output not opened", device);
+            output = mA2dpOutput;
+        } else
+#endif
+        {
+            // if playing on not A2DP device, use hardware output
+            output = mHardwareOutput;
+        }
+    }
+
+
+    LOGW_IF((output ==0), "getOutput() could not find output for stream %d, samplingRate %d, format %d, channels %x, flags %x",
+                stream, samplingRate, format, channels, flags);
+
+    return output;
+}
+
+status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+    LOGV("startOutput() output %d, stream %d", output, stream);
+    ssize_t index = mOutputs.indexOfKey(output);
+    if (index < 0) {
+        LOGW("startOutput() unknow output %d", output);
+        return BAD_VALUE;
+    }
+
+    AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+    routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream);
+
+#ifdef WITH_A2DP
+    if (mA2dpOutput != 0  && !a2dpUsedForSonification() && strategy == STRATEGY_SONIFICATION) {
+        setStrategyMute(STRATEGY_MEDIA, true, mA2dpOutput);
+    }
+#endif
+
+    // incremenent usage count for this stream on the requested output:
+    // NOTE that the usage count is the same for duplicated output and hardware output which is
+    // necassary for a correct control of hardware output routing by startOutput() and stopOutput()
+    outputDesc->changeRefCount(stream, 1);
+
+    setOutputDevice(output, getNewDevice(output));
+
+    // handle special case for sonification while in call
+    if (mPhoneState == AudioSystem::MODE_IN_CALL) {
+        handleIncallSonification(stream, true, false);
+    }
+
+    // apply volume rules for current stream and device if necessary
+    checkAndSetVolume(stream, mStreams[stream].mIndexCur, output, outputDesc->device());
+
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+    LOGV("stopOutput() output %d, stream %d", output, stream);
+    ssize_t index = mOutputs.indexOfKey(output);
+    if (index < 0) {
+        LOGW("stopOutput() unknow output %d", output);
+        return BAD_VALUE;
+    }
+
+    AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+    routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream);
+
+    // handle special case for sonification while in call
+    if (mPhoneState == AudioSystem::MODE_IN_CALL) {
+        handleIncallSonification(stream, false, false);
+    }
+
+    if (outputDesc->mRefCount[stream] > 0) {
+        // decrement usage count of this stream on the output
+        outputDesc->changeRefCount(stream, -1);
+        // store time at which the last music track was stopped - see computeVolume()
+        if (stream == AudioSystem::MUSIC) {
+            mMusicStopTime = systemTime();
+        }
+
+        setOutputDevice(output, getNewDevice(output));
+
+#ifdef WITH_A2DP
+        if (mA2dpOutput != 0 && !a2dpUsedForSonification() && strategy == STRATEGY_SONIFICATION) {
+            setStrategyMute(STRATEGY_MEDIA, false, mA2dpOutput, mOutputs.valueFor(mHardwareOutput)->mLatency*2);
+        }
+#endif
+        return NO_ERROR;
+    } else {
+        LOGW("stopOutput() refcount is already 0 for output %d", output);
+        return INVALID_OPERATION;
+    }
+}
+
+void AudioPolicyManagerBase::releaseOutput(audio_io_handle_t output)
+{
+    LOGV("releaseOutput() %d", output);
+    ssize_t index = mOutputs.indexOfKey(output);
+    if (index < 0) {
+        LOGW("releaseOutput() releasing unknown output %d", output);
+        return;
+    }
+
+#ifdef AUDIO_POLICY_TEST
+    int testIndex = testOutputIndex(output);
+    if (testIndex != 0) {
+        AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+        if (outputDesc->refCount() == 0) {
+            mpClientInterface->closeOutput(output);
+            delete mOutputs.valueAt(index);
+            mOutputs.removeItem(output);
+            mTestOutputs[testIndex] = 0;
+        }
+        return;
+    }
+#endif //AUDIO_POLICY_TEST
+
+    if (mOutputs.valueAt(index)->mFlags & AudioSystem::OUTPUT_FLAG_DIRECT) {
+        mpClientInterface->closeOutput(output);
+        delete mOutputs.valueAt(index);
+        mOutputs.removeItem(output);
+    }
+}
+
+audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource,
+                                    uint32_t samplingRate,
+                                    uint32_t format,
+                                    uint32_t channels,
+                                    AudioSystem::audio_in_acoustics acoustics)
+{
+    audio_io_handle_t input = 0;
+    uint32_t device = getDeviceForInputSource(inputSource);
+
+    LOGV("getInput() inputSource %d, samplingRate %d, format %d, channels %x, acoustics %x", inputSource, samplingRate, format, channels, acoustics);
+
+    if (device == 0) {
+        return 0;
+    }
+
+    // adapt channel selection to input source
+    switch(inputSource) {
+    case AUDIO_SOURCE_VOICE_UPLINK:
+        channels = AudioSystem::CHANNEL_IN_VOICE_UPLINK;
+        break;
+    case AUDIO_SOURCE_VOICE_DOWNLINK:
+        channels = AudioSystem::CHANNEL_IN_VOICE_DNLINK;
+        break;
+    case AUDIO_SOURCE_VOICE_CALL:
+        channels = (AudioSystem::CHANNEL_IN_VOICE_UPLINK | AudioSystem::CHANNEL_IN_VOICE_DNLINK);
+        break;
+    default:
+        break;
+    }
+
+    AudioInputDescriptor *inputDesc = new AudioInputDescriptor();
+
+    inputDesc->mInputSource = inputSource;
+    inputDesc->mDevice = device;
+    inputDesc->mSamplingRate = samplingRate;
+    inputDesc->mFormat = format;
+    inputDesc->mChannels = channels;
+    inputDesc->mAcoustics = acoustics;
+    inputDesc->mRefCount = 0;
+    input = mpClientInterface->openInput(&inputDesc->mDevice,
+                                    &inputDesc->mSamplingRate,
+                                    &inputDesc->mFormat,
+                                    &inputDesc->mChannels,
+                                    inputDesc->mAcoustics);
+
+    // only accept input with the exact requested set of parameters
+    if (input == 0 ||
+        (samplingRate != inputDesc->mSamplingRate) ||
+        (format != inputDesc->mFormat) ||
+        (channels != inputDesc->mChannels)) {
+        LOGV("getInput() failed opening input: samplingRate %d, format %d, channels %d",
+                samplingRate, format, channels);
+        if (input != 0) {
+            mpClientInterface->closeInput(input);
+        }
+        delete inputDesc;
+        return 0;
+    }
+    mInputs.add(input, inputDesc);
+    return input;
+}
+
+status_t AudioPolicyManagerBase::startInput(audio_io_handle_t input)
+{
+    LOGV("startInput() input %d", input);
+    ssize_t index = mInputs.indexOfKey(input);
+    if (index < 0) {
+        LOGW("startInput() unknow input %d", input);
+        return BAD_VALUE;
+    }
+    AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+#ifdef AUDIO_POLICY_TEST
+    if (mTestInput == 0)
+#endif //AUDIO_POLICY_TEST
+    {
+        // refuse 2 active AudioRecord clients at the same time
+        if (getActiveInput() != 0) {
+            LOGW("startInput() input %d failed: other input already started", input);
+            return INVALID_OPERATION;
+        }
+    }
+
+    AudioParameter param = AudioParameter();
+    param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice);
+
+    // use Voice Recognition mode or not for this input based on input source
+    int vr_enabled = inputDesc->mInputSource == AUDIO_SOURCE_VOICE_RECOGNITION ? 1 : 0;
+    param.addInt(String8("vr_mode"), vr_enabled);
+    LOGV("AudioPolicyManager::startInput(%d), setting vr_mode to %d", inputDesc->mInputSource, vr_enabled);
+
+    mpClientInterface->setParameters(input, param.toString());
+
+    inputDesc->mRefCount = 1;
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManagerBase::stopInput(audio_io_handle_t input)
+{
+    LOGV("stopInput() input %d", input);
+    ssize_t index = mInputs.indexOfKey(input);
+    if (index < 0) {
+        LOGW("stopInput() unknow input %d", input);
+        return BAD_VALUE;
+    }
+    AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+    if (inputDesc->mRefCount == 0) {
+        LOGW("stopInput() input %d already stopped", input);
+        return INVALID_OPERATION;
+    } else {
+        AudioParameter param = AudioParameter();
+        param.addInt(String8(AudioParameter::keyRouting), 0);
+        mpClientInterface->setParameters(input, param.toString());
+        inputDesc->mRefCount = 0;
+        return NO_ERROR;
+    }
+}
+
+void AudioPolicyManagerBase::releaseInput(audio_io_handle_t input)
+{
+    LOGV("releaseInput() %d", input);
+    ssize_t index = mInputs.indexOfKey(input);
+    if (index < 0) {
+        LOGW("releaseInput() releasing unknown input %d", input);
+        return;
+    }
+    mpClientInterface->closeInput(input);
+    delete mInputs.valueAt(index);
+    mInputs.removeItem(input);
+    LOGV("releaseInput() exit");
+}
+
+void AudioPolicyManagerBase::initStreamVolume(AudioSystem::stream_type stream,
+                                            int indexMin,
+                                            int indexMax)
+{
+    LOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
+    if (indexMin < 0 || indexMin >= indexMax) {
+        LOGW("initStreamVolume() invalid index limits for stream %d, min %d, max %d", stream , indexMin, indexMax);
+        return;
+    }
+    mStreams[stream].mIndexMin = indexMin;
+    mStreams[stream].mIndexMax = indexMax;
+}
+
+status_t AudioPolicyManagerBase::setStreamVolumeIndex(AudioSystem::stream_type stream, int index)
+{
+
+    if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) {
+        return BAD_VALUE;
+    }
+
+    // Force max volume if stream cannot be muted
+    if (!mStreams[stream].mCanBeMuted) index = mStreams[stream].mIndexMax;
+
+    LOGV("setStreamVolumeIndex() stream %d, index %d", stream, index);
+    mStreams[stream].mIndexCur = index;
+
+    // compute and apply stream volume on all outputs according to connected device
+    status_t status = NO_ERROR;
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), mOutputs.valueAt(i)->device());
+        if (volStatus != NO_ERROR) {
+            status = volStatus;
+        }
+    }
+    return status;
+}
+
+status_t AudioPolicyManagerBase::getStreamVolumeIndex(AudioSystem::stream_type stream, int *index)
+{
+    if (index == 0) {
+        return BAD_VALUE;
+    }
+    LOGV("getStreamVolumeIndex() stream %d", stream);
+    *index =  mStreams[stream].mIndexCur;
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManagerBase::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "\nAudioPolicyManager Dump: %p\n", this);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Hardware Output: %d\n", mHardwareOutput);
+    result.append(buffer);
+#ifdef WITH_A2DP
+    snprintf(buffer, SIZE, " A2DP Output: %d\n", mA2dpOutput);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Duplicated Output: %d\n", mDuplicatedOutput);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " A2DP device address: %s\n", mA2dpDeviceAddress.string());
+    result.append(buffer);
+#endif
+    snprintf(buffer, SIZE, " SCO device address: %s\n", mScoDeviceAddress.string());
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Output devices: %08x\n", mAvailableOutputDevices);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Input devices: %08x\n", mAvailableInputDevices);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Phone state: %d\n", mPhoneState);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Ringer mode: %d\n", mRingerMode);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Force use for communications %d\n", mForceUse[AudioSystem::FOR_COMMUNICATION]);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Force use for media %d\n", mForceUse[AudioSystem::FOR_MEDIA]);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Force use for record %d\n", mForceUse[AudioSystem::FOR_RECORD]);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Force use for dock %d\n", mForceUse[AudioSystem::FOR_DOCK]);
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+
+    snprintf(buffer, SIZE, "\nOutputs dump:\n");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        snprintf(buffer, SIZE, "- Output %d dump:\n", mOutputs.keyAt(i));
+        write(fd, buffer, strlen(buffer));
+        mOutputs.valueAt(i)->dump(fd);
+    }
+
+    snprintf(buffer, SIZE, "\nInputs dump:\n");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < mInputs.size(); i++) {
+        snprintf(buffer, SIZE, "- Input %d dump:\n", mInputs.keyAt(i));
+        write(fd, buffer, strlen(buffer));
+        mInputs.valueAt(i)->dump(fd);
+    }
+
+    snprintf(buffer, SIZE, "\nStreams dump:\n");
+    write(fd, buffer, strlen(buffer));
+    snprintf(buffer, SIZE, " Stream  Index Min  Index Max  Index Cur  Can be muted\n");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+        snprintf(buffer, SIZE, " %02d", i);
+        mStreams[i].dump(buffer + 3, SIZE);
+        write(fd, buffer, strlen(buffer));
+    }
+
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManagerBase
+// ----------------------------------------------------------------------------
+
+AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)
+    :
+#ifdef AUDIO_POLICY_TEST
+    Thread(false),
+#endif //AUDIO_POLICY_TEST
+    mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0), mLimitRingtoneVolume(false)
+{
+    mpClientInterface = clientInterface;
+
+    for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
+        mForceUse[i] = AudioSystem::FORCE_NONE;
+    }
+
+    // devices available by default are speaker, ear piece and microphone
+    mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE |
+                        AudioSystem::DEVICE_OUT_SPEAKER;
+    mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC;
+
+#ifdef WITH_A2DP
+    mA2dpOutput = 0;
+    mDuplicatedOutput = 0;
+    mA2dpDeviceAddress = String8("");
+#endif
+    mScoDeviceAddress = String8("");
+
+    // open hardware output
+    AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
+    outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
+    mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
+                                    &outputDesc->mSamplingRate,
+                                    &outputDesc->mFormat,
+                                    &outputDesc->mChannels,
+                                    &outputDesc->mLatency,
+                                    outputDesc->mFlags);
+
+    if (mHardwareOutput == 0) {
+        LOGE("Failed to initialize hardware output stream, samplingRate: %d, format %d, channels %d",
+                outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels);
+    } else {
+        addOutput(mHardwareOutput, outputDesc);
+        setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true);
+    }
+
+    updateDeviceForStrategy();
+#ifdef AUDIO_POLICY_TEST
+    AudioParameter outputCmd = AudioParameter();
+    outputCmd.addInt(String8("set_id"), 0);
+    mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
+
+    mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER;
+    mTestSamplingRate = 44100;
+    mTestFormat = AudioSystem::PCM_16_BIT;
+    mTestChannels =  AudioSystem::CHANNEL_OUT_STEREO;
+    mTestLatencyMs = 0;
+    mCurOutput = 0;
+    mDirectOutput = false;
+    for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
+        mTestOutputs[i] = 0;
+    }
+
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    snprintf(buffer, SIZE, "AudioPolicyManagerTest");
+    run(buffer, ANDROID_PRIORITY_AUDIO);
+#endif //AUDIO_POLICY_TEST
+}
+
+AudioPolicyManagerBase::~AudioPolicyManagerBase()
+{
+#ifdef AUDIO_POLICY_TEST
+    exit();
+#endif //AUDIO_POLICY_TEST
+   for (size_t i = 0; i < mOutputs.size(); i++) {
+        mpClientInterface->closeOutput(mOutputs.keyAt(i));
+        delete mOutputs.valueAt(i);
+   }
+   mOutputs.clear();
+   for (size_t i = 0; i < mInputs.size(); i++) {
+        mpClientInterface->closeInput(mInputs.keyAt(i));
+        delete mInputs.valueAt(i);
+   }
+   mInputs.clear();
+}
+
+#ifdef AUDIO_POLICY_TEST
+bool AudioPolicyManagerBase::threadLoop()
+{
+    LOGV("entering threadLoop()");
+    while (!exitPending())
+    {
+        String8 command;
+        int valueInt;
+        String8 value;
+
+        Mutex::Autolock _l(mLock);
+        mWaitWorkCV.waitRelative(mLock, milliseconds(50));
+
+        command = mpClientInterface->getParameters(0, String8("test_cmd_policy"));
+        AudioParameter param = AudioParameter(command);
+
+        if (param.getInt(String8("test_cmd_policy"), valueInt) == NO_ERROR &&
+            valueInt != 0) {
+            LOGV("Test command %s received", command.string());
+            String8 target;
+            if (param.get(String8("target"), target) != NO_ERROR) {
+                target = "Manager";
+            }
+            if (param.getInt(String8("test_cmd_policy_output"), valueInt) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_output"));
+                mCurOutput = valueInt;
+            }
+            if (param.get(String8("test_cmd_policy_direct"), value) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_direct"));
+                if (value == "false") {
+                    mDirectOutput = false;
+                } else if (value == "true") {
+                    mDirectOutput = true;
+                }
+            }
+            if (param.getInt(String8("test_cmd_policy_input"), valueInt) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_input"));
+                mTestInput = valueInt;
+            }
+
+            if (param.get(String8("test_cmd_policy_format"), value) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_format"));
+                int format = AudioSystem::INVALID_FORMAT;
+                if (value == "PCM 16 bits") {
+                    format = AudioSystem::PCM_16_BIT;
+                } else if (value == "PCM 8 bits") {
+                    format = AudioSystem::PCM_8_BIT;
+                } else if (value == "Compressed MP3") {
+                    format = AudioSystem::MP3;
+                }
+                if (format != AudioSystem::INVALID_FORMAT) {
+                    if (target == "Manager") {
+                        mTestFormat = format;
+                    } else if (mTestOutputs[mCurOutput] != 0) {
+                        AudioParameter outputParam = AudioParameter();
+                        outputParam.addInt(String8("format"), format);
+                        mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+                    }
+                }
+            }
+            if (param.get(String8("test_cmd_policy_channels"), value) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_channels"));
+                int channels = 0;
+
+                if (value == "Channels Stereo") {
+                    channels =  AudioSystem::CHANNEL_OUT_STEREO;
+                } else if (value == "Channels Mono") {
+                    channels =  AudioSystem::CHANNEL_OUT_MONO;
+                }
+                if (channels != 0) {
+                    if (target == "Manager") {
+                        mTestChannels = channels;
+                    } else if (mTestOutputs[mCurOutput] != 0) {
+                        AudioParameter outputParam = AudioParameter();
+                        outputParam.addInt(String8("channels"), channels);
+                        mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+                    }
+                }
+            }
+            if (param.getInt(String8("test_cmd_policy_sampleRate"), valueInt) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_sampleRate"));
+                if (valueInt >= 0 && valueInt <= 96000) {
+                    int samplingRate = valueInt;
+                    if (target == "Manager") {
+                        mTestSamplingRate = samplingRate;
+                    } else if (mTestOutputs[mCurOutput] != 0) {
+                        AudioParameter outputParam = AudioParameter();
+                        outputParam.addInt(String8("sampling_rate"), samplingRate);
+                        mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+                    }
+                }
+            }
+
+            if (param.get(String8("test_cmd_policy_reopen"), value) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_reopen"));
+
+                mpClientInterface->closeOutput(mHardwareOutput);
+                delete mOutputs.valueFor(mHardwareOutput);
+                mOutputs.removeItem(mHardwareOutput);
+
+                AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
+                outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
+                mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
+                                                &outputDesc->mSamplingRate,
+                                                &outputDesc->mFormat,
+                                                &outputDesc->mChannels,
+                                                &outputDesc->mLatency,
+                                                outputDesc->mFlags);
+                if (mHardwareOutput == 0) {
+                    LOGE("Failed to reopen hardware output stream, samplingRate: %d, format %d, channels %d",
+                            outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels);
+                } else {
+                    AudioParameter outputCmd = AudioParameter();
+                    outputCmd.addInt(String8("set_id"), 0);
+                    mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
+                    addOutput(mHardwareOutput, outputDesc);
+                }
+            }
+
+
+            mpClientInterface->setParameters(0, String8("test_cmd_policy="));
+        }
+    }
+    return false;
+}
+
+void AudioPolicyManagerBase::exit()
+{
+    {
+        AutoMutex _l(mLock);
+        requestExit();
+        mWaitWorkCV.signal();
+    }
+    requestExitAndWait();
+}
+
+int AudioPolicyManagerBase::testOutputIndex(audio_io_handle_t output)
+{
+    for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
+        if (output == mTestOutputs[i]) return i;
+    }
+    return 0;
+}
+#endif //AUDIO_POLICY_TEST
+
+// ---
+
+void AudioPolicyManagerBase::addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc)
+{
+    outputDesc->mId = id;
+    mOutputs.add(id, outputDesc);
+}
+
+
+#ifdef WITH_A2DP
+status_t AudioPolicyManagerBase::handleA2dpConnection(AudioSystem::audio_devices device,
+                                                 const char *device_address)
+{
+    // when an A2DP device is connected, open an A2DP and a duplicated output
+    LOGV("opening A2DP output for device %s", device_address);
+    AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
+    outputDesc->mDevice = device;
+    mA2dpOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
+                                            &outputDesc->mSamplingRate,
+                                            &outputDesc->mFormat,
+                                            &outputDesc->mChannels,
+                                            &outputDesc->mLatency,
+                                            outputDesc->mFlags);
+    if (mA2dpOutput) {
+        // add A2DP output descriptor
+        addOutput(mA2dpOutput, outputDesc);
+        // set initial stream volume for A2DP device
+        applyStreamVolumes(mA2dpOutput, device);
+        if (a2dpUsedForSonification()) {
+            mDuplicatedOutput = mpClientInterface->openDuplicateOutput(mA2dpOutput, mHardwareOutput);
+        }
+        if (mDuplicatedOutput != 0 ||
+            !a2dpUsedForSonification()) {
+            // If both A2DP and duplicated outputs are open, send device address to A2DP hardware
+            // interface
+            AudioParameter param;
+            param.add(String8("a2dp_sink_address"), String8(device_address));
+            mpClientInterface->setParameters(mA2dpOutput, param.toString());
+            mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+
+            if (a2dpUsedForSonification()) {
+                // add duplicated output descriptor
+                AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor();
+                dupOutputDesc->mOutput1 = mOutputs.valueFor(mHardwareOutput);
+                dupOutputDesc->mOutput2 = mOutputs.valueFor(mA2dpOutput);
+                dupOutputDesc->mSamplingRate = outputDesc->mSamplingRate;
+                dupOutputDesc->mFormat = outputDesc->mFormat;
+                dupOutputDesc->mChannels = outputDesc->mChannels;
+                dupOutputDesc->mLatency = outputDesc->mLatency;
+                addOutput(mDuplicatedOutput, dupOutputDesc);
+                applyStreamVolumes(mDuplicatedOutput, device);
+            }
+        } else {
+            LOGW("getOutput() could not open duplicated output for %d and %d",
+                    mHardwareOutput, mA2dpOutput);
+            mpClientInterface->closeOutput(mA2dpOutput);
+            mOutputs.removeItem(mA2dpOutput);
+            mA2dpOutput = 0;
+            delete outputDesc;
+            return NO_INIT;
+        }
+    } else {
+        LOGW("setDeviceConnectionState() could not open A2DP output for device %x", device);
+        delete outputDesc;
+        return NO_INIT;
+    }
+    AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput);
+
+    if (mA2dpDeviceAddress == mScoDeviceAddress) {
+        // It is normal to suspend twice if we are both in call,
+        // and have the hardware audio output routed to BT SCO
+        if (mPhoneState != AudioSystem::MODE_NORMAL) {
+            mpClientInterface->suspendOutput(mA2dpOutput);
+        }
+        if (AudioSystem::isBluetoothScoDevice((AudioSystem::audio_devices)hwOutputDesc->device())) {
+            mpClientInterface->suspendOutput(mA2dpOutput);
+        }
+    }
+
+    if (!a2dpUsedForSonification()) {
+        // mute music on A2DP output if a notification or ringtone is playing
+        uint32_t refCount = hwOutputDesc->strategyRefCount(STRATEGY_SONIFICATION);
+        for (uint32_t i = 0; i < refCount; i++) {
+            setStrategyMute(STRATEGY_MEDIA, true, mA2dpOutput);
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManagerBase::handleA2dpDisconnection(AudioSystem::audio_devices device,
+                                                    const char *device_address)
+{
+    if (mA2dpOutput == 0) {
+        LOGW("setDeviceConnectionState() disconnecting A2DP and no A2DP output!");
+        return INVALID_OPERATION;
+    }
+
+    if (mA2dpDeviceAddress != device_address) {
+        LOGW("setDeviceConnectionState() disconnecting unknow A2DP sink address %s", device_address);
+        return INVALID_OPERATION;
+    }
+
+    // mute media during 2 seconds to avoid outputing sound on hardware output while music stream
+    // is switched from A2DP output and before music is paused by music application
+    setStrategyMute(STRATEGY_MEDIA, true, mHardwareOutput);
+    setStrategyMute(STRATEGY_MEDIA, false, mHardwareOutput, 2000);
+
+    if (!a2dpUsedForSonification()) {
+        // unmute music on A2DP output if a notification or ringtone is playing
+        uint32_t refCount = mOutputs.valueFor(mHardwareOutput)->strategyRefCount(STRATEGY_SONIFICATION);
+        for (uint32_t i = 0; i < refCount; i++) {
+            setStrategyMute(STRATEGY_MEDIA, false, mA2dpOutput);
+        }
+    }
+    mA2dpDeviceAddress = "";
+    return NO_ERROR;
+}
+
+void AudioPolicyManagerBase::closeA2dpOutputs()
+{
+    LOGV("setDeviceConnectionState() closing A2DP and duplicated output!");
+
+    if (mDuplicatedOutput != 0) {
+        mpClientInterface->closeOutput(mDuplicatedOutput);
+        delete mOutputs.valueFor(mDuplicatedOutput);
+        mOutputs.removeItem(mDuplicatedOutput);
+        mDuplicatedOutput = 0;
+    }
+    if (mA2dpOutput != 0) {
+        AudioParameter param;
+        param.add(String8("closing"), String8("true"));
+        mpClientInterface->setParameters(mA2dpOutput, param.toString());
+        mpClientInterface->closeOutput(mA2dpOutput);
+        delete mOutputs.valueFor(mA2dpOutput);
+        mOutputs.removeItem(mA2dpOutput);
+        mA2dpOutput = 0;
+    }
+}
+
+void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy, uint32_t &newDevice)
+{
+    uint32_t prevDevice = getDeviceForStrategy(strategy);
+    uint32_t curDevice = getDeviceForStrategy(strategy, false);
+    bool a2dpWasUsed = AudioSystem::isA2dpDevice((AudioSystem::audio_devices)(prevDevice & ~AudioSystem::DEVICE_OUT_SPEAKER));
+    bool a2dpIsUsed = AudioSystem::isA2dpDevice((AudioSystem::audio_devices)(curDevice & ~AudioSystem::DEVICE_OUT_SPEAKER));
+    AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput);
+    AudioOutputDescriptor *a2dpOutputDesc;
+
+    if (a2dpWasUsed && !a2dpIsUsed) {
+        bool dupUsed = a2dpUsedForSonification() && a2dpWasUsed && (AudioSystem::popCount(prevDevice) == 2);
+
+        if (dupUsed) {
+            LOGV("checkOutputForStrategy() moving strategy %d to duplicated", strategy);
+            a2dpOutputDesc = mOutputs.valueFor(mDuplicatedOutput);
+        } else {
+            LOGV("checkOutputForStrategy() moving strategy %d to a2dp", strategy);
+            a2dpOutputDesc = mOutputs.valueFor(mA2dpOutput);
+        }
+
+        for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
+            if (getStrategy((AudioSystem::stream_type)i) == strategy) {
+                mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, mHardwareOutput);
+                int refCount = a2dpOutputDesc->mRefCount[i];
+                // in the case of duplicated output, the ref count is first incremented
+                // and then decremented on hardware output tus keeping its value
+                hwOutputDesc->changeRefCount((AudioSystem::stream_type)i, refCount);
+                a2dpOutputDesc->changeRefCount((AudioSystem::stream_type)i,-refCount);
+            }
+        }
+        // do not change newDevice is it was already set before this call by a previous call to
+        // getNewDevice() or checkOutputForStrategy() for a strategy with higher priority
+        if (newDevice == 0 && hwOutputDesc->isUsedByStrategy(strategy)) {
+            newDevice = getDeviceForStrategy(strategy, false);
+        }
+    }
+    if (a2dpIsUsed && !a2dpWasUsed) {
+        bool dupUsed = a2dpUsedForSonification() && a2dpIsUsed && (AudioSystem::popCount(curDevice) == 2);
+        audio_io_handle_t a2dpOutput;
+
+        if (dupUsed) {
+            LOGV("checkOutputForStrategy() moving strategy %d from duplicated", strategy);
+            a2dpOutputDesc = mOutputs.valueFor(mDuplicatedOutput);
+            a2dpOutput = mDuplicatedOutput;
+        } else {
+            LOGV("checkOutputForStrategy() moving strategy %d from a2dp", strategy);
+            a2dpOutputDesc = mOutputs.valueFor(mA2dpOutput);
+            a2dpOutput = mA2dpOutput;
+        }
+
+        for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
+            if (getStrategy((AudioSystem::stream_type)i) == strategy) {
+                mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, a2dpOutput);
+                int refCount = hwOutputDesc->mRefCount[i];
+                // in the case of duplicated output, the ref count is first incremented
+                // and then decremented on hardware output tus keeping its value
+                a2dpOutputDesc->changeRefCount((AudioSystem::stream_type)i, refCount);
+                hwOutputDesc->changeRefCount((AudioSystem::stream_type)i,-refCount);
+            }
+        }
+    }
+}
+
+void AudioPolicyManagerBase::checkOutputForAllStrategies(uint32_t &newDevice)
+{
+    // Check strategies in order of priority so that once newDevice is set
+    // for a given strategy it is not modified by subsequent calls to
+    // checkOutputForStrategy()
+    checkOutputForStrategy(STRATEGY_PHONE, newDevice);
+    checkOutputForStrategy(STRATEGY_SONIFICATION, newDevice);
+    checkOutputForStrategy(STRATEGY_MEDIA, newDevice);
+    checkOutputForStrategy(STRATEGY_DTMF, newDevice);
+}
+
+#endif
+
+uint32_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fromCache)
+{
+    uint32_t device = 0;
+
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    // check the following by order of priority to request a routing change if necessary:
+    // 1: we are in call or the strategy phone is active on the hardware output:
+    //      use device for strategy phone
+    // 2: the strategy sonification is active on the hardware output:
+    //      use device for strategy sonification
+    // 3: the strategy media is active on the hardware output:
+    //      use device for strategy media
+    // 4: the strategy DTMF is active on the hardware output:
+    //      use device for strategy DTMF
+    if (mPhoneState == AudioSystem::MODE_IN_CALL ||
+        outputDesc->isUsedByStrategy(STRATEGY_PHONE)) {
+        device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
+    } else if (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION)) {
+        device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
+    } else if (outputDesc->isUsedByStrategy(STRATEGY_MEDIA)) {
+        device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);
+    } else if (outputDesc->isUsedByStrategy(STRATEGY_DTMF)) {
+        device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
+    }
+
+    LOGV("getNewDevice() selected device %x", device);
+    return device;
+}
+
+AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy(AudioSystem::stream_type stream)
+{
+    // stream to strategy mapping
+    switch (stream) {
+    case AudioSystem::VOICE_CALL:
+    case AudioSystem::BLUETOOTH_SCO:
+        return STRATEGY_PHONE;
+    case AudioSystem::RING:
+    case AudioSystem::NOTIFICATION:
+    case AudioSystem::ALARM:
+    case AudioSystem::ENFORCED_AUDIBLE:
+        return STRATEGY_SONIFICATION;
+    case AudioSystem::DTMF:
+        return STRATEGY_DTMF;
+    default:
+        LOGE("unknown stream type");
+    case AudioSystem::SYSTEM:
+        // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
+        // while key clicks are played produces a poor result
+    case AudioSystem::TTS:
+    case AudioSystem::MUSIC:
+        return STRATEGY_MEDIA;
+    }
+}
+
+uint32_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy, bool fromCache)
+{
+    uint32_t device = 0;
+
+    if (fromCache) {
+        LOGV("getDeviceForStrategy() from cache strategy %d, device %x", strategy, mDeviceForStrategy[strategy]);
+        return mDeviceForStrategy[strategy];
+    }
+
+    switch (strategy) {
+    case STRATEGY_DTMF:
+        if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+            // when off call, DTMF strategy follows the same rules as MEDIA strategy
+            device = getDeviceForStrategy(STRATEGY_MEDIA, false);
+            break;
+        }
+        // when in call, DTMF and PHONE strategies follow the same rules
+        // FALL THROUGH
+
+    case STRATEGY_PHONE:
+        // for phone strategy, we first consider the forced use and then the available devices by order
+        // of priority
+        switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) {
+        case AudioSystem::FORCE_BT_SCO:
+            if (mPhoneState != AudioSystem::MODE_IN_CALL || strategy != STRATEGY_DTMF) {
+                device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+                if (device) break;
+            }
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+            if (device) break;
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO;
+            if (device) break;
+            // if SCO device is requested but no SCO device is available, fall back to default case
+            // FALL THROUGH
+
+        default:    // FORCE_NONE
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
+            if (device) break;
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
+            if (device) break;
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_EARPIECE;
+            if (device == 0) {
+                LOGE("getDeviceForStrategy() earpiece device not found");
+            }
+            break;
+
+        case AudioSystem::FORCE_SPEAKER:
+            if (mPhoneState != AudioSystem::MODE_IN_CALL || strategy != STRATEGY_DTMF) {
+                device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+                if (device) break;
+            }
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+            if (device == 0) {
+                LOGE("getDeviceForStrategy() speaker device not found");
+            }
+            break;
+        }
+    break;
+
+    case STRATEGY_SONIFICATION:
+
+        // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
+        // handleIncallSonification().
+        if (mPhoneState == AudioSystem::MODE_IN_CALL) {
+            device = getDeviceForStrategy(STRATEGY_PHONE, false);
+            break;
+        }
+        device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+        if (device == 0) {
+            LOGE("getDeviceForStrategy() speaker device not found");
+        }
+        // The second device used for sonification is the same as the device used by media strategy
+        // FALL THROUGH
+
+    case STRATEGY_MEDIA: {
+        uint32_t device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL;
+#ifdef WITH_A2DP
+        if (mA2dpOutput != 0) {
+            if (strategy == STRATEGY_SONIFICATION && !a2dpUsedForSonification()) {
+                break;
+            }
+            if (device2 == 0) {
+                device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
+            }
+            if (device2 == 0) {
+                device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+            }
+            if (device2 == 0) {
+                device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+            }
+        }
+#endif
+        if (device2 == 0) {
+            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
+        }
+        if (device2 == 0) {
+            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
+        }
+        if (device2 == 0) {
+            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+        }
+
+        // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION, 0 otherwise
+        device |= device2;
+        if (device == 0) {
+            LOGE("getDeviceForStrategy() speaker device not found");
+        }
+        } break;
+
+    default:
+        LOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
+        break;
+    }
+
+    LOGV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
+    return device;
+}
+
+void AudioPolicyManagerBase::updateDeviceForStrategy()
+{
+    for (int i = 0; i < NUM_STRATEGIES; i++) {
+        mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false);
+    }
+}
+
+void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t device, bool force, int delayMs)
+{
+    LOGV("setOutputDevice() output %d device %x delayMs %d", output, device, delayMs);
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+
+
+    if (outputDesc->isDuplicated()) {
+        setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
+        setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
+        return;
+    }
+#ifdef WITH_A2DP
+    // filter devices according to output selected
+    if (output == mHardwareOutput) {
+        device &= ~AudioSystem::DEVICE_OUT_ALL_A2DP;
+    } else {
+        device &= AudioSystem::DEVICE_OUT_ALL_A2DP;
+    }
+#endif
+
+    uint32_t prevDevice = (uint32_t)outputDesc->device();
+    // Do not change the routing if:
+    //  - the requestede device is 0
+    //  - the requested device is the same as current device and force is not specified.
+    // Doing this check here allows the caller to call setOutputDevice() without conditions
+    if (device == 0 ||
+        (device == prevDevice && !force)) {
+        LOGV("setOutputDevice() setting same device %x or null device for output %d", device, output);
+        return;
+    }
+
+    outputDesc->mDevice = device;
+    // mute media streams if both speaker and headset are selected
+    if (output == mHardwareOutput && AudioSystem::popCount(device) == 2) {
+        setStrategyMute(STRATEGY_MEDIA, true, output);
+        // wait for the PCM output buffers to empty before proceeding with the rest of the command
+        usleep(outputDesc->mLatency*2*1000);
+    }
+#ifdef WITH_A2DP
+    // suspend A2D output if SCO device is selected
+    if (AudioSystem::isBluetoothScoDevice((AudioSystem::audio_devices)device)) {
+         if (mA2dpOutput && mScoDeviceAddress == mA2dpDeviceAddress) {
+             mpClientInterface->suspendOutput(mA2dpOutput);
+         }
+    }
+#endif
+    // do the routing
+    AudioParameter param = AudioParameter();
+    param.addInt(String8(AudioParameter::keyRouting), (int)device);
+    mpClientInterface->setParameters(mHardwareOutput, param.toString(), delayMs);
+    // update stream volumes according to new device
+    applyStreamVolumes(output, device, delayMs);
+
+#ifdef WITH_A2DP
+    // if disconnecting SCO device, restore A2DP output
+    if (AudioSystem::isBluetoothScoDevice((AudioSystem::audio_devices)prevDevice)) {
+         if (mA2dpOutput && mScoDeviceAddress == mA2dpDeviceAddress) {
+             LOGV("restore A2DP output");
+             mpClientInterface->restoreOutput(mA2dpOutput);
+         }
+    }
+#endif
+    // if changing from a combined headset + speaker route, unmute media streams
+    if (output == mHardwareOutput && AudioSystem::popCount(prevDevice) == 2) {
+        setStrategyMute(STRATEGY_MEDIA, false, output, delayMs);
+    }
+}
+
+uint32_t AudioPolicyManagerBase::getDeviceForInputSource(int inputSource)
+{
+    uint32_t device;
+
+    switch(inputSource) {
+    case AUDIO_SOURCE_DEFAULT:
+    case AUDIO_SOURCE_MIC:
+    case AUDIO_SOURCE_VOICE_RECOGNITION:
+        if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO &&
+            mAvailableInputDevices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+            device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+        } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_WIRED_HEADSET) {
+            device = AudioSystem::DEVICE_IN_WIRED_HEADSET;
+        } else {
+            device = AudioSystem::DEVICE_IN_BUILTIN_MIC;
+        }
+        break;
+    case AUDIO_SOURCE_CAMCORDER:
+        if (hasBackMicrophone()) {
+            device = AudioSystem::DEVICE_IN_BACK_MIC;
+        } else {
+            device = AudioSystem::DEVICE_IN_BUILTIN_MIC;
+        }
+        break;
+    case AUDIO_SOURCE_VOICE_UPLINK:
+    case AUDIO_SOURCE_VOICE_DOWNLINK:
+    case AUDIO_SOURCE_VOICE_CALL:
+        device = AudioSystem::DEVICE_IN_VOICE_CALL;
+        break;
+    default:
+        LOGW("getInput() invalid input source %d", inputSource);
+        device = 0;
+        break;
+    }
+    LOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
+    return device;
+}
+
+audio_io_handle_t AudioPolicyManagerBase::getActiveInput()
+{
+    for (size_t i = 0; i < mInputs.size(); i++) {
+        if (mInputs.valueAt(i)->mRefCount > 0) {
+            return mInputs.keyAt(i);
+        }
+    }
+    return 0;
+}
+
+float AudioPolicyManagerBase::computeVolume(int stream, int index, audio_io_handle_t output, uint32_t device)
+{
+    float volume = 1.0;
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    StreamDescriptor &streamDesc = mStreams[stream];
+
+    if (device == 0) {
+        device = outputDesc->device();
+    }
+
+    int volInt = (100 * (index - streamDesc.mIndexMin)) / (streamDesc.mIndexMax - streamDesc.mIndexMin);
+    volume = AudioSystem::linearToLog(volInt);
+
+    // if a heaset is connected, apply the following rules to ring tones and notifications
+    // to avoid sound level bursts in user's ears:
+    // - always attenuate ring tones and notifications volume by 6dB
+    // - if music is playing, always limit the volume to current music volume,
+    // with a minimum threshold at -36dB so that notification is always perceived.
+    if ((device &
+        (AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP |
+        AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+        AudioSystem::DEVICE_OUT_WIRED_HEADSET |
+        AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) &&
+        (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) &&
+        streamDesc.mCanBeMuted) {
+        volume *= SONIFICATION_HEADSET_VOLUME_FACTOR;
+        // when the phone is ringing we must consider that music could have been paused just before
+        // by the music application and behave as if music was active if the last music track was
+        // just stopped
+        if (outputDesc->mRefCount[AudioSystem::MUSIC] || mLimitRingtoneVolume) {
+            float musicVol = computeVolume(AudioSystem::MUSIC, mStreams[AudioSystem::MUSIC].mIndexCur, output, device);
+            float minVol = (musicVol > SONIFICATION_HEADSET_VOLUME_MIN) ? musicVol : SONIFICATION_HEADSET_VOLUME_MIN;
+            if (volume > minVol) {
+                volume = minVol;
+                LOGV("computeVolume limiting volume to %f musicVol %f", minVol, musicVol);
+            }
+        }
+    }
+
+    return volume;
+}
+
+status_t AudioPolicyManagerBase::checkAndSetVolume(int stream, int index, audio_io_handle_t output, uint32_t device, int delayMs, bool force)
+{
+
+    // do not change actual stream volume if the stream is muted
+    if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) {
+        LOGV("checkAndSetVolume() stream %d muted count %d", stream, mOutputs.valueFor(output)->mMuteCount[stream]);
+        return NO_ERROR;
+    }
+
+    // do not change in call volume if bluetooth is connected and vice versa
+    if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
+        (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) {
+        LOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
+             stream, mForceUse[AudioSystem::FOR_COMMUNICATION]);
+        return INVALID_OPERATION;
+    }
+
+    float volume = computeVolume(stream, index, output, device);
+    // do not set volume if the float value did not change
+    if (volume != mOutputs.valueFor(output)->mCurVolume[stream] || force) {
+        mOutputs.valueFor(output)->mCurVolume[stream] = volume;
+        LOGV("setStreamVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
+        if (stream == AudioSystem::VOICE_CALL ||
+            stream == AudioSystem::DTMF ||
+            stream == AudioSystem::BLUETOOTH_SCO) {
+            float voiceVolume = -1.0;
+            // offset value to reflect actual hardware volume that never reaches 0
+            // 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java)
+            volume = 0.01 + 0.99 * volume;
+            if (stream == AudioSystem::VOICE_CALL) {
+                voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+            } else if (stream == AudioSystem::BLUETOOTH_SCO) {
+                voiceVolume = 1.0;
+            }
+            if (voiceVolume >= 0 && output == mHardwareOutput) {
+                mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
+            }
+        }
+        mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
+    }
+
+    return NO_ERROR;
+}
+
+void AudioPolicyManagerBase::applyStreamVolumes(audio_io_handle_t output, uint32_t device, int delayMs)
+{
+    LOGV("applyStreamVolumes() for output %d and device %x", output, device);
+
+    for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+        checkAndSetVolume(stream, mStreams[stream].mIndexCur, output, device, delayMs);
+    }
+}
+
+void AudioPolicyManagerBase::setStrategyMute(routing_strategy strategy, bool on, audio_io_handle_t output, int delayMs)
+{
+    LOGV("setStrategyMute() strategy %d, mute %d, output %d", strategy, on, output);
+    for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+        if (getStrategy((AudioSystem::stream_type)stream) == strategy) {
+            setStreamMute(stream, on, output, delayMs);
+        }
+    }
+}
+
+void AudioPolicyManagerBase::setStreamMute(int stream, bool on, audio_io_handle_t output, int delayMs)
+{
+    StreamDescriptor &streamDesc = mStreams[stream];
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+
+    LOGV("setStreamMute() stream %d, mute %d, output %d, mMuteCount %d", stream, on, output, outputDesc->mMuteCount[stream]);
+
+    if (on) {
+        if (outputDesc->mMuteCount[stream] == 0) {
+            if (streamDesc.mCanBeMuted) {
+                checkAndSetVolume(stream, 0, output, outputDesc->device(), delayMs);
+            }
+        }
+        // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored
+        outputDesc->mMuteCount[stream]++;
+    } else {
+        if (outputDesc->mMuteCount[stream] == 0) {
+            LOGW("setStreamMute() unmuting non muted stream!");
+            return;
+        }
+        if (--outputDesc->mMuteCount[stream] == 0) {
+            checkAndSetVolume(stream, streamDesc.mIndexCur, output, outputDesc->device(), delayMs);
+        }
+    }
+}
+
+void AudioPolicyManagerBase::handleIncallSonification(int stream, bool starting, bool stateChange)
+{
+    // if the stream pertains to sonification strategy and we are in call we must
+    // mute the stream if it is low visibility. If it is high visibility, we must play a tone
+    // in the device used for phone strategy and play the tone if the selected device does not
+    // interfere with the device used for phone strategy
+    // if stateChange is true, we are called from setPhoneState() and we must mute or unmute as
+    // many times as there are active tracks on the output
+
+    if (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) {
+        AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mHardwareOutput);
+        LOGV("handleIncallSonification() stream %d starting %d device %x stateChange %d",
+                stream, starting, outputDesc->mDevice, stateChange);
+        if (outputDesc->mRefCount[stream]) {
+            int muteCount = 1;
+            if (stateChange) {
+                muteCount = outputDesc->mRefCount[stream];
+            }
+            if (AudioSystem::isLowVisibility((AudioSystem::stream_type)stream)) {
+                LOGV("handleIncallSonification() low visibility, muteCount %d", muteCount);
+                for (int i = 0; i < muteCount; i++) {
+                    setStreamMute(stream, starting, mHardwareOutput);
+                }
+            } else {
+                LOGV("handleIncallSonification() high visibility");
+                if (outputDesc->device() & getDeviceForStrategy(STRATEGY_PHONE)) {
+                    LOGV("handleIncallSonification() high visibility muted, muteCount %d", muteCount);
+                    for (int i = 0; i < muteCount; i++) {
+                        setStreamMute(stream, starting, mHardwareOutput);
+                    }
+                }
+                if (starting) {
+                    mpClientInterface->startTone(ToneGenerator::TONE_SUP_CALL_WAITING, AudioSystem::VOICE_CALL);
+                } else {
+                    mpClientInterface->stopTone();
+                }
+            }
+        }
+    }
+}
+
+// --- AudioOutputDescriptor class implementation
+
+AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor()
+    : mId(0), mSamplingRate(0), mFormat(0), mChannels(0), mLatency(0),
+    mFlags((AudioSystem::output_flags)0), mDevice(0), mOutput1(0), mOutput2(0)
+{
+    // clear usage count for all stream types
+    for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+        mRefCount[i] = 0;
+        mCurVolume[i] = -1.0;
+        mMuteCount[i] = 0;
+    }
+}
+
+uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::device()
+{
+    uint32_t device = 0;
+    if (isDuplicated()) {
+        device = mOutput1->mDevice | mOutput2->mDevice;
+    } else {
+        device = mDevice;
+    }
+    return device;
+}
+
+void AudioPolicyManagerBase::AudioOutputDescriptor::changeRefCount(AudioSystem::stream_type stream, int delta)
+{
+    // forward usage count change to attached outputs
+    if (isDuplicated()) {
+        mOutput1->changeRefCount(stream, delta);
+        mOutput2->changeRefCount(stream, delta);
+    }
+    if ((delta + (int)mRefCount[stream]) < 0) {
+        LOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]);
+        mRefCount[stream] = 0;
+        return;
+    }
+    mRefCount[stream] += delta;
+    LOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
+}
+
+uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::refCount()
+{
+    uint32_t refcount = 0;
+    for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
+        refcount += mRefCount[i];
+    }
+    return refcount;
+}
+
+uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::strategyRefCount(routing_strategy strategy)
+{
+    uint32_t refCount = 0;
+    for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
+        if (getStrategy((AudioSystem::stream_type)i) == strategy) {
+            refCount += mRefCount[i];
+        }
+    }
+    return refCount;
+}
+
+
+status_t AudioPolicyManagerBase::AudioOutputDescriptor::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Format: %d\n", mFormat);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Channels: %08x\n", mChannels);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Latency: %d\n", mLatency);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Flags %08x\n", mFlags);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Devices %08x\n", device());
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Stream volume refCount muteCount\n");
+    result.append(buffer);
+    for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+        snprintf(buffer, SIZE, " %02d     %.03f     %02d       %02d\n", i, mCurVolume[i], mRefCount[i], mMuteCount[i]);
+        result.append(buffer);
+    }
+    write(fd, result.string(), result.size());
+
+    return NO_ERROR;
+}
+
+// --- AudioInputDescriptor class implementation
+
+AudioPolicyManagerBase::AudioInputDescriptor::AudioInputDescriptor()
+    : mSamplingRate(0), mFormat(0), mChannels(0),
+     mAcoustics((AudioSystem::audio_in_acoustics)0), mDevice(0), mRefCount(0)
+{
+}
+
+status_t AudioPolicyManagerBase::AudioInputDescriptor::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Format: %d\n", mFormat);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Channels: %08x\n", mChannels);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Acoustics %08x\n", mAcoustics);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Ref Count %d\n", mRefCount);
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+
+    return NO_ERROR;
+}
+
+// --- StreamDescriptor class implementation
+
+void AudioPolicyManagerBase::StreamDescriptor::dump(char* buffer, size_t size)
+{
+    snprintf(buffer, size, "      %02d         %02d         %02d         %d\n",
+            mIndexMin,
+            mIndexMax,
+            mIndexCur,
+            mCanBeMuted);
+}
+
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioPolicyManagerGeneric.cpp b/libs/audioflinger/AudioPolicyManagerGeneric.cpp
deleted file mode 100644
index 8cfc204..0000000
--- a/libs/audioflinger/AudioPolicyManagerGeneric.cpp
+++ /dev/null
@@ -1,945 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "AudioPolicyManagerGeneric"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-#include "AudioPolicyManagerGeneric.h"
-#include <media/mediarecorder.h>
-
-namespace android {
-
-
-// ----------------------------------------------------------------------------
-// AudioPolicyInterface implementation
-// ----------------------------------------------------------------------------
-
-
-status_t AudioPolicyManagerGeneric::setDeviceConnectionState(AudioSystem::audio_devices device,
-                                                  AudioSystem::device_connection_state state,
-                                                  const char *device_address)
-{
-
-    LOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);
-
-    // connect/disconnect only 1 device at a time
-    if (AudioSystem::popCount(device) != 1) return BAD_VALUE;
-
-    if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
-        LOGE("setDeviceConnectionState() invalid address: %s", device_address);
-        return BAD_VALUE;
-    }
-
-    // handle output devices
-    if (AudioSystem::isOutputDevice(device)) {
-        switch (state)
-        {
-        // handle output device connection
-        case AudioSystem::DEVICE_STATE_AVAILABLE:
-            if (mAvailableOutputDevices & device) {
-                LOGW("setDeviceConnectionState() device already connected: %x", device);
-                return INVALID_OPERATION;
-            }
-            LOGV("setDeviceConnectionState() connecting device %x", device);
-
-            // register new device as available
-            mAvailableOutputDevices |= device;
-            break;
-        // handle output device disconnection
-        case AudioSystem::DEVICE_STATE_UNAVAILABLE:
-            if (!(mAvailableOutputDevices & device)) {
-                LOGW("setDeviceConnectionState() device not connected: %x", device);
-                return INVALID_OPERATION;
-            }
-            LOGV("setDeviceConnectionState() disconnecting device %x", device);
-            // remove device from available output devices
-            mAvailableOutputDevices &= ~device;
-            break;
-
-        default:
-            LOGE("setDeviceConnectionState() invalid state: %x", state);
-            return BAD_VALUE;
-        }
-        return NO_ERROR;
-    }
-    // handle input devices
-    if (AudioSystem::isInputDevice(device)) {
-        switch (state)
-        {
-        // handle input device connection
-        case AudioSystem::DEVICE_STATE_AVAILABLE:
-            if (mAvailableInputDevices & device) {
-                LOGW("setDeviceConnectionState() device already connected: %d", device);
-                return INVALID_OPERATION;
-            }
-            mAvailableInputDevices |= device;
-            break;
-
-        // handle input device disconnection
-        case AudioSystem::DEVICE_STATE_UNAVAILABLE:
-            if (!(mAvailableInputDevices & device)) {
-                LOGW("setDeviceConnectionState() device not connected: %d", device);
-                return INVALID_OPERATION;
-            }
-            mAvailableInputDevices &= ~device;
-            break;
-
-        default:
-            LOGE("setDeviceConnectionState() invalid state: %x", state);
-            return BAD_VALUE;
-        }
-        return NO_ERROR;
-    }
-
-    LOGW("setDeviceConnectionState() invalid device: %x", device);
-    return BAD_VALUE;
-}
-
-AudioSystem::device_connection_state AudioPolicyManagerGeneric::getDeviceConnectionState(AudioSystem::audio_devices device,
-                                                  const char *device_address)
-{
-    AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE;
-    String8 address = String8(device_address);
-    if (AudioSystem::isOutputDevice(device)) {
-        if (device & mAvailableOutputDevices) {
-            state = AudioSystem::DEVICE_STATE_AVAILABLE;
-        }
-    } else if (AudioSystem::isInputDevice(device)) {
-        if (device & mAvailableInputDevices) {
-            state = AudioSystem::DEVICE_STATE_AVAILABLE;
-        }
-    }
-
-    return state;
-}
-
-void AudioPolicyManagerGeneric::setPhoneState(int state)
-{
-    LOGV("setPhoneState() state %d", state);
-    uint32_t newDevice = 0;
-    if (state < 0 || state >= AudioSystem::NUM_MODES) {
-        LOGW("setPhoneState() invalid state %d", state);
-        return;
-    }
-
-    if (state == mPhoneState ) {
-        LOGW("setPhoneState() setting same state %d", state);
-        return;
-    }
-    // store previous phone state for management of sonification strategy below
-    int oldState = mPhoneState;
-    mPhoneState = state;
-
-    // if leaving or entering in call state, handle special case of active streams
-    // pertaining to sonification strategy see handleIncallSonification()
-    if (state == AudioSystem::MODE_IN_CALL ||
-        oldState == AudioSystem::MODE_IN_CALL) {
-        bool starting = (state == AudioSystem::MODE_IN_CALL) ? true : false;
-        LOGV("setPhoneState() in call state management: new state is %d", state);
-        for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
-            handleIncallSonification(stream, starting);
-        }
-    }
-}
-
-void AudioPolicyManagerGeneric::setRingerMode(uint32_t mode, uint32_t mask)
-{
-    LOGV("setRingerMode() mode %x, mask %x", mode, mask);
-
-    mRingerMode = mode;
-}
-
-void AudioPolicyManagerGeneric::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
-{
-    LOGV("setForceUse) usage %d, config %d, mPhoneState %d", usage, config, mPhoneState);
-    mForceUse[usage] = config;
-}
-
-AudioSystem::forced_config AudioPolicyManagerGeneric::getForceUse(AudioSystem::force_use usage)
-{
-    return mForceUse[usage];
-}
-
-void AudioPolicyManagerGeneric::setSystemProperty(const char* property, const char* value)
-{
-    LOGV("setSystemProperty() property %s, value %s", property, value);
-    if (strcmp(property, "ro.camera.sound.forced") == 0) {
-        if (atoi(value)) {
-            LOGV("ENFORCED_AUDIBLE cannot be muted");
-            mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = false;
-        } else {
-            LOGV("ENFORCED_AUDIBLE can be muted");
-            mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = true;
-        }
-    }
-}
-
-audio_io_handle_t AudioPolicyManagerGeneric::getOutput(AudioSystem::stream_type stream,
-                                    uint32_t samplingRate,
-                                    uint32_t format,
-                                    uint32_t channels,
-                                    AudioSystem::output_flags flags)
-{
-    LOGV("getOutput() stream %d, samplingRate %d, format %d, channels %x, flags %x", stream, samplingRate, format, channels, flags);
-
-#ifdef AUDIO_POLICY_TEST
-    if (mCurOutput != 0) {
-        LOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channels %x, mDirectOutput %d",
-                mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, mDirectOutput);
-
-        if (mTestOutputs[mCurOutput] == 0) {
-            LOGV("getOutput() opening test output");
-            AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
-            outputDesc->mDevice = mTestDevice;
-            outputDesc->mSamplingRate = mTestSamplingRate;
-            outputDesc->mFormat = mTestFormat;
-            outputDesc->mChannels = mTestChannels;
-            outputDesc->mLatency = mTestLatencyMs;
-            outputDesc->mFlags = (AudioSystem::output_flags)(mDirectOutput ? AudioSystem::OUTPUT_FLAG_DIRECT : 0);
-            outputDesc->mRefCount[stream] = 0;
-            mTestOutputs[mCurOutput] = mpClientInterface->openOutput(&outputDesc->mDevice,
-                                            &outputDesc->mSamplingRate,
-                                            &outputDesc->mFormat,
-                                            &outputDesc->mChannels,
-                                            &outputDesc->mLatency,
-                                            outputDesc->mFlags);
-            if (mTestOutputs[mCurOutput]) {
-                AudioParameter outputCmd = AudioParameter();
-                outputCmd.addInt(String8("set_id"),mCurOutput);
-                mpClientInterface->setParameters(mTestOutputs[mCurOutput],outputCmd.toString());
-                mOutputs.add(mTestOutputs[mCurOutput], outputDesc);
-            }
-        }
-        return mTestOutputs[mCurOutput];
-    }
-#endif //AUDIO_POLICY_TEST
-    if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
-        (format != 0 && !AudioSystem::isLinearPCM(format)) ||
-        (channels != 0 && channels != AudioSystem::CHANNEL_OUT_MONO && channels != AudioSystem::CHANNEL_OUT_STEREO)) {
-        return 0;
-    }
-
-    return mHardwareOutput;
-}
-
-status_t AudioPolicyManagerGeneric::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
-{
-    LOGV("startOutput() output %d, stream %d", output, stream);
-    ssize_t index = mOutputs.indexOfKey(output);
-    if (index < 0) {
-        LOGW("startOutput() unknow output %d", output);
-        return BAD_VALUE;
-    }
-
-    AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
-
-    // handle special case for sonification while in call
-    if (mPhoneState == AudioSystem::MODE_IN_CALL) {
-        handleIncallSonification(stream, true);
-    }
-
-    // incremenent usage count for this stream on the requested output:
-    outputDesc->changeRefCount(stream, 1);
-    return NO_ERROR;
-}
-
-status_t AudioPolicyManagerGeneric::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
-{
-    LOGV("stopOutput() output %d, stream %d", output, stream);
-    ssize_t index = mOutputs.indexOfKey(output);
-    if (index < 0) {
-        LOGW("stopOutput() unknow output %d", output);
-        return BAD_VALUE;
-    }
-
-    AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
-
-    // handle special case for sonification while in call
-    if (mPhoneState == AudioSystem::MODE_IN_CALL) {
-        handleIncallSonification(stream, false);
-    }
-
-    if (outputDesc->isUsedByStream(stream)) {
-        // decrement usage count of this stream on the output
-        outputDesc->changeRefCount(stream, -1);
-        return NO_ERROR;
-    } else {
-        LOGW("stopOutput() refcount is already 0 for output %d", output);
-        return INVALID_OPERATION;
-    }
-}
-
-void AudioPolicyManagerGeneric::releaseOutput(audio_io_handle_t output)
-{
-    LOGV("releaseOutput() %d", output);
-    ssize_t index = mOutputs.indexOfKey(output);
-    if (index < 0) {
-        LOGW("releaseOutput() releasing unknown output %d", output);
-        return;
-    }
-
-#ifdef AUDIO_POLICY_TEST
-    int testIndex = testOutputIndex(output);
-    if (testIndex != 0) {
-        AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
-        if (outputDesc->refCount() == 0) {
-            mpClientInterface->closeOutput(output);
-            delete mOutputs.valueAt(index);
-            mOutputs.removeItem(output);
-            mTestOutputs[testIndex] = 0;
-        }
-    }
-#endif //AUDIO_POLICY_TEST
-}
-
-audio_io_handle_t AudioPolicyManagerGeneric::getInput(int inputSource,
-                                    uint32_t samplingRate,
-                                    uint32_t format,
-                                    uint32_t channels,
-                                    AudioSystem::audio_in_acoustics acoustics)
-{
-    audio_io_handle_t input = 0;
-    uint32_t device;
-
-    LOGV("getInput() inputSource %d, samplingRate %d, format %d, channels %x, acoustics %x", inputSource, samplingRate, format, channels, acoustics);
-
-    AudioInputDescriptor *inputDesc = new AudioInputDescriptor();
-    inputDesc->mDevice = AudioSystem::DEVICE_IN_BUILTIN_MIC;
-    inputDesc->mSamplingRate = samplingRate;
-    inputDesc->mFormat = format;
-    inputDesc->mChannels = channels;
-    inputDesc->mAcoustics = acoustics;
-    inputDesc->mRefCount = 0;
-    input = mpClientInterface->openInput(&inputDesc->mDevice,
-                                    &inputDesc->mSamplingRate,
-                                    &inputDesc->mFormat,
-                                    &inputDesc->mChannels,
-                                    inputDesc->mAcoustics);
-
-    // only accept input with the exact requested set of parameters
-    if ((samplingRate != inputDesc->mSamplingRate) ||
-        (format != inputDesc->mFormat) ||
-        (channels != inputDesc->mChannels)) {
-        LOGV("getOutput() failed opening input: samplingRate %d, format %d, channels %d",
-                samplingRate, format, channels);
-        mpClientInterface->closeInput(input);
-        delete inputDesc;
-        return 0;
-    }
-    mInputs.add(input, inputDesc);
-    return input;
-}
-
-status_t AudioPolicyManagerGeneric::startInput(audio_io_handle_t input)
-{
-    LOGV("startInput() input %d", input);
-    ssize_t index = mInputs.indexOfKey(input);
-    if (index < 0) {
-        LOGW("startInput() unknow input %d", input);
-        return BAD_VALUE;
-    }
-    AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
-
-#ifdef AUDIO_POLICY_TEST
-    if (mTestInput == 0)
-#endif //AUDIO_POLICY_TEST
-    {
-        // refuse 2 active AudioRecord clients at the same time
-        for (size_t i = 0; i < mInputs.size(); i++) {
-            if (mInputs.valueAt(i)->mRefCount > 0) {
-                LOGW("startInput() input %d, other input %d already started", input, mInputs.keyAt(i));
-                return INVALID_OPERATION;
-            }
-        }
-    }
-
-    inputDesc->mRefCount = 1;
-    return NO_ERROR;
-}
-
-status_t AudioPolicyManagerGeneric::stopInput(audio_io_handle_t input)
-{
-    LOGV("stopInput() input %d", input);
-    ssize_t index = mInputs.indexOfKey(input);
-    if (index < 0) {
-        LOGW("stopInput() unknow input %d", input);
-        return BAD_VALUE;
-    }
-    AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
-
-    if (inputDesc->mRefCount == 0) {
-        LOGW("stopInput() input %d already stopped", input);
-        return INVALID_OPERATION;
-    } else {
-        inputDesc->mRefCount = 0;
-        return NO_ERROR;
-    }
-}
-
-void AudioPolicyManagerGeneric::releaseInput(audio_io_handle_t input)
-{
-    LOGV("releaseInput() %d", input);
-    ssize_t index = mInputs.indexOfKey(input);
-    if (index < 0) {
-        LOGW("releaseInput() releasing unknown input %d", input);
-        return;
-    }
-    mpClientInterface->closeInput(input);
-    delete mInputs.valueAt(index);
-    mInputs.removeItem(input);
-}
-
-
-
-void AudioPolicyManagerGeneric::initStreamVolume(AudioSystem::stream_type stream,
-                                            int indexMin,
-                                            int indexMax)
-{
-    LOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
-    mStreams[stream].mIndexMin = indexMin;
-    mStreams[stream].mIndexMax = indexMax;
-}
-
-status_t AudioPolicyManagerGeneric::setStreamVolumeIndex(AudioSystem::stream_type stream, int index)
-{
-
-    if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) {
-        return BAD_VALUE;
-    }
-
-    LOGV("setStreamVolumeIndex() stream %d, index %d", stream, index);
-    mStreams[stream].mIndexCur = index;
-
-    // do not change actual stream volume if the stream is muted
-    if (mStreams[stream].mMuteCount != 0) {
-        return NO_ERROR;
-    }
-
-    // Do not changed in call volume if bluetooth is connected and vice versa
-    if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
-        (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) {
-        LOGV("setStreamVolumeIndex() cannot set stream %d volume with force use = %d for comm",
-             stream, mForceUse[AudioSystem::FOR_COMMUNICATION]);
-        return INVALID_OPERATION;
-    }
-
-    // compute and apply stream volume on all outputs according to connected device
-    for (size_t i = 0; i < mOutputs.size(); i++) {
-        AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
-        uint32_t device = outputDesc->device();
-
-        float volume = computeVolume((int)stream, index, device);
-
-        LOGV("setStreamVolume() for output %d stream %d, volume %f", mOutputs.keyAt(i), stream, volume);
-        mpClientInterface->setStreamVolume(stream, volume, mOutputs.keyAt(i));
-    }
-    return NO_ERROR;
-}
-
-status_t AudioPolicyManagerGeneric::getStreamVolumeIndex(AudioSystem::stream_type stream, int *index)
-{
-    if (index == 0) {
-        return BAD_VALUE;
-    }
-    LOGV("getStreamVolumeIndex() stream %d", stream);
-    *index =  mStreams[stream].mIndexCur;
-    return NO_ERROR;
-}
-
-status_t AudioPolicyManagerGeneric::dump(int fd)
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, "\nAudioPolicyManager Dump: %p\n", this);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Hardware Output: %d\n", mHardwareOutput);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Output devices: %08x\n", mAvailableOutputDevices);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Input devices: %08x\n", mAvailableInputDevices);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Phone state: %d\n", mPhoneState);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Ringer mode: %d\n", mRingerMode);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Force use for communications %d\n", mForceUse[AudioSystem::FOR_COMMUNICATION]);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Force use for media %d\n", mForceUse[AudioSystem::FOR_MEDIA]);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Force use for record %d\n", mForceUse[AudioSystem::FOR_RECORD]);
-    result.append(buffer);
-    write(fd, result.string(), result.size());
-
-    snprintf(buffer, SIZE, "\nOutputs dump:\n");
-    write(fd, buffer, strlen(buffer));
-    for (size_t i = 0; i < mOutputs.size(); i++) {
-        snprintf(buffer, SIZE, "- Output %d dump:\n", mOutputs.keyAt(i));
-        write(fd, buffer, strlen(buffer));
-        mOutputs.valueAt(i)->dump(fd);
-    }
-
-    snprintf(buffer, SIZE, "\nInputs dump:\n");
-    write(fd, buffer, strlen(buffer));
-    for (size_t i = 0; i < mInputs.size(); i++) {
-        snprintf(buffer, SIZE, "- Input %d dump:\n", mInputs.keyAt(i));
-        write(fd, buffer, strlen(buffer));
-        mInputs.valueAt(i)->dump(fd);
-    }
-
-    snprintf(buffer, SIZE, "\nStreams dump:\n");
-    write(fd, buffer, strlen(buffer));
-    snprintf(buffer, SIZE, " Stream  Index Min  Index Max  Index Cur  Mute Count  Can be muted\n");
-    write(fd, buffer, strlen(buffer));
-    for (size_t i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
-        snprintf(buffer, SIZE, " %02d", i);
-        mStreams[i].dump(buffer + 3, SIZE);
-        write(fd, buffer, strlen(buffer));
-    }
-
-    return NO_ERROR;
-}
-
-// ----------------------------------------------------------------------------
-// AudioPolicyManagerGeneric
-// ----------------------------------------------------------------------------
-
-// ---  class factory
-
-AudioPolicyManagerGeneric::AudioPolicyManagerGeneric(AudioPolicyClientInterface *clientInterface)
-    :
-#ifdef AUDIO_POLICY_TEST
-    Thread(false),
-#endif //AUDIO_POLICY_TEST
-    mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0)
-{
-    mpClientInterface = clientInterface;
-
-    for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
-        mForceUse[i] = AudioSystem::FORCE_NONE;
-    }
-
-    // devices available by default are speaker, ear piece and microphone
-    mAvailableOutputDevices = AudioSystem::DEVICE_OUT_SPEAKER;
-    mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC;
-
-    // open hardware output
-    AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
-    outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
-    mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
-                                    &outputDesc->mSamplingRate,
-                                    &outputDesc->mFormat,
-                                    &outputDesc->mChannels,
-                                    &outputDesc->mLatency,
-                                    outputDesc->mFlags);
-
-    if (mHardwareOutput == 0) {
-        LOGE("Failed to initialize hardware output stream, samplingRate: %d, format %d, channels %d",
-                outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels);
-    } else {
-        mOutputs.add(mHardwareOutput, outputDesc);
-    }
-
-#ifdef AUDIO_POLICY_TEST
-    AudioParameter outputCmd = AudioParameter();
-    outputCmd.addInt(String8("set_id"), 0);
-    mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
-
-    mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER;
-    mTestSamplingRate = 44100;
-    mTestFormat = AudioSystem::PCM_16_BIT;
-    mTestChannels =  AudioSystem::CHANNEL_OUT_STEREO;
-    mTestLatencyMs = 0;
-    mCurOutput = 0;
-    mDirectOutput = false;
-    for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
-        mTestOutputs[i] = 0;
-    }
-
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    snprintf(buffer, SIZE, "AudioPolicyManagerTest");
-    run(buffer, ANDROID_PRIORITY_AUDIO);
-#endif //AUDIO_POLICY_TEST
-}
-
-AudioPolicyManagerGeneric::~AudioPolicyManagerGeneric()
-{
-#ifdef AUDIO_POLICY_TEST
-    exit();
-#endif //AUDIO_POLICY_TEST
-
-   for (size_t i = 0; i < mOutputs.size(); i++) {
-        mpClientInterface->closeOutput(mOutputs.keyAt(i));
-        delete mOutputs.valueAt(i);
-   }
-   mOutputs.clear();
-   for (size_t i = 0; i < mInputs.size(); i++) {
-        mpClientInterface->closeInput(mInputs.keyAt(i));
-        delete mInputs.valueAt(i);
-   }
-   mInputs.clear();
-}
-
-#ifdef AUDIO_POLICY_TEST
-bool AudioPolicyManagerGeneric::threadLoop()
-{
-    LOGV("entering threadLoop()");
-    while (!exitPending())
-    {
-        String8 command;
-        int valueInt;
-        String8 value;
-
-        Mutex::Autolock _l(mLock);
-        mWaitWorkCV.waitRelative(mLock, milliseconds(50));
-
-        command = mpClientInterface->getParameters(0, String8("test_cmd_policy"));
-        AudioParameter param = AudioParameter(command);
-
-        if (param.getInt(String8("test_cmd_policy"), valueInt) == NO_ERROR &&
-            valueInt != 0) {
-            LOGV("Test command %s received", command.string());
-            String8 target;
-            if (param.get(String8("target"), target) != NO_ERROR) {
-                target = "Manager";
-            }
-            if (param.getInt(String8("test_cmd_policy_output"), valueInt) == NO_ERROR) {
-                param.remove(String8("test_cmd_policy_output"));
-                mCurOutput = valueInt;
-            }
-            if (param.get(String8("test_cmd_policy_direct"), value) == NO_ERROR) {
-                param.remove(String8("test_cmd_policy_direct"));
-                if (value == "false") {
-                    mDirectOutput = false;
-                } else if (value == "true") {
-                    mDirectOutput = true;
-                }
-            }
-            if (param.getInt(String8("test_cmd_policy_input"), valueInt) == NO_ERROR) {
-                param.remove(String8("test_cmd_policy_input"));
-                mTestInput = valueInt;
-            }
-
-            if (param.get(String8("test_cmd_policy_format"), value) == NO_ERROR) {
-                param.remove(String8("test_cmd_policy_format"));
-                int format = AudioSystem::INVALID_FORMAT;
-                if (value == "PCM 16 bits") {
-                    format = AudioSystem::PCM_16_BIT;
-                } else if (value == "PCM 8 bits") {
-                    format = AudioSystem::PCM_8_BIT;
-                } else if (value == "Compressed MP3") {
-                    format = AudioSystem::MP3;
-                }
-                if (format != AudioSystem::INVALID_FORMAT) {
-                    if (target == "Manager") {
-                        mTestFormat = format;
-                    } else if (mTestOutputs[mCurOutput] != 0) {
-                        AudioParameter outputParam = AudioParameter();
-                        outputParam.addInt(String8("format"), format);
-                        mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
-                    }
-                }
-            }
-            if (param.get(String8("test_cmd_policy_channels"), value) == NO_ERROR) {
-                param.remove(String8("test_cmd_policy_channels"));
-                int channels = 0;
-
-                if (value == "Channels Stereo") {
-                    channels =  AudioSystem::CHANNEL_OUT_STEREO;
-                } else if (value == "Channels Mono") {
-                    channels =  AudioSystem::CHANNEL_OUT_MONO;
-                }
-                if (channels != 0) {
-                    if (target == "Manager") {
-                        mTestChannels = channels;
-                    } else if (mTestOutputs[mCurOutput] != 0) {
-                        AudioParameter outputParam = AudioParameter();
-                        outputParam.addInt(String8("channels"), channels);
-                        mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
-                    }
-                }
-            }
-            if (param.getInt(String8("test_cmd_policy_sampleRate"), valueInt) == NO_ERROR) {
-                param.remove(String8("test_cmd_policy_sampleRate"));
-                if (valueInt >= 0 && valueInt <= 96000) {
-                    int samplingRate = valueInt;
-                    if (target == "Manager") {
-                        mTestSamplingRate = samplingRate;
-                    } else if (mTestOutputs[mCurOutput] != 0) {
-                        AudioParameter outputParam = AudioParameter();
-                        outputParam.addInt(String8("sampling_rate"), samplingRate);
-                        mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
-                    }
-                }
-            }
-
-            if (param.get(String8("test_cmd_policy_reopen"), value) == NO_ERROR) {
-                param.remove(String8("test_cmd_policy_reopen"));
-
-                mpClientInterface->closeOutput(mHardwareOutput);
-                delete mOutputs.valueFor(mHardwareOutput);
-                mOutputs.removeItem(mHardwareOutput);
-
-                AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
-                outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
-                mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
-                                                &outputDesc->mSamplingRate,
-                                                &outputDesc->mFormat,
-                                                &outputDesc->mChannels,
-                                                &outputDesc->mLatency,
-                                                outputDesc->mFlags);
-                if (mHardwareOutput == 0) {
-                    LOGE("Failed to reopen hardware output stream, samplingRate: %d, format %d, channels %d",
-                            outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels);
-                } else {
-                    AudioParameter outputCmd = AudioParameter();
-                    outputCmd.addInt(String8("set_id"), 0);
-                    mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
-                    mOutputs.add(mHardwareOutput, outputDesc);
-                }
-            }
-
-
-            mpClientInterface->setParameters(0, String8("test_cmd_policy="));
-        }
-    }
-    return false;
-}
-
-void AudioPolicyManagerGeneric::exit()
-{
-    {
-        AutoMutex _l(mLock);
-        requestExit();
-        mWaitWorkCV.signal();
-    }
-    requestExitAndWait();
-}
-
-int AudioPolicyManagerGeneric::testOutputIndex(audio_io_handle_t output)
-{
-    for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
-        if (output == mTestOutputs[i]) return i;
-    }
-    return 0;
-}
-#endif //AUDIO_POLICY_TEST
-
-// ---
-
-AudioPolicyManagerGeneric::routing_strategy AudioPolicyManagerGeneric::getStrategy(AudioSystem::stream_type stream)
-{
-    // stream to strategy mapping
-    switch (stream) {
-    case AudioSystem::VOICE_CALL:
-    case AudioSystem::BLUETOOTH_SCO:
-        return STRATEGY_PHONE;
-    case AudioSystem::RING:
-    case AudioSystem::NOTIFICATION:
-    case AudioSystem::ALARM:
-    case AudioSystem::ENFORCED_AUDIBLE:
-        return STRATEGY_SONIFICATION;
-    case AudioSystem::DTMF:
-        return STRATEGY_DTMF;
-    default:
-        LOGE("unknown stream type");
-    case AudioSystem::SYSTEM:
-        // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
-        // while key clicks are played produces a poor result
-    case AudioSystem::TTS:
-    case AudioSystem::MUSIC:
-        return STRATEGY_MEDIA;
-    }
-}
-
-
-float AudioPolicyManagerGeneric::computeVolume(int stream, int index, uint32_t device)
-{
-    float volume = 1.0;
-
-    StreamDescriptor &streamDesc = mStreams[stream];
-
-    // Force max volume if stream cannot be muted
-    if (!streamDesc.mCanBeMuted) index = streamDesc.mIndexMax;
-
-    int volInt = (100 * (index - streamDesc.mIndexMin)) / (streamDesc.mIndexMax - streamDesc.mIndexMin);
-    volume = AudioSystem::linearToLog(volInt);
-
-    return volume;
-}
-
-void AudioPolicyManagerGeneric::setStreamMute(int stream, bool on, audio_io_handle_t output)
-{
-    LOGV("setStreamMute() stream %d, mute %d, output %d", stream, on, output);
-
-    StreamDescriptor &streamDesc = mStreams[stream];
-
-    if (on) {
-        if (streamDesc.mMuteCount++ == 0) {
-            if (streamDesc.mCanBeMuted) {
-                mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, 0, output);
-            }
-        }
-    } else {
-        if (streamDesc.mMuteCount == 0) {
-            LOGW("setStreamMute() unmuting non muted stream!");
-            return;
-        }
-        if (--streamDesc.mMuteCount == 0) {
-            uint32_t device = mOutputs.valueFor(output)->mDevice;
-            float volume = computeVolume(stream, streamDesc.mIndexCur, device);
-            mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output);
-        }
-    }
-}
-
-void AudioPolicyManagerGeneric::handleIncallSonification(int stream, bool starting)
-{
-    // if the stream pertains to sonification strategy and we are in call we must
-    // mute the stream if it is low visibility. If it is high visibility, we must play a tone
-    // in the device used for phone strategy and play the tone if the selected device does not
-    // interfere with the device used for phone strategy
-    if (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) {
-        AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mHardwareOutput);
-        LOGV("handleIncallSonification() stream %d starting %d device %x", stream, starting, outputDesc->mDevice);
-        if (outputDesc->isUsedByStream((AudioSystem::stream_type)stream)) {
-            if (AudioSystem::isLowVisibility((AudioSystem::stream_type)stream)) {
-                LOGV("handleIncallSonification() low visibility");
-                setStreamMute(stream, starting, mHardwareOutput);
-            } else {
-                if (starting) {
-                    mpClientInterface->startTone(ToneGenerator::TONE_SUP_CALL_WAITING, AudioSystem::VOICE_CALL);
-                } else {
-                    mpClientInterface->stopTone();
-                }
-            }
-        }
-    }
-}
-
-
-// --- AudioOutputDescriptor class implementation
-
-AudioPolicyManagerGeneric::AudioOutputDescriptor::AudioOutputDescriptor()
-    : mSamplingRate(0), mFormat(0), mChannels(0), mLatency(0),
-    mFlags((AudioSystem::output_flags)0), mDevice(0)
-{
-    // clear usage count for all stream types
-    for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
-        mRefCount[i] = 0;
-    }
-}
-
-uint32_t AudioPolicyManagerGeneric::AudioOutputDescriptor::device()
-{
-    return mDevice;
-}
-
-void AudioPolicyManagerGeneric::AudioOutputDescriptor::changeRefCount(AudioSystem::stream_type stream, int delta)
-{
-    if ((delta + (int)mRefCount[stream]) < 0) {
-        LOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]);
-        mRefCount[stream] = 0;
-        return;
-    }
-    mRefCount[stream] += delta;
-    LOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
-}
-
-uint32_t AudioPolicyManagerGeneric::AudioOutputDescriptor::refCount()
-{
-    uint32_t refcount = 0;
-    for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
-        refcount += mRefCount[i];
-    }
-    return refcount;
-}
-
-status_t AudioPolicyManagerGeneric::AudioOutputDescriptor::dump(int fd)
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Format: %d\n", mFormat);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Channels: %08x\n", mChannels);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Latency: %d\n", mLatency);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Flags %08x\n", mFlags);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Stream refCount\n");
-    result.append(buffer);
-    for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
-        snprintf(buffer, SIZE, " %02d     %d\n", i, mRefCount[i]);
-        result.append(buffer);
-    }
-    write(fd, result.string(), result.size());
-
-    return NO_ERROR;
-}
-
-// --- AudioInputDescriptor class implementation
-
-AudioPolicyManagerGeneric::AudioInputDescriptor::AudioInputDescriptor()
-    : mSamplingRate(0), mFormat(0), mChannels(0),
-     mAcoustics((AudioSystem::audio_in_acoustics)0), mDevice(0), mRefCount(0)
-{
-}
-
-status_t AudioPolicyManagerGeneric::AudioInputDescriptor::dump(int fd)
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Format: %d\n", mFormat);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Channels: %08x\n", mChannels);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Acoustics %08x\n", mAcoustics);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Ref Count %d\n", mRefCount);
-    result.append(buffer);
-    write(fd, result.string(), result.size());
-
-    return NO_ERROR;
-}
-
-// --- StreamDescriptor class implementation
-
-void AudioPolicyManagerGeneric::StreamDescriptor::dump(char* buffer, size_t size)
-{
-    snprintf(buffer, size, "      %02d         %02d         %02d         %02d          %d\n",
-            mIndexMin,
-            mIndexMax,
-            mIndexCur,
-            mMuteCount,
-            mCanBeMuted);
-}
-
-}; // namespace android
diff --git a/libs/audioflinger/AudioPolicyManagerGeneric.h b/libs/audioflinger/AudioPolicyManagerGeneric.h
deleted file mode 100644
index 4997cdf..0000000
--- a/libs/audioflinger/AudioPolicyManagerGeneric.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <hardware_legacy/AudioPolicyInterface.h>
-#include <utils/threads.h>
-
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-#define MAX_DEVICE_ADDRESS_LEN 20
-#define NUM_TEST_OUTPUTS 5
-
-class AudioPolicyManagerGeneric: public AudioPolicyInterface
-#ifdef AUDIO_POLICY_TEST
-    , public Thread
-#endif //AUDIO_POLICY_TEST
-{
-
-public:
-                AudioPolicyManagerGeneric(AudioPolicyClientInterface *clientInterface);
-        virtual ~AudioPolicyManagerGeneric();
-
-        // AudioPolicyInterface
-        virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device,
-                                                          AudioSystem::device_connection_state state,
-                                                          const char *device_address);
-        virtual AudioSystem::device_connection_state getDeviceConnectionState(AudioSystem::audio_devices device,
-                                                                              const char *device_address);
-        virtual void setPhoneState(int state);
-        virtual void setRingerMode(uint32_t mode, uint32_t mask);
-        virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
-        virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage);
-        virtual void setSystemProperty(const char* property, const char* value);
-        virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
-                                            uint32_t samplingRate,
-                                            uint32_t format,
-                                            uint32_t channels,
-                                            AudioSystem::output_flags flags);
-        virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
-        virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
-        virtual void releaseOutput(audio_io_handle_t output);
-        virtual audio_io_handle_t getInput(int inputSource,
-                                            uint32_t samplingRate,
-                                            uint32_t format,
-                                            uint32_t channels,
-                                            AudioSystem::audio_in_acoustics acoustics);
-        // indicates to the audio policy manager that the input starts being used.
-        virtual status_t startInput(audio_io_handle_t input);
-        // indicates to the audio policy manager that the input stops being used.
-        virtual status_t stopInput(audio_io_handle_t input);
-        virtual void releaseInput(audio_io_handle_t input);
-        virtual void initStreamVolume(AudioSystem::stream_type stream,
-                                                    int indexMin,
-                                                    int indexMax);
-        virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index);
-        virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index);
-
-        virtual status_t dump(int fd);
-
-private:
-
-        enum routing_strategy {
-            STRATEGY_MEDIA,
-            STRATEGY_PHONE,
-            STRATEGY_SONIFICATION,
-            STRATEGY_DTMF,
-            NUM_STRATEGIES
-        };
-
-        // descriptor for audio outputs. Used to maintain current configuration of each opened audio output
-        // and keep track of the usage of this output by each audio stream type.
-        class AudioOutputDescriptor
-        {
-        public:
-            AudioOutputDescriptor();
-
-            status_t    dump(int fd);
-
-            uint32_t device();
-            void changeRefCount(AudioSystem::stream_type, int delta);
-            bool isUsedByStream(AudioSystem::stream_type stream) { return mRefCount[stream] > 0 ? true : false; }
-            uint32_t refCount();
-
-            uint32_t mSamplingRate;             //
-            uint32_t mFormat;                   //
-            uint32_t mChannels;                 // output configuration
-            uint32_t mLatency;                  //
-            AudioSystem::output_flags mFlags;   //
-            uint32_t mDevice;                   // current device this output is routed to
-            uint32_t mRefCount[AudioSystem::NUM_STREAM_TYPES]; // number of streams of each type using this output
-        };
-
-        // descriptor for audio inputs. Used to maintain current configuration of each opened audio input
-        // and keep track of the usage of this input.
-        class AudioInputDescriptor
-        {
-        public:
-            AudioInputDescriptor();
-
-            status_t    dump(int fd);
-
-            uint32_t mSamplingRate;                     //
-            uint32_t mFormat;                           // input configuration
-            uint32_t mChannels;                         //
-            AudioSystem::audio_in_acoustics mAcoustics; //
-            uint32_t mDevice;                           // current device this input is routed to
-            uint32_t mRefCount;                         // number of AudioRecord clients using this output
-        };
-
-        // stream descriptor used for volume control
-        class StreamDescriptor
-        {
-        public:
-            StreamDescriptor()
-            :   mIndexMin(0), mIndexMax(1), mIndexCur(1), mMuteCount(0), mCanBeMuted(true) {}
-
-            void dump(char* buffer, size_t size);
-
-            int mIndexMin;      // min volume index
-            int mIndexMax;      // max volume index
-            int mIndexCur;      // current volume index
-            int mMuteCount;     // mute request counter
-            bool mCanBeMuted;   // true is the stream can be muted
-        };
-
-        // return the strategy corresponding to a given stream type
-        static routing_strategy getStrategy(AudioSystem::stream_type stream);
-        // return the output handle of an output routed to the specified device, 0 if no output
-        // is routed to the device
-        float computeVolume(int stream, int index, uint32_t device);
-        // Mute or unmute the stream on the specified output
-        void setStreamMute(int stream, bool on, audio_io_handle_t output);
-        // handle special cases for sonification strategy while in call: mute streams or replace by
-        // a special tone in the device used for communication
-        void handleIncallSonification(int stream, bool starting);
-
-
-#ifdef AUDIO_POLICY_TEST
-        virtual     bool        threadLoop();
-                    void        exit();
-        int testOutputIndex(audio_io_handle_t output);
-#endif //AUDIO_POLICY_TEST
-
-
-        AudioPolicyClientInterface *mpClientInterface;  // audio policy client interface
-        audio_io_handle_t mHardwareOutput;              // hardware output handler
-
-        KeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mOutputs;   // list ot output descritors
-        KeyedVector<audio_io_handle_t, AudioInputDescriptor *> mInputs;     // list of input descriptors
-        uint32_t mAvailableOutputDevices;                                   // bit field of all available output devices
-        uint32_t mAvailableInputDevices;                                    // bit field of all available input devices
-        int mPhoneState;                                                    // current phone state
-        uint32_t                 mRingerMode;                               // current ringer mode
-        AudioSystem::forced_config mForceUse[AudioSystem::NUM_FORCE_USE];   // current forced use configuration
-
-        StreamDescriptor mStreams[AudioSystem::NUM_STREAM_TYPES];           // stream descriptors for volume control
-
-#ifdef AUDIO_POLICY_TEST
-        Mutex   mLock;
-        Condition mWaitWorkCV;
-
-        int             mCurOutput;
-        bool            mDirectOutput;
-        audio_io_handle_t mTestOutputs[NUM_TEST_OUTPUTS];
-        int             mTestInput;
-        uint32_t        mTestDevice;
-        uint32_t        mTestSamplingRate;
-        uint32_t        mTestFormat;
-        uint32_t        mTestChannels;
-        uint32_t        mTestLatencyMs;
-#endif //AUDIO_POLICY_TEST
-
-};
-
-};
diff --git a/libs/audioflinger/AudioPolicyService.cpp b/libs/audioflinger/AudioPolicyService.cpp
index aa48019..bb3905c 100644
--- a/libs/audioflinger/AudioPolicyService.cpp
+++ b/libs/audioflinger/AudioPolicyService.cpp
@@ -30,9 +30,10 @@
 #include <utils/String16.h>
 #include <utils/threads.h>
 #include "AudioPolicyService.h"
-#include "AudioPolicyManagerGeneric.h"
+#include <hardware_legacy/AudioPolicyManagerBase.h>
 #include <cutils/properties.h>
 #include <dlfcn.h>
+#include <hardware_legacy/power.h>
 
 // ----------------------------------------------------------------------------
 // the sim build doesn't have gettid
@@ -43,8 +44,9 @@
 
 namespace android {
 
-static const char* kDeadlockedString = "AudioPolicyService may be deadlocked\n";
-static const char* kCmdDeadlockedString = "AudioPolicyService command thread may be deadlocked\n";
+
+static const char *kDeadlockedString = "AudioPolicyService may be deadlocked\n";
+static const char *kCmdDeadlockedString = "AudioPolicyService command thread may be deadlocked\n";
 
 static const int kDumpLockRetries = 50;
 static const int kDumpLockSleep = 20000;
@@ -67,18 +69,18 @@
     char value[PROPERTY_VALUE_MAX];
 
     // start tone playback thread
-    mTonePlaybackThread = new AudioCommandThread();
+    mTonePlaybackThread = new AudioCommandThread(String8(""));
     // start audio commands thread
-    mAudioCommandThread = new AudioCommandThread();
+    mAudioCommandThread = new AudioCommandThread(String8("ApmCommandThread"));
 
 #if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST)
-    mpPolicyManager = new AudioPolicyManagerGeneric(this);
+    mpPolicyManager = new AudioPolicyManagerBase(this);
     LOGV("build for GENERIC_AUDIO - using generic audio policy");
 #else
     // if running in emulation - use the emulator driver
     if (property_get("ro.kernel.qemu", value, 0)) {
         LOGV("Running in emulation - using generic audio policy");
-        mpPolicyManager = new AudioPolicyManagerGeneric(this);
+        mpPolicyManager = new AudioPolicyManagerBase(this);
     }
     else {
         LOGV("Using hardware specific audio policy");
@@ -556,8 +558,8 @@
 
 // -----------  AudioPolicyService::AudioCommandThread implementation ----------
 
-AudioPolicyService::AudioCommandThread::AudioCommandThread()
-    :   Thread(false)
+AudioPolicyService::AudioCommandThread::AudioCommandThread(String8 name)
+    : Thread(false), mName(name)
 {
     mpToneGenerator = NULL;
 }
@@ -565,18 +567,20 @@
 
 AudioPolicyService::AudioCommandThread::~AudioCommandThread()
 {
+    if (mName != "" && !mAudioCommands.isEmpty()) {
+        release_wake_lock(mName.string());
+    }
     mAudioCommands.clear();
     if (mpToneGenerator != NULL) delete mpToneGenerator;
 }
 
 void AudioPolicyService::AudioCommandThread::onFirstRef()
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-
-    snprintf(buffer, SIZE, "AudioCommandThread");
-
-    run(buffer, ANDROID_PRIORITY_AUDIO);
+    if (mName != "") {
+        run(mName.string(), ANDROID_PRIORITY_AUDIO);
+    } else {
+        run("AudioCommandThread", ANDROID_PRIORITY_AUDIO);
+    }
 }
 
 bool AudioPolicyService::AudioCommandThread::threadLoop()
@@ -657,6 +661,10 @@
                 break;
             }
         }
+        // release delayed commands wake lock
+        if (mName != "" && mAudioCommands.isEmpty()) {
+            release_wake_lock(mName.string());
+        }
         LOGV("AudioCommandThread() going to sleep");
         mWaitWorkCV.waitRelative(mLock, waitTime);
         LOGV("AudioCommandThread() waking up");
@@ -815,6 +823,11 @@
 
     command->mTime = systemTime() + milliseconds(delayMs);
 
+    // acquire wake lock to make sure delayed commands are processed
+    if (mName != "" && mAudioCommands.isEmpty()) {
+        acquire_wake_lock(PARTIAL_WAKE_LOCK, mName.string());
+    }
+
     // check same pending commands with later time stamps and eliminate them
     for (i = mAudioCommands.size()-1; i >= 0; i--) {
         AudioCommand *command2 = mAudioCommands[i];
@@ -883,7 +896,7 @@
     removedCommands.clear();
 
     // insert command at the right place according to its time stamp
-    LOGV("inserting command: %d at index %ld, num commands %d", command->mCommand, i+1, mAudioCommands.size());
+    LOGV("inserting command: %d at index %d, num commands %d", command->mCommand, (int)i+1, mAudioCommands.size());
     mAudioCommands.insertAt(command, i + 1);
 }
 
diff --git a/libs/audioflinger/AudioPolicyService.h b/libs/audioflinger/AudioPolicyService.h
index b9234ec..a13d0bd 100644
--- a/libs/audioflinger/AudioPolicyService.h
+++ b/libs/audioflinger/AudioPolicyService.h
@@ -132,7 +132,7 @@
             SET_VOICE_VOLUME
         };
 
-        AudioCommandThread ();
+        AudioCommandThread (String8 name);
         virtual             ~AudioCommandThread();
 
                     status_t    dump(int fd);
@@ -195,7 +195,8 @@
         Condition mWaitWorkCV;
         Vector <AudioCommand *> mAudioCommands; // list of pending commands
         ToneGenerator *mpToneGenerator;     // the tone generator
-        AudioCommand mLastCommand;
+        AudioCommand mLastCommand;          // last processed command (used by dump)
+        String8 mName;                      // string used by wake lock fo delayed commands
     };
 
     // Internal dump utilities.
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index b2a7db8..473f580 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -292,6 +292,7 @@
 static bool gHaveTLS = false;
 static pthread_key_t gTLS = 0;
 static bool gShutdown = false;
+static bool gDisableBackgroundScheduling = false;
 
 IPCThreadState* IPCThreadState::self()
 {
@@ -332,6 +333,11 @@
     }
 }
 
+void IPCThreadState::disableBackgroundScheduling(bool disable)
+{
+    gDisableBackgroundScheduling = disable;
+}
+
 sp<ProcessState> IPCThreadState::process()
 {
     return mProcess;
@@ -386,6 +392,11 @@
 
     mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
     
+    // This thread may have been spawned by a thread that was in the background
+    // scheduling group, so first we will make sure it is in the default/foreground
+    // one to avoid performing an initial transaction in the background.
+    androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
+        
     status_t result;
     do {
         int32_t cmd;
@@ -427,19 +438,13 @@
         }
         
         // After executing the command, ensure that the thread is returned to the
-        // default cgroup and priority before rejoining the pool.  This is a failsafe
-        // in case the command implementation failed to properly restore the thread's
-        // scheduling parameters upon completion.
-        int my_id;
-#ifdef HAVE_GETTID
-        my_id = gettid();
-#else
-        my_id = getpid();
-#endif
-        if (!set_sched_policy(my_id, SP_FOREGROUND)) {
-            // success; reset the priority as well
-            setpriority(PRIO_PROCESS, my_id, ANDROID_PRIORITY_NORMAL);
-        }
+        // default cgroup before rejoining the pool.  The driver takes care of
+        // restoring the priority, but doesn't do anything with cgroups so we
+        // need to take care of that here in userspace.  Note that we do make
+        // sure to go in the foreground after executing a transaction, but
+        // there are other callbacks into user code that could have changed
+        // our group so we want to make absolutely sure it is put back.
+        androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
 
         // Let this thread exit the thread pool if it is no longer
         // needed and it is not the main process thread.
@@ -583,10 +588,10 @@
 }
 
 IPCThreadState::IPCThreadState()
-    : mProcess(ProcessState::self())
+    : mProcess(ProcessState::self()), mMyThreadId(androidGetTid())
 {
     pthread_setspecific(gTLS, this);
-        clearCaller();
+    clearCaller();
     mIn.setDataCapacity(256);
     mOut.setDataCapacity(256);
 }
@@ -930,6 +935,17 @@
             mCallingPid = tr.sender_pid;
             mCallingUid = tr.sender_euid;
             
+            bool doBackground = !gDisableBackgroundScheduling &&
+                    getpriority(PRIO_PROCESS, mMyThreadId)
+                            >= ANDROID_PRIORITY_BACKGROUND;
+            if (doBackground) {
+                // We have inherited a background priority from the caller.
+                // Ensure this thread is in the background scheduling class,
+                // since the driver won't modify scheduling classes for us.
+                androidSetThreadSchedulingGroup(mMyThreadId,
+                        ANDROID_TGROUP_BG_NONINTERACT);
+            }
+            
             //LOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
             
             Parcel reply;
@@ -967,6 +983,13 @@
             mCallingPid = origPid;
             mCallingUid = origUid;
             
+            if (doBackground) {
+                // We moved to the background scheduling group to execute
+                // this transaction, so now that we are done go back in the
+                // foreground.
+                androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
+            }
+            
             IF_LOG_TRANSACTIONS() {
                 TextOutput::Bundle _b(alog);
                 alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 8003d22..4d7bef8 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -444,12 +444,21 @@
         glLoadIdentity();
 
         // the texture's source is rotated
-        if (texture.transform == HAL_TRANSFORM_ROT_90) {
-            // TODO: handle the other orientations
-            glTranslatef(0, 1, 0);
-            glRotatef(-90, 0, 0, 1);
+        switch (texture.transform) {
+            case HAL_TRANSFORM_ROT_90:
+                glTranslatef(0, 1, 0);
+                glRotatef(-90, 0, 0, 1);
+                break;
+            case HAL_TRANSFORM_ROT_180:
+                glTranslatef(1, 1, 0);
+                glRotatef(-180, 0, 0, 1);
+                break;
+            case HAL_TRANSFORM_ROT_270:
+                glTranslatef(1, 0, 0);
+                glRotatef(-270, 0, 0, 1);
+                break;
         }
-        
+
         if (texture.NPOTAdjust) {
             glScalef(texture.wScale, texture.hScale, 1.0f);
         }
@@ -809,7 +818,7 @@
 }
 
 sp<OverlayRef> LayerBaseClient::Surface::createOverlay(
-        uint32_t w, uint32_t h, int32_t format) 
+        uint32_t w, uint32_t h, int32_t format, int32_t orientation)
 {
     return NULL;
 };
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index ed07b3f..f73ea0c 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -351,7 +351,7 @@
         virtual void postBuffer(ssize_t offset);
         virtual void unregisterBuffers();
         virtual sp<OverlayRef> createOverlay(uint32_t w, uint32_t h,
-                int32_t format);
+                int32_t format, int32_t orientation);
 
     protected:
         friend class LayerBaseClient;
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 2ff6167..2735aa2 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -182,14 +182,15 @@
 /**
  * This creates an "overlay" source for this surface
  */
-sp<OverlayRef> LayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t f)
+sp<OverlayRef> LayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t f,
+        int32_t orientation)
 {
     sp<OverlayRef> result;
     Mutex::Autolock _l(mLock);
     if (mSource != 0)
         return result;
 
-    sp<OverlaySource> source = new OverlaySource(*this, &result, w, h, f);
+    sp<OverlaySource> source = new OverlaySource(*this, &result, w, h, f, orientation);
     if (result != 0) {
         mSource = source;
     }
@@ -248,11 +249,11 @@
 }
 
 sp<OverlayRef> LayerBuffer::SurfaceLayerBuffer::createOverlay(
-        uint32_t w, uint32_t h, int32_t format) {
+        uint32_t w, uint32_t h, int32_t format, int32_t orientation) {
     sp<OverlayRef> result;
     sp<LayerBuffer> owner(getOwner());
     if (owner != 0)
-        result = owner->createOverlay(w, h, format);
+        result = owner->createOverlay(w, h, format, orientation);
     return result;
 }
 
@@ -261,7 +262,7 @@
 // ============================================================================
 
 LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, ssize_t offset)
-    : mBufferHeap(buffers)
+    : mBufferHeap(buffers), mSupportsCopybit(false)
 {
     NativeBuffer& src(mNativeBuffer);
     src.crop.l = 0;
@@ -283,10 +284,8 @@
                 offset, buffers.heap->base(),
                 &src.img.handle);
 
-        LOGE_IF(err, "CREATE_HANDLE_FROM_BUFFER (heapId=%d, size=%d, "
-             "offset=%ld, base=%p) failed (%s)",
-                buffers.heap->heapID(), buffers.heap->getSize(),
-                offset, buffers.heap->base(), strerror(-err));
+        // we can fail here is the passed buffer is purely software
+        mSupportsCopybit = (err == NO_ERROR);
     }
  }
 
@@ -372,8 +371,23 @@
 
 LayerBuffer::BufferSource::~BufferSource()
 {    
+    class MessageDestroyTexture : public MessageBase {
+        SurfaceFlinger* flinger;
+        GLuint name;
+    public:
+        MessageDestroyTexture(
+                SurfaceFlinger* flinger, GLuint name)
+            : flinger(flinger), name(name) { }
+        virtual bool handler() {
+            glDeleteTextures(1, &name);
+            return true;
+        }
+    };
+
     if (mTexture.name != -1U) {
-        glDeleteTextures(1, &mTexture.name);
+        // GL textures can only be destroyed from the GL thread
+        mLayer.mFlinger->mEventQueue.postMessage(
+                new MessageDestroyTexture(mLayer.mFlinger.get(), mTexture.name) );
     }
     if (mTexture.image != EGL_NO_IMAGE_KHR) {
         EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay());
@@ -453,7 +467,7 @@
 #if defined(EGL_ANDROID_image_native_buffer)
     if (mLayer.mFlags & DisplayHardware::DIRECT_TEXTURE) {
         copybit_device_t* copybit = mLayer.mBlitEngine;
-        if (copybit) {
+        if (copybit && ourBuffer->supportsCopybit()) {
             // create our EGLImageKHR the first time
             err = initTempBuffer();
             if (err == NO_ERROR) {
@@ -465,7 +479,9 @@
                 copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
                 err = copybit->stretch(copybit, &dst.img, &src.img,
                         &dst.crop, &src.crop, &clip);
-
+                if (err != NO_ERROR) {
+                    clearTempBufferImage();
+                }
             }
         } else {
             err = INVALID_OPERATION;
@@ -504,16 +520,21 @@
         int t = w; w = h; h = t;
     }
 
+    // we're in the copybit case, so make sure we can handle this blit
+    // we don't have to keep the aspect ratio here
+    copybit_device_t* copybit = mLayer.mBlitEngine;
+    const int down = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
+    const int up = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
+    if (buffers.w > w*down)     w = buffers.w / down;
+    else if (w > buffers.w*up)  w = buffers.w*up;
+    if (buffers.h > h*down)     h = buffers.h / down;
+    else if (h > buffers.h*up)  h = buffers.h*up;
+
     if (mTexture.image != EGL_NO_IMAGE_KHR) {
         // we have an EGLImage, make sure the needed size didn't change
         if (w!=mTexture.width || h!= mTexture.height) {
             // delete the EGLImage and texture
-            EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay());
-            glDeleteTextures(1, &mTexture.name);
-            eglDestroyImageKHR(dpy, mTexture.image);
-            Texture defaultTexture;
-            mTexture = defaultTexture;
-            mTempGraphicBuffer.clear();
+            clearTempBufferImage();
         } else {
             // we're good, we have an EGLImageKHR and it's (still) the
             // right size
@@ -560,13 +581,29 @@
     return err;
 }
 
+void LayerBuffer::BufferSource::clearTempBufferImage() const
+{
+    // delete the image
+    EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay());
+    eglDestroyImageKHR(dpy, mTexture.image);
+
+    // and the associated texture (recreate a name)
+    glDeleteTextures(1, &mTexture.name);
+    Texture defaultTexture;
+    mTexture = defaultTexture;
+    mTexture.name = mLayer.createTexture();
+
+    // and the associated buffer
+    mTempGraphicBuffer.clear();
+}
+
 // ---------------------------------------------------------------------------
 
 LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer,
         sp<OverlayRef>* overlayRef, 
-        uint32_t w, uint32_t h, int32_t format)
+        uint32_t w, uint32_t h, int32_t format, int32_t orientation)
     : Source(layer), mVisibilityChanged(false),
-    mOverlay(0), mOverlayHandle(0), mOverlayDevice(0)
+    mOverlay(0), mOverlayHandle(0), mOverlayDevice(0), mOrientation(orientation)
 {
     overlay_control_device_t* overlay_dev = mLayer.mFlinger->getOverlayEngine();
     if (overlay_dev == NULL) {
@@ -648,8 +685,12 @@
             if (mOverlay) {
                 overlay_control_device_t* overlay_dev = mOverlayDevice;
                 overlay_dev->setPosition(overlay_dev, mOverlay, x,y,w,h);
+                // we need to combine the layer orientation and the
+                // user-requested orientation.
+                Transform finalTransform = Transform(mOrientation) *
+                        Transform(mLayer.getOrientation());
                 overlay_dev->setParameter(overlay_dev, mOverlay,
-                        OVERLAY_TRANSFORM, mLayer.getOrientation());
+                        OVERLAY_TRANSFORM, finalTransform.getOrientation());
                 overlay_dev->commit(overlay_dev, mOverlay);
             }
         }
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 2ca63ac..e03f92c 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -74,7 +74,8 @@
     status_t registerBuffers(const ISurface::BufferHeap& buffers);
     void postBuffer(ssize_t offset);
     void unregisterBuffers();
-    sp<OverlayRef> createOverlay(uint32_t w, uint32_t h, int32_t format);
+    sp<OverlayRef> createOverlay(uint32_t w, uint32_t h, int32_t format,
+            int32_t orientation);
     
     sp<Source> getSource() const;
     sp<Source> clearSource();
@@ -99,6 +100,9 @@
     class Buffer : public LightRefBase<Buffer> {
     public:
         Buffer(const ISurface::BufferHeap& buffers, ssize_t offset);
+        inline bool supportsCopybit() const {
+            return mSupportsCopybit;
+        }
         inline status_t getStatus() const {
             return mBufferHeap.heap!=0 ? NO_ERROR : NO_INIT;
         }
@@ -113,6 +117,7 @@
     private:
         ISurface::BufferHeap    mBufferHeap;
         NativeBuffer            mNativeBuffer;
+        bool                    mSupportsCopybit;
     };
 
     class BufferSource : public Source {
@@ -131,6 +136,7 @@
         virtual void destroy() { }
     private:
         status_t initTempBuffer() const;
+        void clearTempBufferImage() const;
         mutable Mutex                   mBufferSourceLock;
         sp<Buffer>                      mBuffer;
         status_t                        mStatus;
@@ -145,7 +151,7 @@
     public:
         OverlaySource(LayerBuffer& layer,
                 sp<OverlayRef>* overlayRef, 
-                uint32_t w, uint32_t h, int32_t format);
+                uint32_t w, uint32_t h, int32_t format, int32_t orientation);
         virtual ~OverlaySource();
         virtual void onDraw(const Region& clip) const;
         virtual void onTransaction(uint32_t flags);
@@ -178,6 +184,7 @@
         int32_t mFormat;
         int32_t mWidthStride;
         int32_t mHeightStride;
+        int32_t mOrientation;
         mutable Mutex mOverlaySourceLock;
         bool mInitialized;
     };
@@ -195,7 +202,7 @@
         virtual void unregisterBuffers();
         
         virtual sp<OverlayRef> createOverlay(
-                uint32_t w, uint32_t h, int32_t format);
+                uint32_t w, uint32_t h, int32_t format, int32_t orientation);
     private:
         sp<LayerBuffer> getOwner() const {
             return static_cast<LayerBuffer*>(Surface::getOwner().get());
diff --git a/libs/surfaceflinger/Transform.cpp b/libs/surfaceflinger/Transform.cpp
index 1501536..ab6f7ba 100644
--- a/libs/surfaceflinger/Transform.cpp
+++ b/libs/surfaceflinger/Transform.cpp
@@ -42,6 +42,17 @@
 {
 }
 
+Transform::Transform(int32_t flags) {
+    mTransform.reset();
+    int sx = (flags & FLIP_H) ? -1 : 1;
+    int sy = (flags & FLIP_V) ? -1 : 1;
+    if (flags & ROT_90) {
+        this->set(0, -sy, sx, 0);
+    } else {
+        this->set(sx, 0, 0, sy);
+    }
+}
+
 Transform::~Transform() {
 }
 
diff --git a/libs/surfaceflinger/Transform.h b/libs/surfaceflinger/Transform.h
index 78f5c19..ddab404 100644
--- a/libs/surfaceflinger/Transform.h
+++ b/libs/surfaceflinger/Transform.h
@@ -38,6 +38,7 @@
 public:
                     Transform();
                     Transform(const Transform&  other);
+                    Transform(int32_t flags);
                     ~Transform();
 
             enum orientation_flags {
diff --git a/libs/ui/CameraParameters.cpp b/libs/ui/CameraParameters.cpp
index 8f1749d..a94f6b9 100644
--- a/libs/ui/CameraParameters.cpp
+++ b/libs/ui/CameraParameters.cpp
@@ -36,7 +36,7 @@
 const char CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS[] = "picture-format-values";
 const char CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH[] = "jpeg-thumbnail-width";
 const char CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT[] = "jpeg-thumbnail-height";
-const char CameraParameters::KEY_SUPPORTED_THUMBNAIL_SIZES[] = "jpeg-thumbnail-size-values";
+const char CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES[] = "jpeg-thumbnail-size-values";
 const char CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY[] = "jpeg-thumbnail-quality";
 const char CameraParameters::KEY_JPEG_QUALITY[] = "jpeg-quality";
 const char CameraParameters::KEY_ROTATION[] = "rotation";
@@ -121,9 +121,6 @@
 const char CameraParameters::FOCUS_MODE_MACRO[] = "macro";
 const char CameraParameters::FOCUS_MODE_FIXED[] = "fixed";
 
-static const char* portrait = "portrait";
-static const char* landscape = "landscape";
-
 CameraParameters::CameraParameters()
                 : mMap()
 {
@@ -282,23 +279,6 @@
     set(KEY_PREVIEW_FORMAT, format);
 }
 
-int CameraParameters::getOrientation() const
-{
-    const char* orientation = get("orientation");
-    if (orientation && !strcmp(orientation, portrait))
-        return CAMERA_ORIENTATION_PORTRAIT;
-    return CAMERA_ORIENTATION_LANDSCAPE;
-}
-
-void CameraParameters::setOrientation(int orientation)
-{
-    if (orientation == CAMERA_ORIENTATION_PORTRAIT) {
-        set("orientation", portrait);
-    } else {
-        set("orientation", landscape);
-    }
-}
-
 const char *CameraParameters::getPreviewFormat() const
 {
     return get(KEY_PREVIEW_FORMAT);
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 4aac455..c4d4f99 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -489,7 +489,6 @@
 {
     int version;
     int fd;
-    int attempt;
     struct pollfd *new_mFDs;
     device_t **new_devices;
     char **new_device_names;
@@ -502,16 +501,11 @@
 
     AutoMutex _l(mLock);
 
-    for (attempt = 0; attempt < 10; attempt++) {
-        fd = open(deviceName, O_RDWR);
-        if (fd >= 0) break;
-        usleep(100);
-    }
+    fd = open(deviceName, O_RDWR);
     if(fd < 0) {
         LOGE("could not open %s, %s\n", deviceName, strerror(errno));
         return -1;
     }
-    LOGV("Opened device: %s (%d failures)", deviceName, attempt);
 
     if(ioctl(fd, EVIOCGVERSION, &version)) {
         LOGE("could not get driver version for %s, %s\n", deviceName, strerror(errno));
diff --git a/libs/ui/ISurface.cpp b/libs/ui/ISurface.cpp
index 4fb38ed..6f3d762 100644
--- a/libs/ui/ISurface.cpp
+++ b/libs/ui/ISurface.cpp
@@ -115,13 +115,14 @@
     }
 
     virtual sp<OverlayRef> createOverlay(
-             uint32_t w, uint32_t h, int32_t format)
+             uint32_t w, uint32_t h, int32_t format, int32_t orientation)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
         data.writeInt32(w);
         data.writeInt32(h);
         data.writeInt32(format);
+        data.writeInt32(orientation);
         remote()->transact(CREATE_OVERLAY, data, &reply);
         return OverlayRef::readFromParcel(reply);
     }
@@ -173,7 +174,8 @@
             int w = data.readInt32();
             int h = data.readInt32();
             int f = data.readInt32();
-            sp<OverlayRef> o = createOverlay(w, h, f);
+            int orientation = data.readInt32();
+            sp<OverlayRef> o = createOverlay(w, h, f, orientation);
             return OverlayRef::writeToParcel(reply, o);
         } break;
         default:
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
index 24ae27f..c7be05b 100644
--- a/libs/ui/Surface.cpp
+++ b/libs/ui/Surface.cpp
@@ -607,13 +607,21 @@
 status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking) 
 {
     if (mApiLock.tryLock() != NO_ERROR) {
-        LOGE("calling Surface::lock() from different threads!");
+        LOGE("calling Surface::lock from different threads!");
         CallStack stack;
         stack.update();
         stack.dump("Surface::lock called from different threads");
         return WOULD_BLOCK;
     }
+
+    /* Here we're holding mApiLock */
     
+    if (mLockedBuffer != 0) {
+        LOGE("Surface::lock failed, already locked");
+        mApiLock.unlock();
+        return INVALID_OPERATION;
+    }
+
     // we're intending to do software rendering from this point
     setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
 
@@ -682,8 +690,8 @@
 status_t Surface::unlockAndPost() 
 {
     if (mLockedBuffer == 0) {
-        LOGE("unlockAndPost failed, no locked buffer");
-        return BAD_VALUE;
+        LOGE("Surface::unlockAndPost failed, no locked buffer");
+        return INVALID_OPERATION;
     }
 
     status_t err = mLockedBuffer->unlock();
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 450af8d..e8bd5cf 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -229,12 +229,12 @@
 // --------------------------------------------------------------------
 
 ResStringPool::ResStringPool()
-    : mError(NO_INIT), mOwnedData(NULL)
+    : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL)
 {
 }
 
 ResStringPool::ResStringPool(const void* data, size_t size, bool copyData)
-    : mError(NO_INIT), mOwnedData(NULL)
+    : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL)
 {
     setTo(data, size, copyData);
 }
@@ -296,7 +296,17 @@
                     (int)size);
             return (mError=BAD_TYPE);
         }
-        mStrings = (const char16_t*)
+
+        size_t charSize;
+        if (mHeader->flags&ResStringPool_header::UTF8_FLAG) {
+            charSize = sizeof(uint8_t);
+            mCache = (char16_t**)malloc(sizeof(char16_t**)*mHeader->stringCount);
+            memset(mCache, 0, sizeof(char16_t**)*mHeader->stringCount);
+        } else {
+            charSize = sizeof(char16_t);
+        }
+
+        mStrings = (const void*)
             (((const uint8_t*)data)+mHeader->stringsStart);
         if (mHeader->stringsStart >= (mHeader->header.size-sizeof(uint16_t))) {
             LOGW("Bad string block: string pool starts at %d, after total size %d\n",
@@ -305,7 +315,7 @@
         }
         if (mHeader->styleCount == 0) {
             mStringPoolSize =
-                (mHeader->header.size-mHeader->stringsStart)/sizeof(uint16_t);
+                (mHeader->header.size-mHeader->stringsStart)/charSize;
         } else {
             // check invariant: styles follow the strings
             if (mHeader->stylesStart <= mHeader->stringsStart) {
@@ -314,7 +324,7 @@
                 return (mError=BAD_TYPE);
             }
             mStringPoolSize =
-                (mHeader->stylesStart-mHeader->stringsStart)/sizeof(uint16_t);
+                (mHeader->stylesStart-mHeader->stringsStart)/charSize;
         }
 
         // check invariant: stringCount > 0 requires a string pool to exist
@@ -329,13 +339,19 @@
             for (i=0; i<mHeader->stringCount; i++) {
                 e[i] = dtohl(mEntries[i]);
             }
-            char16_t* s = const_cast<char16_t*>(mStrings);
-            for (i=0; i<mStringPoolSize; i++) {
-                s[i] = dtohs(mStrings[i]);
+            if (!(mHeader->flags&ResStringPool_header::UTF8_FLAG)) {
+                const char16_t* strings = (const char16_t*)mStrings;
+                char16_t* s = const_cast<char16_t*>(strings);
+                for (i=0; i<mStringPoolSize; i++) {
+                    s[i] = dtohs(strings[i]);
+                }
             }
         }
 
-        if (mStrings[mStringPoolSize-1] != 0) {
+        if ((mHeader->flags&ResStringPool_header::UTF8_FLAG &&
+                ((uint8_t*)mStrings)[mStringPoolSize-1] != 0) ||
+                (!mHeader->flags&ResStringPool_header::UTF8_FLAG &&
+                ((char16_t*)mStrings)[mStringPoolSize-1] != 0)) {
             LOGW("Bad string block: last string is not 0-terminated\n");
             return (mError=BAD_TYPE);
         }
@@ -410,24 +426,67 @@
         free(mOwnedData);
         mOwnedData = NULL;
     }
+    if (mHeader != NULL && mCache != NULL) {
+        for (size_t x = 0; x < mHeader->stringCount; x++) {
+            if (mCache[x] != NULL) {
+                free(mCache[x]);
+                mCache[x] = NULL;
+            }
+        }
+        free(mCache);
+        mCache = NULL;
+    }
 }
 
+#define DECODE_LENGTH(str, chrsz, len) \
+    len = *(str); \
+    if (*(str)&(1<<(chrsz*8-1))) { \
+        (str)++; \
+        len = (((len)&((1<<(chrsz*8-1))-1))<<(chrsz*8)) + *(str); \
+    } \
+    (str)++;
+
 const uint16_t* ResStringPool::stringAt(size_t idx, size_t* outLen) const
 {
     if (mError == NO_ERROR && idx < mHeader->stringCount) {
-        const uint32_t off = (mEntries[idx]/sizeof(uint16_t));
+        const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0;
+        const uint32_t off = mEntries[idx]/(isUTF8?sizeof(char):sizeof(char16_t));
         if (off < (mStringPoolSize-1)) {
-            const char16_t* str = mStrings+off;
-            *outLen = *str;
-            if ((*str)&0x8000) {
-                str++;
-                *outLen = (((*outLen)&0x7fff)<<16) + *str;
-            }
-            if ((uint32_t)(str+1+*outLen-mStrings) < mStringPoolSize) {
-                return str+1;
+            if (!isUTF8) {
+                const char16_t* strings = (char16_t*)mStrings;
+                const char16_t* str = strings+off;
+                DECODE_LENGTH(str, sizeof(char16_t), *outLen)
+                if ((uint32_t)(str+*outLen-strings) < mStringPoolSize) {
+                    return str;
+                } else {
+                    LOGW("Bad string block: string #%d extends to %d, past end at %d\n",
+                            (int)idx, (int)(str+*outLen-strings), (int)mStringPoolSize);
+                }
             } else {
-                LOGW("Bad string block: string #%d extends to %d, past end at %d\n",
-                        (int)idx, (int)(str+1+*outLen-mStrings), (int)mStringPoolSize);
+                const uint8_t* strings = (uint8_t*)mStrings;
+                const uint8_t* str = strings+off;
+                DECODE_LENGTH(str, sizeof(uint8_t), *outLen)
+                size_t encLen;
+                DECODE_LENGTH(str, sizeof(uint8_t), encLen)
+                if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
+                    AutoMutex lock(mDecodeLock);
+                    if (mCache[idx] != NULL) {
+                        return mCache[idx];
+                    }
+                    char16_t *u16str = (char16_t *)calloc(*outLen+1, sizeof(char16_t));
+                    if (!u16str) {
+                        LOGW("No memory when trying to allocate decode cache for string #%d\n",
+                                (int)idx);
+                        return NULL;
+                    }
+                    const unsigned char *u8src = reinterpret_cast<const unsigned char *>(str);
+                    utf8_to_utf16(u8src, encLen, u16str, *outLen);
+                    mCache[idx] = u16str;
+                    return u16str;
+                } else {
+                    LOGW("Bad string block: string #%d extends to %d, past end at %d\n",
+                            (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
+                }
             }
         } else {
             LOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
@@ -466,6 +525,10 @@
 
     size_t len;
 
+    // TODO optimize searching for UTF-8 strings taking into account
+    // the cache fill to determine when to convert the searched-for
+    // string key to UTF-8.
+
     if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
         // Do a binary search for the string...
         ssize_t l = 0;
@@ -513,6 +576,13 @@
     return (mError == NO_ERROR) ? mHeader->stringCount : 0;
 }
 
+#ifndef HAVE_ANDROID_OS
+bool ResStringPool::isUTF8() const
+{
+    return (mHeader->flags&ResStringPool_header::UTF8_FLAG)!=0;
+}
+#endif
+
 // --------------------------------------------------------------------
 // --------------------------------------------------------------------
 // --------------------------------------------------------------------
@@ -1043,6 +1113,7 @@
 void ResXMLTree::uninit()
 {
     mError = NO_INIT;
+    mStrings.uninit();
     if (mOwnedData) {
         free(mOwnedData);
         mOwnedData = NULL;
@@ -3952,7 +4023,8 @@
         if (str == NULL) {
             printf("(string) null\n");
         } else {
-            printf("(string) \"%s\"\n",
+            printf("(string%d) \"%s\"\n",
+                    pkg->header->values.isUTF8()?8:16,
                     String8(str, len).string());
         } 
     } else if (value.dataType == Res_value::TYPE_FLOAT) {
diff --git a/libs/utils/String16.cpp b/libs/utils/String16.cpp
index aef67f2..eab7b2b 100644
--- a/libs/utils/String16.cpp
+++ b/libs/utils/String16.cpp
@@ -172,10 +172,6 @@
            : 0);
 }
 
-// ---------------------------------------------------------------------------
-
-namespace android {
-
 static inline size_t
 utf8_char_len(uint8_t ch)
 {
@@ -215,8 +211,38 @@
     //printf("Char at %p: len=%d, utf-16=%p\n", src, length, (void*)result);
 }
 
+void
+utf8_to_utf16(const uint8_t *src, size_t srcLen,
+        char16_t* dst, const size_t dstLen)
+{
+    const uint8_t* const end = src + srcLen;
+    const char16_t* const dstEnd = dst + dstLen;
+    while (src < end && dst < dstEnd) {
+        size_t len = utf8_char_len(*src);
+        uint32_t codepoint = utf8_to_utf32((const uint8_t*)src, len);
+
+        // Convert the UTF32 codepoint to one or more UTF16 codepoints
+        if (codepoint <= 0xFFFF) {
+            // Single UTF16 character
+            *dst++ = (char16_t) codepoint;
+        } else {
+            // Multiple UTF16 characters with surrogates
+            codepoint = codepoint - 0x10000;
+            *dst++ = (char16_t) ((codepoint >> 10) + 0xD800);
+            *dst++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00);
+        }
+
+        src += len;
+    }
+    if (dst < dstEnd) {
+        *dst = 0;
+    }
+}
+
 // ---------------------------------------------------------------------------
 
+namespace android {
+
 static SharedBuffer* gEmptyStringBuf = NULL;
 static char16_t* gEmptyString = NULL;
 
@@ -260,30 +286,14 @@
         p += utf8len;
     }
     
-    SharedBuffer* buf = SharedBuffer::alloc((chars+1)*sizeof(char16_t));
+    size_t bufSize = (chars+1)*sizeof(char16_t);
+    SharedBuffer* buf = SharedBuffer::alloc(bufSize);
     if (buf) {
         p = in;
         char16_t* str = (char16_t*)buf->data();
-        char16_t* d = str;
-        while (p < end) {
-            size_t len = utf8_char_len(*p);
-            uint32_t codepoint = utf8_to_utf32((const uint8_t*)p, len);
-
-            // Convert the UTF32 codepoint to one or more UTF16 codepoints
-            if (codepoint <= 0xFFFF) {
-                // Single UTF16 character
-                *d++ = (char16_t) codepoint;
-            } else {
-                // Multiple UTF16 characters with surrogates
-                codepoint = codepoint - 0x10000;
-                *d++ = (char16_t) ((codepoint >> 10) + 0xD800);
-                *d++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00);
-            }
-
-            p += len;
-        }
-        *d = 0;
         
+        utf8_to_utf16((const uint8_t*)p, len, str, bufSize);
+
         //printf("Created UTF-16 string from UTF-8 \"%s\":", in);
         //printHexData(1, str, buf->size(), 16, 1);
         //printf("\n");
diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp
index e908ec1..3a34838 100644
--- a/libs/utils/String8.cpp
+++ b/libs/utils/String8.cpp
@@ -208,10 +208,23 @@
     return getEmptyString();
 }
 
-// Note: not dealing with expanding surrogate pairs.
 static char* allocFromUTF16(const char16_t* in, size_t len)
 {
-    return allocFromUTF16OrUTF32<char16_t, size_t>(in, len);
+    if (len == 0) return getEmptyString();
+
+    const size_t bytes = utf8_length_from_utf16(in, len);
+
+    SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
+    LOG_ASSERT(buf, "Unable to allocate shared buffer");
+    if (buf) {
+        char* str = (char*)buf->data();
+
+        utf16_to_utf8(in, len, str, bytes+1);
+
+        return str;
+    }
+
+    return getEmptyString();
 }
 
 static char* allocFromUTF32(const char32_t* in, size_t len)
@@ -762,6 +775,26 @@
     return ret;
 }
 
+size_t utf8_length_from_utf16(const char16_t *src, size_t src_len)
+{
+    if (src == NULL || src_len == 0) {
+        return 0;
+    }
+    size_t ret = 0;
+    const char16_t* const end = src + src_len;
+    while (src < end) {
+        if ((*src & 0xFC00) == 0xD800 && (src + 1) < end
+                && (*++src & 0xFC00) == 0xDC00) {
+            // surrogate pairs are always 4 bytes.
+            ret += 4;
+            src++;
+        } else {
+            ret += android::utf32_to_utf8_bytes((char32_t) *src++);
+        }
+    }
+    return ret;
+}
+
 static int32_t utf32_at_internal(const char* cur, size_t *num_read)
 {
     const char first_char = *cur;
@@ -848,3 +881,33 @@
     }
     return cur - dst;
 }
+
+size_t utf16_to_utf8(const char16_t* src, size_t src_len,
+                     char* dst, size_t dst_len)
+{
+    if (src == NULL || src_len == 0 || dst == NULL || dst_len == 0) {
+        return 0;
+    }
+    const char16_t* cur_utf16 = src;
+    const char16_t* const end_utf16 = src + src_len;
+    char *cur = dst;
+    const char* const end = dst + dst_len;
+    while (cur_utf16 < end_utf16 && cur < end) {
+        char32_t utf32;
+        // surrogate pairs
+        if ((*cur_utf16 & 0xFC00) == 0xD800 && (cur_utf16 + 1) < end_utf16) {
+            utf32 = (*cur_utf16++ - 0xD800) << 10;
+            utf32 |= *cur_utf16++ - 0xDC00;
+            utf32 += 0x10000;
+        } else {
+            utf32 = (char32_t) *cur_utf16++;
+        }
+        size_t len = android::utf32_to_utf8_bytes(utf32);
+        android::utf32_to_utf8((uint8_t*)cur, utf32, len);
+        cur += len;
+    }
+    if (cur < end) {
+        *cur = '\0';
+    }
+    return cur - dst;
+}
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index ec3db09..2b1f490 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -20,6 +20,8 @@
 #include <utils/threads.h>
 #include <utils/Log.h>
 
+#include <cutils/sched_policy.h>
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <memory.h>
@@ -269,6 +271,58 @@
     gCreateThreadFn = func;
 }
 
+pid_t androidGetTid()
+{
+#ifdef HAVE_GETTID
+    return gettid();
+#else
+    return getpid();
+#endif
+}
+
+int androidSetThreadSchedulingGroup(pid_t tid, int grp)
+{
+    if (grp > ANDROID_TGROUP_MAX || grp < 0) { 
+        return BAD_VALUE;
+    }
+
+#if defined(HAVE_PTHREADS)
+    if (set_sched_policy(tid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
+                                      SP_BACKGROUND : SP_FOREGROUND)) {
+        return PERMISSION_DENIED;
+    }
+#endif
+    
+    return NO_ERROR;
+}
+
+int androidSetThreadPriority(pid_t tid, int pri)
+{
+    int rc = 0;
+    
+#if defined(HAVE_PTHREADS)
+    int lasterr = 0;
+
+    if (pri >= ANDROID_PRIORITY_BACKGROUND) {
+        rc = set_sched_policy(tid, SP_BACKGROUND);
+    } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) {
+        rc = set_sched_policy(tid, SP_FOREGROUND);
+    }
+
+    if (rc) {
+        lasterr = errno;
+    }
+
+    if (setpriority(PRIO_PROCESS, tid, pri) < 0) {
+        rc = INVALID_OPERATION;
+    } else {
+        errno = lasterr;
+    }
+#endif
+    
+    return rc;
+}
+
 namespace android {
 
 /*
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
index 9837845..c2e9f31 100644
--- a/opengl/libagl/Android.mk
+++ b/opengl/libagl/Android.mk
@@ -39,6 +39,11 @@
 
 ifneq ($(TARGET_SIMULATOR),true)
     # we need to access the private Bionic header <bionic_tls.h>
+    # on ARM platforms, we need to mirror the ARCH_ARM_HAVE_TLS_REGISTER
+    # behavior from the bionic Android.mk file
+    ifeq ($(TARGET_ARCH)-$(ARCH_ARM_HAVE_TLS_REGISTER),arm-true)
+        LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+    endif
     LOCAL_C_INCLUDES += bionic/libc/private
 endif
 
diff --git a/opengl/libagl/fixed_asm.S b/opengl/libagl/fixed_asm.S
index 6cbc56f..05044f2 100644
--- a/opengl/libagl/fixed_asm.S
+++ b/opengl/libagl/fixed_asm.S
@@ -20,7 +20,9 @@
     .align
     
     .global gglFloatToFixed
+    .type gglFloatToFixed, %function
     .global gglFloatToFixedFast
+    .type gglFloatToFixedFast, %function
 
 
 /*
diff --git a/opengl/libagl/iterators.S b/opengl/libagl/iterators.S
index daf2937..8c86482 100644
--- a/opengl/libagl/iterators.S
+++ b/opengl/libagl/iterators.S
@@ -21,6 +21,7 @@
     .arm
     
     .global iterators0032
+    .type iterators0032, %function
 
 /*
  * iterators0032
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index 13d078e..2875c13 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -583,7 +583,7 @@
 
 
 static __attribute__((noinline))
-void set_depth_and_fog(ogles_context_t* c, GLint z)
+void set_depth_and_fog(ogles_context_t* c, GGLfixed z)
 {
     const uint32_t enables = c->rasterizer.state.enables;
     // we need to compute Zw
@@ -592,8 +592,8 @@
     GGLfixed Zw;
     GGLfixed n = gglFloatToFixed(c->transforms.vpt.zNear);
     GGLfixed f = gglFloatToFixed(c->transforms.vpt.zFar);
-    if (z<=0)       Zw = n;
-    else if (z>=1)  Zw = f;
+    if (z<=0)               Zw = n;
+    else if (z>=0x10000)    Zw = f;
     else            Zw = gglMulAddx(z, (f-n), n);
     if (enables & GGL_ENABLE_FOG) {
         // set up fog if needed...
@@ -836,7 +836,7 @@
             c->rasterizer.procs.texCoord2i(c, s0, t0);
             const uint32_t enables = c->rasterizer.state.enables;
             if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
-                set_depth_and_fog(c, z);
+                set_depth_and_fog(c, gglIntToFixed(z));
 
             c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
             c->rasterizer.procs.disable(c, GGL_W_LERP);
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 37b9a43..6b7020f 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -20,6 +20,11 @@
 ifeq ($(TARGET_SIMULATOR),true)
 else
     LOCAL_SHARED_LIBRARIES += libdl
+    # Bionic's private TLS header relies on the ARCH_ARM_HAVE_TLS_REGISTER to
+    # select the appropriate TLS codepath
+    ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
+        LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+    endif
     # we need to access the private Bionic header <bionic_tls.h>
     LOCAL_C_INCLUDES += bionic/libc/private
 endif
@@ -75,6 +80,9 @@
 else
     LOCAL_SHARED_LIBRARIES += libdl
     # we need to access the private Bionic header <bionic_tls.h>
+    ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
+        LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+    endif
     LOCAL_C_INCLUDES += bionic/libc/private
 endif
 
@@ -108,6 +116,9 @@
 else
     LOCAL_SHARED_LIBRARIES += libdl
     # we need to access the private Bionic header <bionic_tls.h>
+    ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
+        LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+    endif
     LOCAL_C_INCLUDES += bionic/libc/private
 endif
 
@@ -136,3 +147,17 @@
 
 include $(BUILD_HOST_STATIC_LIBRARY)
 
+###############################################################################
+# Build the ETC1 device library
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= 		\
+	ETC1/etc1.cpp 	\
+#
+
+LOCAL_LDLIBS := -lpthread -ldl
+LOCAL_MODULE:= libETC1
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index c22c21b..d2f8ced 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -1111,10 +1111,10 @@
         if (cur_c == NULL) {
             // no current context
             if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
-                // calling eglMakeCurrent( ..., EGL_NO_CONTEXT, !=0, !=0);
-                return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+                // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
+                return setError(EGL_BAD_MATCH, EGL_FALSE);
             }
-            // not an error, there is just not current context.
+            // not an error, there is just no current context.
             return EGL_TRUE;
         }
     }
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
index 0c9352e..e7757a8 100644
--- a/opengl/libs/GLES_CM/gl.cpp
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -47,6 +47,12 @@
         GLsizei stride, const GLvoid *pointer, GLsizei count);
 GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type,
         GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glPointSizePointerOESBounds(GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glMatrixIndexPointerOESBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
 }
 
 void glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
@@ -66,6 +72,21 @@
     glVertexPointer(size, type, stride, pointer);
 }
 
+void GL_APIENTRY glPointSizePointerOESBounds(GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count) {
+    glPointSizePointerOES(type, stride, pointer);
+}
+
+GL_API void GL_APIENTRY glMatrixIndexPointerOESBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count) {
+    glMatrixIndexPointerOES(size, type, stride, pointer);
+}
+
+GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count) {
+    glWeightPointerOES(size, type, stride, pointer);
+}
+
 // ----------------------------------------------------------------------------
 // Actual GL entry-points
 // ----------------------------------------------------------------------------
diff --git a/opengl/tests/fillrate/Android.mk b/opengl/tests/fillrate/Android.mk
index a7d30c2..191c59b 100644
--- a/opengl/tests/fillrate/Android.mk
+++ b/opengl/tests/fillrate/Android.mk
@@ -6,6 +6,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
+	libutils \
     libEGL \
     libGLESv1_CM \
     libui
diff --git a/opengl/tests/finish/Android.mk b/opengl/tests/finish/Android.mk
index 5620814..aa607c6 100644
--- a/opengl/tests/finish/Android.mk
+++ b/opengl/tests/finish/Android.mk
@@ -6,6 +6,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
+	libutils \
     libEGL \
     libGLESv1_CM \
     libui
diff --git a/opengl/tests/gl2_java/Android.mk b/opengl/tests/gl2_java/Android.mk
new file mode 100644
index 0000000..34f4aee
--- /dev/null
+++ b/opengl/tests/gl2_java/Android.mk
@@ -0,0 +1,18 @@
+#########################################################################
+# OpenGL ES 2.0 Java sample
+#########################################################################
+
+TOP_LOCAL_PATH:= $(call my-dir)
+
+# Build activity
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := GL2Java
+
+include $(BUILD_PACKAGE)
diff --git a/opengl/tests/gl2_java/AndroidManifest.xml b/opengl/tests/gl2_java/AndroidManifest.xml
new file mode 100644
index 0000000..585b63f
--- /dev/null
+++ b/opengl/tests/gl2_java/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.gl2java">
+    <uses-feature android:glEsVersion="0x00020000" />
+    <application
+            android:label="@string/gl2java_activity">
+        <activity android:name="GL2JavaActivity"
+                android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+            	android:launchMode="singleTask"
+            	android:configChanges="orientation|keyboardHidden">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/opengl/tests/gl2_java/res/values/strings.xml b/opengl/tests/gl2_java/res/values/strings.xml
new file mode 100644
index 0000000..d718b1d
--- /dev/null
+++ b/opengl/tests/gl2_java/res/values/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<!-- This file contains resource definitions for displayed strings, allowing
+     them to be changed based on the locale and options. -->
+
+<resources>
+    <!-- Simple strings. -->
+    <string name="gl2java_activity">GL2Java</string>
+
+</resources>
+
diff --git a/opengl/tests/gl2_java/src/com/android/gl2java/GL2JavaActivity.java b/opengl/tests/gl2_java/src/com/android/gl2java/GL2JavaActivity.java
new file mode 100644
index 0000000..37654fb
--- /dev/null
+++ b/opengl/tests/gl2_java/src/com/android/gl2java/GL2JavaActivity.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gl2java;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.WindowManager;
+
+import java.io.File;
+
+
+public class GL2JavaActivity extends Activity {
+
+    GL2JavaView mView;
+
+    @Override protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        mView = new GL2JavaView(getApplication());
+	setContentView(mView);
+    }
+
+    @Override protected void onPause() {
+        super.onPause();
+        mView.onPause();
+    }
+
+    @Override protected void onResume() {
+        super.onResume();
+        mView.onResume();
+    }
+}
diff --git a/opengl/tests/gl2_java/src/com/android/gl2java/GL2JavaView.java b/opengl/tests/gl2_java/src/com/android/gl2java/GL2JavaView.java
new file mode 100644
index 0000000..7f2bfd3
--- /dev/null
+++ b/opengl/tests/gl2_java/src/com/android/gl2java/GL2JavaView.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gl2java;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.opengl.GLES20;
+
+/**
+ * An implementation of SurfaceView that uses the dedicated surface for
+ * displaying an OpenGL animation.  This allows the animation to run in a
+ * separate thread, without requiring that it be driven by the update mechanism
+ * of the view hierarchy.
+ *
+ * The application-specific rendering code is delegated to a GLView.Renderer
+ * instance.
+ */
+class GL2JavaView extends GLSurfaceView {
+    private static String TAG = "GL2JavaView";
+
+    public GL2JavaView(Context context) {
+        super(context);
+        setEGLContextClientVersion(2);
+        setRenderer(new Renderer());
+    }
+
+    private static class Renderer implements GLSurfaceView.Renderer {
+
+        public Renderer() {
+            mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length * 4)
+                .order(ByteOrder.nativeOrder()).asFloatBuffer();
+            mTriangleVertices.put(mTriangleVerticesData).position(0);
+        }
+
+        public void onDrawFrame(GL10 gl) {
+            GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
+            GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
+            GLES20.glUseProgram(mProgram);
+            checkGlError("glUseProgram");
+
+            GLES20.glVertexAttribPointer(mvPositionHandle, 2, GLES20.GL_FLOAT, false, 0, mTriangleVertices);
+            checkGlError("glVertexAttribPointer");
+            GLES20.glEnableVertexAttribArray(mvPositionHandle);
+            checkGlError("glEnableVertexAttribArray");
+            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
+            checkGlError("glDrawArrays");
+
+        }
+
+        public void onSurfaceChanged(GL10 gl, int width, int height) {
+            GLES20.glViewport(0, 0, width, height);
+        }
+
+        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+            mProgram = createProgram(mVertexShader, mFragmentShader);
+            if (mProgram == 0) {
+                return;
+            }
+            mvPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
+            checkGlError("glGetAttribLocation");
+            if (mvPositionHandle == -1) {
+                throw new RuntimeException("Could not get attrib location for vPosition");
+            }
+        }
+
+        private int loadShader(int shaderType, String source) {
+            int shader = GLES20.glCreateShader(shaderType);
+            if (shader != 0) {
+                GLES20.glShaderSource(shader, source);
+                GLES20.glCompileShader(shader);
+                int[] compiled = new int[1];
+                GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
+                if (compiled[0] == 0) {
+                    Log.e(TAG, "Could not compile shader " + shaderType + ":");
+                    Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
+                    GLES20.glDeleteShader(shader);
+                    shader = 0;
+                }
+            }
+            return shader;
+        }
+
+        private int createProgram(String vertexSource, String fragmentSource) {
+            int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
+            if (vertexShader == 0) {
+                return 0;
+            }
+
+            int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
+            if (pixelShader == 0) {
+                return 0;
+            }
+
+            int program = GLES20.glCreateProgram();
+            if (program != 0) {
+                GLES20.glAttachShader(program, vertexShader);
+                checkGlError("glAttachShader");
+                GLES20.glAttachShader(program, pixelShader);
+                checkGlError("glAttachShader");
+                GLES20.glLinkProgram(program);
+                int[] linkStatus = new int[1];
+                GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
+                if (linkStatus[0] != GLES20.GL_TRUE) {
+                    Log.e(TAG, "Could not link program: ");
+                    Log.e(TAG, GLES20.glGetProgramInfoLog(program));
+                    GLES20.glDeleteProgram(program);
+                    program = 0;
+                }
+            }
+            return program;
+        }
+
+        private void checkGlError(String op) {
+            int error;
+            while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
+                Log.e(TAG, op + ": glError " + error);
+                throw new RuntimeException(op + ": glError " + error);
+            }
+        }
+
+        private final float[] mTriangleVerticesData = { 0.0f, 0.5f, -0.5f, -0.5f,
+                0.5f, -0.5f };
+
+        private FloatBuffer mTriangleVertices;
+
+        private final String mVertexShader = "attribute vec4 vPosition;\n"
+            + "void main() {\n"
+            + "  gl_Position = vPosition;\n"
+            + "}\n";
+
+        private final String mFragmentShader = "precision mediump float;\n"
+            + "void main() {\n"
+            + "  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
+            + "}\n";
+
+        private int mProgram;
+        private int mvPositionHandle;
+
+    }
+}
+
diff --git a/opengl/tests/gl2_jni/Android.mk b/opengl/tests/gl2_jni/Android.mk
index 81247df..384966c 100644
--- a/opengl/tests/gl2_jni/Android.mk
+++ b/opengl/tests/gl2_jni/Android.mk
@@ -11,7 +11,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := user
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
diff --git a/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIView.java b/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIView.java
index 2dae090..72b1dfb 100644
--- a/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIView.java
+++ b/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIView.java
@@ -56,19 +56,22 @@
  */
 class GL2JNIView extends GLSurfaceView {
     private static String TAG = "GL2JNIView";
-    GL2JNIView(Context context) {
+
+    public GL2JNIView(Context context) {
         super(context);
-        init();
+        init(false, 0, 0);
     }
 
-    public GL2JNIView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        init();
+    public GL2JNIView(Context context, boolean translucent, int depth, int stencil) {
+        super(context);
+        init(translucent, depth, stencil);
     }
 
-    private void init() {
+    private void init(boolean translucent, int depth, int stencil) {
         setEGLContextFactory(new ContextFactory());
-        setEGLConfigChooser(new ConfigChooser());
+        setEGLConfigChooser( translucent ?
+              new ConfigChooser(8,8,8,8, depth, stencil) :
+              new ConfigChooser(5,6,5,0, depth, stencil));
         setRenderer(new Renderer());
     }
 
@@ -105,6 +108,16 @@
             EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
             EGL10.EGL_NONE
         };
+
+        public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) {
+            mRedSize = r;
+            mGreenSize = g;
+            mBlueSize = b;
+            mAlphaSize = a;
+            mDepthSize = depth;
+            mStencilSize = stencil;
+        }
+
         public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
 
             int[] num_config = new int[1];
@@ -112,14 +125,158 @@
 
             int numConfigs = num_config[0];
 
-            Log.w(TAG, String.format("Found %d configurations", numConfigs));
             if (numConfigs <= 0) {
                 throw new IllegalArgumentException("No configs match configSpec");
             }
             EGLConfig[] configs = new EGLConfig[numConfigs];
             egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config);
-            return configs[0];
+            // printConfigs(egl, display, configs);
+            return chooseConfig(egl, display, configs);
         }
+
+        public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
+                EGLConfig[] configs) {
+            EGLConfig closestConfig = null;
+            int closestDistance = 1000;
+            for(EGLConfig config : configs) {
+                int d = findConfigAttrib(egl, display, config,
+                        EGL10.EGL_DEPTH_SIZE, 0);
+                int s = findConfigAttrib(egl, display, config,
+                        EGL10.EGL_STENCIL_SIZE, 0);
+                if (d >= mDepthSize && s>= mStencilSize) {
+                    int r = findConfigAttrib(egl, display, config,
+                            EGL10.EGL_RED_SIZE, 0);
+                    int g = findConfigAttrib(egl, display, config,
+                             EGL10.EGL_GREEN_SIZE, 0);
+                    int b = findConfigAttrib(egl, display, config,
+                              EGL10.EGL_BLUE_SIZE, 0);
+                    int a = findConfigAttrib(egl, display, config,
+                            EGL10.EGL_ALPHA_SIZE, 0);
+                    int distance = Math.abs(r - mRedSize)
+                                + Math.abs(g - mGreenSize)
+                                + Math.abs(b - mBlueSize)
+                                + Math.abs(a - mAlphaSize);
+                    if (distance < closestDistance) {
+                        closestDistance = distance;
+                        closestConfig = config;
+                    }
+                }
+            }
+            return closestConfig;
+        }
+
+        private int findConfigAttrib(EGL10 egl, EGLDisplay display,
+                EGLConfig config, int attribute, int defaultValue) {
+
+            if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
+                return mValue[0];
+            }
+            return defaultValue;
+        }
+
+        private void printConfigs(EGL10 egl, EGLDisplay display,
+            EGLConfig[] configs) {
+            int numConfigs = configs.length;
+            Log.w(TAG, String.format("%d configurations", numConfigs));
+            for (int i = 0; i < numConfigs; i++) {
+                Log.w(TAG, String.format("Configuration %d:\n", i));
+                printConfig(egl, display, configs[i]);
+            }
+        }
+
+        private void printConfig(EGL10 egl, EGLDisplay display,
+                EGLConfig config) {
+            int[] attributes = {
+                    EGL10.EGL_BUFFER_SIZE,
+                    EGL10.EGL_ALPHA_SIZE,
+                    EGL10.EGL_BLUE_SIZE,
+                    EGL10.EGL_GREEN_SIZE,
+                    EGL10.EGL_RED_SIZE,
+                    EGL10.EGL_DEPTH_SIZE,
+                    EGL10.EGL_STENCIL_SIZE,
+                    EGL10.EGL_CONFIG_CAVEAT,
+                    EGL10.EGL_CONFIG_ID,
+                    EGL10.EGL_LEVEL,
+                    EGL10.EGL_MAX_PBUFFER_HEIGHT,
+                    EGL10.EGL_MAX_PBUFFER_PIXELS,
+                    EGL10.EGL_MAX_PBUFFER_WIDTH,
+                    EGL10.EGL_NATIVE_RENDERABLE,
+                    EGL10.EGL_NATIVE_VISUAL_ID,
+                    EGL10.EGL_NATIVE_VISUAL_TYPE,
+                    0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
+                    EGL10.EGL_SAMPLES,
+                    EGL10.EGL_SAMPLE_BUFFERS,
+                    EGL10.EGL_SURFACE_TYPE,
+                    EGL10.EGL_TRANSPARENT_TYPE,
+                    EGL10.EGL_TRANSPARENT_RED_VALUE,
+                    EGL10.EGL_TRANSPARENT_GREEN_VALUE,
+                    EGL10.EGL_TRANSPARENT_BLUE_VALUE,
+                    0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
+                    0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
+                    0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
+                    0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
+                    EGL10.EGL_LUMINANCE_SIZE,
+                    EGL10.EGL_ALPHA_MASK_SIZE,
+                    EGL10.EGL_COLOR_BUFFER_TYPE,
+                    EGL10.EGL_RENDERABLE_TYPE,
+                    0x3042 // EGL10.EGL_CONFORMANT
+            };
+            String[] names = {
+                    "EGL_BUFFER_SIZE",
+                    "EGL_ALPHA_SIZE",
+                    "EGL_BLUE_SIZE",
+                    "EGL_GREEN_SIZE",
+                    "EGL_RED_SIZE",
+                    "EGL_DEPTH_SIZE",
+                    "EGL_STENCIL_SIZE",
+                    "EGL_CONFIG_CAVEAT",
+                    "EGL_CONFIG_ID",
+                    "EGL_LEVEL",
+                    "EGL_MAX_PBUFFER_HEIGHT",
+                    "EGL_MAX_PBUFFER_PIXELS",
+                    "EGL_MAX_PBUFFER_WIDTH",
+                    "EGL_NATIVE_RENDERABLE",
+                    "EGL_NATIVE_VISUAL_ID",
+                    "EGL_NATIVE_VISUAL_TYPE",
+                    "EGL_PRESERVED_RESOURCES",
+                    "EGL_SAMPLES",
+                    "EGL_SAMPLE_BUFFERS",
+                    "EGL_SURFACE_TYPE",
+                    "EGL_TRANSPARENT_TYPE",
+                    "EGL_TRANSPARENT_RED_VALUE",
+                    "EGL_TRANSPARENT_GREEN_VALUE",
+                    "EGL_TRANSPARENT_BLUE_VALUE",
+                    "EGL_BIND_TO_TEXTURE_RGB",
+                    "EGL_BIND_TO_TEXTURE_RGBA",
+                    "EGL_MIN_SWAP_INTERVAL",
+                    "EGL_MAX_SWAP_INTERVAL",
+                    "EGL_LUMINANCE_SIZE",
+                    "EGL_ALPHA_MASK_SIZE",
+                    "EGL_COLOR_BUFFER_TYPE",
+                    "EGL_RENDERABLE_TYPE",
+                    "EGL_CONFORMANT"
+            };
+            int[] value = new int[1];
+            for (int i = 0; i < attributes.length; i++) {
+                int attribute = attributes[i];
+                String name = names[i];
+                if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {
+                    Log.w(TAG, String.format("  %s: %d\n", name, value[0]));
+                } else {
+                    // Log.w(TAG, String.format("  %s: failed\n", name));
+                    while (egl.eglGetError() != EGL10.EGL_SUCCESS);
+                }
+            }
+        }
+
+        // Subclasses can adjust these values:
+        protected int mRedSize;
+        protected int mGreenSize;
+        protected int mBlueSize;
+        protected int mAlphaSize;
+        protected int mDepthSize;
+        protected int mStencilSize;
+        private int[] mValue = new int[1];
     }
 
     private static class Renderer implements GLSurfaceView.Renderer {
diff --git a/opengl/tests/gl_basic/gl_basic.cpp b/opengl/tests/gl_basic/gl_basic.cpp
index 7dc2378..feb964a 100644
--- a/opengl/tests/gl_basic/gl_basic.cpp
+++ b/opengl/tests/gl_basic/gl_basic.cpp
@@ -1,32 +1,39 @@
 // Simple OpenGL ES 1.x application showing how to initialize and draw something.
 
-#include <EGL/egl.h>

+#include <EGL/egl.h>
+
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
 #include <ui/FramebufferNativeWindow.h>
 #include <ui/EGLUtils.h>
 
-#include <stdio.h>

+#include <stdio.h>
+
 #include <stdlib.h>
 #include <math.h>
 
 using namespace android;
-

-EGLDisplay eglDisplay;

-EGLSurface eglSurface;

-EGLContext eglContext;

-GLuint texture;

-

+
+EGLDisplay eglDisplay;
+EGLSurface eglSurface;
+EGLContext eglContext;
+GLuint texture;
+
 #define FIXED_ONE 0x10000
-#define ITERATIONS 50

-

-int init_gl_surface(void);

-void free_gl_surface(void);

-void init_scene(void);

-void render();

+#define ITERATIONS 50
+
+int init_gl_surface(void);
+void free_gl_surface(void);
+void init_scene(void);
+void render();
 void create_texture(void);
-int readTimer(void);

+int readTimer(void);
+
+static void printGLString(const char *name, GLenum s) {
+    const char *v = (const char *) glGetString(s);
+    fprintf(stderr, "GL %s = %s\n", name, v);
+}
 
 static void gluLookAt(float eyeX, float eyeY, float eyeZ,
         float centerX, float centerY, float centerZ, float upX, float upY,
@@ -87,7 +94,6 @@
     glTranslatef(-eyeX, -eyeY, -eyeZ);
 }
 
-
 void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
 
 #define X(VAL) {VAL, #VAL}
@@ -183,125 +189,129 @@
     free(configs);
     return true;
 }
-

-int main(int argc, char **argv)

-{

+
+int main(int argc, char **argv)
+{
     int q;
-    int start, end;

-
+    int start, end;
     printf("Initializing EGL...\n");
-

-    if(!init_gl_surface())

-    {

-        printf("GL initialisation failed - exiting\n");

-        return 0;

-    }

-

-    init_scene();

-

-    create_texture();

-

+    if(!init_gl_surface())
+    {
+        printf("GL initialisation failed - exiting\n");
+        return 0;
+    }
+    init_scene();
+    create_texture();
     printf("Running...\n");
-
     while(true) {
         render();
-    }

-

-    free_gl_surface();

-

-    return 0;

-}

-

-int init_gl_surface(void)

-{

-    EGLint numConfigs = 1;

-    EGLConfig myConfig = {0};

-    EGLint attrib[] =

-    {

-            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,

-            EGL_NONE

-    };

-

-    if ( (eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY )

-    {

-        printf("eglGetDisplay failed\n");

-        return 0;

     }
-

-    if ( eglInitialize(eglDisplay, NULL, NULL) != EGL_TRUE )

-    {

-        printf("eglInitialize failed\n");

-        return 0;

+    free_gl_surface();
+    return 0;
+}
+
+int init_gl_surface(void)
+{
+    EGLint numConfigs = 1;
+    EGLConfig myConfig = {0};
+    EGLint attrib[] =
+    {
+            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+            EGL_NONE
+    };
+
+    if ( (eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY )
+    {
+        printf("eglGetDisplay failed\n");
+        return 0;
+    }
+    
+    if ( eglInitialize(eglDisplay, NULL, NULL) != EGL_TRUE )
+    {
+        printf("eglInitialize failed\n");
+        return 0;
     }
 
     if (! printEGLConfigurations(eglDisplay)) {
         printf("printEGLConfigurations failed.\n");
         return 0;
-    }

-    EGLNativeWindowType window = android_createDisplaySurface();

-    EGLUtils::selectConfigForNativeWindow(eglDisplay, attrib, window, &myConfig);

-

+    }
+
+    EGLNativeWindowType window = android_createDisplaySurface();
+    EGLUtils::selectConfigForNativeWindow(eglDisplay, attrib, window, &myConfig);
+
     if ( (eglSurface = eglCreateWindowSurface(eglDisplay, myConfig,
-            window, 0)) == EGL_NO_SURFACE )

-    {

-        printf("eglCreateWindowSurface failed\n");

-        return 0;

-    }

-

-    if ( (eglContext = eglCreateContext(eglDisplay, myConfig, 0, 0)) == EGL_NO_CONTEXT )

-    {

-        printf("eglCreateContext failed\n");

-        return 0;

-    }

-

-    if ( eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext) != EGL_TRUE )

-    {

-        printf("eglMakeCurrent failed\n");

-        return 0;

-    }

-

-    return 1;

-}

-

-void free_gl_surface(void)

-{

-    if (eglDisplay != EGL_NO_DISPLAY)

-    {

-        eglMakeCurrent( EGL_NO_DISPLAY, EGL_NO_SURFACE,

-                EGL_NO_SURFACE, EGL_NO_CONTEXT );

-        eglDestroyContext( eglDisplay, eglContext );

-        eglDestroySurface( eglDisplay, eglSurface );

-        eglTerminate( eglDisplay );

-        eglDisplay = EGL_NO_DISPLAY;

-    }

-}

-

-void init_scene(void)

-{

+            window, 0)) == EGL_NO_SURFACE )
+    {
+        printf("eglCreateWindowSurface failed\n");
+        return 0;
+    }
+
+    if ( (eglContext = eglCreateContext(eglDisplay, myConfig, 0, 0)) == EGL_NO_CONTEXT )
+    {
+        printf("eglCreateContext failed\n");
+        return 0;
+    }
+
+    if ( eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext) != EGL_TRUE )
+    {
+        printf("eglMakeCurrent failed\n");
+        return 0;
+    }
+    
+    int w, h;
+
+    eglQuerySurface(eglDisplay, eglSurface, EGL_WIDTH, &w);
+    checkEglError("eglQuerySurface");
+    eglQuerySurface(eglDisplay, eglSurface, EGL_HEIGHT, &h);
+    checkEglError("eglQuerySurface");
+    GLint dim = w < h ? w : h;
+    
+    fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
+
+    printGLString("Version", GL_VERSION);
+    printGLString("Vendor", GL_VENDOR);
+    printGLString("Renderer", GL_RENDERER);
+    printGLString("Extensions", GL_EXTENSIONS);
+
+    return 1;
+}
+
+void free_gl_surface(void)
+{
+    if (eglDisplay != EGL_NO_DISPLAY)
+    {
+        eglMakeCurrent( EGL_NO_DISPLAY, EGL_NO_SURFACE,
+                EGL_NO_SURFACE, EGL_NO_CONTEXT );
+        eglDestroyContext( eglDisplay, eglContext );
+        eglDestroySurface( eglDisplay, eglSurface );
+        eglTerminate( eglDisplay );
+        eglDisplay = EGL_NO_DISPLAY;
+    }
+}
+
+void init_scene(void)
+{
     glDisable(GL_DITHER);
     glEnable(GL_CULL_FACE);
-
     float ratio = 320.0f / 480.0f;
     glViewport(0, 0, 320, 480);
-
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
     glFrustumf(-ratio, ratio, -1, 1, 1, 10);
-
-    glMatrixMode(GL_MODELVIEW);

+    glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     gluLookAt(
             0, 0, 3,  // eye
             0, 0, 0,  // center
             0, 1, 0); // up
-

-    glEnable(GL_TEXTURE_2D);

-    glEnableClientState(GL_VERTEX_ARRAY);

+    glEnable(GL_TEXTURE_2D);
+    glEnableClientState(GL_VERTEX_ARRAY);
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-}

-

-void create_texture(void)

-{

+}
+
+void create_texture(void)
+{
     const unsigned int on = 0xff0000ff;
     const unsigned int off = 0xffffffff;
     const unsigned int pixels[] =
@@ -314,44 +324,42 @@
             off, on, off, on, off, on, off, on,
             on, off, on, off, on, off, on, off,
             off, on, off, on, off, on, off, on,
-    };

-    glGenTextures(1, &texture);

-    glBindTexture(GL_TEXTURE_2D, texture);

-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

-    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

-}

-

-void render()

-{

+    };
+
+    glGenTextures(1, &texture);
+    glBindTexture(GL_TEXTURE_2D, texture);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+}
+
+void render()
+{
     int i, j;
-    int quads = 1;

-

-    const GLfloat vertices[] = {

-            -1,  -1,  0,

-             1,  -1,  0,

-             1,   1,  0,

-            -1,   1,  0

-    };

-

-    const GLfixed texCoords[] = {

-            0,            0,

-            FIXED_ONE,    0,

-            FIXED_ONE,    FIXED_ONE,

-            0,            FIXED_ONE

-    };

-

+    int quads = 1;
+
+    const GLfloat vertices[] = {
+            -1,  -1,  0,
+             1,  -1,  0,
+             1,   1,  0,
+            -1,   1,  0
+    };
+
+    const GLfixed texCoords[] = {
+            0,            0,
+            FIXED_ONE,    0,
+            FIXED_ONE,    FIXED_ONE,
+            0,            FIXED_ONE
+    };
+
     const GLushort indices[] = { 0, 1, 2,  0, 2, 3 };
-

-    glVertexPointer(3, GL_FLOAT, 0, vertices);

+
+    glVertexPointer(3, GL_FLOAT, 0, vertices);
     glTexCoordPointer(2, GL_FIXED, 0, texCoords);
-
     glClearColor(1.0, 1.0, 1.0, 1.0);
-
     int nelem = sizeof(indices)/sizeof(indices[0]);
     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
     glDrawElements(GL_TRIANGLES, nelem, GL_UNSIGNED_SHORT, indices);
-    eglSwapBuffers(eglDisplay, eglSurface);

-}

-
+    eglSwapBuffers(eglDisplay, eglSurface);
+}
diff --git a/opengl/tests/gl_jni/Android.mk b/opengl/tests/gl_jni/Android.mk
index 4029fa1..f1bd31d 100644
--- a/opengl/tests/gl_jni/Android.mk
+++ b/opengl/tests/gl_jni/Android.mk
@@ -11,7 +11,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := user
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
diff --git a/opengl/tests/gldual/Android.mk b/opengl/tests/gldual/Android.mk
new file mode 100644
index 0000000..995a5d7
--- /dev/null
+++ b/opengl/tests/gldual/Android.mk
@@ -0,0 +1,51 @@
+#########################################################################
+# OpenGL ES JNI sample
+# This makefile builds both an activity and a shared library.
+#########################################################################
+ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean
+
+TOP_LOCAL_PATH:= $(call my-dir)
+
+# Build activity
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := GLDual
+
+LOCAL_JNI_SHARED_LIBRARIES := libgldualjni
+
+include $(BUILD_PACKAGE)
+
+#########################################################################
+# Build JNI Shared Library
+#########################################################################
+
+LOCAL_PATH:= $(LOCAL_PATH)/jni
+
+include $(CLEAR_VARS)
+
+# Optional tag would mean it doesn't get installed by default
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS := -Werror
+
+LOCAL_SRC_FILES:= \
+  gl_code.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libutils \
+	libEGL \
+	libGLESv2
+
+LOCAL_MODULE := libgldualjni
+
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif # TARGET_SIMULATOR
diff --git a/opengl/tests/gldual/AndroidManifest.xml b/opengl/tests/gldual/AndroidManifest.xml
new file mode 100644
index 0000000..06f4c4d
--- /dev/null
+++ b/opengl/tests/gldual/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.gldual">
+    <application
+            android:label="@string/gldual_activity">
+        <activity android:name="GLDualActivity"
+                android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+            	android:launchMode="singleTask"
+            	android:configChanges="orientation|keyboardHidden">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/opengl/tests/gldual/jni/gl_code.cpp b/opengl/tests/gldual/jni/gl_code.cpp
new file mode 100644
index 0000000..f1f0a1f
--- /dev/null
+++ b/opengl/tests/gldual/jni/gl_code.cpp
@@ -0,0 +1,165 @@
+// OpenGL ES 2.0 code
+
+#include <nativehelper/jni.h>
+#define LOG_TAG "GL2JNI gl_code.cpp"
+#include <utils/Log.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+static void printGLString(const char *name, GLenum s) {
+    const char *v = (const char *) glGetString(s);
+    LOGI("GL %s = %s\n", name, v);
+}
+
+static void checkGlError(const char* op) {
+    for (GLint error = glGetError(); error; error
+            = glGetError()) {
+        LOGI("after %s() glError (0x%x)\n", op, error);
+    }
+}
+
+static const char gVertexShader[] = "attribute vec4 vPosition;\n"
+    "void main() {\n"
+    "  gl_Position = vPosition;\n"
+    "}\n";
+
+static const char gFragmentShader[] = "precision mediump float;\n"
+    "void main() {\n"
+    "  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
+    "}\n";
+
+GLuint loadShader(GLenum shaderType, const char* pSource) {
+    GLuint shader = glCreateShader(shaderType);
+    if (shader) {
+        glShaderSource(shader, 1, &pSource, NULL);
+        glCompileShader(shader);
+        GLint compiled = 0;
+        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+        if (!compiled) {
+            GLint infoLen = 0;
+            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+            if (infoLen) {
+                char* buf = (char*) malloc(infoLen);
+                if (buf) {
+                    glGetShaderInfoLog(shader, infoLen, NULL, buf);
+                    LOGE("Could not compile shader %d:\n%s\n",
+                            shaderType, buf);
+                    free(buf);
+                }
+                glDeleteShader(shader);
+                shader = 0;
+            }
+        }
+    }
+    return shader;
+}
+
+GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
+    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+    if (!vertexShader) {
+        return 0;
+    }
+
+    GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+    if (!pixelShader) {
+        return 0;
+    }
+
+    GLuint program = glCreateProgram();
+    if (program) {
+        glAttachShader(program, vertexShader);
+        checkGlError("glAttachShader");
+        glAttachShader(program, pixelShader);
+        checkGlError("glAttachShader");
+        glLinkProgram(program);
+        GLint linkStatus = GL_FALSE;
+        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+        if (linkStatus != GL_TRUE) {
+            GLint bufLength = 0;
+            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+            if (bufLength) {
+                char* buf = (char*) malloc(bufLength);
+                if (buf) {
+                    glGetProgramInfoLog(program, bufLength, NULL, buf);
+                    LOGE("Could not link program:\n%s\n", buf);
+                    free(buf);
+                }
+            }
+            glDeleteProgram(program);
+            program = 0;
+        }
+    }
+    return program;
+}
+
+GLuint gProgram;
+GLuint gvPositionHandle;
+
+bool setupGraphics(int w, int h) {
+    printGLString("Version", GL_VERSION);
+    printGLString("Vendor", GL_VENDOR);
+    printGLString("Renderer", GL_RENDERER);
+    printGLString("Extensions", GL_EXTENSIONS);
+
+    LOGI("setupGraphics(%d, %d)", w, h);
+    gProgram = createProgram(gVertexShader, gFragmentShader);
+    if (!gProgram) {
+        LOGE("Could not create program.");
+        return false;
+    }
+    gvPositionHandle = glGetAttribLocation(gProgram, "vPosition");
+    checkGlError("glGetAttribLocation");
+    LOGI("glGetAttribLocation(\"vPosition\") = %d\n",
+            gvPositionHandle);
+
+    glViewport(0, 0, w, h);
+    checkGlError("glViewport");
+    return true;
+}
+
+const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f,
+        0.5f, -0.5f };
+
+void renderFrame() {
+    static float grey;
+    grey += 0.01f;
+    if (grey > 1.0f) {
+        grey = 0.0f;
+    }
+    glClearColor(grey, grey, grey, 1.0f);
+    checkGlError("glClearColor");
+    glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+    checkGlError("glClear");
+
+    glUseProgram(gProgram);
+    checkGlError("glUseProgram");
+
+    glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
+    checkGlError("glVertexAttribPointer");
+    glEnableVertexAttribArray(gvPositionHandle);
+    checkGlError("glEnableVertexAttribArray");
+    glDrawArrays(GL_TRIANGLES, 0, 3);
+    checkGlError("glDrawArrays");
+}
+
+extern "C" {
+    JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_init(JNIEnv * env, jobject obj, jint width, jint height);
+    JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_step(JNIEnv * env, jobject obj);
+};
+
+JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_init(JNIEnv * env, jobject obj, jint width, jint height)

+{
+    setupGraphics(width, height);
+}
+
+JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_step(JNIEnv * env, jobject obj)
+{
+    renderFrame();
+}
+
diff --git a/opengl/tests/gldual/res/layout/gldual_activity.xml b/opengl/tests/gldual/res/layout/gldual_activity.xml
new file mode 100644
index 0000000..d75acbc
--- /dev/null
+++ b/opengl/tests/gldual/res/layout/gldual_activity.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text"
+
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+  <android.opengl.GLSurfaceView android:id="@+id/gl1"
+	android:layout_width="match_parent"
+	    android:layout_height="0dip"
+	    android:layout_weight="1" />
+  <com.android.gldual.GLDualGL2View android:id="@+id/gl2"
+	android:layout_width="match_parent"
+            android:layout_height="0dip"
+            android:layout_weight="1" />
+</LinearLayout>
diff --git a/opengl/tests/gldual/res/values/strings.xml b/opengl/tests/gldual/res/values/strings.xml
new file mode 100644
index 0000000..4267dff
--- /dev/null
+++ b/opengl/tests/gldual/res/values/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<!-- This file contains resource definitions for displayed strings, allowing
+     them to be changed based on the locale and options. -->
+
+<resources>
+    <!-- Simple strings. -->
+    <string name="gldual_activity">GLDual</string>
+
+</resources>
+
diff --git a/opengl/tests/gldual/src/com/android/gldual/GLDualActivity.java b/opengl/tests/gldual/src/com/android/gldual/GLDualActivity.java
new file mode 100644
index 0000000..9d88f64
--- /dev/null
+++ b/opengl/tests/gldual/src/com/android/gldual/GLDualActivity.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gldual;
+
+import android.app.Activity;
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.LinearLayout;
+
+
+public class GLDualActivity extends Activity {
+
+    GLSurfaceView mGLView;
+    GLDualGL2View mGL2View;
+
+    @Override protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        View root = getLayoutInflater().inflate(R.layout.gldual_activity, null);
+        mGLView = (GLSurfaceView) root.findViewById(R.id.gl1);
+        mGLView.setEGLConfigChooser(5,6,5,0,0,0);
+        mGLView.setRenderer(new TriangleRenderer());
+        mGL2View = (GLDualGL2View) root.findViewById(R.id.gl2);
+        setContentView(root);
+    }
+
+    @Override protected void onPause() {
+        super.onPause();
+        mGLView.onPause();
+        mGL2View.onPause();
+    }
+
+    @Override protected void onResume() {
+        super.onResume();
+        mGLView.onResume();
+        mGL2View.onResume();
+    }
+}
diff --git a/opengl/tests/gldual/src/com/android/gldual/GLDualGL2View.java b/opengl/tests/gldual/src/com/android/gldual/GLDualGL2View.java
new file mode 100644
index 0000000..8f5e347
--- /dev/null
+++ b/opengl/tests/gldual/src/com/android/gldual/GLDualGL2View.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gldual;
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+
+/**
+ * An implementation of SurfaceView that uses the dedicated surface for
+ * displaying an OpenGL animation.  This allows the animation to run in a
+ * separate thread, without requiring that it be driven by the update mechanism
+ * of the view hierarchy.
+ *
+ * The application-specific rendering code is delegated to a GLView.Renderer
+ * instance.
+ */
+class GLDualGL2View extends GLSurfaceView {
+    private static String TAG = "GLDualGL2View";
+
+    public GLDualGL2View(Context context) {
+        super(context);
+        init(false, 0, 0);
+    }
+
+    public GLDualGL2View(Context context, AttributeSet set) {
+        super(context, set);
+        init(false, 0, 0);
+    }
+
+    public GLDualGL2View(Context context, boolean translucent, int depth, int stencil) {
+        super(context);
+        init(translucent, depth, stencil);
+    }
+
+    private void init(boolean translucent, int depth, int stencil) {
+        setEGLContextFactory(new ContextFactory());
+        setEGLConfigChooser( translucent ?
+              new ConfigChooser(8,8,8,8, depth, stencil) :
+              new ConfigChooser(5,6,5,0, depth, stencil));
+        setRenderer(new Renderer());
+    }
+
+    private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
+        private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+        public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
+            Log.w(TAG, "creating OpenGL ES 2.0 context");
+            checkEglError("Before eglCreateContext", egl);
+            int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+            EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
+            checkEglError("After eglCreateContext", egl);
+            return context;
+        }
+
+        public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
+            egl.eglDestroyContext(display, context);
+        }
+    }
+
+    private static void checkEglError(String prompt, EGL10 egl) {
+        int error;
+        while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) {
+            Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));
+        }
+    }
+
+    private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser {
+        private static int EGL_OPENGL_ES2_BIT = 4;
+        private static int[] s_configAttribs2 =
+        {
+            EGL10.EGL_RED_SIZE, 4,
+            EGL10.EGL_GREEN_SIZE, 4,
+            EGL10.EGL_BLUE_SIZE, 4,
+            EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+            EGL10.EGL_NONE
+        };
+
+        public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) {
+            mRedSize = r;
+            mGreenSize = g;
+            mBlueSize = b;
+            mAlphaSize = a;
+            mDepthSize = depth;
+            mStencilSize = stencil;
+        }
+
+        public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
+
+            int[] num_config = new int[1];
+            egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config);
+
+            int numConfigs = num_config[0];
+
+            if (numConfigs <= 0) {
+                throw new IllegalArgumentException("No configs match configSpec");
+            }
+            EGLConfig[] configs = new EGLConfig[numConfigs];
+            egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config);
+            // printConfigs(egl, display, configs);
+            return chooseConfig(egl, display, configs);
+        }
+
+        public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
+                EGLConfig[] configs) {
+            EGLConfig closestConfig = null;
+            int closestDistance = 1000;
+            for(EGLConfig config : configs) {
+                int d = findConfigAttrib(egl, display, config,
+                        EGL10.EGL_DEPTH_SIZE, 0);
+                int s = findConfigAttrib(egl, display, config,
+                        EGL10.EGL_STENCIL_SIZE, 0);
+                if (d >= mDepthSize && s>= mStencilSize) {
+                    int r = findConfigAttrib(egl, display, config,
+                            EGL10.EGL_RED_SIZE, 0);
+                    int g = findConfigAttrib(egl, display, config,
+                             EGL10.EGL_GREEN_SIZE, 0);
+                    int b = findConfigAttrib(egl, display, config,
+                              EGL10.EGL_BLUE_SIZE, 0);
+                    int a = findConfigAttrib(egl, display, config,
+                            EGL10.EGL_ALPHA_SIZE, 0);
+                    int distance = Math.abs(r - mRedSize)
+                                + Math.abs(g - mGreenSize)
+                                + Math.abs(b - mBlueSize)
+                                + Math.abs(a - mAlphaSize);
+                    if (distance < closestDistance) {
+                        closestDistance = distance;
+                        closestConfig = config;
+                    }
+                }
+            }
+            return closestConfig;
+        }
+
+        private int findConfigAttrib(EGL10 egl, EGLDisplay display,
+                EGLConfig config, int attribute, int defaultValue) {
+
+            if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
+                return mValue[0];
+            }
+            return defaultValue;
+        }
+
+        private void printConfigs(EGL10 egl, EGLDisplay display,
+            EGLConfig[] configs) {
+            int numConfigs = configs.length;
+            Log.w(TAG, String.format("%d configurations", numConfigs));
+            for (int i = 0; i < numConfigs; i++) {
+                Log.w(TAG, String.format("Configuration %d:\n", i));
+                printConfig(egl, display, configs[i]);
+            }
+        }
+
+        private void printConfig(EGL10 egl, EGLDisplay display,
+                EGLConfig config) {
+            int[] attributes = {
+                    EGL10.EGL_BUFFER_SIZE,
+                    EGL10.EGL_ALPHA_SIZE,
+                    EGL10.EGL_BLUE_SIZE,
+                    EGL10.EGL_GREEN_SIZE,
+                    EGL10.EGL_RED_SIZE,
+                    EGL10.EGL_DEPTH_SIZE,
+                    EGL10.EGL_STENCIL_SIZE,
+                    EGL10.EGL_CONFIG_CAVEAT,
+                    EGL10.EGL_CONFIG_ID,
+                    EGL10.EGL_LEVEL,
+                    EGL10.EGL_MAX_PBUFFER_HEIGHT,
+                    EGL10.EGL_MAX_PBUFFER_PIXELS,
+                    EGL10.EGL_MAX_PBUFFER_WIDTH,
+                    EGL10.EGL_NATIVE_RENDERABLE,
+                    EGL10.EGL_NATIVE_VISUAL_ID,
+                    EGL10.EGL_NATIVE_VISUAL_TYPE,
+                    0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
+                    EGL10.EGL_SAMPLES,
+                    EGL10.EGL_SAMPLE_BUFFERS,
+                    EGL10.EGL_SURFACE_TYPE,
+                    EGL10.EGL_TRANSPARENT_TYPE,
+                    EGL10.EGL_TRANSPARENT_RED_VALUE,
+                    EGL10.EGL_TRANSPARENT_GREEN_VALUE,
+                    EGL10.EGL_TRANSPARENT_BLUE_VALUE,
+                    0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
+                    0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
+                    0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
+                    0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
+                    EGL10.EGL_LUMINANCE_SIZE,
+                    EGL10.EGL_ALPHA_MASK_SIZE,
+                    EGL10.EGL_COLOR_BUFFER_TYPE,
+                    EGL10.EGL_RENDERABLE_TYPE,
+                    0x3042 // EGL10.EGL_CONFORMANT
+            };
+            String[] names = {
+                    "EGL_BUFFER_SIZE",
+                    "EGL_ALPHA_SIZE",
+                    "EGL_BLUE_SIZE",
+                    "EGL_GREEN_SIZE",
+                    "EGL_RED_SIZE",
+                    "EGL_DEPTH_SIZE",
+                    "EGL_STENCIL_SIZE",
+                    "EGL_CONFIG_CAVEAT",
+                    "EGL_CONFIG_ID",
+                    "EGL_LEVEL",
+                    "EGL_MAX_PBUFFER_HEIGHT",
+                    "EGL_MAX_PBUFFER_PIXELS",
+                    "EGL_MAX_PBUFFER_WIDTH",
+                    "EGL_NATIVE_RENDERABLE",
+                    "EGL_NATIVE_VISUAL_ID",
+                    "EGL_NATIVE_VISUAL_TYPE",
+                    "EGL_PRESERVED_RESOURCES",
+                    "EGL_SAMPLES",
+                    "EGL_SAMPLE_BUFFERS",
+                    "EGL_SURFACE_TYPE",
+                    "EGL_TRANSPARENT_TYPE",
+                    "EGL_TRANSPARENT_RED_VALUE",
+                    "EGL_TRANSPARENT_GREEN_VALUE",
+                    "EGL_TRANSPARENT_BLUE_VALUE",
+                    "EGL_BIND_TO_TEXTURE_RGB",
+                    "EGL_BIND_TO_TEXTURE_RGBA",
+                    "EGL_MIN_SWAP_INTERVAL",
+                    "EGL_MAX_SWAP_INTERVAL",
+                    "EGL_LUMINANCE_SIZE",
+                    "EGL_ALPHA_MASK_SIZE",
+                    "EGL_COLOR_BUFFER_TYPE",
+                    "EGL_RENDERABLE_TYPE",
+                    "EGL_CONFORMANT"
+            };
+            int[] value = new int[1];
+            for (int i = 0; i < attributes.length; i++) {
+                int attribute = attributes[i];
+                String name = names[i];
+                if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {
+                    Log.w(TAG, String.format("  %s: %d\n", name, value[0]));
+                } else {
+                    // Log.w(TAG, String.format("  %s: failed\n", name));
+                    while (egl.eglGetError() != EGL10.EGL_SUCCESS);
+                }
+            }
+        }
+
+        // Subclasses can adjust these values:
+        protected int mRedSize;
+        protected int mGreenSize;
+        protected int mBlueSize;
+        protected int mAlphaSize;
+        protected int mDepthSize;
+        protected int mStencilSize;
+        private int[] mValue = new int[1];
+    }
+
+    private static class Renderer implements GLSurfaceView.Renderer {
+        public void onDrawFrame(GL10 gl) {
+            GLDualLib.step();
+        }
+
+        public void onSurfaceChanged(GL10 gl, int width, int height) {
+            GLDualLib.init(width, height);
+        }
+
+        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+            // Do nothing.
+        }
+    }
+}
+
diff --git a/opengl/tests/gldual/src/com/android/gldual/GLDualLib.java b/opengl/tests/gldual/src/com/android/gldual/GLDualLib.java
new file mode 100644
index 0000000..d8f765e
--- /dev/null
+++ b/opengl/tests/gldual/src/com/android/gldual/GLDualLib.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gldual;
+
+// Wrapper for native library
+
+public class GLDualLib {
+
+     static {
+         System.loadLibrary("gldualjni");
+     }
+
+    /**
+     * @param width the current view width
+     * @param height the current view height
+     */
+     public static native void init(int width, int height);
+     public static native void step();
+}
diff --git a/opengl/tests/gldual/src/com/android/gldual/TriangleRenderer.java b/opengl/tests/gldual/src/com/android/gldual/TriangleRenderer.java
new file mode 100644
index 0000000..098c4d2
--- /dev/null
+++ b/opengl/tests/gldual/src/com/android/gldual/TriangleRenderer.java
@@ -0,0 +1,149 @@
+package com.android.gldual;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.nio.ShortBuffer;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.opengl.GLSurfaceView;
+import android.opengl.GLU;
+import android.os.SystemClock;
+
+public class TriangleRenderer implements GLSurfaceView.Renderer{
+
+    public TriangleRenderer() {
+        mTriangle = new Triangle();
+    }
+
+    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+        /*
+         * By default, OpenGL enables features that improve quality
+         * but reduce performance. One might want to tweak that
+         * especially on software renderer.
+         */
+        gl.glDisable(GL10.GL_DITHER);
+
+        /*
+         * Some one-time OpenGL initialization can be made here
+         * probably based on features of this particular context
+         */
+        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
+                GL10.GL_FASTEST);
+
+        gl.glClearColor(.5f, .5f, .5f, 1);
+        gl.glShadeModel(GL10.GL_SMOOTH);
+    }
+
+    public void onDrawFrame(GL10 gl) {
+        /*
+         * By default, OpenGL enables features that improve quality
+         * but reduce performance. One might want to tweak that
+         * especially on software renderer.
+         */
+        gl.glDisable(GL10.GL_DITHER);
+
+        /*
+         * Usually, the first thing one might want to do is to clear
+         * the screen. The most efficient way of doing this is to use
+         * glClear().
+         */
+
+        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
+
+        /*
+         * Now we're ready to draw some 3D objects
+         */
+
+        gl.glMatrixMode(GL10.GL_MODELVIEW);
+        gl.glLoadIdentity();
+
+        GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
+
+        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
+
+        long time = SystemClock.uptimeMillis() % 4000L;
+        float angle = 0.090f * ((int) time);
+
+        gl.glRotatef(angle, 0, 0, 1.0f);
+
+        mTriangle.draw(gl);
+    }
+
+    public void onSurfaceChanged(GL10 gl, int w, int h) {
+        gl.glViewport(0, 0, w, h);
+
+        /*
+        * Set our projection matrix. This doesn't have to be done
+        * each time we draw, but usually a new projection needs to
+        * be set when the viewport is resized.
+        */
+
+        float ratio = (float) w / h;
+        gl.glMatrixMode(GL10.GL_PROJECTION);
+        gl.glLoadIdentity();
+        gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7);
+
+    }
+
+    private Triangle mTriangle;
+}
+
+class Triangle {
+    public Triangle() {
+
+        // Buffers to be passed to gl*Pointer() functions
+        // must be direct, i.e., they must be placed on the
+        // native heap where the garbage collector cannot
+        // move them.
+        //
+        // Buffers with multi-byte datatypes (e.g., short, int, float)
+        // must have their byte order set to native order
+
+        ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);
+        vbb.order(ByteOrder.nativeOrder());
+        mFVertexBuffer = vbb.asFloatBuffer();
+
+        ByteBuffer tbb = ByteBuffer.allocateDirect(VERTS * 2 * 4);
+        tbb.order(ByteOrder.nativeOrder());
+
+        ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2);
+        ibb.order(ByteOrder.nativeOrder());
+        mIndexBuffer = ibb.asShortBuffer();
+
+        // A unit-sided equalateral triangle centered on the origin.
+        float[] coords = {
+                // X, Y, Z
+                -0.5f, -0.25f, 0,
+                 0.5f, -0.25f, 0,
+                 0.0f,  0.559016994f, 0
+        };
+
+        for (int i = 0; i < VERTS; i++) {
+            for(int j = 0; j < 3; j++) {
+                mFVertexBuffer.put(coords[i*3+j] * 2.0f);
+            }
+        }
+
+        for(int i = 0; i < VERTS; i++) {
+            mIndexBuffer.put((short) i);
+        }
+
+        mFVertexBuffer.position(0);
+        mIndexBuffer.position(0);
+    }
+
+    public void draw(GL10 gl) {
+        gl.glFrontFace(GL10.GL_CCW);
+        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
+        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, VERTS,
+                GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
+    }
+
+    private final static int VERTS = 3;
+
+    private FloatBuffer mFVertexBuffer;
+    private ShortBuffer mIndexBuffer;
+}
diff --git a/opengl/tests/swapinterval/Android.mk b/opengl/tests/swapinterval/Android.mk
index 619447c..9a4145e 100644
--- a/opengl/tests/swapinterval/Android.mk
+++ b/opengl/tests/swapinterval/Android.mk
@@ -6,6 +6,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
+	libutils \
     libEGL \
     libGLESv1_CM \
     libui
diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen
index 9bff0b2..6c1a231 100755
--- a/opengl/tools/glgen/gen
+++ b/opengl/tools/glgen/gen
@@ -63,7 +63,7 @@
 
 pushd out > /dev/null
 mkdir classes
-javac -d classes com/google/android/gles_jni/GLImpl.java javax/microedition/khronos/opengles/GL10.java javax/microedition/khronos/opengles/GL10Ext.java javax/microedition/khronos/opengles/GL11.java javax/microedition/khronos/opengles/GL11Ext.java javax/microedition/khronos/opengles/GL11ExtensionPack.java android/opengl/GLES10.java android/opengl/GLES10Ext.java android/opengl/GLES11.java android/opengl/GLES11Ext.java
+javac -d classes com/google/android/gles_jni/GLImpl.java javax/microedition/khronos/opengles/GL10.java javax/microedition/khronos/opengles/GL10Ext.java javax/microedition/khronos/opengles/GL11.java javax/microedition/khronos/opengles/GL11Ext.java javax/microedition/khronos/opengles/GL11ExtensionPack.java android/opengl/GLES10.java android/opengl/GLES10Ext.java android/opengl/GLES11.java android/opengl/GLES11Ext.java android/opengl/GLES20.java
 popd > /dev/null
 JAVA_RESULT=$?
 if [ $JAVA_RESULT -ne 0 ]; then
@@ -109,7 +109,7 @@
     compareGenerated ../../java/javax/microedition/khronos/opengles generated/javax/microedition/khronos/opengles $x
 done
 
-for x in GLES10 GLES10Ext GLES11 GLES11Ext
+for x in GLES10 GLES10Ext GLES11 GLES11Ext GLES20
 do
     compareGenerated ../../java/android/opengl generated/android/opengl ${x}.java
     compareGenerated ../../../core/jni generated/C android_opengl_${x}.cpp
diff --git a/opengl/tools/glgen/specs/gles11/GLES20.spec b/opengl/tools/glgen/specs/gles11/GLES20.spec
new file mode 100644
index 0000000..61094d1
--- /dev/null
+++ b/opengl/tools/glgen/specs/gles11/GLES20.spec
@@ -0,0 +1,142 @@
+void glActiveTexture ( GLenum texture )

+void glAttachShader ( GLuint program, GLuint shader )

+void glBindAttribLocation ( GLuint program, GLuint index, const char *name )

+void glBindBuffer ( GLenum target, GLuint buffer )

+void glBindFramebuffer ( GLenum target, GLuint framebuffer )

+void glBindRenderbuffer ( GLenum target, GLuint renderbuffer )

+void glBindTexture ( GLenum target, GLuint texture )

+void glBlendColor ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )

+void glBlendEquation ( GLenum mode )

+void glBlendEquationSeparate ( GLenum modeRGB, GLenum modeAlpha )

+void glBlendFunc ( GLenum sfactor, GLenum dfactor )

+void glBlendFuncSeparate ( GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha )

+void glBufferData ( GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage )

+void glBufferSubData ( GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data )

+GLenum glCheckFramebufferStatus ( GLenum target )

+void glClear ( GLbitfield mask )

+void glClearColor ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )

+void glClearDepthf ( GLclampf depth )

+void glClearStencil ( GLint s )

+void glColorMask ( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha )

+void glCompileShader ( GLuint shader )

+void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data )

+void glCompressedTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data )

+void glCopyTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border )

+void glCopyTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height )

+GLuint glCreateProgram ( void )

+GLuint glCreateShader ( GLenum type )

+void glCullFace ( GLenum mode )

+void glDeleteBuffers ( GLsizei n, const GLuint *buffers )

+void glDeleteFramebuffers ( GLsizei n, const GLuint *framebuffers )

+void glDeleteProgram ( GLuint program )

+void glDeleteRenderbuffers ( GLsizei n, const GLuint *renderbuffers )

+void glDeleteShader ( GLuint shader )

+void glDeleteTextures ( GLsizei n, const GLuint *textures )

+void glDepthFunc ( GLenum func )

+void glDepthMask ( GLboolean flag )

+void glDepthRangef ( GLclampf zNear, GLclampf zFar )

+void glDetachShader ( GLuint program, GLuint shader )

+void glDisable ( GLenum cap )

+void glDisableVertexAttribArray ( GLuint index )

+void glDrawArrays ( GLenum mode, GLint first, GLsizei count )

+void glDrawElements ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices )

+void glEnable ( GLenum cap )

+void glEnableVertexAttribArray ( GLuint index )

+void glFinish ( void )

+void glFlush ( void )

+void glFramebufferRenderbuffer ( GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer )

+void glFramebufferTexture2D ( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level )

+void glFrontFace ( GLenum mode )

+void glGenBuffers ( GLsizei n, GLuint *buffers )

+void glGenerateMipmap ( GLenum target )

+void glGenFramebuffers ( GLsizei n, GLuint *framebuffers )

+void glGenRenderbuffers ( GLsizei n, GLuint *renderbuffers )

+void glGenTextures ( GLsizei n, GLuint *textures )

+void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name )

+void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name )

+void glGetAttachedShaders ( GLuint program, GLsizei maxcount, GLsizei *count, GLuint *shaders )

+int glGetAttribLocation ( GLuint program, const char *name )

+void glGetBooleanv ( GLenum pname, GLboolean *params )

+void glGetBufferParameteriv ( GLenum target, GLenum pname, GLint *params )

+GLenum glGetError ( void )

+void glGetFloatv ( GLenum pname, GLfloat *params )

+void glGetFramebufferAttachmentParameteriv ( GLenum target, GLenum attachment, GLenum pname, GLint *params )

+void glGetIntegerv ( GLenum pname, GLint *params )

+void glGetProgramiv ( GLuint program, GLenum pname, GLint *params )

+void glGetProgramInfoLog ( GLuint program, GLsizei bufsize, GLsizei *length, char *infolog )

+void glGetRenderbufferParameteriv ( GLenum target, GLenum pname, GLint *params )

+void glGetShaderiv ( GLuint shader, GLenum pname, GLint *params )

+void glGetShaderInfoLog ( GLuint shader, GLsizei bufsize, GLsizei *length, char *infolog )

+void glGetShaderPrecisionFormat ( GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision )

+void glGetShaderSource ( GLuint shader, GLsizei bufsize, GLsizei *length, char *source )

+const GLubyte * glGetString ( GLenum name )

+void glGetTexParameterfv ( GLenum target, GLenum pname, GLfloat *params )

+void glGetTexParameteriv ( GLenum target, GLenum pname, GLint *params )

+void glGetUniformfv ( GLuint program, GLint location, GLfloat *params )

+void glGetUniformiv ( GLuint program, GLint location, GLint *params )

+int glGetUniformLocation ( GLuint program, const char *name )

+void glGetVertexAttribfv ( GLuint index, GLenum pname, GLfloat *params )

+void glGetVertexAttribiv ( GLuint index, GLenum pname, GLint *params )

+// void glGetVertexAttribPointerv ( GLuint index, GLenum pname, void **pointer )

+void glHint ( GLenum target, GLenum mode )

+GLboolean glIsBuffer ( GLuint buffer )

+GLboolean glIsEnabled ( GLenum cap )

+GLboolean glIsFramebuffer ( GLuint framebuffer )

+GLboolean glIsProgram ( GLuint program )

+GLboolean glIsRenderbuffer ( GLuint renderbuffer )

+GLboolean glIsShader ( GLuint shader )

+GLboolean glIsTexture ( GLuint texture )

+void glLineWidth ( GLfloat width )

+void glLinkProgram ( GLuint program )

+void glPixelStorei ( GLenum pname, GLint param )

+void glPolygonOffset ( GLfloat factor, GLfloat units )

+void glReadPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels )

+void glReleaseShaderCompiler ( void )

+void glRenderbufferStorage ( GLenum target, GLenum internalformat, GLsizei width, GLsizei height )

+void glSampleCoverage ( GLclampf value, GLboolean invert )

+void glScissor ( GLint x, GLint y, GLsizei width, GLsizei height )

+void glShaderBinary ( GLsizei n, const GLuint *shaders, GLenum binaryformat, const GLvoid *binary, GLsizei length )

+void glShaderSource ( GLuint shader )

+void glStencilFunc ( GLenum func, GLint ref, GLuint mask )

+void glStencilFuncSeparate ( GLenum face, GLenum func, GLint ref, GLuint mask )

+void glStencilMask ( GLuint mask )

+void glStencilMaskSeparate ( GLenum face, GLuint mask )

+void glStencilOp ( GLenum fail, GLenum zfail, GLenum zpass )

+void glStencilOpSeparate ( GLenum face, GLenum fail, GLenum zfail, GLenum zpass )

+void glTexImage2D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels )

+void glTexParameterf ( GLenum target, GLenum pname, GLfloat param )

+void glTexParameterfv ( GLenum target, GLenum pname, const GLfloat *params )

+void glTexParameteri ( GLenum target, GLenum pname, GLint param )

+void glTexParameteriv ( GLenum target, GLenum pname, const GLint *params )

+void glTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels )

+void glUniform1f ( GLint location, GLfloat x )

+void glUniform1fv ( GLint location, GLsizei count, const GLfloat *v )

+void glUniform1i ( GLint location, GLint x )

+void glUniform1iv ( GLint location, GLsizei count, const GLint *v )

+void glUniform2f ( GLint location, GLfloat x, GLfloat y )

+void glUniform2fv ( GLint location, GLsizei count, const GLfloat *v )

+void glUniform2i ( GLint location, GLint x, GLint y )

+void glUniform2iv ( GLint location, GLsizei count, const GLint *v )

+void glUniform3f ( GLint location, GLfloat x, GLfloat y, GLfloat z )

+void glUniform3fv ( GLint location, GLsizei count, const GLfloat *v )

+void glUniform3i ( GLint location, GLint x, GLint y, GLint z )

+void glUniform3iv ( GLint location, GLsizei count, const GLint *v )

+void glUniform4f ( GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w )

+void glUniform4fv ( GLint location, GLsizei count, const GLfloat *v )

+void glUniform4i ( GLint location, GLint x, GLint y, GLint z, GLint w )

+void glUniform4iv ( GLint location, GLsizei count, const GLint *v )

+void glUniformMatrix2fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )

+void glUniformMatrix3fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )

+void glUniformMatrix4fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )

+void glUseProgram ( GLuint program )

+void glValidateProgram ( GLuint program )

+void glVertexAttrib1f ( GLuint indx, GLfloat x )

+void glVertexAttrib1fv ( GLuint indx, const GLfloat *values )

+void glVertexAttrib2f ( GLuint indx, GLfloat x, GLfloat y )

+void glVertexAttrib2fv ( GLuint indx, const GLfloat *values )

+void glVertexAttrib3f ( GLuint indx, GLfloat x, GLfloat y, GLfloat z )

+void glVertexAttrib3fv ( GLuint indx, const GLfloat *values )

+void glVertexAttrib4f ( GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w )

+void glVertexAttrib4fv ( GLuint indx, const GLfloat *values )

+void glVertexAttribPointer ( GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *ptr )

+void glViewport ( GLint x, GLint y, GLsizei width, GLsizei height )
\ No newline at end of file
diff --git a/opengl/tools/glgen/specs/gles11/checks.spec b/opengl/tools/glgen/specs/gles11/checks.spec
index 1468ab9..f917128 100644
--- a/opengl/tools/glgen/specs/gles11/checks.spec
+++ b/opengl/tools/glgen/specs/gles11/checks.spec
@@ -37,7 +37,6 @@
 glBlendEquationSeparate unsupported
 glBlendFuncSeparate unsupported
 glCheckFramebufferStatusOES unsupported return 0
-glCurrentPaletteMatrixOES unsupported
 glDeleteFramebuffersOES unsupported
 glDeleteRenderbuffersOES unsupported
 glFramebufferRenderbufferOES unsupported
@@ -52,11 +51,8 @@
 glGetTexGen unsupported
 glIsFramebufferOES unsupported return JNI_FALSE
 glIsRenderbufferOES unsupported return JNI_FALSE
-glLoadPaletteFromModelViewMatrixOES unsupported
-glMatrixIndexPointerOES unsupported
 glRenderbufferStorageOES unsupported return false
 glTexGen unsupported
 glTexGenf unsupported
 glTexGeni unsupported
 glTexGenx unsupported
-glWeightPointerOES unsupported
diff --git a/opengl/tools/glgen/specs/jsr239/glspec-checks b/opengl/tools/glgen/specs/jsr239/glspec-checks
index 063cdc7..c28e403 100644
--- a/opengl/tools/glgen/specs/jsr239/glspec-checks
+++ b/opengl/tools/glgen/specs/jsr239/glspec-checks
@@ -35,7 +35,6 @@
 glBlendEquationSeparate unsupported
 glBlendFuncSeparate unsupported
 glCheckFramebufferStatusOES unsupported return 0
-glCurrentPaletteMatrixOES unsupported
 glDeleteFramebuffersOES unsupported
 glDeleteRenderbuffersOES unsupported
 glFramebufferRenderbufferOES unsupported
@@ -50,11 +49,8 @@
 glGetTexGen unsupported
 glIsFramebufferOES unsupported return JNI_FALSE
 glIsRenderbufferOES unsupported return JNI_FALSE
-glLoadPaletteFromModelViewMatrixOES unsupported
-glMatrixIndexPointerOES unsupported
 glRenderbufferStorageOES unsupported return false
 glTexGen unsupported
 glTexGenf unsupported
 glTexGeni unsupported
 glTexGenx unsupported
-glWeightPointerOES unsupported
diff --git a/opengl/tools/glgen/src/CType.java b/opengl/tools/glgen/src/CType.java
index 826c90d..d49e9ef 100644
--- a/opengl/tools/glgen/src/CType.java
+++ b/opengl/tools/glgen/src/CType.java
@@ -44,8 +44,12 @@
         baseType.equals("void");
     }
 
+    public boolean isConstCharPointer() {
+        return isConst && isPointer && baseType.equals("char");
+    }
+
     public boolean isTypedPointer() {
-    return isPointer() && !isVoid();
+    return isPointer() && !isVoid() && !isConstCharPointer();
     }
 
     public void setBaseType(String baseType) {
diff --git a/opengl/tools/glgen/src/GenerateGLES.java b/opengl/tools/glgen/src/GenerateGLES.java
index 60775b7..08063f3 100644
--- a/opengl/tools/glgen/src/GenerateGLES.java
+++ b/opengl/tools/glgen/src/GenerateGLES.java
@@ -70,7 +70,7 @@
 
         // Generate files
         for(String suffix: new String[] {"GLES10", "GLES10Ext",
-                "GLES11", "GLES11Ext"})
+                "GLES11", "GLES11Ext", "GLES20"})
         {
             BufferedReader spec11Reader =
                 new BufferedReader(new FileReader("specs/gles11/"
diff --git a/opengl/tools/glgen/src/JType.java b/opengl/tools/glgen/src/JType.java
index df1177b..32d9fe7 100644
--- a/opengl/tools/glgen/src/JType.java
+++ b/opengl/tools/glgen/src/JType.java
@@ -6,6 +6,7 @@
     String baseType;
     boolean isArray;
     boolean isClass;
+    boolean isString;
 
     static HashMap<CType,JType> typeMapping = new HashMap<CType,JType>();
     static HashMap<CType,JType> arrayTypeMapping = new HashMap<CType,JType>();
@@ -27,7 +28,10 @@
     typeMapping.put(new CType("GLubyte"), new JType("byte"));
     typeMapping.put(new CType("GLuint"), new JType("int"));
     typeMapping.put(new CType("void"), new JType("void"));
-    typeMapping.put(new CType("GLubyte", true, true), new JType("String"));
+    typeMapping.put(new CType("GLubyte", true, true), new JType("String", false, false));
+    typeMapping.put(new CType("char", false, true), new JType("byte"));
+    typeMapping.put(new CType("char", true, true), new JType("String", false, false));
+    typeMapping.put(new CType("int"), new JType("int"));
 
     // Untyped pointers map to untyped Buffers
     typeMapping.put(new CType("GLvoid", true, true),
@@ -42,6 +46,8 @@
     // Typed pointers map to typed Buffers
     typeMapping.put(new CType("GLboolean", false, true),
             new JType("java.nio.IntBuffer", true, false));
+    typeMapping.put(new CType("GLenum", false, true),
+            new JType("java.nio.IntBuffer", true, false));
     typeMapping.put(new CType("GLfixed", false, true),
             new JType("java.nio.IntBuffer", true, false));
     typeMapping.put(new CType("GLfixed", true, true),
@@ -54,6 +60,8 @@
             new JType("java.nio.IntBuffer", true, false));
     typeMapping.put(new CType("GLint", true, true),
             new JType("java.nio.IntBuffer", true, false));
+    typeMapping.put(new CType("GLsizei", false, true),
+            new JType("java.nio.IntBuffer", true, false));
     typeMapping.put(new CType("GLuint", false, true),
             new JType("java.nio.IntBuffer", true, false));
     typeMapping.put(new CType("GLuint", true, true),
@@ -62,8 +70,11 @@
             new JType("java.nio.ShortBuffer", true, false));
 
     // Typed pointers map to arrays + offsets
+    arrayTypeMapping.put(new CType("char", false, true),
+            new JType("byte", false, true));
     arrayTypeMapping.put(new CType("GLboolean", false, true),
                  new JType("boolean", false, true));
+    arrayTypeMapping.put(new CType("GLenum", false, true), new JType("int", false, true));
     arrayTypeMapping.put(new CType("GLfixed", true, true), new JType("int", false, true));
     arrayTypeMapping.put(new CType("GLfixed", false, true), new JType("int", false, true));
     arrayTypeMapping.put(new CType("GLfloat", false, true), new JType("float", false, true));
@@ -71,6 +82,8 @@
     arrayTypeMapping.put(new CType("GLint", false, true), new JType("int", false, true));
     arrayTypeMapping.put(new CType("GLint", true, true), new JType("int", false, true));
     arrayTypeMapping.put(new CType("GLshort", true, true), new JType("short", false, true));
+    arrayTypeMapping.put(new CType("GLsizei", false, true), new JType("int", false, true));
+    arrayTypeMapping.put(new CType("GLsizei", true, true), new JType("int", false, true));
     arrayTypeMapping.put(new CType("GLuint", false, true), new JType("int", false, true));
     arrayTypeMapping.put(new CType("GLuint", true, true), new JType("int", false, true));
     arrayTypeMapping.put(new CType("GLintptr"), new JType("int", false, true));
@@ -109,6 +122,10 @@
     return isClass;
     }
 
+    public boolean isString() {
+        return baseType.equals("String");
+    }
+
     public boolean isPrimitive() {
     return !isClass() && !isArray();
     }
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index 2cdb244..e79170a 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -37,6 +37,12 @@
             jniName += "L";
         } else if (baseType.equals("byte")) {
             jniName += "B";
+        } else if (baseType.equals("String")) {
+            jniName += "Ljava/lang/String;";
+        } else if (baseType.equals("void")) {
+            // nothing.
+        } else {
+            throw new RuntimeException("Uknown primitive basetype " + baseType);
         }
         return jniName;
     }
@@ -113,10 +119,15 @@
         emitFunction(jfunc, out, false, false);
     }
 
+    boolean isPointerFunc(JFunc jfunc) {
+        String name = jfunc.getName();
+        return (name.endsWith("Pointer") || name.endsWith("PointerOES"))
+            && jfunc.getCFunc().hasPointerArg();
+    }
+
     void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray) {
         boolean isVoid = jfunc.getType().isVoid();
-        boolean isPointerFunc = jfunc.getName().endsWith("Pointer") &&
-            jfunc.getCFunc().hasPointerArg();
+        boolean isPointerFunc = isPointerFunc(jfunc);
 
         if (!isVoid) {
             out.println(iii +
@@ -400,9 +411,7 @@
      *   if !interfaceDecl: public <returntype> func(args) { body }
      */
     void emitFunction(JFunc jfunc, PrintStream out, boolean nativeDecl, boolean interfaceDecl) {
-        boolean isPointerFunc =
-            jfunc.getName().endsWith("Pointer") &&
-            jfunc.getCFunc().hasPointerArg();
+        boolean isPointerFunc = isPointerFunc(jfunc);
 
         if (!nativeDecl && !interfaceDecl && !isPointerFunc) {
             // If it's not a pointer function, we've already emitted it
@@ -504,6 +513,34 @@
                     out.println(iii + "    (stride >= 0)) {");
                     out.println(iii + indent + "_vertexPointer = pointer;");
                     out.println(iii + "}");
+                } else if (fname.equals("glPointSizePointerOES")) {
+                    out.println(iii + "if (((type == GL_FLOAT) ||");
+                    out.println(iii + "     (type == GL_FIXED)) &&");
+                    out.println(iii + "    (stride >= 0)) {");
+                    out.println(iii + indent + "_pointSizePointerOES = pointer;");
+                    out.println(iii + "}");
+                } else if (fname.equals("glMatrixIndexPointerOES")) {
+                    out.println(iii + "if (((size == 2) ||");
+                    out.println(iii + "     (size == 3) ||");
+                    out.println(iii + "     (size == 4)) &&");
+                    out.println(iii + "    ((type == GL_FLOAT) ||");
+                    out.println(iii + "     (type == GL_BYTE) ||");
+                    out.println(iii + "     (type == GL_SHORT) ||");
+                    out.println(iii + "     (type == GL_FIXED)) &&");
+                    out.println(iii + "    (stride >= 0)) {");
+                    out.println(iii + indent + "_matrixIndexPointerOES = pointer;");
+                    out.println(iii + "}");
+                } else if (fname.equals("glWeightPointer")) {
+                    out.println(iii + "if (((size == 2) ||");
+                    out.println(iii + "     (size == 3) ||");
+                    out.println(iii + "     (size == 4)) &&");
+                    out.println(iii + "    ((type == GL_FLOAT) ||");
+                    out.println(iii + "     (type == GL_BYTE) ||");
+                    out.println(iii + "     (type == GL_SHORT) ||");
+                    out.println(iii + "     (type == GL_FIXED)) &&");
+                    out.println(iii + "    (stride >= 0)) {");
+                    out.println(iii + indent + "_weightPointerOES = pointer;");
+                    out.println(iii + "}");
                 }
             }
 
@@ -603,9 +640,9 @@
         //
 
         String outName = "android_" + jfunc.getName();
-        boolean isPointerFunc = outName.endsWith("Pointer") &&
-            jfunc.getCFunc().hasPointerArg();
+        boolean isPointerFunc = isPointerFunc(jfunc);
         boolean isVBOPointerFunc = (outName.endsWith("Pointer") ||
+                outName.endsWith("PointerOES") ||
             outName.endsWith("DrawElements")) &&
             !jfunc.getCFunc().hasPointerArg();
         if (isPointerFunc) {
@@ -629,7 +666,7 @@
         }
 
         // Append signature to function name
-        String sig = getJniMangledName(signature).replace('.', '_');
+        String sig = getJniMangledName(signature).replace('.', '_').replace('/', '_');
         out.print("__" + sig);
         outName += "__" + sig;
 
@@ -652,6 +689,7 @@
         nativeRegistrations.add(s);
 
         List<Integer> nonPrimitiveArgs = new ArrayList<Integer>();
+        List<Integer> stringArgs = new ArrayList<Integer>();
         int numBufferArgs = 0;
         List<String> bufferArgNames = new ArrayList<String>();
 
@@ -682,6 +720,9 @@
             } else {
                 suffix = "";
             }
+            if (argType.isString()) {
+                stringArgs.add(new Integer(i));
+            }
 
             out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix);
         }
@@ -692,14 +733,19 @@
 
         int numArrays = 0;
         int numBuffers = 0;
+        int numStrings = 0;
         for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
             int idx = nonPrimitiveArgs.get(i).intValue();
-            if (jfunc.getArgType(idx).isArray()) {
+            JType argType = jfunc.getArgType(idx);
+            if (argType.isArray()) {
                 ++numArrays;
             }
-            if (jfunc.getArgType(idx).isBuffer()) {
+            if (argType.isBuffer()) {
                 ++numBuffers;
             }
+            if (argType.isString()) {
+                ++numStrings;
+            }
         }
 
         // Emit method body
@@ -736,7 +782,9 @@
                 "android::gl::ogles_context_t *ctx = getContext(_env, _this);");
         }
 
-        boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0) &&
+        boolean initializeReturnValue = stringArgs.size() > 0;
+
+        boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0 || numStrings > 0) &&
             hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs);
         // mChecker.getChecks(cfunc.getName()) != null
 
@@ -759,6 +807,9 @@
             if (retval != null) {
                 out.println(indent + returnType.getDeclaration() +
                             " _returnValue = " + retval + ";");
+            } else if (initializeReturnValue) {
+                out.println(indent + returnType.getDeclaration() +
+                " _returnValue = 0;");
             } else {
                 out.println(indent + returnType.getDeclaration() +
                             " _returnValue;");
@@ -789,7 +840,7 @@
                                 jfunc.getArgName(idx) +
                                 "_base = (" + decl + ") 0;");
                 }
-                remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
+                remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" :
                     "_" + cname + "Remaining";
                 out.println(indent +
                             "jint " + remaining + ";");
@@ -803,6 +854,40 @@
             out.println();
         }
 
+        // Emit local variable declaration for strings
+        if (stringArgs.size() > 0) {
+            for (int i = 0; i < stringArgs.size(); i++) {
+                int idx = stringArgs.get(i).intValue();
+                int cIndex = jfunc.getArgCIndex(idx);
+                String cname = cfunc.getArgName(cIndex);
+
+                out.println(indent + "const char* _native" + cname + " = 0;");
+            }
+
+            out.println();
+        }
+
+        // Null pointer checks and GetStringUTFChars
+        if (stringArgs.size() > 0) {
+            for (int i = 0; i < stringArgs.size(); i++) {
+                int idx = stringArgs.get(i).intValue();
+                int cIndex = jfunc.getArgCIndex(idx);
+                String cname = cfunc.getArgName(cIndex);
+
+                CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
+                String decl = type.getDeclaration();
+                out.println(indent + "if (!" + cname + ") {");
+                out.println(indent + "    _env->ThrowNew(IAEClass, \"" + cname + " == null\");");
+                out.println(indent + "    goto exit;");
+                needsExit = true;
+                out.println(indent + "}");
+
+                out.println(indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);");
+            }
+
+            out.println();
+        }
+
         // Emit 'GetPrimitiveArrayCritical' for arrays
         // Emit 'GetPointer' calls for Buffer pointers
         int bufArgIdx = 0;
@@ -814,7 +899,7 @@
                 String cname = cfunc.getArgName(cIndex);
                 offset = numArrays <= 1 ? "offset" :
                     cname + "Offset";
-                remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
+                remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" :
                     "_" + cname + "Remaining";
 
                 if (jfunc.getArgType(idx).isArray()) {
@@ -957,8 +1042,11 @@
                 out.print(indent + indent +
                           "(" +
                           typecast +
-                          ")" +
-                          cfunc.getArgName(i));
+                          ")");
+                if (cfunc.getArgType(i).isConstCharPointer()) {
+                    out.print("_native");
+                }
+                out.print(cfunc.getArgName(i));
 
                 if (i == numArgs - 1) {
                     if (isPointerFunc) {
@@ -1025,6 +1113,22 @@
             }
         }
 
+        // Emit local variable declaration for strings
+        if (stringArgs.size() > 0) {
+            for (int i = 0; i < stringArgs.size(); i++) {
+                int idx = stringArgs.get(i).intValue();
+                int cIndex = jfunc.getArgCIndex(idx);
+                String cname = cfunc.getArgName(cIndex);
+
+                out.println(indent + "if (_native" + cname + ") {");
+                out.println(indent + "    _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");");
+                out.println(indent + "}");
+            }
+
+            out.println();
+        }
+
+
         if (!isVoid) {
             out.println(indent + "return _returnValue;");
         }
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if b/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if
index 428ccee..c5e34cd 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if
+++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if
@@ -18,6 +18,8 @@
 
 package android.opengl;
 
+import java.nio.Buffer;
+
 public class GLES11Ext {
     public static final int GL_BLEND_EQUATION_RGB_OES                               = 0x8009;
     public static final int GL_BLEND_EQUATION_ALPHA_OES                             = 0x883D;
@@ -127,4 +129,10 @@
     static {
 	    _nativeClassInit();
     }
-    
\ No newline at end of file
+    
+    private static final int GL_BYTE = GLES10.GL_BYTE;
+    private static final int GL_FIXED = GLES10.GL_FIXED;
+    private static final int GL_FLOAT = GLES10.GL_FLOAT;
+    private static final int GL_SHORT = GLES10.GL_SHORT;
+    
+    private static Buffer _matrixIndexPointerOES;
\ No newline at end of file
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
index 294d1ce..2548b32 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
@@ -23,6 +23,15 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
+/* special calls implemented in Android's GLES wrapper used to more
+ * efficiently bound-check passed arrays */
+extern "C" {
+GL_API void GL_APIENTRY glMatrixIndexPointerOESBounds(GLint size, GLenum type, GLsizei stride,
+        const GLvoid *ptr, GLsizei count);
+GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, GLsizei stride,
+        const GLvoid *ptr, GLsizei count);
+}
+
 static int initialized = 0;
 
 static jclass nioAccessClass;
@@ -121,5 +130,17 @@
 					   commit ? 0 : JNI_ABORT);
 }
 
+static void *
+getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
+    char* buf = (char*) _env->GetDirectBufferAddress(buffer);
+    if (buf) {
+        jint position = _env->GetIntField(buffer, positionID);
+        jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+        buf += position << elementSizeShift;
+    } else {
+        _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+    }
+    return (void*) buf;
+}
 // --------------------------------------------------------------------------
 
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11Header.java-if b/opengl/tools/glgen/stubs/gles11/GLES11Header.java-if
index 26f466f..81572d2 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11Header.java-if
+++ b/opengl/tools/glgen/stubs/gles11/GLES11Header.java-if
@@ -149,3 +149,4 @@
 	    _nativeClassInit();
     }
 
+    private static Buffer _pointSizePointerOES;
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
index 294d1ce..4c297f7 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
@@ -23,6 +23,13 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
+/* special calls implemented in Android's GLES wrapper used to more
+ * efficiently bound-check passed arrays */
+extern "C" {
+GL_API void GL_APIENTRY glPointSizePointerOESBounds(GLenum type, GLsizei stride,
+        const GLvoid *ptr, GLsizei count);
+}
+
 static int initialized = 0;
 
 static jclass nioAccessClass;
@@ -121,5 +128,18 @@
 					   commit ? 0 : JNI_ABORT);
 }
 
+static void *
+getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
+    char* buf = (char*) _env->GetDirectBufferAddress(buffer);
+    if (buf) {
+        jint position = _env->GetIntField(buffer, positionID);
+        jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+        buf += position << elementSizeShift;
+    } else {
+        _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+    }
+    return (void*) buf;
+}
+
 // --------------------------------------------------------------------------
 
diff --git a/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if b/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if
new file mode 100644
index 0000000..b615e0a
--- /dev/null
+++ b/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if
@@ -0,0 +1,330 @@
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+// This source file is automatically generated
+
+package android.opengl;
+
+/** OpenGL ES 2.0
+ */
+public class GLES20 {
+    public static final int GL_ACTIVE_TEXTURE                          = 0x84E0;
+    public static final int GL_DEPTH_BUFFER_BIT                        = 0x00000100;
+    public static final int GL_STENCIL_BUFFER_BIT                      = 0x00000400;
+    public static final int GL_COLOR_BUFFER_BIT                        = 0x00004000;
+    public static final int GL_FALSE                                   = 0;
+    public static final int GL_TRUE                                    = 1;
+    public static final int GL_POINTS                                  = 0x0000;
+    public static final int GL_LINES                                   = 0x0001;
+    public static final int GL_LINE_LOOP                               = 0x0002;
+    public static final int GL_LINE_STRIP                              = 0x0003;
+    public static final int GL_TRIANGLES                               = 0x0004;
+    public static final int GL_TRIANGLE_STRIP                          = 0x0005;
+    public static final int GL_TRIANGLE_FAN                            = 0x0006;
+    public static final int GL_ZERO                                    = 0;
+    public static final int GL_ONE                                     = 1;
+    public static final int GL_SRC_COLOR                               = 0x0300;
+    public static final int GL_ONE_MINUS_SRC_COLOR                     = 0x0301;
+    public static final int GL_SRC_ALPHA                               = 0x0302;
+    public static final int GL_ONE_MINUS_SRC_ALPHA                     = 0x0303;
+    public static final int GL_DST_ALPHA                               = 0x0304;
+    public static final int GL_ONE_MINUS_DST_ALPHA                     = 0x0305;
+    public static final int GL_DST_COLOR                               = 0x0306;
+    public static final int GL_ONE_MINUS_DST_COLOR                     = 0x0307;
+    public static final int GL_SRC_ALPHA_SATURATE                      = 0x0308;
+    public static final int GL_FUNC_ADD                                = 0x8006;
+    public static final int GL_BLEND_EQUATION                          = 0x8009;
+    public static final int GL_BLEND_EQUATION_RGB                      = 0x8009;   /* same as BLEND_EQUATION */
+    public static final int GL_BLEND_EQUATION_ALPHA                    = 0x883D;
+    public static final int GL_FUNC_SUBTRACT                           = 0x800A;
+    public static final int GL_FUNC_REVERSE_SUBTRACT                   = 0x800B;
+    public static final int GL_BLEND_DST_RGB                           = 0x80C8;
+    public static final int GL_BLEND_SRC_RGB                           = 0x80C9;
+    public static final int GL_BLEND_DST_ALPHA                         = 0x80CA;
+    public static final int GL_BLEND_SRC_ALPHA                         = 0x80CB;
+    public static final int GL_CONSTANT_COLOR                          = 0x8001;
+    public static final int GL_ONE_MINUS_CONSTANT_COLOR                = 0x8002;
+    public static final int GL_CONSTANT_ALPHA                          = 0x8003;
+    public static final int GL_ONE_MINUS_CONSTANT_ALPHA                = 0x8004;
+    public static final int GL_BLEND_COLOR                             = 0x8005;
+    public static final int GL_ARRAY_BUFFER                            = 0x8892;
+    public static final int GL_ELEMENT_ARRAY_BUFFER                    = 0x8893;
+    public static final int GL_ARRAY_BUFFER_BINDING                    = 0x8894;
+    public static final int GL_ELEMENT_ARRAY_BUFFER_BINDING            = 0x8895;
+    public static final int GL_STREAM_DRAW                             = 0x88E0;
+    public static final int GL_STATIC_DRAW                             = 0x88E4;
+    public static final int GL_DYNAMIC_DRAW                            = 0x88E8;
+    public static final int GL_BUFFER_SIZE                             = 0x8764;
+    public static final int GL_BUFFER_USAGE                            = 0x8765;
+    public static final int GL_CURRENT_VERTEX_ATTRIB                   = 0x8626;
+    public static final int GL_FRONT                                   = 0x0404;
+    public static final int GL_BACK                                    = 0x0405;
+    public static final int GL_FRONT_AND_BACK                          = 0x0408;
+    public static final int GL_TEXTURE_2D                              = 0x0DE1;
+    public static final int GL_CULL_FACE                               = 0x0B44;
+    public static final int GL_BLEND                                   = 0x0BE2;
+    public static final int GL_DITHER                                  = 0x0BD0;
+    public static final int GL_STENCIL_TEST                            = 0x0B90;
+    public static final int GL_DEPTH_TEST                              = 0x0B71;
+    public static final int GL_SCISSOR_TEST                            = 0x0C11;
+    public static final int GL_POLYGON_OFFSET_FILL                     = 0x8037;
+    public static final int GL_SAMPLE_ALPHA_TO_COVERAGE                = 0x809E;
+    public static final int GL_SAMPLE_COVERAGE                         = 0x80A0;
+    public static final int GL_NO_ERROR                                = 0;
+    public static final int GL_INVALID_ENUM                            = 0x0500;
+    public static final int GL_INVALID_VALUE                           = 0x0501;
+    public static final int GL_INVALID_OPERATION                       = 0x0502;
+    public static final int GL_OUT_OF_MEMORY                           = 0x0505;
+    public static final int GL_CW                                      = 0x0900;
+    public static final int GL_CCW                                     = 0x0901;
+    public static final int GL_LINE_WIDTH                              = 0x0B21;
+    public static final int GL_ALIASED_POINT_SIZE_RANGE                = 0x846D;
+    public static final int GL_ALIASED_LINE_WIDTH_RANGE                = 0x846E;
+    public static final int GL_CULL_FACE_MODE                          = 0x0B45;
+    public static final int GL_FRONT_FACE                              = 0x0B46;
+    public static final int GL_DEPTH_RANGE                             = 0x0B70;
+    public static final int GL_DEPTH_WRITEMASK                         = 0x0B72;
+    public static final int GL_DEPTH_CLEAR_VALUE                       = 0x0B73;
+    public static final int GL_DEPTH_FUNC                              = 0x0B74;
+    public static final int GL_STENCIL_CLEAR_VALUE                     = 0x0B91;
+    public static final int GL_STENCIL_FUNC                            = 0x0B92;
+    public static final int GL_STENCIL_FAIL                            = 0x0B94;
+    public static final int GL_STENCIL_PASS_DEPTH_FAIL                 = 0x0B95;
+    public static final int GL_STENCIL_PASS_DEPTH_PASS                 = 0x0B96;
+    public static final int GL_STENCIL_REF                             = 0x0B97;
+    public static final int GL_STENCIL_VALUE_MASK                      = 0x0B93;
+    public static final int GL_STENCIL_WRITEMASK                       = 0x0B98;
+    public static final int GL_STENCIL_BACK_FUNC                       = 0x8800;
+    public static final int GL_STENCIL_BACK_FAIL                       = 0x8801;
+    public static final int GL_STENCIL_BACK_PASS_DEPTH_FAIL            = 0x8802;
+    public static final int GL_STENCIL_BACK_PASS_DEPTH_PASS            = 0x8803;
+    public static final int GL_STENCIL_BACK_REF                        = 0x8CA3;
+    public static final int GL_STENCIL_BACK_VALUE_MASK                 = 0x8CA4;
+    public static final int GL_STENCIL_BACK_WRITEMASK                  = 0x8CA5;
+    public static final int GL_VIEWPORT                                = 0x0BA2;
+    public static final int GL_SCISSOR_BOX                             = 0x0C10;
+    public static final int GL_COLOR_CLEAR_VALUE                       = 0x0C22;
+    public static final int GL_COLOR_WRITEMASK                         = 0x0C23;
+    public static final int GL_UNPACK_ALIGNMENT                        = 0x0CF5;
+    public static final int GL_PACK_ALIGNMENT                          = 0x0D05;
+    public static final int GL_MAX_TEXTURE_SIZE                        = 0x0D33;
+    public static final int GL_MAX_VIEWPORT_DIMS                       = 0x0D3A;
+    public static final int GL_SUBPIXEL_BITS                           = 0x0D50;
+    public static final int GL_RED_BITS                                = 0x0D52;
+    public static final int GL_GREEN_BITS                              = 0x0D53;
+    public static final int GL_BLUE_BITS                               = 0x0D54;
+    public static final int GL_ALPHA_BITS                              = 0x0D55;
+    public static final int GL_DEPTH_BITS                              = 0x0D56;
+    public static final int GL_STENCIL_BITS                            = 0x0D57;
+    public static final int GL_POLYGON_OFFSET_UNITS                    = 0x2A00;
+    public static final int GL_POLYGON_OFFSET_FACTOR                   = 0x8038;
+    public static final int GL_TEXTURE_BINDING_2D                      = 0x8069;
+    public static final int GL_SAMPLE_BUFFERS                          = 0x80A8;
+    public static final int GL_SAMPLES                                 = 0x80A9;
+    public static final int GL_SAMPLE_COVERAGE_VALUE                   = 0x80AA;
+    public static final int GL_SAMPLE_COVERAGE_INVERT                  = 0x80AB;
+    public static final int GL_NUM_COMPRESSED_TEXTURE_FORMATS          = 0x86A2;
+    public static final int GL_COMPRESSED_TEXTURE_FORMATS              = 0x86A3;
+    public static final int GL_DONT_CARE                               = 0x1100;
+    public static final int GL_FASTEST                                 = 0x1101;
+    public static final int GL_NICEST                                  = 0x1102;
+    public static final int GL_GENERATE_MIPMAP_HINT                    = 0x8192;
+    public static final int GL_BYTE                                    = 0x1400;
+    public static final int GL_UNSIGNED_BYTE                           = 0x1401;
+    public static final int GL_SHORT                                   = 0x1402;
+    public static final int GL_UNSIGNED_SHORT                          = 0x1403;
+    public static final int GL_INT                                     = 0x1404;
+    public static final int GL_UNSIGNED_INT                            = 0x1405;
+    public static final int GL_FLOAT                                   = 0x1406;
+    public static final int GL_FIXED                                   = 0x140C;
+    public static final int GL_DEPTH_COMPONENT                         = 0x1902;
+    public static final int GL_ALPHA                                   = 0x1906;
+    public static final int GL_RGB                                     = 0x1907;
+    public static final int GL_RGBA                                    = 0x1908;
+    public static final int GL_LUMINANCE                               = 0x1909;
+    public static final int GL_LUMINANCE_ALPHA                         = 0x190A;
+    public static final int GL_UNSIGNED_SHORT_4_4_4_4                  = 0x8033;
+    public static final int GL_UNSIGNED_SHORT_5_5_5_1                  = 0x8034;
+    public static final int GL_UNSIGNED_SHORT_5_6_5                    = 0x8363;
+    public static final int GL_FRAGMENT_SHADER                           = 0x8B30;
+    public static final int GL_VERTEX_SHADER                             = 0x8B31;
+    public static final int GL_MAX_VERTEX_ATTRIBS                        = 0x8869;
+    public static final int GL_MAX_VERTEX_UNIFORM_VECTORS                = 0x8DFB;
+    public static final int GL_MAX_VARYING_VECTORS                       = 0x8DFC;
+    public static final int GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS          = 0x8B4D;
+    public static final int GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS            = 0x8B4C;
+    public static final int GL_MAX_TEXTURE_IMAGE_UNITS                   = 0x8872;
+    public static final int GL_MAX_FRAGMENT_UNIFORM_VECTORS              = 0x8DFD;
+    public static final int GL_SHADER_TYPE                               = 0x8B4F;
+    public static final int GL_DELETE_STATUS                             = 0x8B80;
+    public static final int GL_LINK_STATUS                               = 0x8B82;
+    public static final int GL_VALIDATE_STATUS                           = 0x8B83;
+    public static final int GL_ATTACHED_SHADERS                          = 0x8B85;
+    public static final int GL_ACTIVE_UNIFORMS                           = 0x8B86;
+    public static final int GL_ACTIVE_UNIFORM_MAX_LENGTH                 = 0x8B87;
+    public static final int GL_ACTIVE_ATTRIBUTES                         = 0x8B89;
+    public static final int GL_ACTIVE_ATTRIBUTE_MAX_LENGTH               = 0x8B8A;
+    public static final int GL_SHADING_LANGUAGE_VERSION                  = 0x8B8C;
+    public static final int GL_CURRENT_PROGRAM                           = 0x8B8D;
+    public static final int GL_NEVER                                   = 0x0200;
+    public static final int GL_LESS                                    = 0x0201;
+    public static final int GL_EQUAL                                   = 0x0202;
+    public static final int GL_LEQUAL                                  = 0x0203;
+    public static final int GL_GREATER                                 = 0x0204;
+    public static final int GL_NOTEQUAL                                = 0x0205;
+    public static final int GL_GEQUAL                                  = 0x0206;
+    public static final int GL_ALWAYS                                  = 0x0207;
+    public static final int GL_KEEP                                    = 0x1E00;
+    public static final int GL_REPLACE                                 = 0x1E01;
+    public static final int GL_INCR                                    = 0x1E02;
+    public static final int GL_DECR                                    = 0x1E03;
+    public static final int GL_INVERT                                  = 0x150A;
+    public static final int GL_INCR_WRAP                               = 0x8507;
+    public static final int GL_DECR_WRAP                               = 0x8508;
+    public static final int GL_VENDOR                                  = 0x1F00;
+    public static final int GL_RENDERER                                = 0x1F01;
+    public static final int GL_VERSION                                 = 0x1F02;
+    public static final int GL_EXTENSIONS                              = 0x1F03;
+    public static final int GL_NEAREST                                 = 0x2600;
+    public static final int GL_LINEAR                                  = 0x2601;
+    public static final int GL_NEAREST_MIPMAP_NEAREST                  = 0x2700;
+    public static final int GL_LINEAR_MIPMAP_NEAREST                   = 0x2701;
+    public static final int GL_NEAREST_MIPMAP_LINEAR                   = 0x2702;
+    public static final int GL_LINEAR_MIPMAP_LINEAR                    = 0x2703;
+    public static final int GL_TEXTURE_MAG_FILTER                      = 0x2800;
+    public static final int GL_TEXTURE_MIN_FILTER                      = 0x2801;
+    public static final int GL_TEXTURE_WRAP_S                          = 0x2802;
+    public static final int GL_TEXTURE_WRAP_T                          = 0x2803;
+    public static final int GL_TEXTURE                                 = 0x1702;
+    public static final int GL_TEXTURE_CUBE_MAP                        = 0x8513;
+    public static final int GL_TEXTURE_BINDING_CUBE_MAP                = 0x8514;
+    public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_X             = 0x8515;
+    public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_X             = 0x8516;
+    public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Y             = 0x8517;
+    public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y             = 0x8518;
+    public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Z             = 0x8519;
+    public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z             = 0x851A;
+    public static final int GL_MAX_CUBE_MAP_TEXTURE_SIZE               = 0x851C;
+    public static final int GL_TEXTURE0                                = 0x84C0;
+    public static final int GL_TEXTURE1                                = 0x84C1;
+    public static final int GL_TEXTURE2                                = 0x84C2;
+    public static final int GL_TEXTURE3                                = 0x84C3;
+    public static final int GL_TEXTURE4                                = 0x84C4;
+    public static final int GL_TEXTURE5                                = 0x84C5;
+    public static final int GL_TEXTURE6                                = 0x84C6;
+    public static final int GL_TEXTURE7                                = 0x84C7;
+    public static final int GL_TEXTURE8                                = 0x84C8;
+    public static final int GL_TEXTURE9                                = 0x84C9;
+    public static final int GL_TEXTURE10                               = 0x84CA;
+    public static final int GL_TEXTURE11                               = 0x84CB;
+    public static final int GL_TEXTURE12                               = 0x84CC;
+    public static final int GL_TEXTURE13                               = 0x84CD;
+    public static final int GL_TEXTURE14                               = 0x84CE;
+    public static final int GL_TEXTURE15                               = 0x84CF;
+    public static final int GL_TEXTURE16                               = 0x84D0;
+    public static final int GL_TEXTURE17                               = 0x84D1;
+    public static final int GL_TEXTURE18                               = 0x84D2;
+    public static final int GL_TEXTURE19                               = 0x84D3;
+    public static final int GL_TEXTURE20                               = 0x84D4;
+    public static final int GL_TEXTURE21                               = 0x84D5;
+    public static final int GL_TEXTURE22                               = 0x84D6;
+    public static final int GL_TEXTURE23                               = 0x84D7;
+    public static final int GL_TEXTURE24                               = 0x84D8;
+    public static final int GL_TEXTURE25                               = 0x84D9;
+    public static final int GL_TEXTURE26                               = 0x84DA;
+    public static final int GL_TEXTURE27                               = 0x84DB;
+    public static final int GL_TEXTURE28                               = 0x84DC;
+    public static final int GL_TEXTURE29                               = 0x84DD;
+    public static final int GL_TEXTURE30                               = 0x84DE;
+    public static final int GL_TEXTURE31                               = 0x84DF;
+    public static final int GL_REPEAT                                  = 0x2901;
+    public static final int GL_CLAMP_TO_EDGE                           = 0x812F;
+    public static final int GL_MIRRORED_REPEAT                         = 0x8370;
+    public static final int GL_FLOAT_VEC2                              = 0x8B50;
+    public static final int GL_FLOAT_VEC3                              = 0x8B51;
+    public static final int GL_FLOAT_VEC4                              = 0x8B52;
+    public static final int GL_INT_VEC2                                = 0x8B53;
+    public static final int GL_INT_VEC3                                = 0x8B54;
+    public static final int GL_INT_VEC4                                = 0x8B55;
+    public static final int GL_BOOL                                    = 0x8B56;
+    public static final int GL_BOOL_VEC2                               = 0x8B57;
+    public static final int GL_BOOL_VEC3                               = 0x8B58;
+    public static final int GL_BOOL_VEC4                               = 0x8B59;
+    public static final int GL_FLOAT_MAT2                              = 0x8B5A;
+    public static final int GL_FLOAT_MAT3                              = 0x8B5B;
+    public static final int GL_FLOAT_MAT4                              = 0x8B5C;
+    public static final int GL_SAMPLER_2D                              = 0x8B5E;
+    public static final int GL_SAMPLER_CUBE                            = 0x8B60;
+    public static final int GL_VERTEX_ATTRIB_ARRAY_ENABLED                 = 0x8622;
+    public static final int GL_VERTEX_ATTRIB_ARRAY_SIZE                    = 0x8623;
+    public static final int GL_VERTEX_ATTRIB_ARRAY_STRIDE                  = 0x8624;
+    public static final int GL_VERTEX_ATTRIB_ARRAY_TYPE                    = 0x8625;
+    public static final int GL_VERTEX_ATTRIB_ARRAY_NORMALIZED              = 0x886A;
+    public static final int GL_VERTEX_ATTRIB_ARRAY_POINTER                 = 0x8645;
+    public static final int GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING          = 0x889F;
+    public static final int GL_IMPLEMENTATION_COLOR_READ_TYPE            = 0x8B9A;
+    public static final int GL_IMPLEMENTATION_COLOR_READ_FORMAT          = 0x8B9B;
+    public static final int GL_COMPILE_STATUS                          = 0x8B81;
+    public static final int GL_INFO_LOG_LENGTH                         = 0x8B84;
+    public static final int GL_SHADER_SOURCE_LENGTH                    = 0x8B88;
+    public static final int GL_SHADER_COMPILER                         = 0x8DFA;
+    public static final int GL_SHADER_BINARY_FORMATS                   = 0x8DF8;
+    public static final int GL_NUM_SHADER_BINARY_FORMATS               = 0x8DF9;
+    public static final int GL_LOW_FLOAT                               = 0x8DF0;
+    public static final int GL_MEDIUM_FLOAT                            = 0x8DF1;
+    public static final int GL_HIGH_FLOAT                              = 0x8DF2;
+    public static final int GL_LOW_INT                                 = 0x8DF3;
+    public static final int GL_MEDIUM_INT                              = 0x8DF4;
+    public static final int GL_HIGH_INT                                = 0x8DF5;
+    public static final int GL_FRAMEBUFFER                             = 0x8D40;
+    public static final int GL_RENDERBUFFER                            = 0x8D41;
+    public static final int GL_RGBA4                                   = 0x8056;
+    public static final int GL_RGB5_A1                                 = 0x8057;
+    public static final int GL_RGB565                                  = 0x8D62;
+    public static final int GL_DEPTH_COMPONENT16                       = 0x81A5;
+    public static final int GL_STENCIL_INDEX                           = 0x1901;
+    public static final int GL_STENCIL_INDEX8                          = 0x8D48;
+    public static final int GL_RENDERBUFFER_WIDTH                      = 0x8D42;
+    public static final int GL_RENDERBUFFER_HEIGHT                     = 0x8D43;
+    public static final int GL_RENDERBUFFER_INTERNAL_FORMAT            = 0x8D44;
+    public static final int GL_RENDERBUFFER_RED_SIZE                   = 0x8D50;
+    public static final int GL_RENDERBUFFER_GREEN_SIZE                 = 0x8D51;
+    public static final int GL_RENDERBUFFER_BLUE_SIZE                  = 0x8D52;
+    public static final int GL_RENDERBUFFER_ALPHA_SIZE                 = 0x8D53;
+    public static final int GL_RENDERBUFFER_DEPTH_SIZE                 = 0x8D54;
+    public static final int GL_RENDERBUFFER_STENCIL_SIZE               = 0x8D55;
+    public static final int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE      = 0x8CD0;
+    public static final int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME      = 0x8CD1;
+    public static final int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL    = 0x8CD2;
+    public static final int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3;
+    public static final int GL_COLOR_ATTACHMENT0                       = 0x8CE0;
+    public static final int GL_DEPTH_ATTACHMENT                        = 0x8D00;
+    public static final int GL_STENCIL_ATTACHMENT                      = 0x8D20;
+    public static final int GL_NONE                                    = 0;
+    public static final int GL_FRAMEBUFFER_COMPLETE                    = 0x8CD5;
+    public static final int GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT       = 0x8CD6;
+    public static final int GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT          = 0x8CD7;
+    public static final int GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS       = 0x8CD9;
+    public static final int GL_FRAMEBUFFER_UNSUPPORTED                 = 0x8CDD;
+    public static final int GL_FRAMEBUFFER_BINDING                     = 0x8CA6;
+    public static final int GL_RENDERBUFFER_BINDING                    = 0x8CA7;
+    public static final int GL_MAX_RENDERBUFFER_SIZE                   = 0x84E8;
+    public static final int GL_INVALID_FRAMEBUFFER_OPERATION           = 0x0506;
+
+    native private static void _nativeClassInit();
+    static {
+	    _nativeClassInit();
+    }
diff --git a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
new file mode 100644
index 0000000..e451e9a
--- /dev/null
+++ b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
@@ -0,0 +1,150 @@
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+// This source file is automatically generated
+
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/misc.h>
+
+#include <assert.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+static int initialized = 0;
+
+static jclass nioAccessClass;
+static jclass bufferClass;
+static jclass OOMEClass;
+static jclass UOEClass;
+static jclass IAEClass;
+static jclass AIOOBEClass;
+static jmethodID getBasePointerID;
+static jmethodID getBaseArrayID;
+static jmethodID getBaseArrayOffsetID;
+static jfieldID positionID;
+static jfieldID limitID;
+static jfieldID elementSizeShiftID;
+
+/* Cache method IDs each time the class is loaded. */
+
+static void
+nativeClassInitBuffer(JNIEnv *_env)
+{
+    jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
+    nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
+
+    jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
+    bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
+
+    getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
+            "getBasePointer", "(Ljava/nio/Buffer;)J");
+    getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
+            "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
+    getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
+            "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
+
+    positionID = _env->GetFieldID(bufferClass, "position", "I");
+    limitID = _env->GetFieldID(bufferClass, "limit", "I");
+    elementSizeShiftID =
+        _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
+}
+
+
+static void
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
+{
+    nativeClassInitBuffer(_env);
+
+    jclass IAEClassLocal =
+        _env->FindClass("java/lang/IllegalArgumentException");
+    jclass OOMEClassLocal =
+         _env->FindClass("java/lang/OutOfMemoryError");
+    jclass UOEClassLocal =
+         _env->FindClass("java/lang/UnsupportedOperationException");
+    jclass AIOOBEClassLocal =
+         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
+
+    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
+    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
+    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
+    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
+}
+
+static void *
+getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
+{
+    jint position;
+    jint limit;
+    jint elementSizeShift;
+    jlong pointer;
+    jint offset;
+    void *data;
+
+    position = _env->GetIntField(buffer, positionID);
+    limit = _env->GetIntField(buffer, limitID);
+    elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+    *remaining = (limit - position) << elementSizeShift;
+    pointer = _env->CallStaticLongMethod(nioAccessClass,
+            getBasePointerID, buffer);
+    if (pointer != 0L) {
+        *array = NULL;
+        return (void *) (jint) pointer;
+    }
+    
+    *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
+            getBaseArrayID, buffer);
+    offset = _env->CallStaticIntMethod(nioAccessClass,
+            getBaseArrayOffsetID, buffer);
+    data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
+    
+    return (void *) ((char *) data + offset);
+}
+
+
+static void
+releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
+{
+    _env->ReleasePrimitiveArrayCritical(array, data,
+					   commit ? 0 : JNI_ABORT);
+}
+
+static void *
+getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
+    char* buf = (char*) _env->GetDirectBufferAddress(buffer);
+    if (buf) {
+        jint position = _env->GetIntField(buffer, positionID);
+        jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+        buf += position << elementSizeShift;
+    } else {
+        _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+    }
+    return (void*) buf;
+}
+
+static int
+getNumCompressedTextureFormats() {
+    int numCompressedTextureFormats = 0;
+    glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numCompressedTextureFormats);
+    return numCompressedTextureFormats;
+}
+
+static void glVertexAttribPointerBounds(GLuint indx, GLint size, GLenum type,
+        GLboolean normalized, GLsizei stride, const GLvoid *pointer, GLsizei count) {
+    glVertexAttribPointer(indx, size, type, normalized, stride, pointer);
+}
+
+// --------------------------------------------------------------------------
+
diff --git a/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp b/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp
new file mode 100644
index 0000000..d92f515
--- /dev/null
+++ b/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp
@@ -0,0 +1,27 @@
+#include <string.h>
+
+/* void glGetProgramInfoLog ( GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog ) */
+static
+jstring
+android_glGetProgramInfoLog (JNIEnv *_env, jobject _this, jint shader) {
+    GLint infoLen = 0;
+    jstring _result = 0;
+    char* buf = 0;
+    glGetProgramiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+    if (infoLen) {
+        char* buf = (char*) malloc(infoLen);
+        if (buf == 0) {
+            _env->ThrowNew(IAEClass, "out of memory");
+            goto exit;
+        }
+        glGetProgramInfoLog(shader, infoLen, NULL, buf);
+        _result = _env->NewStringUTF(buf);
+    } else {
+        _result = _env->NewStringUTF("");
+    }
+exit:
+    if (buf) {
+            free(buf);
+    }
+    return _result;
+}
\ No newline at end of file
diff --git a/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.java b/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.java
new file mode 100644
index 0000000..19504f2
--- /dev/null
+++ b/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.java
@@ -0,0 +1,6 @@
+    // C function void glGetProgramInfoLog( GLuint program, GLsizei maxLength, GLsizei * length,
+ 	//     GLchar * infoLog);
+
+    public static native String glGetProgramInfoLog(
+        int program
+    );
diff --git a/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.nativeReg b/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.nativeReg
new file mode 100644
index 0000000..8553f2d
--- /dev/null
+++ b/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.nativeReg
@@ -0,0 +1 @@
+{"glGetProgramInfoLog", "(I)Ljava/lang/String;", (void *) android_glGetProgramInfoLog },
diff --git a/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp b/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp
new file mode 100644
index 0000000..5441d66
--- /dev/null
+++ b/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp
@@ -0,0 +1,27 @@
+#include <string.h>
+
+/* void glGetShaderInfoLog ( GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog ) */
+static
+jstring
+android_glGetShaderInfoLog (JNIEnv *_env, jobject _this, jint shader) {
+    GLint infoLen = 0;
+    jstring _result = 0;
+    char* buf = 0;
+    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+    if (infoLen) {
+        char* buf = (char*) malloc(infoLen);
+        if (buf == 0) {
+            _env->ThrowNew(IAEClass, "out of memory");
+            goto exit;
+        }
+        glGetShaderInfoLog(shader, infoLen, NULL, buf);
+        _result = _env->NewStringUTF(buf);
+    } else {
+        _result = _env->NewStringUTF("");
+    }
+exit:
+    if (buf) {
+            free(buf);
+    }
+    return _result;
+}
\ No newline at end of file
diff --git a/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.java b/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.java
new file mode 100644
index 0000000..1fac6be
--- /dev/null
+++ b/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.java
@@ -0,0 +1,6 @@
+    // C function void glGetShaderInfoLog( GLuint shader, GLsizei maxLength, GLsizei * length,
+ 	//     GLchar * infoLog);
+
+    public static native String glGetShaderInfoLog(
+        int shader
+    );
diff --git a/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.nativeReg b/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.nativeReg
new file mode 100644
index 0000000..71163c3
--- /dev/null
+++ b/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.nativeReg
@@ -0,0 +1 @@
+{"glGetShaderInfoLog", "(I)Ljava/lang/String;", (void *) android_glGetShaderInfoLog },
diff --git a/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp b/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp
new file mode 100644
index 0000000..c274108
--- /dev/null
+++ b/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp
@@ -0,0 +1,17 @@
+
+/* void glShaderSource ( GLuint shader, GLsizei count, const GLchar ** string, const GLint * length ) */
+static
+void
+android_glShaderSource
+    (JNIEnv *_env, jobject _this, jint shader, jstring string) {
+
+    if (!string) {
+        _env->ThrowNew(IAEClass, "string == null");
+        return;
+    }
+
+    const char* nativeString = _env->GetStringUTFChars(string, 0);
+    const char* strings[] = {nativeString};
+    glShaderSource(shader, 1, strings, 0);
+    _env->ReleaseStringUTFChars(string, nativeString);
+}
diff --git a/opengl/tools/glgen/stubs/gles11/glShaderSource.java b/opengl/tools/glgen/stubs/gles11/glShaderSource.java
new file mode 100644
index 0000000..a9c338a
--- /dev/null
+++ b/opengl/tools/glgen/stubs/gles11/glShaderSource.java
@@ -0,0 +1,6 @@
+    // C function void glShaderSource ( GLuint shader, GLsizei count, const GLchar ** string, const GLint* length )
+
+    public static native void glShaderSource(
+        int shader,
+        String string
+    );
diff --git a/opengl/tools/glgen/stubs/gles11/glShaderSource.nativeReg b/opengl/tools/glgen/stubs/gles11/glShaderSource.nativeReg
new file mode 100644
index 0000000..b17783a
--- /dev/null
+++ b/opengl/tools/glgen/stubs/gles11/glShaderSource.nativeReg
@@ -0,0 +1 @@
+{"glShaderSource", "(ILjava/lang/String;)V", (void *) android_glShaderSource },
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index 4494643..b3d1c6c 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -34,6 +34,12 @@
         GLsizei stride, const GLvoid *pointer, GLsizei count);
 GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type,
         GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glPointSizePointerOESBounds(GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glMatrixIndexPointerOESBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
 }
 
 static int initialized = 0;
diff --git a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
index fe60c5d..76fea3f 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
+++ b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
@@ -44,6 +44,9 @@
     Buffer _normalPointer = null;
     Buffer _texCoordPointer = null;
     Buffer _vertexPointer = null;
+    Buffer _pointSizePointerOES = null;
+    Buffer _matrixIndexPointerOES = null;
+    Buffer _weightPointerOES = null;
 
     public GLImpl() {
     }
diff --git a/vpn/java/android/net/vpn/VpnManager.java b/vpn/java/android/net/vpn/VpnManager.java
index 6df612e..ce40b5d 100644
--- a/vpn/java/android/net/vpn/VpnManager.java
+++ b/vpn/java/android/net/vpn/VpnManager.java
@@ -16,11 +16,15 @@
 
 package android.net.vpn;
 
+import java.io.File;
+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.os.Environment;
+import android.os.SystemProperties;
 import android.util.Log;
 
 /**
@@ -65,7 +69,7 @@
     /** Error code to indicate a successful connection. */
     public static final int VPN_ERROR_NO_ERROR = 0;
 
-    public static final String PROFILES_PATH = "/data/misc/vpn/profiles";
+    public static final String PROFILES_PATH = "/misc/vpn/profiles";
 
     private static final String PACKAGE_PREFIX =
             VpnManager.class.getPackage().getName() + ".";
@@ -77,7 +81,13 @@
     private static final String ACTION_VPN_SETTINGS =
             PACKAGE_PREFIX + "SETTINGS";
 
-    private static final String TAG = VpnManager.class.getSimpleName();
+    public static final String TAG = VpnManager.class.getSimpleName();
+
+    // TODO(oam): Test VPN when EFS is enabled (will do later)...
+    public static String getProfilePath() {
+        // This call will return the correct path if Encrypted FS is enabled or not.
+        return Environment.getSecureDataDirectory().getPath() + PROFILES_PATH;
+    }
 
     /**
      * Returns all supported VPN types.