am 47f1d4d5: am b1780474: Merge "Instead of caputre the memory footprint before and after the test. We would like to monitor the memory trend while the test is running. This can eliminate the overhead for the frist test case in creating the player." into eclair

Merge commit '47f1d4d509b271ddb2f158c761e572413f39f1a8'

* commit '47f1d4d509b271ddb2f158c761e572413f39f1a8':
  Instead of caputre the memory footprint before and after the test. We would like to monitor the memory trend while the test is running. This can eliminate the overhead for the frist test case in creating the player.
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..81d60dc 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
@@ -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..055dbca
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyManagerBase.cpp
@@ -0,0 +1,1925 @@
+/*
+ * 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.