From 9d29be7f7249789d6ffd0440067187a9f040c2cd Mon Sep 17 00:00:00 2001
From: huangcm <1263938474@qq.com>
Date: Wed, 18 Dec 2024 03:25:06 +0000
Subject: [PATCH] feat(4g): Compatible with ec20 and ec200

---
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61eb                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0622                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1307_1169                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_f00e                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea17                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_f00f                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9800                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1782_0003                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0627                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_060c                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5010                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7361                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1597                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_c100                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2015_0001                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_c031                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_9000                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.tcl                          | 1015 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0632                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d357                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-subcmd.h                                           |   92 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/201e_2009                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/make-load-static-exts.tcl               |   48 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-subcmd.c                                           |  293 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7111                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8200                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0637                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8201                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_061d                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/057c_62ff                  |    7 
 android/external/usb_modeswitch/usb_modeswitch/jim/make-bootstrap-jim                                     |  104 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2077_f000                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7051                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_101e                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/Makefile                                                   |  105 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_002a                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/make-index                              |   70 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-interactive.c                       |  137 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-array.c                                            |  274 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_f000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1031                                 |    7 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1030                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_c700                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9017                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1de1_1101                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-package.c                                          |  259 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9013                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9bfe                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9011                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/Android.mk                                                 |   21 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.conf                         |   31 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_0010                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1a8d_1000                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1782_0023                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_062c                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_1000                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7381                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fd1_1000                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1b7d_0700                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/COPYING                                                    |  340 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0304                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1dd6_1000                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch@.service                     |    8 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0318                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61dd                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/config.guess                                 | 1508 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=AnyDATA      |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/Makefile                                    |  105 
 android/external/usb_modeswitch/usb_modeswitch/ChangeLog                                                  |  288 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=DGT                         |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7271                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1033_0035                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61e7                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7031                                 |    5 
 android/external/usb_modeswitch/usb_dongle/NetlinkManager.h                                               |   48 
 android/external/usb_modeswitch/usb_modeswitch/jim/jimregexp.h                                            |  117 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20a6_f00a                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_dongle/MiscManager.cpp                                 |   89 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61aa                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/Makefile.in                             |  198 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/10a9_606f                                 |    7 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15bb                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/jim/jimregexp.c                                            | 1756 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9d00                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15d0                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20a6_f00e                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/201e_1023                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1076_7f40                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5055                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15c1                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/10a9_6080                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5059                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0325                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_00a6                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/ChangeLog                                   |  288 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d157                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_581d                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15c0                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8006                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1e0e_f000                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d001                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901f                  |    4 
 android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/ip-up                               |    0 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901c                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5041                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1420                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901b                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d155                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.tcl                                         | 1015 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_022c                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/clemens.txt                                    |   87 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6803                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/jim/make-load-static-exts.tcl                              |   48 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6804                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9053                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15f0                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9051                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Option                      |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/auto.def                                |  436 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-win32compat.h                                      |   69 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15e7                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5031                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ab7_5700                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5030                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_9a1d                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1237                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0103                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0101                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15cf                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15ce                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/README                                                     |  271 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0610                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15ca                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_2000                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2077_1000                  |    4 
 android/external/usb_modeswitch/usb_dongle/G3Dev.cpp                                                      |  206 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15cd                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1da1                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_2001                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9041                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0618                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5023                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/057c_84ff                  |    7 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5020                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0110                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15d2                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7071                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0115                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_6000                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1201                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1207                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/pat.txt                         |   84 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_6503                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8304                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1449                                 |    4 
 android/external/usb_modeswitch/usb_dongle/MiscManager.cpp                                                |   89 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1446                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1dbc_0669                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/CleanSpec.mk                                               |   53 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_1001                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-format.c                            |  433 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f19                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0bdb_1910                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1210                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0120                                 |    7 
 android/device/softwinner/common/sepolicy/vendor/rild.te                                                  |   56 
 android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libreference-ril-ndk.so                     |    0 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1219                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1216                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-readline.c                                         |   61 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_4007                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_151a                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_226e                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_226f                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c7_1000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8600                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9063                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/salvatore.txt                                  |   88 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0bdb_190d                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_531d                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_631d                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1520                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20b9_1682                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1521                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1225                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1b                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1edf_6003                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1523                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1526                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1d                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1224                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1c                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8302                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1527                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1e                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7211                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1227                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8300                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c1b                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_0002                                 |    4 
 android/vendor/aw/public/prebuild/lib/librild/radio_common.mk                                             |  122 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7301                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/Android.mk                                  |   21 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_607f                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_521d                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c24                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1232                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c25                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1233                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/tclcompat.tcl                                          |  279 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_00ca                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/uwe.txt                         |   73 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-sdl.c                                              |  234 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1237                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0146                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0388                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0149                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1238                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0930_0d46                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d103                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1003                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-clock.c                                            |  159 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c0b                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1001                                 |    8 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_sVe=Option       |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/jimsh.c                                                |  111 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-nvp.h                                              |  275 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6190                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/LICENSE                                 |   45 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-nvp.c                                              |  338 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1007                                 |    6 
 android/external/usb_modeswitch/usb_dongle/Misc.h                                                         |   43 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0150                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0154                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1001                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/jim/make-c-ext.tcl                                         |   38 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1009                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1a8d_2000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1007                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_f000_sMo=U209         |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1009                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1003                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b14                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/jim/tree.tcl                                               |  219 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1553                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0166                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1013                                 |    6 
 android/external/usb_modeswitch/usb_dongle/NetlinkManager.cpp                                             |  113 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_613f                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0169                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1557                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_9200                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1017                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/rlprompt.tcl                            |   45 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1001                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_613a                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1019                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_155a                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/072f_100d                                 |    7 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_#android              |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_155b                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b03                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b05                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7311                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8400                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_541d                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b06                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/regtest.tcl                                            |  158 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1020                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1046                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/initjimsh.tcl                           |   27 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f000_uMa=Yota                        |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch_dispatcher.1                 |   21 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0198                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1042                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b11                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1022                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7011                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7251                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1026                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04bb_bccd                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/stdlib.tcl                              |  150 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_156a                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-readline.c                          |   61 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0ace_20ff                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/oharboe.txt                     |   85 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_689a                  |    6 
 android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/ip-down                             |    0 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1580                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7a01                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1030                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1571                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/make-c-ext.tcl                          |   38 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1570                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1038                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1573                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7a05                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1572                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1034                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1034                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1038                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_bccd                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1726_f00e                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1030                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/COPYING                                     |  340 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_a000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_681d                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1d50                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6156                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_157c                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_157d                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1019                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1017                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1582                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1026                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1042                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_614e                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1581                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_#linux                |    7 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1583                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0198                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1022                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d5_f000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1046                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1020                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1010                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8700                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7801                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6951                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6711                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1009                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1007                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0166                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1171                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0169                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1013                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Vertex       |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0130                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1175                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jimsh.c                                 |  111 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1179                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6771                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_98ff                                 |    4 
 android/hardware/ril/libril/Android.mk                                                                    |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f000                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-array.c                             |  274 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7601                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_98ff                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/jim/AUTHORS                                                |   41 
 android/external/usb_modeswitch/usb_modeswitch/usb_dongle/Misc.h                                          |   43 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000d                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0149                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1021                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_b000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1237                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1238                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1001                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0154                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000c                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000b                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/jim/make-index                                             |   70 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0150                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1f28_0021                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_d000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22de_6801                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1505                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04fc_2140                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1614_0802                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-win32compat.h                       |   69 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/046d_c261                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1614_0800                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22de_6803                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6731                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6971                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1227                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f03                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f04                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1025                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f01                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1233                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f02                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0146                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0388                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1232                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/21f5_1000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f09                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0007                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6751                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f07                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f05                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f06                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6731                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0001                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/jim/README.usb_modeswitch                                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_9020                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0ace_2011                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0003                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1edf_6003                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-syslog.c                                           |  190 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8900                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Vertex                      |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1219                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1f28_0021                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1216                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1224                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1225                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20b9_1682                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6281                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_6061_uPr=Storage      |    3 
 android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/cc-shared.tcl                                |   63 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1d                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1e                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1527                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1b                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1526                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1c                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1521                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1520                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1523                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7601                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_dongle/NetlinkHandler.h                                |   34 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_98ff                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb-modeswitch-upstart.conf                                |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/README                                      |  271 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0115                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1207                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6751                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f000                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0130                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/21f5_3010                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_631d                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_680c                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/jimautoconf.h.in                                       |  145 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1210                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0120                  |    7 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a401                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1003                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a403                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1001                  |    8 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a405                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1007                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Co.,Ltd      |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a407                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a406                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-config.h.in                         |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-readdir.c                           |  119 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f010                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f15                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1201                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f11                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0110                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f18                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f19                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f16                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f17                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/find-tclsh                    |   17 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_9020                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a40a                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f01                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f03                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/config.sub                    | 1739 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-syslog.c                            |  190 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f02                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/andrew.txt                                     |   65 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6771                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f05                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_98ff                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a40d                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f04                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f07                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f06                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0151                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0101                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_dongle/Misc.cpp                                        |   69 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0103                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-config.h.in                                        |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0150                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-eventloop.c                         |  760 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-eventloop.h                         |   87 
 android/external/usb_modeswitch/usb_modeswitch/usb_dongle/usb_dongle.rc                                   |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6791                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0151                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0150                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7401                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_1001                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-aio.c                               | 1353 
 android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/apns-full-conf.xml                        | 35501 ++++++++++++++++
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_680c                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/046d_c261                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_0002_uPr=Product      |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f11                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8700                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f16                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0325                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f15                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f18                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f17                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f010                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f09                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1420                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_521d                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_151a                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1e0e_f000                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1505                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15c1                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15c0                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5041                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/duane.txt                                      |   65 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0318                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/21f5_3010                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_#android                             |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-signal.c                            |  514 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d033                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d031                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9101                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea43                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d035                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-signal.h                            |   24 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2262_0001                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_7600                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15d0                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15d2                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6911                                 |    5 
 android/external/usb_modeswitch/usb_dongle/main.cpp                                                       |  139 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1de1_1101                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2357_0200                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5055                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5059                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_sVe=Option                      |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0304                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0007                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_6000                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/ed09_1021                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0003                                 |    2 
 android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libril-an10.so                              |    0 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0001                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15bb                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0ace_2011                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_9a1d                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000c                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0df7_0800                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000d                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000b                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15e7                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5023                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5020                  |    4 
 android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/manifest.xml                              |   12 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-clock.c                             |  159 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea25                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d257                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15ca                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d013                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d255                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1da1                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15ce                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15cd                  |    4 
 android/external/usb_modeswitch/usb_dongle/MiscManager.h                                                  |   57 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/109b_f009                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-subcmd.c                            |  293 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15cf                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fca_8020                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/configure                                              |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-subcmd.h                            |   92 
 android/hardware/ril/rild/Android.mk                                                                      |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_dongle/Android.mk                                      |   47 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-package.c                           |  259 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15f0                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9d00                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_025e                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5030                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_9024                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d058                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_022c                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5031                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_c700                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d057                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d055                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_7001                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/pat.txt                                        |   84 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_000f                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8900                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/linenoise.c                             | 1379 
 android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/autosetup                                    | 1820 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6911                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/linenoise.h                             |   62 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1210_uMa=Philips      |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/utf8.c                                  |  192 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=SAMSUNG      |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_7600                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/ed09_1021                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/utf8.h                                  |  110 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2262_0001                                 |    4 
 android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/chat                                |    0 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a805                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_d000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0df                  |    2 
 android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libreference-ril-ndk.so                     |    0 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f000_uMa=USB_Modem    |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6971                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/system.tcl                    |  268 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6711                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7801                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9011                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/stdlib.tcl                                             |  150 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6951                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/jim/README                                                 |  235 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9013                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0e1                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9017                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_000f                  |    4 
 android/external/usb_modeswitch/usb_dongle/G3Dev.h                                                        |   38 
 android/vendor/aw/public/prebuild/lib/librild/libquecte/Android.mk                                        |   43 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea43                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea17                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/cc-shared.tcl                 |   63 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f000_uMa=Yota         |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0cf                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/109b_f009                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/23a2_1010                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0e1                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_9024                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6281                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0cf                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_025e                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_7001                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1b7d_0700                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a80b                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d055                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/198f_bccd                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9101                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_0010                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/23a2_1010                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d057                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d058                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jimregexp.h                             |  117 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/198f_bccd                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=StrongRising                |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a80b                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2357_0200                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jimregexp.c                             | 1756 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0df                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0df7_0800                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fca_8020                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/cc.tcl                        |  660 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a805                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-format.c                                           |  433 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea25                                 |    4 
 android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libril-an12.so                              |    0 
 android/external/usb_modeswitch/usb_modeswitch/jim/bootstrap.tcl                                          |    3 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-regexp.c                                           |  566 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9041                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_00a6                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/autosetup                     | 1820 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b11                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/tclcompat.tcl                           |  279 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b14                  |    6 
 android/external/usb_modeswitch/usb_dongle/NetlinkHandler.h                                               |   34 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb-modeswitch-upstart.conf                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=CELOT        |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d001                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20a6_f00a                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7a05                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/201e_1023                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1076_7f40                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20a6_f00e                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7a01                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9053                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22f4_0021                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=SAMSUNG                     |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.conf                                        |   31 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1a8d_2000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d103                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1001                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1003                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/057c_84ff                                 |    7 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-nvp.h                               |  275 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-nvp.c                               |  338 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1009                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9051                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0413                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2077_1000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/README.autosetup                             |    1 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-aio.c                                              | 1353 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1517                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_681d                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0083_uPr=WCDMA                       |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_98ff                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-file.c                              |  929 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jimautoconf.h.in                        |  145 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_9200                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1010                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_0002                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6804                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/configure.ac                            |    1 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6803                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1511                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/parse-unidata.tcl                                      |   64 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1514                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1528                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61aa                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_101e                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_f000                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1030                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim.h                                   |  917 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7011                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7251                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b03                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/057c_62ff                                 |    7 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901c                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901b                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim.c                                   | 14478 ++++++
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_#linux                               |    7 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1523                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1520                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901f                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8006                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_581d                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b05                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b06                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/dispatcher.c                                |   88 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0632                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_226f                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-pack.c                              |  380 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_226e                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_061d                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1031                  |    7 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d357                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_002a                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0627                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1536                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_225c                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1782_0003                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0622                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9bfe                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/config.sub                                   | 1739 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_f000_sMo=U209                        |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_060c                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5010                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/initjimsh.tcl                                          |   27 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7031                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_c031                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_2001                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_2000                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7271                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_dongle/MiscManager.h                                   |   57 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2015_0001                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d035                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d033                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1542                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/regtest.tcl                             |  158 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d031                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0618                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9063                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_dongle/NetlinkHandler.cpp                              |   59 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14ba                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/clemens.txt                     |   87 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9e00                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14d1                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9e08                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_2251                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_9000                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/config.guess                  | 1508 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a40a                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c3                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c5                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c4                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9401                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-posix.c                             |  231 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/make-bootstrap-jim                      |  104 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a40d                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1782_0023                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14ad                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a401                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/uwe.txt                                        |   73 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d257                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_f000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a407                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c1                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_062c                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a403                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1dd6_1000                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a406                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a405                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c7_1000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14b5                                 |    4 
 longan/kernel/linux-4.9/drivers/usb/serial/option.c                                                       |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14b7                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7051                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/jim/linenoise.c                                            | 1379 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0637                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d013                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d255                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/jim/linenoise.h                                            |   62 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/AUTHORS                                 |   41 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1210_uMa=Wisue        |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_380b                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_155b                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7401                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_155a                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6791                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_#linux                               |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1726_f00e                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0003                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1a8d_1000                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1557                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/10a9_606f                  |    7 
 android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/call-pppd                           |   34 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1553                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/10a9_6080                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-regexp.c                            |  566 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_6503                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1580                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/15eb_7153                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1588                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_0002_uPr=MT           |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_0002_uPr=MT                          |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_bccd                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/072f_100d                  |    7 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d5_f000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0610                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_157d                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1d50                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_157c                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_641d                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1237                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1595                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/201e_2009                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1583                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0026                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1414                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1582                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1413                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1025                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0266                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/LICENSE                                      |   35 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_f00e                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_607f                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1021                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1581                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1580                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1307_1169                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ab7_5700                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_156a                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_531d                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_541d                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-interactive.c                                      |  137 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1572                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1571                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_b000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1573                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2077_f000                                 |    5 
 android/external/usb_modeswitch/usb_dongle/usb_dongle.rc                                                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8400                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1570                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7311                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/duane.txt                       |   65 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/cc-lib.tcl                    |   77 
 android/external/usb_modeswitch/usb_modeswitch/usb_dongle/main.cpp                                        |  139 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-readdir.c                                          |  119 
 android/external/usb_modeswitch/usb_modeswitch/jim/utf8.h                                                 |  110 
 android/external/usb_modeswitch/usb_modeswitch/usb_dongle/G3Dev.cpp                                       |  206 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_a000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_a804                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0040                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1033_0035                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1179                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7381                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=DGT          |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1175                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6190                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1171                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/jim/utf8.c                                                 |  192 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/README                                  |  235 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_689a                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_f00f                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1597                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04fc_2140                  |    4 
 android/external/usb_modeswitch/CleanSpec.mk                                                              |   53 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-sdl.c                               |  234 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0930_0d46                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0d46_45a5                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_a800                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/tcl.license.terms                                      |   40 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0053                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04bb_bccd                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_c100                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1446                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1449                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0d46_45a1                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_0fff                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.1                            |  172 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-load.c                                             |  126 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_00ca                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f000_uMa=USB_Modem                   |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c24                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c25                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/jim/Makefile.in                                            |  198 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_2004                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c0b                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_2000                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_2000                  |    5 
 android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libril-an10.so                              |    0 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22de_6803                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/cc.tcl                                       |  660 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1210_uMa=Philips                     |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0ace_20ff                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7361                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_2004                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_f000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9800                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fd1_1000                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1614_0802                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22de_6801                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1614_0800                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8304                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8302                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7211                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8300                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.c                            | 2095 
 android/external/usb_modeswitch/usb_dongle/Misc.cpp                                                       |   69 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0053                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.h                            |  116 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/21f5_1000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c1b                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8200                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7111                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8201                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_dongle/G3Dev.h                                         |   38 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6156                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/8888_6500                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_#linux                |    3 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-signal.c                                           |  514 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/test-tclsh                    |   20 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_a804                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_931d                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_613a                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f052                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-signal.h                                           |   24 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_613f                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Co.,Ltd                     |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0040                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/system.tcl                                   |  268 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_ffe6                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/glob.tcl                                |  129 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_a800                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1e89_f000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/README.autosetup              |    1 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/andrew.txt                      |   65 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/README.usb_modeswitch                   |    6 
 android/external/usb_modeswitch/usb_modeswitch/jim/auto.def                                               |  436 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/tree.tcl                                |  219 
 android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libreference-ril-an12.so                    |    0 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_614e                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1805                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2357_f000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0060                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_700b                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8800                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_700a                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7706                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0063                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1266_1000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f000                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0068                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7701                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0d46_45a1                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_0fff                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0266                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1da5_f000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0026                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1595                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0d46_45a5                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/rlprompt.tcl                                           |   45 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.sh                           |   72 
 android/external/usb_modeswitch/usb_modeswitch/usb_dongle/NetlinkManager.h                                |   48 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7701                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7706                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-file.c                                             |  929 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0482_024d                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f017                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2357_f000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_ffde                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_f000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/6000_1000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1588                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f00c                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_610c                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1580                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_fff6                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_fff5                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-exec.c                              | 1619 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0040                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.1                                           |  172 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0048                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0045                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_380b                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0003                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_2251                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_c000                                 |    4 
 android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libril-an12.so                              |    0 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0083_uPr=WCDMA        |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/LICENSE                                                |   45 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7301                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8800                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/make_string.tcl                             |   31 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_ffe6                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0054                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1210_uMa=Wisue                       |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_004a                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=CELOT                       |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1266_1000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_610c                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1dbc_0669                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_6061_uPr=Storage                     |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_1000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_004f                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/6000_1000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_ffde                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_4007                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_0002_uPr=Product                     |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/parse-unidata.tcl                       |   64 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_225c                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=StrongRising |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7501                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/15eb_7153                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_fff6                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_fff5                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_c000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_641d                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0032                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0032                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_7109                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6327                  |    4 
 android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libreference-ril-an10.so                    |    0 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0685_2000                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1414                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7501                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/LICENSE                       |   35 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1413                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0060                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0bdb_1910                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_004a                                 |    4 
 android/external/usb_modeswitch/usb_dongle/NetlinkHandler.cpp                                             |   59 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1536                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_004f                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/jim/configure.ac                                           |    1 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1542                  |    4 
 android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libreference-ril-an10.so                    |    0 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0063                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8600                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0068                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/tcl.license.terms                       |   40 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0bdb_190d                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f017                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0003                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1528                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/198a_0003                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1523                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d155                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9401                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-posix.c                                            |  231 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_sVe=GT           |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0007                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1726_1900                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/148f_2578                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d157                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0009                  |    5 
 android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/ql-ril.conf                         |   42 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9e08                  |    6 
 android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libreference-ril-an12.so                    |    0 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0054                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_011f                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9e00                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/bootstrap.tcl                           |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_911d                  |    2 
 android/external/usb_modeswitch/usb_dongle/Android.mk                                                     |   47 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14b5                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0013                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14b7                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6327                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1517                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1514                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0048                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f00c                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_7109                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1520                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0018                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7071                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0040                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/make_string.tcl                                            |   31 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0045                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14fe                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c1                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c4                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c3                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=SSE          |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c5                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.h                                           |  116 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0413                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1511                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9200                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.c                                           | 2095 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14ad                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/dispatcher.c                                               |   88 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0685_2000                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14d1                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f001                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-exec.c                                             | 1619 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f000                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_sVe=GT                          |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/148e_a000                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f017                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_1000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14ba                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/find-tclsh                                   |   17 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0cf3_20ff                                 |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/salvatore.txt                   |   88 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-pack.c                                             |  380 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_f000                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61dd                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f017                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=AnyDATA                     |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-eventloop.h                                        |   87 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=SSE                         |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22f4_0021                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_011f                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1805                                 |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9200                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.sh                                          |   72 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0482_024d                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0018                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_911d                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0103                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim-eventloop.c                                        |  760 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0013                                 |    5 
 android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/dhcpcd                              |    0 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim.h                                                  |  917 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_1000                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/test-tclsh                                   |   20 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0101                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1726_1900                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/8888_6500                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a707                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a706                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1e89_f000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61e7                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0003                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0cf3_20ff                  |    6 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0007                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a708                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0009                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_931d                  |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f000                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch@.service                                    |    8 
 android/external/usb_modeswitch/usb_modeswitch/jim/glob.tcl                                               |  129 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/198a_0003                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f001                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/148e_a000                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6811                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Option       |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7901                  |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_dongle/NetlinkManager.cpp                              |  113 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/configure                               |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a706                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a708                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a707                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/jim.c                                                  | 14478 ++++++
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_98ff                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6811                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-load.c                              |  126 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f052                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7901                                 |    5 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_700a                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch_dispatcher.1                                |   21 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_700b                  |    3 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61eb                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/oharboe.txt                                    |   85 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14fe                  |    4 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0103                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1da5_f000                                 |    4 
 android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/cc-lib.tcl                                   |   77 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0101                                 |    2 
 android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/148f_2578                                 |    6 
 1,188 files changed, 126,836 insertions(+), 18 deletions(-)

diff --git a/android/device/softwinner/common/sepolicy/vendor/rild.te b/android/device/softwinner/common/sepolicy/vendor/rild.te
index 8fdddc5..0dcdba2 100755
--- a/android/device/softwinner/common/sepolicy/vendor/rild.te
+++ b/android/device/softwinner/common/sepolicy/vendor/rild.te
@@ -8,3 +8,59 @@
 
 allow rild vendor_toolbox_exec:file execute_no_trans;
 allow rild vendor_shell_exec:file execute_no_trans;
+
+# allow rild net_dns_prop:file { getattr open read };
+allow rild ppp_device:chr_file ioctl;
+allow rild rootfs:dir { open read };
+#TODO removed for Q
+#allow rild system_file:file execute_no_trans;
+allow rild vendor_file:file execute_no_trans;
+allow rild init:dir search;
+allow rild init:file { open read };
+allow rild kernel:dir search;
+allow rild kernel:file { open read };
+allow rild vendor_init:dir search;
+allow rild vendor_init:file read;
+allow rild vendor_toolbox_exec:file execute_no_trans;
+allow rild hal_keymaster_default:dir search;
+allow rild hwservicemanager:dir search;
+allow rild logd:dir search;
+allow rild servicemanager:dir search;
+allow rild tee:dir search;
+allow rild ueventd:dir search;
+allow rild vendor_init:file open;
+allow rild vndservicemanager:dir search;
+allow rild hal_keymaster_default:file read;
+allow rild hwservicemanager:file { open read };
+allow rild logd:file { open read };
+allow rild servicemanager:file { open read };
+allow rild tee:file read;
+allow rild ueventd:file { open read };
+allow rild vndservicemanager:file read;
+allow rild vold:dir search;
+allow rild hal_audio_default:dir search;
+allow rild hal_bluetooth_default:dir search;
+allow rild hal_camera_default:dir search;
+allow rild hal_keymaster_default:file open;
+allow rild healthd:dir search;
+allow rild tee:file open;
+allow rild vndservicemanager:file open;
+allow rild vold:file read;
+allow rild hal_audio_default:file { open read };
+allow rild healthd:file { open read };
+allow rild vold:file open;
+allow rild proc_net:file write;
+allow rild self:packet_socket create;
+allow rild self:packet_socket setopt;
+allow rild self:packet_socket { bind read write read};
+allow rild audioserver:file { open read };
+allow rild hal_bluetooth_default:file { open read };
+allow rild hal_camera_default:file { open read };
+allow rild hal_cas_default:dir search;
+allow rild hal_configstore_default:dir search;
+allow rild hal_drm_clearkey:dir search;
+allow rild hal_drm_default:dir search;
+allow rild hal_drm_widevine:dir search;
+allow rild lmkd:file { open read };
+
+
diff --git a/android/external/usb_modeswitch/CleanSpec.mk b/android/external/usb_modeswitch/CleanSpec.mk
new file mode 100755
index 0000000..b0b9d8d
--- /dev/null
+++ b/android/external/usb_modeswitch/CleanSpec.mk
@@ -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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/usb_modeswitch.d)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/usb_modeswitch)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/usb_dongle.rc)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/usb_dongle)
diff --git a/android/external/usb_modeswitch/usb_dongle/Android.mk b/android/external/usb_modeswitch/usb_dongle/Android.mk
new file mode 100755
index 0000000..f9fb9cf
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_dongle/Android.mk
@@ -0,0 +1,47 @@
+LOCAL_PATH:= $(call my-dir)
+
+common_src_files := \
+	NetlinkManager.cpp \
+	NetlinkHandler.cpp \
+	MiscManager.cpp \
+	Misc.cpp \
+	G3Dev.cpp
+
+common_shared_libraries := \
+	libsysutils \
+	libbinder \
+	libcutils \
+	liblog \
+	libselinux \
+	libutils \
+	libbase \
+	libhwbinder
+
+common_cflags := -Wall -Wno-missing-field-initializers -Wno-unused-variable -Wno-unused-parameter
+
+#common_local_tidy_flags := -warnings-as-errors=clang-analyzer-security*,cert-*
+common_local_tidy_checks := -*,clang-analyzer-security*,cert-*,-cert-err34-c,-cert-err58-cpp
+common_local_tidy_checks += ,-cert-env33-c
+
+include $(CLEAR_VARS)
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_MODULE := usb_dongle
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_CLANG := true
+LOCAL_TIDY := true
+LOCAL_TIDY_FLAGS := $(common_local_tidy_flags)
+LOCAL_TIDY_CHECKS := $(common_local_tidy_checks)
+LOCAL_SRC_FILES := \
+	main.cpp \
+	$(common_src_files)
+
+LOCAL_INIT_RC := usb_dongle.rc
+
+LOCAL_CFLAGS := $(common_cflags)
+#LOCAL_CFLAGS += -Werror=format
+LOCAL_CFLAGS += -DUSE_USB_MODE_SWITCH
+
+LOCAL_SHARED_LIBRARIES := $(common_shared_libraries)
+
+include $(BUILD_EXECUTABLE)
diff --git a/android/external/usb_modeswitch/usb_dongle/G3Dev.cpp b/android/external/usb_modeswitch/usb_dongle/G3Dev.cpp
new file mode 100755
index 0000000..55d928d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_dongle/G3Dev.cpp
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+
+#define LOG_TAG "USB_DONGLE"
+
+#include <cutils/log.h>
+#include <sysutils/NetlinkEvent.h>
+
+#include "G3Dev.h"
+#include "MiscManager.h"
+#include <unistd.h>
+
+#if PLATFORM_SDK_VERSION >= 16
+#define LOGV(fmt,args...) ALOGV(fmt,##args)
+#define LOGD(fmt,args...) ALOGD(fmt,##args)
+#define LOGI(fmt,args...) ALOGI(fmt,##args)
+#define LOGW(fmt,args...) ALOGW(fmt,##args)
+#define LOGE(fmt,args...) ALOGE(fmt,##args)
+#endif
+
+static char modeswitch_cmd[256] = "";
+
+
+G3Dev::G3Dev(MiscManager *mm):Misc(mm)
+{
+	
+}
+
+G3Dev::~G3Dev() {
+}
+
+int G3Dev::handleUsbEvent(NetlinkEvent *evt) {
+ const char *devtype = evt->findParam("DEVTYPE");
+    if( devtype!=NULL &&strcmp(devtype, "usb_device") )
+        return 0;
+	pid_t status ;
+
+	NetlinkEvent::Action action = evt->getAction();
+	if( action == NetlinkEvent::Action::kAdd)
+	{
+        const char *product = evt->findParam("PRODUCT");
+        if(product!=NULL && product[0] != 0 && devtype[0] != 0 )
+        {
+            // ��ȡVID/PID
+            int vid = 0;
+            int pid = 0;
+            char * next = (char*)product;
+            vid = strtol(product, &next, 16);
+		
+			//char pre[]="sVe.GT";
+            ++next;
+            pid = strtol(next, NULL, 16);
+
+            SLOGD("== current usb device: %04X/%04X ===", vid, pid);
+
+            char configure_file[2048];
+			
+			
+            sprintf(configure_file, "/vendor/etc/usb_modeswitch.d/%04x_%04x", vid, pid);
+            if( access(configure_file, 0) == 0 )
+            {
+		sprintf(modeswitch_cmd, "/vendor/bin/usb_modeswitch -W -v %04x -p %04x -c %s &", vid, pid,configure_file);
+	    	SLOGD("=== USB Switch: %s", modeswitch_cmd);
+                system(modeswitch_cmd);
+            }
+        }
+	}
+	
+    return 0;
+}
+int G3Dev::handleScsiEvent(NetlinkEvent *evt) {
+/*
+    ��һ��������usb_device ���event��ִ�е�usb_modeswitchû�гɹ�����Ϊ����
+    �ֶΣ���SCSI���event���ٴ�ִ��usb_modeswitch
+ */
+    if(evt->getAction()==NetlinkEvent::Action::kAdd && modeswitch_cmd[0] != 0)
+    {
+        SLOGD("=== SCSI Switch: %s", modeswitch_cmd);
+        system(modeswitch_cmd);
+        modeswitch_cmd[0] = 0;
+    }
+
+    return 0;
+}
+int G3Dev::handleUsb(){
+
+ 
+ char configure_file[2048];
+ int pid,vid;
+ this->get_tty_id(&vid,& pid);
+  
+ sprintf(configure_file, "/vendor/etc/usb_modeswitch.d/%04x_%04x", vid,pid);
+ SLOGD("=== config_file is: %04x_%04x", vid ,pid);
+ if( access(configure_file, 0) == 0 )
+ {
+	sprintf(modeswitch_cmd, "/vendor/bin/usb_modeswitch -W -v %04x -p %04x -c %s &", vid, pid,configure_file);
+	SLOGD("=== USB Switch: %s", modeswitch_cmd);
+	system(modeswitch_cmd);
+ 
+  }
+ return 0;
+ }
+int G3Dev:: get_tty_id(int *vid, int* pid)
+{
+   
+	   char linkto[1024]="";
+	   //SLOGD("began find device path");
+	  // SLOGD("device path: %s", tty_path);////	  
+	   		   
+	   //  LOGD("USB device path: %s", plink);
+	   char pidpath[PATH_MAX]="/sys/bus/usb/devices/1-1";
+	   
+		   FILE* fp = NULL;
+		   char buf[5] = {0};
+		   strlcat(pidpath, "/idVendor",PATH_MAX);
+	   	 SLOGD("Vendor path: %s", pidpath);
+		   fp = fopen(pidpath, "r");
+		   if(fp == NULL)
+			   return -2;
+		   if(fread(buf, 1, 4, fp) != 4)
+		   {
+			   fclose(fp);
+			   return -2;
+		   }
+		   fclose(fp);
+		   *vid = atox(buf, 16);
+	   char vidpath[PATH_MAX]="/sys/bus/usb/devices/1-1";
+	//sys/bus/usb/devices/1-1	
+		   strlcat(vidpath, "/idProduct",PATH_MAX);
+	   //	 LOGD("Product path: %s", plink);
+		   fp = fopen(vidpath, "r");
+		   if(fp == NULL)
+			   return -3;
+		   if(fread(buf, 1, 4, fp) != 4)
+		   {
+			   fclose(fp);
+			   return -3;
+		   }
+		   fclose(fp);
+		   *pid =atox(buf, 16);
+
+    return 0;
+}
+#define EATCHAR(x, c) for (; *(x) == (c); (x)++) ; 
+/* -1:error. */
+int G3Dev:: atox( const char * line, int f_base )
+{
+    int base = 10;
+    char max = '9';
+    int v = 0;
+
+    EATCHAR(line, ' ');
+    if(*line == 0) return 0;
+    
+    if( line[1] == 'x' || line[1] == 'X' ){
+        base = 16;
+        max = 'f';      /* F*/
+        line += 2;
+    }
+    else if(f_base==16)
+    {
+        base = 16;
+        max = 'f';      /* F*/
+    }
+    
+    if( base == 10 ) {
+            while( *line >= '0' && *line <= max ) {
+                        v *= base ;
+                        v += *line-'0';
+                        line++;
+            }
+    } else {
+            while( *line >= '0' && *line <= max ) {
+                        v *= base ;
+                        if( *line >= 'a' )
+                                v += *line-'a'+10;
+                        else if ( *line >= 'A' )
+                                v += *line-'A'+10;
+                        else
+                                v += *line-'0';
+                        line++;
+                }
+    }
+    return v;
+}
+
diff --git a/android/external/usb_modeswitch/usb_dongle/G3Dev.h b/android/external/usb_modeswitch/usb_dongle/G3Dev.h
new file mode 100755
index 0000000..2010dcb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_dongle/G3Dev.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#ifndef _G3DEV_H
+#define _G3DEV_H
+
+#include <utils/List.h>
+
+#include "Misc.h"
+class NetlinkEvent;
+
+class G3Dev : public Misc {
+public:
+    G3Dev(MiscManager *mm);
+    virtual ~G3Dev();
+    NetlinkEvent *env;
+    int handleUsbEvent(NetlinkEvent *evt);
+    int handleScsiEvent(NetlinkEvent *evt);
+    int handleUsb();
+    int get_tty_id(int *vid, int* pid);
+    int atox( const char * line, int f_base );
+};
+
+#endif
+
diff --git a/android/external/usb_modeswitch/usb_dongle/Misc.cpp b/android/external/usb_modeswitch/usb_dongle/Misc.cpp
new file mode 100755
index 0000000..519201e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_dongle/Misc.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <cutils/properties.h>
+
+#define LOG_TAG "USB_DONGLE"
+
+#include <cutils/log.h>
+
+#include "Misc.h"
+
+Misc::Misc(MiscManager *mm)
+{
+    mMm = mm;
+    mDebug = false;
+}
+
+Misc::~Misc()
+{
+}
+
+void Misc::setDebug(bool enable) {
+    mDebug = enable;
+}
+/*
+	�ú�����������ʵ��
+ */
+int Misc::handleUsbEvent(NetlinkEvent *evt) {
+    errno = ENOSYS;
+    return -1;
+}
+
+/*
+	�ú�����������ʵ��
+ */
+int Misc::handleScsiEvent(NetlinkEvent *evt) {
+    errno = ENOSYS;
+    return -1;
+}
+
+int Misc::handleUsb()
+{  errno = ENOSYS;
+    return -1;}
+
+
diff --git a/android/external/usb_modeswitch/usb_dongle/Misc.h b/android/external/usb_modeswitch/usb_dongle/Misc.h
new file mode 100755
index 0000000..e3d4f93
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_dongle/Misc.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#ifndef _MISC_H
+#define _MISC_H
+
+#include <utils/List.h>
+
+class NetlinkEvent;
+class MiscManager;
+
+class Misc {
+protected:
+    MiscManager *mMm;
+    bool mDebug;
+
+public:
+    Misc(MiscManager *mm);
+    virtual ~Misc();
+
+    virtual int handleUsbEvent(NetlinkEvent *evt);
+    virtual int handleScsiEvent(NetlinkEvent *evt);
+	virtual int handleUsb();
+    void setDebug(bool enable);
+};
+
+typedef android::List<Misc *> MiscCollection;
+
+#endif
+
diff --git a/android/external/usb_modeswitch/usb_dongle/MiscManager.cpp b/android/external/usb_modeswitch/usb_dongle/MiscManager.cpp
new file mode 100755
index 0000000..06173e0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_dongle/MiscManager.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define LOG_TAG "USB_DONGLE"
+
+#include <cutils/log.h>
+
+#include <sysutils/NetlinkEvent.h>
+
+#include "MiscManager.h"
+
+
+MiscManager *MiscManager::sInstance = NULL;
+
+MiscManager *MiscManager::Instance() {
+    if (!sInstance)
+        sInstance = new MiscManager();
+    return sInstance;
+}
+
+MiscManager::MiscManager() {
+    mDebug = false;
+    mMiscs = new MiscCollection();
+    mBroadcaster = NULL;
+}
+
+MiscManager::~MiscManager() {
+    delete mMiscs;
+}
+
+void MiscManager::setDebug(bool enable) {
+    mDebug = enable;
+    MiscCollection::iterator it;
+    for (it = mMiscs->begin(); it != mMiscs->end(); ++it) {
+        (*it)->setDebug(enable);
+    }
+}
+
+int MiscManager::start() {
+    return 0;
+}
+
+int MiscManager::stop() {
+    return 0;
+}
+
+int MiscManager::addMisc(Misc *m) {
+    mMiscs->push_back(m);
+    return 0;
+}
+
+void MiscManager::handleEvent(NetlinkEvent *evt) {
+	const char *subsys = evt->getSubsystem();
+    MiscCollection::iterator it;
+    bool hit = false;
+
+	SLOGD("%s, %d", subsys, evt->getAction());
+	
+		
+    for (it = mMiscs->begin(); it != mMiscs->end(); ++it) {
+	    if (!strcmp(subsys, "usb")) {
+			(*it)->handleUsbEvent(evt);
+	    } else if (!strcmp(subsys, "scsi_device")) {
+	    	(*it)->handleScsiEvent(evt);
+	    }
+    }
+}
+
diff --git a/android/external/usb_modeswitch/usb_dongle/MiscManager.h b/android/external/usb_modeswitch/usb_dongle/MiscManager.h
new file mode 100755
index 0000000..a7cee2b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_dongle/MiscManager.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#ifndef _MISCMANAGER_H
+#define _MISCMANAGER_H
+
+#include <pthread.h>
+
+#include <utils/List.h>
+#include <sysutils/SocketListener.h>
+#include "Misc.h"
+
+class MiscManager {
+private:
+    static MiscManager *sInstance;
+
+private:
+    SocketListener        *mBroadcaster;
+    MiscCollection        *mMiscs;
+    bool                   mDebug;
+
+public:
+    virtual ~MiscManager();
+
+    int start();
+    int stop();
+
+    void handleEvent(NetlinkEvent *evt);
+
+    int addMisc(Misc *v);
+    
+    void setDebug(bool enable);
+
+    void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
+    SocketListener *getBroadcaster() { return mBroadcaster; }
+
+    static MiscManager *Instance();
+
+private:
+    MiscManager();
+    Misc *lookupMisc(const char *label);
+};
+#endif
+
diff --git a/android/external/usb_modeswitch/usb_dongle/NetlinkHandler.cpp b/android/external/usb_modeswitch/usb_dongle/NetlinkHandler.cpp
new file mode 100755
index 0000000..32b5180
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_dongle/NetlinkHandler.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#define LOG_TAG "USB_DONGLE"
+
+#include <cutils/log.h>
+
+#include <sysutils/NetlinkEvent.h>
+#include "NetlinkHandler.h"
+#include "MiscManager.h"
+NetlinkHandler::NetlinkHandler(int listenerSocket) :
+                NetlinkListener(listenerSocket) {
+}
+
+NetlinkHandler::~NetlinkHandler() {
+}
+
+int NetlinkHandler::start() {
+    return this->startListener();
+}
+
+int NetlinkHandler::stop() {
+    return this->stopListener();
+}
+
+void NetlinkHandler::onEvent(NetlinkEvent *evt) {
+    const char *subsys = evt->getSubsystem();
+
+    if (!subsys) {
+        SLOGW("No subsystem found in netlink event");
+        return;
+    }
+
+#ifdef USE_USB_MODE_SWITCH
+    if (!strcmp(subsys, "usb") || !strcmp(subsys, "scsi_device")) {
+        SLOGW("subsystem found in netlink event");
+        MiscManager *mm = MiscManager::Instance();
+        mm->handleEvent(evt);
+#endif
+    }
+}
diff --git a/android/external/usb_modeswitch/usb_dongle/NetlinkHandler.h b/android/external/usb_modeswitch/usb_dongle/NetlinkHandler.h
new file mode 100755
index 0000000..56eb23c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_dongle/NetlinkHandler.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef _NETLINKHANDLER_H
+#define _NETLINKHANDLER_H
+
+#include <sysutils/NetlinkListener.h>
+
+class NetlinkHandler: public NetlinkListener {
+
+public:
+    explicit NetlinkHandler(int listenerSocket);
+    virtual ~NetlinkHandler();
+
+    int start(void);
+    int stop(void);
+
+protected:
+    virtual void onEvent(NetlinkEvent *evt);
+};
+#endif
diff --git a/android/external/usb_modeswitch/usb_dongle/NetlinkManager.cpp b/android/external/usb_modeswitch/usb_dongle/NetlinkManager.cpp
new file mode 100755
index 0000000..63e7475
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_dongle/NetlinkManager.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include <linux/netlink.h>
+
+#define LOG_TAG "USB_DONGLE"
+
+#include <android-base/logging.h>
+
+#include "NetlinkManager.h"
+#include "NetlinkHandler.h"
+
+NetlinkManager *NetlinkManager::sInstance = NULL;
+
+NetlinkManager *NetlinkManager::Instance() {
+    if (!sInstance)
+        sInstance = new NetlinkManager();
+    return sInstance;
+}
+
+NetlinkManager::NetlinkManager() {
+    mBroadcaster = NULL;
+}
+
+NetlinkManager::~NetlinkManager() {
+}
+
+int NetlinkManager::start() {
+    struct sockaddr_nl nladdr;
+    int sz = 64 * 1024;
+    int on = 1;
+
+    memset(&nladdr, 0, sizeof(nladdr));
+    nladdr.nl_family = AF_NETLINK;
+    nladdr.nl_pid = getpid();
+    nladdr.nl_groups = 0xffffffff;
+
+    if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,
+            NETLINK_KOBJECT_UEVENT)) < 0) {
+        PLOG(ERROR) << "Unable to create uevent socket";
+        return -1;
+    }
+
+    // When running in a net/user namespace, SO_RCVBUFFORCE will fail because
+    // it will check for the CAP_NET_ADMIN capability in the root namespace.
+    // Try using SO_RCVBUF if that fails.
+    if ((setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) &&
+        (setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0)) {
+        PLOG(ERROR) << "Unable to set uevent socket SO_RCVBUF/SO_RCVBUFFORCE option";
+        goto out;
+    }
+
+    if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
+        PLOG(ERROR) << "Unable to set uevent socket SO_PASSCRED option";
+        goto out;
+    }
+
+    if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
+        PLOG(ERROR) << "Unable to bind uevent socket";
+        goto out;
+    }
+
+    mHandler = new NetlinkHandler(mSock);
+    if (mHandler->start()) {
+        PLOG(ERROR) << "Unable to start NetlinkHandler";
+        goto out;
+    }
+
+    return 0;
+
+out:
+    close(mSock);
+    return -1;
+}
+
+int NetlinkManager::stop() {
+    int status = 0;
+
+    if (mHandler->stop()) {
+        PLOG(ERROR) << "Unable to stop NetlinkHandler";
+        status = -1;
+    }
+    delete mHandler;
+    mHandler = NULL;
+
+    close(mSock);
+    mSock = -1;
+
+    return status;
+}
diff --git a/android/external/usb_modeswitch/usb_dongle/NetlinkManager.h b/android/external/usb_modeswitch/usb_dongle/NetlinkManager.h
new file mode 100755
index 0000000..9c7ba11
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_dongle/NetlinkManager.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#ifndef _NETLINKMANAGER_H
+#define _NETLINKMANAGER_H
+
+#include <sysutils/SocketListener.h>
+#include <sysutils/NetlinkListener.h>
+
+class NetlinkHandler;
+
+class NetlinkManager {
+private:
+    static NetlinkManager *sInstance;
+
+private:
+    SocketListener       *mBroadcaster;
+    NetlinkHandler       *mHandler;
+    int                  mSock;
+
+public:
+    virtual ~NetlinkManager();
+
+    int start();
+    int stop();
+
+    void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
+    SocketListener *getBroadcaster() { return mBroadcaster; }
+
+    static NetlinkManager *Instance();
+
+private:
+    NetlinkManager();
+};
+#endif
diff --git a/android/external/usb_modeswitch/usb_dongle/main.cpp b/android/external/usb_modeswitch/usb_dongle/main.cpp
new file mode 100755
index 0000000..1e29146
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_dongle/main.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+#include "NetlinkManager.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <cutils/klog.h>
+#include <cutils/properties.h>
+#include <cutils/sockets.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#ifdef USE_USB_MODE_SWITCH
+#include "G3Dev.h"
+#include  "MiscManager.h"
+#endif
+
+#define LOG_TAG "USB_DONGLE"
+
+static void coldboot(const char *path);
+
+struct fstab *fstab;
+
+struct selabel_handle *sehandle;
+
+using android::base::StringPrintf;
+
+int main(int argc, char** argv) {
+    setenv("ANDROID_LOG_TAGS", "*:v", 1);
+    android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
+
+    LOG(INFO) << "USB_MODE_SWITCH";
+
+    NetlinkManager *nm;
+
+
+    klog_set_level(6);
+
+    if (!(nm = NetlinkManager::Instance())) {
+        LOG(ERROR) << "Unable to create NetlinkManager";
+        exit(1);
+    }
+
+    if (nm->start()) {
+        PLOG(ERROR) << "Unable to start NetlinkManager";
+        exit(1);
+    }
+
+#ifdef USE_USB_MODE_SWITCH
+	MiscManager *mm;
+	if (!(mm = MiscManager::Instance())) {
+		PLOG(ERROR) << "Unable to create MiscManager";
+		exit(1);
+	};
+	//mm->setBroadcaster((SocketListener *) cl);
+	if (mm->start()) {
+		LOG(ERROR) << "Unable to start MiscManager";
+		exit(1);
+	}
+	G3Dev* g3 = new G3Dev(mm);
+	g3->handleUsb();
+	mm->addMisc(g3);
+#endif
+    // Do coldboot here so it won't block booting,
+    // also the cold boot is needed in case we have flash drive
+    coldboot("/sys/block");
+    // Eventually we'll become the monitoring thread
+    while(1) {
+        pause();
+    }
+
+    LOG(ERROR) << "USB_MODE_SWITCH exiting";
+    exit(0);
+}
+
+static void do_coldboot(DIR *d, int lvl) {
+    struct dirent *de;
+    int dfd, fd;
+
+    dfd = dirfd(d);
+
+    fd = openat(dfd, "uevent", O_WRONLY | O_CLOEXEC);
+    if(fd >= 0) {
+        write(fd, "add\n", 4);
+        close(fd);
+    }
+
+    while((de = readdir(d))) {
+        DIR *d2;
+
+        if (de->d_name[0] == '.')
+            continue;
+
+        if (de->d_type != DT_DIR && lvl > 0)
+            continue;
+
+        fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+        if(fd < 0)
+            continue;
+
+        d2 = fdopendir(fd);
+        if(d2 == 0)
+            close(fd);
+        else {
+            do_coldboot(d2, lvl + 1);
+            closedir(d2);
+        }
+    }
+}
+
+static void coldboot(const char *path) {
+    DIR *d = opendir(path);
+    if(d) {
+        do_coldboot(d, 0);
+        closedir(d);
+    }
+}
diff --git a/android/external/usb_modeswitch/usb_dongle/usb_dongle.rc b/android/external/usb_modeswitch/usb_dongle/usb_dongle.rc
new file mode 100755
index 0000000..c20f161
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_dongle/usb_dongle.rc
@@ -0,0 +1,4 @@
+service usb_dongle /vendor/bin/usb_dongle
+    class main
+    oneshot
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/Android.mk b/android/external/usb_modeswitch/usb_modeswitch/Android.mk
new file mode 100755
index 0000000..5dacae0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+INCLUDES = $(LOCAL_PATH)
+INCLUDES += external/libusb/libusb
+
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE := usb_modeswitch
+LOCAL_SRC_FILES := usb_modeswitch.c
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES :=$(INCLUDES)
+LOCAL_SHARED_LIBRARIES := libusb
+
+LOCAL_CFLAGS += -Wno-self-assign -Wno-sometimes-uninitialized
+LOCAL_CFLAGS += -Wno-error=deprecated-declarations -Wno-deprecated-declarations
+
+$(shell mkdir -p $(PRODUCT_OUT)/vendor/etc)
+$(shell cp -R $(LOCAL_PATH)/usb_modeswitch.d $(PRODUCT_OUT)/vendor/etc)
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/COPYING b/android/external/usb_modeswitch/usb_modeswitch/COPYING
new file mode 100755
index 0000000..d60c31a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/android/external/usb_modeswitch/usb_modeswitch/ChangeLog b/android/external/usb_modeswitch/usb_modeswitch/ChangeLog
new file mode 100755
index 0000000..42ee92a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/ChangeLog
@@ -0,0 +1,288 @@
+
+History of USB_ModeSwitch
+=========================
+
+Version 2.4.0, 2016/06/12
+    ATTENTION: All ad-hoc driver binding code (using new_id driver attribute)
+    removed - was a potential source of side effects and should now be
+    obsoleted by good kernel support for modems; Added "dummy" setting for
+    config files, to conditionally refrain from handling a device (see this
+    topic: www.draisberghof.de/usb_modeswitch/bb/viewtopic.php?f=4&t=2458 );
+    extended StandardEject sequence to include LUN 1, required for some D-Link
+    devices; add device class 239 ("miscellaneous") to sanity check (thanks to
+    Daniel Drake for reporting); udev shell script - removed driver binding,
+    removed almost all waiting and forking, improved check for systemd (thanks
+    to Daniel Drake for problem analysis and solution, see this topic/patch:
+    www.draisberghof.de/usb_modeswitch/bb/viewtopic.php?p=16777#p16777 ,
+    gist.github.com/dsd/9f83c4830ab78ce94078aedb2cf16a8f )
+Version 2.3.0, 2016/01/12
+    ATTENTION: -I flag is now history and being ignored - determining SCSI
+    attributes is really an 'outside task'; -n flag (NeedResponse) is being
+    ignored, CSW response will now always be read; introduction of parameter
+    "OptionMode", wrapping the standard bulk message for all newer Huawei
+    devices; fixed missing variable initialization in dispatcher script which
+    could lead to crash (thanks, Dmitry Kunilov!); fixed bug which prevented
+    early logging; fixed success report for Cisco AM10; some source code
+    formatting and clean-up
+Version 2.2.6, 2015/11/01
+    Renamed function abort(), avoiding possible conflicts in static builds
+    with libjim (thanks, Gustavo Zacharias); removed storage class check of
+    interface 0 from dispatcher, enabling new multi-config devices in data
+    package 20151101
+Version 2.2.5, 2015/07/16
+    Fixed bug in configuration check, possibly leading to segfault (thanks,
+    Leonid Lisovskiy); fixed Pantech commandline parameter evaluation (was
+    not working at all); added driver unbind step via sysfs in wrapper,
+    getting rid of the USB subsystem complaint "interface 0 claimed by
+    usb-storage while 'usb_modeswitch' <does this and that>"
+Version 2.2.4, 2015/07/14
+    Fixed buggy check of USB configuration selection (possibly leading
+    to segfault), tested with Alcatel X602D; removed call to 'libusb_strerror'
+    from libusb initialization - not available in earlier libusb1 versions
+Version 2.2.3, 2015/06/29
+    Fixed problem arising with systemd version 221 (220 untested), which
+    affects starting the usb_modeswitch systemd unit from the sh script
+    (reported by Archlinux users)
+Version 2.2.2, 2015/06/27
+    Added catch for libusb init error (thanks, Henrik Gustafsson); removed
+    global function result variable; added catch for USB configuration
+    read error (both thanks to "otila"); fixed wrapper script where port
+    search for symlinking modem port was broken ("/dev/gsmmodem"); changed
+    PantechMode parameter to represent different targets; added global
+    config option to disable MBIM checking and setting alltogether (request
+    from "kai"); changed udev sh script so that systemd processing takes
+    precedence over upstart; changed systemd template unit parameter to
+    avoid escaping problems
+Version 2.2.1, 2015/01/15
+    Fixed unreliable switching function for Cisco AM10
+Version 2.2.0, 2014/05/29
+    Introduction of parameter "HuaweiNewMode", wrapping the standard bulk
+    message for all newer Huawei devices; support for generic fall-back
+    config files, combined with OS switch (per vendor ID), implementation
+    to use a specific switching command on Android for all Huawei devices
+    (see README of data package for details); this change was suggested
+    by Huawei
+Version 2.1.1, 2014/03/27
+    Code cleanup, better use of libusb1; this also fixes problems with
+    determination of the active USB configuration (Samsung, Option modems);
+    "Interface" parameter was not working as expected, fixed (see also:
+    https://bugs.launchpad.net/bugs/1261923 ); fixed bogus interface release
+    in "inquire" function, again a report by "Sonya@zte"
+Version 2.1.0, 2014/01/28
+    ATTENTION: -I flag meaning reversed, default is to skip SCSI inquiry;
+    introduction of StandardEject, replacing many MessageContents with the
+    same function, reducing size of device config files, and always including
+    the 'Allow Medium Removal' before ejecting (thanks to Lars Melin for
+    the idea); fix in "bulk_read", removing bogus CSW request (report from
+    "Sonya@zte")
+Version 2.0.1, 2013/09/03
+    Fixed stupid string size bug which could lead to memory corruption
+    (thanks to Leonid Myravjev)
+Version 2.0.0, 2013/09/01
+    Switched to libusb1.0, with much help from folks of the wl500g project
+    (http://wl500g.googlecode.com): Vladislav Grishenko, Leonid Lisovskiy,
+    Roman Samarev, Andrey Tikhomirov;
+    major code and debug output cleanup; man page corrections and additions
+    (thanks to Thomas Haller);
+    experimental systemd and upstart integration, if present
+    (Explanation: newer udev versions kill all subprocesses, detached or
+    not. The suggested way to handle longer running processes like the
+    usb_modeswitch_dispatcher is to add simple services or tasks and start
+    these by sending signals from the udev rule)
+    !! Attention, system integrators: a crude install facility is included
+    in the Makefile to check if "upstart" or "systemd" is active and to
+    install the matching service file; you may want to adapt it better to
+    your respective system, possibly adding dependencies/targets to the
+    services. Note that the udev starter script usb_modeswitch.sh also
+    checks for the existence of the service/unit files
+Version 1.2.7, 2013/08/07
+    Two new dedicated control message functions to support Pantech LTE
+    (thanks to Adam Goode) and Blackberry Q10/Z10 (thanks to Daniel Mende)
+Version 1.2.6, 2013/06/02
+    Several changes to streamline compiling as part of larger projects
+    (thanks to Nicolas Carrier), mostly in Makefile; fix compiler warnings
+    appearing in certain build environments (N. Carrier); new Quanta
+    procedure (thanks to Andrey Tikhomirov) for Quanta 1K3 LTE; fix for
+    error with cascaded hubs in dispatcher script (hint from N. Carrier)
+Version 1.2.5, 2012/11/09
+    Initial support for MBIM devices, use with data package >= 20121109;
+    checking for these is the automatic default, new parameter NoMBIMCheck
+    prevents the check per device in case of problems; new global option
+    to set "delay_use" of usb-storage (as low values may prevent
+    mode-switching); fix for handling multi-configuration devices (thanks
+    to Bjørn Mork for advice)
+Version 1.2.4, 2012/08/12
+    Additional interface checks to prevent sending UFI commands to non-
+    storage interfaces (prompted by more ambiguous device IDs popping up);
+    change in SierraMode for handling newer devices which caused an error
+    abort before; Makefile fix for parallelized make runs
+Version 1.2.3, 2012/01/28
+    Fixed two bugs both causing the embedded-jimsh install variant of the
+    dispatcher crash (the "pure-script" install variant was NOT affected);
+    fixed some "regexp" incompatibilities with Debian's libjim
+Version 1.2.2, 2012/01/19
+    Fixed bad bug preventing mode switch for devices using TargetClass;
+    improved logging in case of negative success check
+Version 1.2.1, 2011/12/26
+    Fixed possible ambiguities when multiple identical modems are plugged
+    synchronously; this is achieved by adding -b and -g parameter (busnum
+    and devnum) for proper id'ing; some resulting workflow changes and
+    shortcuts in "system integration" mode (use sysfs/wrapper for success
+    control, reduce informative checks); improved hub usage robustness;
+    future data packages can be ridded of redundancies (default ID, success
+    check parameters), resulting in smaller files;
+    fixed bad bug which may prevent switching completely when logging is
+    not activated; fixed possible overflow in dispatcher C code (thanks to
+    Gilles Espinasse)
+Version 1.2.0, 2011/10/23
+    Added QisdaMode for Qisda H21 (thanks to Chi-Hang Long for the code);
+    dispatcher can now be installed with an embedded interpreter, so that
+    Tcl is no longer required; added command line options for binary program
+    to accept configuration data via stdin or as a long string parameter -
+    this fixes the bug with non-writable temporary file during boot;
+    reversed skipping of pre-switching delay, which has caused problems;
+    fixed potential buffer overflow (thanks to Rafael Silva for the find);
+    get first interface right even on some broken devices (thanks to
+    Alexander Gordeev for the patch); increased post-switch delay before
+    driver binding to avoid possible conflict with usb-storage
+Version 1.1.9, 2011/08/05
+    Added CiscoMode for Valet device; additional checking for CDC ACM device
+    to prevent erroneous driver loading after switching; no more post-switch
+    check for access to initial device if target parameters are given
+Version 1.1.8, 2011/06/19
+    Cleaned up switchSendMessage(); added workaround for quirky devices not
+    reporting configuration setting; added non-CSW response for arbitrary
+    bulk transfers; added SequansMode and MobileActionMode; check for active
+    configuration will be skipped if bNumConfigurations is 1 (most cases)
+Version 1.1.7, 2011/02/27
+    Attention: paths for runtime files and database have changed! Old places
+    will be found but are deprecated; /usr/share/usb_modeswitch for database,
+    /var/lib/usb_modeswitch for "remembered" IDs;
+    fix for configuration setting race (thanks to Amit Mendapara); discovered
+    incompatibility between Tcl versions <= 8.3 and >=8.4, so 8.4 is the
+    minimum prerequisite now;
+    first availability of an alternative source pack which includes "jimsh",
+    a fast Tcl mini shell, intended for resource-constrained systems
+Version 1.1.6, 2010/12/22
+    Moved warm-boot driver binding to sh wrapper, was unreliable in 1.1.5;
+    sh wrapper overhaul, made compatible with Ubuntu's "dash" shell, tclsh
+    calls reduced further; initial device checking includes current
+    bConfigurationValue now, should work with config setting for multiple
+    devices; made tcl script conform to limitations of "jimsh", the minimal
+    tcl shell (hint from Barry Kauler); fixes for "usbserial" fallback
+    (driver binding for old systems); in the C program, changed parameter
+    "MessageDelay" (hitherto unused) to "ReleaseDelay", to be used in one
+    device configuration (delay interface release after bulk message sending)
+Version 1.1.5, 2010/11/28
+    Added special control message for Kobil devices (patch from Filip Aben);
+    try to get active configuration for interface class checking (there are
+    some new devices 'switching' via configuration selection);
+    fixed "0000" target product ID - again; new bash and tcl wrapper logic:
+    the convenience functions for driver binding and symlinking will now
+    start the tcl shell ONLY for known devices; changed and appended logging
+    capabilities of said convenience functions; add loading of "usbserial"
+    as a fallback for older systems to support new devices;
+    add workaround for bug in libusb1 which affects device search during
+    success check
+Version 1.1.4, 2010/08/17
+    The package should work at boot time now (cold and warm);
+    product IDs of "0000" do exist but were not accepted, fixed (thanks to
+    Sakis Dimopoulos); response endpoint is now always detected (led to
+    possible error report when resetting all endpoints in version 1.1.3);
+    wrapper script can now work with a packed collection of config files as
+    well as with the plain folder of files; use with the "install-packed"
+    make target of the data package (for use on systems with resource
+    constraints); wrapper fix for the symlink feature: handling of multiple
+    interrupt ports was incomplete; wrapper does not longer use a temporary
+    file for the symlink feature (security considerations, Marco d'Itri)
+Version 1.1.3, 2010/06/21
+    Added delay option to separate multiple message transfers by millisecs;
+    fixed (possibly dangerous) sloppy string handling (thanks to Christophe
+    Fergeau); added "clear_halt" for response endpoint; small additions in
+    Makefile (install with -D); changes in option handling (NO MORE DEFAULT
+    CONFIG FILE!) and help text; symlink feature in wrapper can now cope
+    with devices providing more than one interrupt port; wrapper now ignores
+    package manager leftovers in config folder; replaced bash-specific syntax
+    in wrapper; changed ZTE skipping (if existing rules are found) to warning
+Version 1.1.2, 2010/04/18
+    Added support for two additional bulk messages; wrapper handles special
+    ZTE case; generalized driver loading, new parameter "DriverModule" and
+    "DriverIDPath"; new wrapper facility to add symlink pointing to interrupt
+    port (used in rule file from data pack >= 20100418)
+Version 1.1.1, 2010/03/17
+    Attention: old usb_modeswitch.conf renamed to usb_modeswitch.setup!
+    Add separate config file for wrapper (global settings for switching and
+    logging); add config file option to disable driver loading; handling of
+    kernel attribute AVOID_RESET_QUIRK added; bug fixed in SonyMode (reported
+    by "no-0n3"); bug fixed in SuccessCheck logic; minor flow alignments and
+    fixes; new devices
+Version 1.1.0, 2010/01/24
+    Attention: wrapper script location changed, uninstall old versions!
+    Major fixes in the wrapper script (stabilizing and time-saving);
+    back to unified installation, defaults to "integrated" approach;
+    new -D parameter to enable "integrated" behaviour; bugs fixed in
+    success check; man file included (borrowed from the Debian package);
+    C code and binary works with the compat library from libusb-1.0;
+    some new devices
+Version 1.0.7, 2010/01/06
+    Bug fixed for Sony mode, thanks to Marco Chiaranda; fix for parameter
+    substitution in newer udev versions, fix for bad bug in wrapper script
+    practically disabling automatic mode
+Version 1.0.6, 2009/12/21
+    New "GCT Mode", fixes for device quirks (NXP Dragonfly), fix for multiple
+    Huawei devices, cleanups, loads of new devices in config file and database,
+    minor tcl script changes
+Version 1.0.5, 2009/08/26
+    More changes and fixes regarding success check; "--version" option;
+    config "database" updated
+Version 1.0.4, 2009/08/23
+    Success check bugs (and others) fixed
+Version 1.0.3, 2009/08/20
+    Success check improved; experimental system integration (fully automated),
+    optional; new parameter "TargetProductList" needed for this; other
+    necessary small adaptations; more devices
+Version 1.0.2, 2009/06/10
+    Output bugs fixed
+Version 1.0.1, 2009/06/08
+    Added output of descriptor strings for further identification
+Version 1.0.0, 2009/06/01
+    Attention: possible incompatibilities for command line control!
+    On/off flags don't require arguments anymore (-H, -S, -O, -d, -R,
+    -n, new: -I), meaning "-R 0" does a reset like "-R 1" or "-R";
+    long option names changed to standard format (e.g. --HuaweiMode to
+    --huawei-mode); added device inquiry, for future help with device
+    identification; catch error -19 as possible success; send and response
+    endpoints now autoselected (consequently NeedResponse is back);
+    new devices
+Version 0.9.7, 2009/04/15
+    Updated SonyMode, MD 400 now stable; automatic default endpoint
+    detection from Andrew Bird
+Version 0.9.7beta, 2009/03/15
+    Major code clean up, optional success control (both suggested
+    by Daniel Cooper), new devices
+Version 0.9.6, 2009/01/08
+    Special modes added for Sierra and Sony Ericsson, new devices
+Version 0.9.5, 2008/10/27
+    New options for USB tuning (jokedst), lots of new devices, clean up
+Version 0.9.4, 2008/06/09
+    Compat fix for libusb on FreeBSD quirks, more devices
+Version 0.9.4beta2, 2008/03/19
+    Successful udev device release fix
+Version 0.9.4beta, 2008/03/16
+    Multiple device support
+Version 0.9.3, 2008/03/09
+    More devices, no changes from beta version
+Version 0.9.3beta, 2007/12/30
+    New TargetClass parameter for recent Option firmware (Paul Hardwick), more
+    devices
+Version 0.9.2, 2007/11/02
+    New Huawei mode (code from Miroslav Bobovsky, added by Denis Sutter), more
+    devices
+Version 0.9.1beta, 2007/09/04 (jokedst)
+    Added command line parsing, cleaned up config stuff, doc updates
+Version 0.9beta, 2007/08/15
+    Name change from "icon_switch", parameter file and generalizing
+Version 0.2, 2006/09/25
+    Code cleaning, more messages
+Version 0.1, 2006/09/24
+    (as "icon_switch") Just very basic functionality ...
diff --git a/android/external/usb_modeswitch/usb_modeswitch/CleanSpec.mk b/android/external/usb_modeswitch/usb_modeswitch/CleanSpec.mk
new file mode 100755
index 0000000..b0b9d8d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/CleanSpec.mk
@@ -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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/usb_modeswitch.d)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/usb_modeswitch)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/usb_dongle.rc)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/usb_dongle)
diff --git a/android/external/usb_modeswitch/usb_modeswitch/Makefile b/android/external/usb_modeswitch/usb_modeswitch/Makefile
new file mode 100755
index 0000000..47ed794
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/Makefile
@@ -0,0 +1,105 @@
+PROG        = usb_modeswitch
+VERS        = 2.4.0
+CC          ?= gcc
+CFLAGS      += -Wall
+LIBS        = `pkg-config --libs --cflags libusb-1.0`
+RM          = /bin/rm -f
+OBJS        = usb_modeswitch.c
+PREFIX      = $(DESTDIR)/usr
+ETCDIR      = $(DESTDIR)/etc
+SYSDIR      = $(ETCDIR)/systemd/system
+UPSDIR      = $(ETCDIR)/init
+UDEVDIR     = $(DESTDIR)/lib/udev
+SBINDIR     = $(PREFIX)/sbin
+MANDIR      = $(PREFIX)/share/man/man1
+VPATH       = jimtcl
+HOST_TCL   := $(shell cd jim && ./autosetup/find-tclsh)
+ifeq (,$(findstring jimsh0,$(HOST_TCL)))
+TCL        ?= $(HOST_TCL)
+else
+TCL        ?= /usr/bin/tclsh
+endif
+JIM_CONFIGURE_OPTS = --disable-lineedit \
+	--with-out-jim-ext="stdlib posix load signal syslog" --prefix=/usr
+
+.PHONY: clean install install-common uninstall \
+	script shared static \
+	dispatcher-script dispatcher-shared dispatcher-static \
+	install-script install-shared install-static
+
+all: script
+
+script: $(PROG) dispatcher-script
+
+shared: $(PROG) dispatcher-shared
+
+static: $(PROG) dispatcher-static
+
+$(PROG): $(OBJS) usb_modeswitch.h
+	$(CC) -o $(PROG) $(OBJS) $(CFLAGS) $(LIBS) $(LDFLAGS)
+
+jim/libjim.so:
+	cd jim && CFLAGS="$(CFLAGS)" CC="$(CC)" ./configure $(JIM_CONFIGURE_OPTS) --shared
+	$(MAKE) -C jim lib
+
+jim/libjim.a:
+	cd jim && CFLAGS="$(CFLAGS)" CC="$(CC)" ./configure $(JIM_CONFIGURE_OPTS)
+	$(MAKE) -C jim lib
+
+dispatcher-script: usb_modeswitch.tcl
+	sed 's_!/usr/bin/tclsh_!'"$(TCL)"'_' < usb_modeswitch.tcl > usb_modeswitch_dispatcher
+
+dispatcher-shared: jim/libjim.so dispatcher.c usb_modeswitch.string
+	$(CC) dispatcher.c $(LDFLAGS) -Ljim -ljim -Ijim -o usb_modeswitch_dispatcher $(CFLAGS)
+
+dispatcher-static: jim/libjim.a dispatcher.c usb_modeswitch.string
+	$(CC) dispatcher.c $(LDFLAGS) jim/libjim.a -Ijim -o usb_modeswitch_dispatcher $(CFLAGS)
+
+usb_modeswitch.string: usb_modeswitch.tcl
+	$(HOST_TCL) make_string.tcl usb_modeswitch.tcl > $@
+
+clean:
+	$(RM) usb_modeswitch
+	$(RM) usb_modeswitch_dispatcher
+	$(RM) usb_modeswitch.string
+	$(RM) jim/autosetup/jimsh0
+	$(RM) jim/autosetup/jimsh0.c
+
+distclean: clean
+	-$(MAKE) -C jim distclean
+
+ums-clean:
+	$(RM) usb_modeswitch
+	$(RM) usb_modeswitch_dispatcher
+	$(RM) usb_modeswitch.string
+
+# If the systemd folder is present, install the service for starting the dispatcher
+# If not, use the dispatcher directly from the udev rule as in previous versions
+
+install-common: $(PROG) usb_modeswitch_dispatcher
+	install -D --mode=755 usb_modeswitch $(SBINDIR)/usb_modeswitch
+	install -D --mode=755 usb_modeswitch.sh $(UDEVDIR)/usb_modeswitch
+	install -D --mode=644 usb_modeswitch.conf $(ETCDIR)/usb_modeswitch.conf
+	install -D --mode=644 usb_modeswitch.1 $(MANDIR)/usb_modeswitch.1
+	install -D --mode=644 usb_modeswitch_dispatcher.1 $(MANDIR)/usb_modeswitch_dispatcher.1
+	install -D --mode=755 usb_modeswitch_dispatcher $(SBINDIR)/usb_modeswitch_dispatcher
+	install -d $(DESTDIR)/var/lib/usb_modeswitch
+	test -d $(UPSDIR) -a -e /sbin/initctl && install --mode=644 usb-modeswitch-upstart.conf $(UPSDIR) || test 1
+	test -d $(SYSDIR) -a \( -e /usr/bin/systemctl -o -e /bin/systemctl \) && install --mode=644 usb_modeswitch@.service $(SYSDIR) || test 1
+
+install: install-script
+
+install-script: dispatcher-script install-common
+
+install-shared: dispatcher-shared install-common
+
+install-static: dispatcher-static install-common
+
+uninstall:
+	$(RM) $(SBINDIR)/usb_modeswitch
+	$(RM) $(SBINDIR)/usb_modeswitch_dispatcher
+	$(RM) $(UDEVDIR)/usb_modeswitch
+	$(RM) $(ETCDIR)/usb_modeswitch.conf
+	$(RM) $(MANDIR)/usb_modeswitch.1
+	$(RM) -R $(DESTDIR)/var/lib/usb_modeswitch
+	$(RM) $(SYSDIR)/usb_modeswitch@.service
diff --git a/android/external/usb_modeswitch/usb_modeswitch/README b/android/external/usb_modeswitch/usb_modeswitch/README
new file mode 100755
index 0000000..da6fb351
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/README
@@ -0,0 +1,271 @@
+README for USB_ModeSwitch
+
+For up-to-date and more detailed information (plus a friendly forum) visit
+http://www.draisberghof.de/usb_modeswitch
+
+
+What it is
+==========
+
+USB_ModeSwitch is - hardly surprising -  a mode switching tool for controlling
+USB devices with multiple "modes". Now, what does THAT mean?
+
+More and more USB devices have their MS Windows drivers onboard; when plugged
+in for the first time they act like a flash storage and offer their driver
+installation from there.
+After installation (and on every consecutive plugging) the driver switches the
+mode internally by sending a certain command sequence; the storage device
+vanishes (in most cases) and a different device - like a USB modem - shows up.
+To the host, this is like unplugging one device and then plugging annother.
+
+At first this feature appeared on devices with cell phone chipsets, presumably
+because some of them were already able to change the mode of their USB port
+from storage to communication - so why not make use of this in a modem stick?
+Modem maker "Option" calls that feature "ZeroCD (TM)" since it eliminates the
+need for shipping a separate driver carrier.
+
+In the beginning, nothing of this was documented in any form and there was
+hardly any Linux/Unix support available.
+On the good side, most of the known devices are working out of the box in all
+modes with available Linux modules like "usb-storage" or serial USB drivers.
+That leaves only the problem of the mode-switching from storage to whatever
+the thing is supposed to do.
+
+Fortunately there are things like human smartness, USB sniffing programs and
+LibUSB. The obvious way is to eavesdrop on the communication of the MS Windows
+driver, to isolate the command or action that does the switching, and then re-
+play the same sequence in a non-Windows system.
+
+In theory, this task could also be handled on the kernel driver level, but a
+userspace program is much more flexible and can easily be disabled if access
+to the initial mode of those devices should be desired. There has been a
+principle decision by kernel developers to keep mode-switching outside of the
+kernel.
+
+So USB_ModeSwitch has evolved to make this process easy to handle by taking the
+relevant parameters from configuration files and handling all initialization
+and communication business, with essential help from "libusb".
+
+In Linux and friends it is intended to work automatically - via udev events
+and rules - and doing the mode switch without any user interaction.
+However, the core C program should be as portable als libusb itself; it does not
+rely on specific Linux features.
+It can also be run as an interactive command line tool, particularly useful when
+trying to tinker with hitherto unknown devices.
+
+We have already collected a wide range of information on how to mode-switch all
+sorts of devices. If you run into a new one that is unknown yet, don't despair:
+we can find out what you need to do!
+
+
+How to install
+==============
+
+If you only need the core C program, just run "make". All further steps de-
+scribed below are referring to a common, fairly current Linux system where
+USB_ModeSwitch is expected to do its work automatically.
+
+!! You need the usb-modeswitch-data package from the same source as this !!
+
+If you have an earlier version installed, de-installation is recommended ("make
+uninstall") but not mandatory. The wrapper script location changed in 1.1.0;
+old files might be orphaned but will not do any harm.
+
+The main prerequisite for installing from source is the development package for
+"libusb". It may be called "libusb-dev" or similar in your distribution. From
+usb_modeswitch 2.0.0 on, it should have an "1.x" in the name to reflect the change
+to libusb-1. There are also variants around called "libusbx" if libusb-1 is not
+available on your distribution.
+
+To install the tool set, unpack and run the install command (see below) in the
+newly created directory.
+
+From version 1.2.0, there are three flavours of installing. The only difference
+between those is the way the dispatcher is installed, but this affects the
+dependencies as well:
+
+1. If you have the "Tcl" scripting language available on your system (packages
+   "tcl" or "jimsh"), use the light-weight installation:
+
+   # make install
+
+2. If you are size-constrained and have the Jimsh library on your system
+   (package "libjim-dev"), you can have the Tcl interpreter embedded with the
+   dispatcher, using its shared lib:
+
+   # make install-shared
+
+3. If you are size-constrained and definitely don't need a Tcl interpreter
+   for anything else, choose the statically embedded flavour. This will have
+   no further dependency as it uses the included interpreter code, which is
+   configured for small size:
+
+   # make install-static
+
+Note that the "static"/"shared" targets are NOT referring to the usb_modeswitch
+program, only to the dispatcher!
+Any one of these commands will install a small posix shell script, the
+dispatcher (wrapper) as script or as binary, a global config file, the core
+program and a man page.
+
+Install the data package as well and you are set.
+
+NOTE: installing over (possibly outdated) Linux distribution packages of this
+program and the data collection should not be a problem.
+
+
+How to use
+==========
+
+If your device is known, you should be able to just plug it and use it. If
+it doesn't work - we will find out why.
+
+For manual use just run "usb_modeswitch" (as root). Work with the command
+line interface or with a setup file. You can use any file and give its path
+with the "-c" parameter.
+The file named "device_reference.txt" that you can find on the home site of
+this package is a device and configuration reference containing most known
+devices; you can use it as a "database" to create your own configuration file.
+It's heavily commented and should tell you what to do. It also contains a
+thorough explanation of all the parameters.
+
+Run "usb_modeswitch -h" to list the command line parameters.
+See also the provided man page.
+
+Important note: Manual use is mainly intended for testing and analyzing!!
+The program puts no limits on what you can send to your USB device, so I
+assume it is possible to screw it up profoundly.
+
+Once your new device is switching fine you can add it to the data files to
+make the process automatic.
+
+For this to work, add a rule entry to the rules file to let udev run
+usb_modeswitch as soon as the default IDs are found (when the device is
+plugged). If you look into the rules file you will see immediately how
+your new entry should look like.
+The location is:
+/lib/udev/rules.d/40-usb_modeswitch.rules
+
+Then add your new config file to the folder
+"/etc/usb_modeswitch.d" (only for custom config files!).
+And don't forget to report your success !!
+
+Again, remember that the rules file and the default device config folder
+(/usr/share/usb_modeswitch) are installed by the usb_modeswitch data package.
+
+
+##########
+Important: libusb programs - like this tool - want to be run with administrative
+privileges (as root or with sudo)!
+##########
+
+
+
+Known working hardware, Troubleshooting
+=======================================
+
+Please go to the homepage (see link at the top). Read carefully.
+For support questions use ONLY public posts in the forum.
+
+
+
+Contribute
+==========
+
+USB_ModeSwitch comes quite handy for experimenting with your own hardware if
+not supported yet. You could try this approach:
+
+Note the device's vendor and product ID from /proc/bus/usb/devices (or from the
+output of lsusb); the assigned driver is usually "usb-storage". Then try spying
+on the USB communication to the device with the same ID inside MS Windoze. I
+recommend this tool:
+"SniffUSB" (http://benoit.papillault.free.fr/usbsnoop/index.php.en).
+
+PLEASE post any improvements, new device information and/or bug reports to the
+forum (see above) or send it to the author (see below)!
+
+
+Whodunit
+========
+
+Copyright 2007 - 2015 Josua Dietze (for non-support notifications write a personal
+message through the forum to "Josh"; everything else only in a forum thread)
+
+ !!! NO SUPPORT QUESTIONS VIA E-MAIL, use the forum !!!
+
+Major contributions:
+
+Command line parsing and other essential contributions:
+ Joakim Wennergren
+
+TargetClass parameter implementation to support new Option devices/firmware:
+ Paul Hardwick (http://www.pharscape.org)
+
+Created with initial help from:
+ "usbsnoop2libusb.pl" by Timo Lindfors
+ (http://iki.fi/lindi/usb/usbsnoop2libusb.pl)
+
+Config file parsing code borrowed from:
+ Guillaume Dargaud (http://www.gdargaud.net/Hack/SourceCode.html)
+
+Hexstr2bin function borrowed from:
+ Jouni Malinen (http://hostap.epitest.fi/wpa_supplicant, from "common.c")
+
+Indispensable help with device research and compilation:
+ Lars Melin
+
+Code, fixes and ideas contributed by:
+ Aki Makkonen
+ Denis Sutter
+ Lucas Benedicic
+ Roman Laube
+ Luigi Iotti
+ Vincent Teoh
+ Tommy Cheng
+ Daniel Cooper
+ Andrew Bird
+ Yaroslav Levandovskiy
+ Sakis Dimopoulos
+ Steven Fernandez
+ Christophe Fergeau
+ Nils Radtke
+ Filip Aben
+ Amit Mendapara
+ Roman S. Samarev
+ Chi-Hang Long
+ Andrey Tikhomirov
+ Daniel Mende
+ Nicholas Carrier
+ Adam Goode
+ Leonid Lisovskiy
+ Vladislav Grishenko
+ Daniel Drake
+
+Device information contributors are named in the "device_reference.txt" file.
+
+JimTcl is currently maintained by Steve Bennett; see README in subfolder
+ for details. It is released under a FreeBSD-style license.
+ Visit http://jim.tcl.tk/
+
+
+
+Legal
+=====
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details:
+
+http://www.gnu.org/licenses/gpl.txt
+
+Or find it as the file COPYING in this folder.
+
+
+
+
+Last revised: 2016-06-12, Josua Dietze
diff --git a/android/external/usb_modeswitch/usb_modeswitch/dispatcher.c b/android/external/usb_modeswitch/usb_modeswitch/dispatcher.c
new file mode 100755
index 0000000..c38ae31
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/dispatcher.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2011-2016 Josua Dietze, usb_modeswitch version 2.3.0
+ * Contains code under
+ * Copyright (c) 2010 Wojciech A. Koszek <wkoszek@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <jim.h>
+
+/* RAW is defined to the complete Tcl code in that file: */
+#include "usb_modeswitch.string"
+
+#define MAX_ARGSIZE 1024
+
+int main(int argc, char **argv)
+{
+	int i, retval;
+	char arg[MAX_ARGSIZE];
+	char arglist[MAX_ARGSIZE]; 
+
+	Jim_Interp *interp;
+
+	interp = NULL;
+	arglist[0] = '\0';
+
+	for (i=1; i<argc; i++) {
+		if (strlen(argv[i]) > MAX_ARGSIZE-4) {
+			printf("Argument #%d extends maximum size, skip it\n", i);
+			continue;
+		}
+		if ( (strlen(arglist) + strlen(argv[i])) > MAX_ARGSIZE-4) {
+			printf("Argument #%d would extend maximum list size, skip it\n", i);
+			continue;
+		}
+		sprintf(arg,"{%s} ",argv[i]);
+		strncat(arglist,arg,MAX_ARGSIZE-1);
+	}
+
+	char code[sizeof(RAW) + sizeof(arglist) + 28];
+	sprintf(code, "set argv {%s}\nset argc %d\n", arglist, argc-1);
+	strncat(code, RAW, sizeof(RAW));
+
+	/* Create Jim instance */
+	interp = Jim_CreateInterp();
+	assert(interp != NULL && "Could not create interpreter!");
+
+	/* Register base commands, actually implementing Tcl */
+	Jim_RegisterCoreCommands(interp);
+
+	/* Initialize any static extensions */
+	Jim_InitStaticExtensions(interp);
+
+	/* Evaluate the script that's now in "code" */
+	retval = Jim_Eval(interp, code);
+	if (retval < 0)
+		printf("Evaluation returned error %d\n", retval);
+
+	/* Free the interpreter */
+	Jim_FreeInterp(interp);
+	return (EXIT_SUCCESS);
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/AUTHORS b/android/external/usb_modeswitch/usb_modeswitch/jim/AUTHORS
new file mode 100755
index 0000000..73413a5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/AUTHORS
@@ -0,0 +1,41 @@
+Salvatore Sanfilippo <antirez@invece.org>
+
+with the help (patches, bug reports, ideas, extensions) of:
+
+Pat Thoyts
+Clemens Hintze
+
+See also the ChangeLog and README files for other credits.
+
+DESIGN CREDITS:
+
+some of the idea inside Jim are the fruit of long discussions
+inside the Tclers chat room. The feedback of the Tcl
+comunity in general, and of the members of the Tcl Core Team, was
+very important to avoid mistakes: I used the great experience of
+this people as a test for some of the ideas I put into Jim.
+Bad ideas tend to be demolished in no time by good engineers.
+
+Also the following ideas are due to the following authors:
+
+- Jim locals were originally proposed by Miguel Sofer, I (SS) added
+  the feature that make they similar to lexical scoped closures
+  using capturing of the local variables value if no explicit
+  intialization is provided.
+
+- The [lmap] command is my (SS) design, but I incorporated inside the
+  command an interesting idea of Donal K. Fellows that proposed that
+  the [continue] command may be used to skip the accumulation of the
+  current-iteartion result, providing in one command the power of
+  [map] and [filter] together.
+
+ 
+ChangeLog committers to be identified. Tentative list:  
+ 
+antirez - Salvatore Sanfilippo <antirez@gmail.com>
+patthoyts - Pat Thoyts <patthoyts@users.sf.net> 
+oharboe - �yvind Harboe - soyvind.harboe@zylin.com
+Andrew Lunn <andrew@lunn.ch> 
+Duane Ellis <openocd@duaneellis.com>
+Uwe Klein <uklein@klein-messgeraete.de>
+Clemens Hintze ml-jim@qiao.in-berlin.de aka chi
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/LICENSE b/android/external/usb_modeswitch/usb_modeswitch/jim/LICENSE
new file mode 100755
index 0000000..d5b9ecb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/LICENSE
@@ -0,0 +1,45 @@
+Unless explicitly stated, all files within Jim repository are released
+under following license:
+
+/* Jim - A small embeddable Tcl interpreter
+ *
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
+ * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net> 
+ * Copyright 2008 oharboe - �yvind Harboe - oyvind.harboe@zylin.com
+ * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
+ * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
+ * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
+ * Copyright 2008 Steve Bennett <steveb@workware.net.au>
+ * Copyright 2009 Nico Coesel <ncoesel@dealogic.nl>
+ * Copyright 2009 Zachary T Welch zw@superlucidity.net
+ * Copyright 2009 David Brownell
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ */
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/Makefile.in b/android/external/usb_modeswitch/usb_modeswitch/jim/Makefile.in
new file mode 100755
index 0000000..0191c83
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/Makefile.in
@@ -0,0 +1,198 @@
+# Tools
+CC ?= @CCACHE@ @CC@
+CXX = @CCACHE@ @CXX@
+RANLIB = @RANLIB@
+AR = @AR@
+STRIP = @STRIP@
+
+# Configuration
+
+SH_CFLAGS ?= @SH_CFLAGS@
+SH_LDFLAGS ?= @SH_LDFLAGS@
+SHOBJ_CFLAGS ?= @SHOBJ_CFLAGS@
+SHOBJ_LDFLAGS ?= @SHOBJ_LDFLAGS@
+CFLAGS = @CFLAGS@
+CXXFLAGS = @CXXFLAGS@
+LDFLAGS = @LDFLAGS@
+LDLIBS += @LDLIBS@
+exec_prefix ?= @exec_prefix@
+prefix ?= @prefix@
+
+CC += -D_GNU_SOURCE -Wall $(OPTIM) -I.
+CXX += -D_GNU_SOURCE -Wall $(OPTIM) -I.
+@if srcdir != .
+CFLAGS += -I@srcdir@
+CXXFLAGS += -I@srcdir@
+VPATH := @srcdir@
+@endif
+
+@if JIM_STATICLIB
+LIBJIM := libjim.a
+@else
+LIBJIM := libjim.so
+SH_LIBJIM := $(LIBJIM)
+CC += $(SH_CFLAGS)
+CXX += $(SH_CFLAGS)
+DEF_LD_PATH := @LD_LIBRARY_PATH@=`pwd` 
+@endif
+
+@if HAVE_CXX_EXTENSIONS
+JIMSH_CC := $(CXX) $(CXXFLAGS)
+@else
+JIMSH_CC := $(CC) $(CFLAGS)
+@endif
+
+OBJS := _load-static-exts.o jim-subcmd.o jim-interactive.o jim-format.o jim.o utf8.o jimregexp.o \
+    @EXTRA_OBJS@ @C_EXT_OBJS@ @TCL_EXT_OBJS@
+
+JIMSH := jimsh@EXEEXT@
+
+all: $(JIMSH) @C_EXT_SHOBJS@
+
+# Create C extensions from pure Tcl extensions
+.SUFFIXES: .tcl
+.tcl.o:
+	@tclsh@ @srcdir@/make-c-ext.tcl $< >_$*.c || ( rm _$*.c; exit 1)
+	$(CC) $(CFLAGS) -c -o $@ _$*.c || ( rm _$*.c; exit 1)
+	@rm -f _$*.c
+
+docs: Tcl.html
+
+$(JIMSH): $(LIBJIM) jimsh.o initjimsh.o
+	$(JIMSH_CC) @SH_LINKFLAGS@ $(LDFLAGS) -o $@ jimsh.o initjimsh.o $(LIBJIM) $(LDLIBS)
+
+@if JIM_INSTALL
+install: all docs @TCL_EXTS@ install-exec
+	mkdir -p $(DESTDIR)$(prefix)/lib/jim
+	cp $(LIBJIM) $(DESTDIR)$(prefix)/lib
+	cp @srcdir@/README.extensions @C_EXT_SHOBJS@ @TCL_EXTS@ $(DESTDIR)$(prefix)/lib/jim
+	mkdir -p $(DESTDIR)$(prefix)/include
+	cp @srcdir@/jim.h @srcdir@/jim-eventloop.h @srcdir@/jim-nvp.h @srcdir@/jim-signal.h \
+		@srcdir@/jim-subcmd.h @srcdir@/jim-win32compat.h $(DESTDIR)$(prefix)/include
+	cp jim-config.h $(DESTDIR)$(prefix)/include
+	mkdir -p $(DESTDIR)$(prefix)/doc/jim
+	cp Tcl.html $(DESTDIR)$(prefix)/doc/jim
+
+install-exec: all
+	mkdir -p $(DESTDIR)$(prefix)/bin
+	cp $(JIMSH) $(DESTDIR)$(prefix)/bin
+
+uninstall:
+	rm -f $(DESTDIR)$(prefix)/bin/$(JIMSH)
+	rm -f $(DESTDIR)$(prefix)/lib/$(LIBJIM)
+	for i in README.extensions @C_EXT_SHOBJS@ @TCL_EXTS@; do rm -f $(DESTDIR)$(prefix)/lib/jim/$$i; done
+	rm -f $(DESTDIR)$(prefix)/include/jim*.h
+	rm -f $(DESTDIR)$(prefix)/doc/jim/Tcl.html
+@else
+install install-exec uninstall:
+@endif
+
+test: $(JIMSH)
+	$(DEF_LD_PATH) $(MAKE) -C @srcdir@/tests jimsh=`pwd`/jimsh
+
+$(OBJS): Makefile
+
+@if JIM_UTF8
+# Generate the unicode case mapping
+utf8.o: _unicode_mapping.c
+
+_unicode_mapping.c: @srcdir@/UnicodeData.txt @srcdir@/parse-unidata.tcl
+	@tclsh@ @srcdir@/parse-unidata.tcl @srcdir@/UnicodeData.txt >$@ || ( rm $@; exit 1)
+@endif
+
+_load-static-exts.c: @srcdir@/make-load-static-exts.tcl Makefile
+	@tclsh@ @srcdir@/make-load-static-exts.tcl @STATIC_EXTS@ >$@ || ( rm $@; exit 1)
+
+@if JIM_STATICLIB
+$(LIBJIM): $(OBJS)
+	$(AR) cr $@ $(OBJS)
+	$(RANLIB) $@
+@else
+$(LIBJIM): $(OBJS)
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SH_LDFLAGS) -o $@ $(OBJS) $(LDLIBS)
+@endif
+
+# Note that $> $^ is for compatibility with both GNU make and BSD make
+readdir.so: jim-readdir.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-readdir.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-readdir.o $(SH_LIBJIM) 
+
+array.so: jim-array.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-array.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-array.o $(SH_LIBJIM) 
+
+clock.so: jim-clock.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-clock.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-clock.o $(SH_LIBJIM) 
+
+file.so: jim-file.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-file.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-file.o $(SH_LIBJIM) 
+
+posix.so: jim-posix.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-posix.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-posix.o $(SH_LIBJIM) 
+
+regexp.so: jim-regexp.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-regexp.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-regexp.o $(SH_LIBJIM) 
+
+syslog.so: jim-syslog.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-syslog.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-syslog.o $(SH_LIBJIM) 
+
+readline.so: jim-readline.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-readline.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-readline.o $(SH_LIBJIM) @LDLIBS_readline@
+
+pack.so: jim-pack.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-pack.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-pack.o $(SH_LIBJIM) @LDLIBS_pack@
+
+sqlite.so: jim-sqlite.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-sqlite.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-sqlite.o $(SH_LIBJIM) @LDLIBS_sqlite@
+
+sqlite3.so: jim-sqlite3.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-sqlite3.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-sqlite3.o $(SH_LIBJIM) @LDLIBS_sqlite3@
+
+win32.so: jim-win32.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-win32.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-win32.o $(SH_LIBJIM) @LDLIBS_win32@
+
+mk.so: jim-mk.cpp
+	$(CXX) $(CXXFLAGS) $(SHOBJ_CFLAGS) -c -o jim-mk.o $> $^
+	$(CXX) $(CXXFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-mk.o $(SH_LIBJIM) @LDLIBS_mk@
+
+sdl.so: jim-sdl.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-sdl.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-sdl.o $(SH_LIBJIM) @LDLIBS_sdl@
+
+Tcl.html: jim_tcl.txt
+	@tclsh@ @srcdir@/make-index $> $^ | asciidoc -o $@ -d manpage - || cp @srcdir@/Tcl_shipped.html Tcl.html
+
+clean:
+	rm -f *.o *.so lib*.a $(JIMSH) Tcl.html _*.c
+
+distclean: clean
+	rm -f jimautoconf.h jim-config.h Makefile config.log autosetup/jimsh0.c autosetup/jimsh0@EXEEXT@
+
+ship: Tcl.html
+	cp $< Tcl_shipped.html
+
+# automake compatibility. do nothing for all these targets
+EMPTY_AUTOMAKE_TARGETS := dvi pdf ps info html tags ctags mostlyclean maintainer-clean check installcheck installdirs \
+ install-pdf install-ps install-info install-html -install-dvi uninstall install-data
+.PHONY: $(EMPTY_AUTOMAKE_TARGETS)
+$(EMPTY_AUTOMAKE_TARGETS):
+
+# automake compatibility - install sources from the current dir to $(distdir)
+distdir_full := $(shell cd $(distdir); pwd)
+distdir:
+	cd "@srcdir@"; git ls-files | cpio -pdmu $(distdir_full)
+
+reconfig:
+	CC='@CC@' @AUTOREMAKE@
+
+lib: $(LIBJIM)
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/README b/android/external/usb_modeswitch/usb_modeswitch/jim/README
new file mode 100755
index 0000000..8acacc4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/README
@@ -0,0 +1,235 @@
+The Jim Interpreter
+
+A small-footprint implementation of the Tcl programming language.
+
+--------------------------------------------------------------------------------
+WHAT IS JIM?
+--------------------------------------------------------------------------------
+
+Jim is a small footprint implementation of the Tcl programming language
+written from scratch. Currently Jim Tcl is very feature complete with
+an extensive test suite (see the tests directory).
+There are some Tcl commands and features which are not implemented
+(and likely never will be), including namespaces, traces and Tk. However
+Jim Tcl offers a number of both Tcl8.5 and Tcl8.6 features ({*}, dict, lassign,
+tailcall and optional UTF-8 support) and some unique features.
+These unique features include [lambda] with garbage collection, a general GC/references
+system, arrays as syntax sugar for [dict]tionaries, object-based I/O and more.
+
+Other common features of the Tcl programming language are present, like
+the "everything is a string" behaviour, implemented internally as
+dual ported objects to ensure that the execution time does not reflect
+the semantic of the language :)
+
+--------------------------------------------------------------------------------
+WHEN JIM CAN BE USEFUL?
+--------------------------------------------------------------------------------
+
+1) If you are writing an application, and want to make it scriptable, with
+Jim you have a way to do it that does not require to link your application
+with a big system. You can include the Jim source directly in your project
+and use the Jim API to write the glue code that makes your application
+scriptable in Jim, with the following advantages:
+
+- Jim is not the next "little language", but it's a Tcl implementation.
+  You can reuse your knowledge if you already Tcl skills, or enjoy
+  the availability of documentation, books, web resources, ...
+  (for example check my online Tcl book at http://www.invece.org/tclwise)
+
+- Jim is simple, 14k lines of core code. If you want to adapt it you can hack
+  the source code to meet the needs of your application. It makes you
+  able to have scripting for default, and avoid external dependences.
+
+  Having scripting support *inside*, and in a way that a given version
+  of your program always gets shipped a given version of Jim, you can
+  write part of your application in Jim itself. Like it happens for
+  Emacs/Elisp, or Gimp/Scheme, both this applications have the interpreter
+  inside.
+
+- Jim is Tcl, and Tcl looks like a configuration file if you want. So
+  if you use Jim you have also a flexible syntax for your config file.
+  This is a valid Tcl script:
+
+     set MyFeature on
+     ifssl {
+       set SslPort 45000
+       use compression
+     }
+
+  It looks like a configuration file, but if you implement the [ifssl]
+  and [use] commands, it's a valid Tcl script.
+
+- Tcl scales with the user. Not all know it, but Tcl is so powerful that
+  you can reprogram the language in itself. Jim support this features
+  of the Tcl programming language. You can write new control structures,
+  use the flexible data types it offers (Lists are a central data structure,
+  with Dictionaries that are also lists). Still Tcl is simpler for the
+  casual programmer, especially if compared to other languages offering
+  small footprint implementations (like Scheme and FORTH).
+
+- Because of the Tcl semantic (pass by value, everything is a command
+  since there are no reserved words), there is a nice API to glue
+  your application with Jim. See under the Jim Tcl manual for more detail.
+
+- Jim is supported. If you need commercial software, contact the original author
+  at 'antirez@gmail.com' or the current maintainer at 'steveb@workware.net.au'.
+
+2) The other "field" where Jim can be useful is obviously embedded systems.
+
+3) We are working to make Jim as feature-complete as possible, thanks to
+   dynamically loaded extensions it may stay as little as it is today
+   but able to do interesting things for you. So it's not excluded that
+   in the future Jim will be an option as general purpose language.
+   But don't mind, for this there is already the mainstream Tcl
+   implementation ;).
+
+--------------------------------------------------------------------------------
+HOW BIG IS IT?
+--------------------------------------------------------------------------------
+
+Jim with the default extensions configured and compiled with -Os is about 130k.
+Without any extensions, it is about 85k.
+
+--------------------------------------------------------------------------------
+HOW FAST IS IT?
+--------------------------------------------------------------------------------
+
+Jim is in most code faster than Tcl7.6p2 (latest 7.x version),
+and slower than Tcl 8.4.x. You can expect pretty decent performance
+for such a little interpreter.
+
+If you want a more precise measure, there is 'bench.tcl' inside this
+distribution that will run both under Jim and Tcl, so just execute
+it with both the interpreters and see what you get :)
+
+--------------------------------------------------------------------------------
+HOW TO COMPILE
+--------------------------------------------------------------------------------
+
+Jim was tested under Linux, FreeBSD, MacosX, eCos, QNX, Windows XP (mingw, MVC).
+
+To compile jim itself try:
+
+  ./configure
+  make
+
+--------------------------------------------------------------------------------
+EXTENSIONS
+--------------------------------------------------------------------------------
+
+Many optional extensions are included. Some are C extensions and others are pure Tcl.
+Form more information, try:
+
+  ./configure --help
+
+--------------------------------------------------------------------------------
+HOW TO EMBED JIM INTO APPLICATIONS
+--------------------------------------------------------------------------------
+
+See the "examples.api" directory
+
+--------------------------------------------------------------------------------
+HOW TO WRITE EXTENSIONS FOR JIM
+--------------------------------------------------------------------------------
+
+See the extensions shipped with Jim, jim-readline.c, jim-clock.c, glob.tcl and oo.tcl
+
+--------------------------------------------------------------------------------
+COPYRIGHT and LICENSE
+--------------------------------------------------------------------------------
+
+Unless explicitly stated, all files within Jim repository are released
+under following license:
+
+/* Jim - A small embeddable Tcl interpreter
+ *
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
+ * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net> 
+ * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
+ * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
+ * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
+ * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
+ * Copyright 2008 Steve Bennett <steveb@workware.net.au>
+ * Copyright 2009 Nico Coesel <ncoesel@dealogic.nl>
+ * Copyright 2009 Zachary T Welch zw@superlucidity.net
+ * Copyright 2009 David Brownell
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ */
+--------------------------------------------------------------------------------
+HISTORY
+--------------------------------------------------------------------------------
+
+"first Jim goal: to vent my need to hack on Tcl."
+
+And actually this is exactly why I started Jim, in the first days
+of Jenuary 2005. After a month of hacking Jim was able to run
+simple scripts, now, after two months it started to be clear to
+me that it was not just the next toy to throw away but something
+that may evolve into a real interpreter. In the same time
+Pat Thoyts and Clemens Hintze started to contribute code, so that
+the development of new core commands was faster, and also more
+people hacking on the same code had as result fixes in the API,
+C macros, and so on.
+
+Currently we are at the point that the core interpreter is almost finished
+and it is entering the Beta stage. There is to add some other core command,
+to do a code review to ensure quality of all the parts and to write
+documentation.
+
+We already started to work on extensions like OOP, event loop,
+I/O, networking, regexp. Some extensions are already ready for
+prime time, like the Sqlite extension and the ANSI I/O.
+
+------------------------------------------------------------------------------
+Thanks to...
+------------------------------------------------------------------------------
+
+- First of all, thanks to every guy that are listed in the AUTHORS file,
+  that directly helped with code and ideas. Also check the ChangeLog
+  file for additional credits about patches or bug reports.
+- Elisa Manara that helped me to select this ill conceived name for
+  an interpreter.
+- Many people on the Tclers Chat that helped me to explore issues
+  about the use and the implementation of the Tcl programming language.
+- David Welton for the tech info sharing and our chats about
+  programming languages design and the ability of software to "scale down".
+- Martin S. Weber for the great help with Solaris issues, debugging of
+  problems with [load] on this arch, 64bit tests.
+- The authors of "valgrind", for this wonderful tool, that helped me a
+  lot to fix bugs in minutes instead of hours.
+
+
+----
+Enjoy!
+Salvatore Sanfilippo
+10 Mar 2005
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/README.usb_modeswitch b/android/external/usb_modeswitch/usb_modeswitch/jim/README.usb_modeswitch
new file mode 100755
index 0000000..7f3ae41
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/README.usb_modeswitch
@@ -0,0 +1,6 @@
+The content of this folder is customized for shipping with usb_modeswitch;
+for the original source see:
+
+http://repo.or.cz/w/jimtcl.git
+
+This is version 0.72 of jimtcl
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/auto.def b/android/external/usb_modeswitch/usb_modeswitch/jim/auto.def
new file mode 100755
index 0000000..2cdb85c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/auto.def
@@ -0,0 +1,436 @@
+# vim:se syn=tcl:
+#
+
+# Note: modules which support options *must* be included before 'options'
+use cc cc-shared
+
+options {
+    utf8            => "include support for utf8-encoded strings"
+    lineedit=1      => "disable line editing"
+    references=1    => "disable support for references"
+    math            => "include support for math functions"
+    ipv6            => "include ipv6 support in the aio extension"
+    maintainer      => {enable the [debug] command and JimPanic}
+    full            => "Enable some optional features: ipv6, math, utf8, binary, oo, tree"
+    with-jim-shared shared => "build a shared library instead of a static library"
+    jim-regexp      => "use the built-in (Tcl-compatible) regexp, even if POSIX regex is available"
+    with-jim-ext: {with-ext:"ext1 ext2 ..."} => {
+        Specify additional jim extensions to include.
+        These are enabled by default:
+
+        aio       - ANSI I/O, including open and socket
+        eventloop - after, vwait, update
+        array     - Tcl-compatible array command
+        clock     - Tcl-compatible clock command
+        exec      - Tcl-compatible exec command
+        file      - Tcl-compatible file command
+        glob      - Tcl-compatible glob command
+        readdir   - Required for glob
+        package   - Package management with the package command
+        load      - Load binary extensions at runtime with load or package
+        posix     - Posix APIs including os.fork, os.wait, pid
+        regexp    - Tcl-compatible regexp, regsub commands
+        signal    - Signal handling
+        stdlib    - Built-in commands including lassign, lambda, alias
+        syslog    - System logging with syslog
+        tclcompat - Tcl compatible read, gets, puts, parray, case, ...
+
+        These are disabled by default:
+
+        nvp       - Name-value pairs C-only API
+        oo        - Jim OO extension
+        tree      - OO tree structure, similar to tcllib ::struct::tree
+        binary    - Tcl-compatible 'binary' command
+        readline  - Interface to libreadline
+        rlprompt  - Tcl wrapper around the readline extension
+        mk        - Interface to Metakit
+        sqlite    - Interface to sqlite
+        sqlite3   - Interface to sqlite3
+        win32     - Interface to win32
+    }
+    with-out-jim-ext: {without-ext:"default|ext1 ext2 ..."} => {
+        Specify jim extensions to exclude.
+        If 'default' is given, the default extensions will not be added.
+    }
+    with-jim-extmod: {with-mod:"ext1 ext2 ..."} => {
+        Specify jim extensions to build as separate modules (either C or Tcl).
+        Note that not all extensions can be built as loadable modules.
+    }
+    # To help out openocd with automake
+    install-jim=1
+}
+
+cc-check-types "long long"
+
+cc-check-includes sys/socket.h netinet/in.h arpa/inet.h netdb.h
+cc-check-includes sys/un.h dlfcn.h unistd.h crt_externs.h
+
+define LDLIBS ""
+
+# Haiku needs -lnetwork, Solaris needs -lnsl
+if {[cc-check-function-in-lib inet_ntop {nsl network}]} {
+    # This does nothing if no libs are needed
+    cc-with [list -libs [get-define lib_inet_ntop]]
+    define-append LDLIBS [get-define lib_inet_ntop]
+}
+# Solaris needs -lsocket, Windows needs -lwsock32
+if {[cc-check-function-in-lib socket socket]} {
+    define-append LDLIBS [get-define lib_socket]
+}
+
+cc-check-functions ualarm lstat fork vfork system select
+cc-check-functions backtrace geteuid mkstemp realpath strptime gettimeofday
+cc-check-functions regcomp waitpid sigaction sys_signame sys_siglist
+cc-check-functions syslog opendir readlink sleep usleep pipe getaddrinfo utimes
+if {[cc-check-functions sysinfo]} {
+    cc-with {-includes sys/sysinfo.h} {
+        cc-check-members "struct sysinfo.uptime"
+    }
+}
+
+define TCL_LIBRARY [get-define prefix]/lib/jim
+
+lassign [split [get-define host] -] host_cpu host_vendor host_os
+# Scrub revision from the host_os
+regsub -all {[0-9.]} $host_os {} host_os
+
+switch -glob -- $host_os {
+    mingw* {
+        # We provide our own implementation of dlopen for mingw32
+        define-feature dlopen-compat
+        define-feature winconsole
+        define TCL_PLATFORM_OS $host_os
+        define TCL_PLATFORM_PLATFORM windows
+        define TCL_PLATFORM_PATH_SEPARATOR {;}
+    }
+    default {
+        # Note that cygwin is considered a unix platform
+        define TCL_PLATFORM_OS $host_os
+        define TCL_PLATFORM_PLATFORM unix
+        define TCL_PLATFORM_PATH_SEPARATOR :
+    }
+}
+
+# Find some tools
+cc-check-tools ar ranlib strip
+define tclsh [info nameofexecutable]
+
+if {![cc-check-functions _NSGetEnviron]} {
+    msg-checking "Checking environ declared in unistd.h..."
+    if {[cctest -cflags -D_GNU_SOURCE -includes unistd.h -code {char **ep = environ;}]} {
+        define NO_ENVIRON_EXTERN
+        msg-result "yes"
+    } else {
+        msg-result "no"
+    }
+}
+
+# Windows has a mkdir with no permission arg
+cc-check-includes sys/types.h sys/stat.h
+msg-checking "Checking for mkdir with one arg..."
+if {[cctest -includes {sys/types.h sys/stat.h} -code {mkdir("/dummy");}]} {
+    define HAVE_MKDIR_ONE_ARG
+    msg-result yes
+} else {
+    msg-result no
+}
+
+# autosetup can't handle C++ libraries
+proc check-metakit {} {
+    set found 0
+    cc-with {-lang c++} {
+        msg-checking "Checking for Metakit..."
+        if {[cctest -includes mk4.h -libs -lmk4 -code {c4_Storage dummy();}]} {
+            msg-result ok
+            define lib_mk -lmk4
+            incr found
+        } else {
+            msg-result "not found"
+        }
+    }
+    return $found
+}
+
+set extra_objs {}
+set jimregexp 0
+
+if {[opt-bool utf8 full]} {
+    msg-result "Enabling UTF-8"
+    define JIM_UTF8
+    incr jimregexp
+} else {
+    define JIM_UTF8 0
+}
+if {[opt-bool maintainer]} {
+    msg-result "Enabling maintainer settings"
+    define JIM_MAINTAINER
+}
+if {[opt-bool math full]} {
+    msg-result "Enabling math functions"
+    define JIM_MATH_FUNCTIONS
+    cc-check-function-in-lib sin m
+    define-append LDLIBS [get-define lib_sin]
+}
+if {[opt-bool ipv6 full]} {
+    msg-result "Enabling IPv6"
+    define JIM_IPV6
+}
+if {[opt-bool lineedit full]} {
+    if {([cc-check-includes termios.h] && [cc-check-functions isatty]) || [have-feature winconsole]} {
+        msg-result "Enabling line editing"
+        define USE_LINENOISE
+        lappend extra_objs linenoise.o
+    }
+}
+if {[opt-bool references]} {
+    msg-result "Enabling references"
+    define JIM_REFERENCES
+}
+if {[opt-bool shared with-jim-shared]} {
+    msg-result "Building shared library"
+} else {
+    msg-result "Building static library"
+    define JIM_STATICLIB
+}
+define JIM_INSTALL [opt-bool install-jim]
+
+# Note: Extension handling is mapped directly from the configure.ac
+# implementation
+
+set without [join [opt-val {without-ext with-out-jim-ext}]]
+set withext [join [opt-val {with-ext with-jim-ext}]]
+set withmod [join [opt-val {with-mod with-jim-extmod}]]
+
+# Tcl extensions
+set ext_tcl "stdlib glob tclcompat tree rlprompt oo binary"
+# Native extensions
+set ext_c "load package readdir array clock exec file posix regexp signal aio eventloop pack syslog nvp readline mk sqlite sqlite3 win32 sdl"
+
+# C++ extensions
+set ext_cxx "mk"
+
+# Tcl extensions which can be modules
+set ext_tcl_mod "glob tree rlprompt oo binary"
+# Native extensions which can be modules
+set ext_c_mod "readdir array clock file posix regexp syslog readline pack mk sqlite sqlite3 win32 sdl"
+
+# All extensions
+set ext_all [concat $ext_c $ext_tcl]
+
+# Default static extensions
+set ext_default "stdlib load package readdir glob array clock exec file posix regexp signal tclcompat aio eventloop syslog"
+
+if {[opt-bool full]} {
+    lappend ext_default tree binary
+}
+
+if {$without eq "default"} {
+    set ext_default stdlib
+    set without {}
+}
+
+# Check valid extension names
+foreach i [concat $withext $without $withmod] {
+    if {$i ni $ext_all} {
+        user-error "Unknown extension: $i"
+    }
+}
+
+# needs_xxx="expression" means that the expr must eval to 1 to select the extension
+# dep_xxx="yyy zzz" means that if xxx is selected, so is yyy and zzz
+set dep(glob) readdir
+set dep(rlprompt) readline
+set dep(tree) oo
+set dep(binary) pack
+
+set needs(exec) {expr {([have-feature vfork] && [have-feature waitpid]) || [have-feature system]}}
+set needs(load) {expr {[cc-check-function-in-lib dlopen dl] || [have-feature dlopen-compat]}}
+set libdep(load) lib_dlopen
+set needs(posix) {have-feature waitpid}
+set needs(readdir) {have-feature opendir}
+set needs(readline) {cc-check-function-in-lib readline readline}
+set libdep(readline) lib_readline
+set needs(signal) {expr {[have-feature sigaction] && [have-feature vfork]}}
+set needs(mk) {check-metakit}
+set libdep(mk) lib_mk
+set needs(sqlite) {cc-check-function-in-lib sqlite_open sqlite}
+set libdep(sqlite) lib_sqlite_open
+set needs(sqlite3) {cc-check-function-in-lib sqlite3_open sqlite3}
+set libdep(sqlite3) lib_sqlite3_open
+set needs(syslog) {have-feature syslog}
+set needs(win32) {have-feature windows}
+set needs(sdl) {expr {[cc-check-function-in-lib SDL_SetVideoMode SDL] && [cc-check-function-in-lib rectangleRGBA SDL_gfx]}}
+set libdep(sdl) {lib_SDL_SetVideoMode lib_rectangleRGBA}
+
+# First handle dependencies. If an extension is enabled, also enable its dependency
+foreach i [concat $ext_default $withext] {
+    if {$i in $without} {
+        continue
+    }
+    if {[info exists dep($i)]} {
+        lappend withext {*}$dep($i)
+    }
+}
+
+foreach i $withmod {
+    if {[info exists dep($i)]} {
+        # Theoretically, a mod could depend upon something which must be static
+        # If already configured static, don't make it a module
+        foreach d $dep($i) {
+            if {$d ni $withext} {
+                lappend withmod $d
+            }
+        }
+    }
+}
+
+# Now that we know what the platform supports:
+
+# For all known extensions:
+# - If it is disabled, remove it
+# - Otherwise, check to see if it's pre-requisites are met
+# -   If yes, add it if it is enabled or is a default
+# -   If no, error if it is enabled, or do nothing otherwise
+# - Modules may be either C or Tcl
+
+set extmodtcl {}
+set extmod {}
+set ext {}
+
+foreach i [lsort $ext_all] {
+    # First discard the extension if disabled or not enabled
+    if {$i in $without} {
+        msg-result "Extension $i...disabled"
+        continue
+    }
+    if {$i ni [concat $withext $withmod $ext_default]} {
+        msg-result "Extension $i...not enabled"
+        continue
+    }
+
+    # Check dependencies
+    set met 1
+    if {[info exists needs($i)]} {
+        set met [eval $needs($i)]
+    }
+
+    define LDLIBS_$i ""
+
+    msg-checking "Extension $i..."
+
+    # Selected as a module?
+    if {$i in $withmod} {
+        if {$i in $ext_tcl_mod} {
+            # Easy, a Tcl module
+            msg-result "tcl"
+            lappend extmodtcl $i
+            continue
+        }
+        if {$i ni $ext_c_mod} {
+            user-error "not a module"
+        }
+        if {!$met} {
+            user-error "dependencies not met"
+        }
+        msg-result "module"
+        lappend extmod $i
+        if {[info exists libdep($i)]} {
+            foreach j $libdep($i) {
+                define-append LDLIBS_$i [get-define $j ""]
+            }
+        }
+        continue
+    }
+
+    # Selected as a static extension?
+    if {$i in $withext} {
+        if {!$met} {
+            user-error "dependencies not met"
+        }
+        msg-result "enabled"
+    } elseif {$i in $ext_default} {
+        if {!$met} {
+            msg-result "disabled (dependencies)"
+            continue
+        }
+        msg-result "enabled (default)"
+    } else {
+        continue
+    }
+
+    lappend ext $i
+    if {[info exists libdep($i)]} {
+        foreach j $libdep($i) {
+            define-append LDLIBS [get-define $j ""]
+        }
+    }
+}
+
+if {[have-feature windows]} {
+    lappend extra_objs jim-win32compat.o
+
+    if {$extmod ne "" && [get-define JIM_LIBTYPE] eq "static"} {
+        user-error "cygwin/mingw require --shared for dynamic modules"
+    }
+}
+
+if {"regexp" in "$ext $extmod"} {
+    # No regcomp means we need to use the built-in version
+    if {![have-feature regcomp]} {
+        incr jimregexp
+    }
+}
+
+if {$jimregexp || [opt-bool jim-regexp]} {
+    msg-result "Using built-in regexp"
+    define JIM_REGEXP
+
+    # If the built-in regexp overrides the system regcomp, etc.
+    # jim must be built shared so that the correct symbols are found
+    if {"regexp" in $extmod && [get-define JIM_LIBTYPE] eq "static" && [have-feature regcomp]} {
+        user-error "Must use --shared with regexp module and built-in regexp"
+    }
+}
+if {"load" ni $ext} {
+    # If we don't have load, no need to support shared objects
+    define SH_LINKFLAGS ""
+}
+
+msg-result "Jim static extensions: [lsort $ext]"
+if {$extmodtcl ne ""} {
+    msg-result "Jim Tcl extensions: [lsort $extmodtcl]"
+}
+if {$extmod ne ""} {
+    msg-result "Jim dynamic extensions: [lsort $extmod]"
+}
+
+# Separate out the static extensions into C and Tcl
+set ext_static_c {}
+set ext_static_tcl {}
+foreach e $ext {
+    define jim_ext_$e
+    if {$e in $ext_tcl} {
+        lappend ext_static_tcl $e
+    } else {
+        lappend ext_static_c $e
+    }
+}
+
+# If there are any static C++ extensions, jimsh must be linked using
+# the C++ compiler
+foreach e $ext_static_c {
+    if {$e in $ext_cxx} {
+        define HAVE_CXX_EXTENSIONS
+    }
+}
+
+define STATIC_EXTS [concat $ext_static_c $ext_static_tcl]
+define C_EXT_OBJS [prefix jim- [suffix .o $ext_static_c]]
+define TCL_EXT_OBJS [suffix .o $ext_static_tcl]
+define C_EXT_SHOBJS [suffix .so $extmod]
+define TCL_EXTS [suffix .tcl $extmodtcl]
+define EXTRA_OBJS $extra_objs
+
+make-config-header jim-config.h -auto {HAVE_LONG_LONG* JIM_UTF8} -none *
+make-config-header jimautoconf.h -auto {jim_ext_* TCL_PLATFORM_* TCL_LIBRARY USE_* JIM_*}
+make-template Makefile.in
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/LICENSE b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/LICENSE
new file mode 100755
index 0000000..4fe636c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/LICENSE
@@ -0,0 +1,35 @@
+Unless explicitly stated, all files which form part of autosetup
+are released under the following license:
+
+---------------------------------------------------------------------
+autosetup - A build environment "autoconfigurator"
+
+Copyright (c) 2010-2011, WorkWare Systems <http://workware.net.au/>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following
+   disclaimer in the documentation and/or other materials
+   provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE WORKWARE SYSTEMS ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WORKWARE
+SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation
+are those of the authors and should not be interpreted as representing
+official policies, either expressed or implied, of WorkWare Systems.
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/README.autosetup b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/README.autosetup
new file mode 100755
index 0000000..c7f69a8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/README.autosetup
@@ -0,0 +1 @@
+This is autosetup v0.6.3. See http://msteveb.github.com/autosetup/
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/autosetup b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/autosetup
new file mode 100755
index 0000000..b1134c8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/autosetup
@@ -0,0 +1,1820 @@
+#!/bin/sh
+# Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+# vim:se syntax=tcl:
+# \
+dir=`dirname "$0"`; exec "`$dir/find-tclsh`" "$0" "$@"
+
+set autosetup(version) 0.6.3
+
+# Can be set to 1 to debug early-init problems
+set autosetup(debug) 0
+
+##################################################################
+#
+# Main flow of control, option handling
+#
+proc main {argv} {
+	global autosetup define
+
+	# There are 3 potential directories involved:
+	# 1. The directory containing autosetup (this script)
+	# 2. The directory containing auto.def
+	# 3. The current directory
+
+	# From this we need to determine:
+	# a. The path to this script (and related support files)
+	# b. The path to auto.def
+	# c. The build directory, where output files are created
+
+	# This is also complicated by the fact that autosetup may
+	# have been run via the configure wrapper ([getenv WRAPPER] is set)
+
+	# Here are the rules.
+	# a. This script is $::argv0
+	#    => dir, prog, exe, libdir
+	# b. auto.def is in the directory containing the configure wrapper,
+	#    otherwise it is in the current directory.
+	#    => srcdir, autodef
+	# c. The build directory is the current directory
+	#    => builddir, [pwd]
+
+	# 'misc' is needed before we can do anything, so set a temporary libdir
+	# in case this is the development version
+	set autosetup(libdir) [file dirname $::argv0]/lib
+	use misc
+
+	# (a)
+	set autosetup(dir) [realdir [file dirname [realpath $::argv0]]]
+	set autosetup(prog) [file join $autosetup(dir) [file tail $::argv0]]
+	set autosetup(exe) [getenv WRAPPER $autosetup(prog)]
+	if {$autosetup(installed)} {
+		set autosetup(libdir) $autosetup(dir)
+	} else {
+		set autosetup(libdir) [file join $autosetup(dir) lib]
+	}
+	autosetup_add_dep $autosetup(prog)
+
+	# (b)
+	if {[getenv WRAPPER ""] eq ""} {
+		# Invoked directly
+		set autosetup(srcdir) [pwd]
+	} else {
+		# Invoked via the configure wrapper
+		set autosetup(srcdir) [file dirname $autosetup(exe)]
+	}
+	set autosetup(autodef) [relative-path $autosetup(srcdir)/auto.def]
+
+	# (c)
+	set autosetup(builddir) [pwd]
+
+	set autosetup(argv) $argv
+	set autosetup(cmdline) {}
+	set autosetup(options) {}
+	set autosetup(optionhelp) {}
+	set autosetup(showhelp) 0
+
+	# Parse options
+	use getopt
+
+	array set ::useropts [getopt argv]
+
+	#"=Core Options:"
+	options-add {
+		help:=local  => "display help and options. Optionally specify a module name, such as --help=system"
+		version      => "display the version of autosetup"
+		ref:=text manual:=text
+		reference:=text => "display the autosetup command reference. 'text', 'wiki', 'asciidoc' or 'markdown'"
+		debug        => "display debugging output as autosetup runs"
+		install:=.   => "install autosetup to the current or given directory (in the 'autosetup/' subdirectory)"
+		force init   => "create an initial 'configure' script if none exists"
+		# Undocumented options
+		option-checking=1
+		nopager
+		quiet
+		timing
+		conf:
+	}
+
+	#parray ::useropts
+	if {[opt-bool version]} {
+		puts $autosetup(version)
+		exit 0
+	}
+
+	# autosetup --conf=alternate-auto.def
+	if {[opt-val conf] ne ""} {
+		set autosetup(autodef) [opt-val conf]
+	}
+
+	# Debugging output (set this early)
+	incr autosetup(debug) [opt-bool debug]
+	incr autosetup(force) [opt-bool force]
+	incr autosetup(msg-quiet) [opt-bool quiet]
+	incr autosetup(msg-timing) [opt-bool timing]
+
+	# If the local module exists, source it now to allow for
+	# project-local customisations
+	if {[file exists $autosetup(libdir)/local.tcl]} {
+		use local
+	}
+
+	if {[opt-val help] ne ""} {
+		incr autosetup(showhelp)
+		use help
+		autosetup_help [opt-val help]
+	}
+
+	if {[opt-val {manual ref reference}] ne ""} {
+		use help
+		autosetup_reference [opt-val {manual ref reference}]
+	}
+
+	if {[opt-bool init]} {
+		use init
+		autosetup_init
+	}
+
+	if {[opt-val install] ne ""} {
+		use install
+		autosetup_install [opt-val install]
+	}
+
+	if {![file exists $autosetup(autodef)]} {
+		# Check for invalid option first
+		options {}
+		user-error "No auto.def found in $autosetup(srcdir)"
+	}
+
+	# Parse extra arguments into autosetup(cmdline)
+	foreach arg $argv {
+		if {[regexp {([^=]*)=(.*)} $arg -> n v]} {
+			dict set autosetup(cmdline) $n $v
+			define $n $v
+		} else {
+			user-error "Unexpected parameter: $arg"
+		}
+	}
+
+	autosetup_add_dep $autosetup(autodef)
+
+	set cmd [file-normalize $autosetup(exe)]
+	foreach arg $autosetup(argv) {
+		append cmd " [quote-if-needed $arg]"
+	}
+	define AUTOREMAKE $cmd
+
+	# Log how we were invoked
+	configlog "Invoked as: [getenv WRAPPER $::argv0] [quote-argv $autosetup(argv)]"
+
+	source $autosetup(autodef)
+
+	# Could warn here if options {} was not specified
+
+	show-notices
+
+	if {$autosetup(debug)} {
+		parray define
+	}
+
+	exit 0
+}
+
+# @opt-bool option ...
+#
+# Check each of the named, boolean options and return 1 if any of them have
+# been set by the user.
+#
+proc opt-bool {args} {
+	option-check-names {*}$args
+	opt_bool ::useropts {*}$args
+}
+
+# @opt-val option-list ?default=""?
+#
+# Returns a list containing all the values given for the non-boolean options in 'option-list'.
+# There will be one entry in the list for each option given by the user, including if the
+# same option was used multiple times.
+# If only a single value is required, use something like:
+#
+## lindex [opt-val $names] end
+#
+# If no options were set, $default is returned (exactly, not as a list).
+#
+proc opt-val {names {default ""}} {
+	option-check-names {*}$names
+	join [opt_val ::useropts $names $default]
+}
+
+proc option-check-names {args} {
+	foreach o $args {
+		if {$o ni $::autosetup(options)} {
+			autosetup-error "Request for undeclared option --$o"
+		}
+	}
+}
+
+# Parse the option definition in $opts and update
+# ::useropts() and ::autosetup(optionhelp) appropriately
+#
+proc options-add {opts {header ""}} {
+	global useropts autosetup
+
+	# First weed out comment lines
+	set realopts {}
+	foreach line [split $opts \n] {
+		if {![string match "#*" [string trimleft $line]]} {
+			append realopts $line \n
+		}
+	}
+	set opts $realopts
+
+	for {set i 0} {$i < [llength $opts]} {incr i} {
+		set opt [lindex $opts $i]
+		if {[string match =* $opt]} {
+			# This is a special heading
+			lappend autosetup(optionhelp) $opt ""
+			set header {}
+			continue
+		}
+
+		#puts "i=$i, opt=$opt"
+		regexp {^([^:=]*)(:)?(=)?(.*)$} $opt -> name colon equal value
+		if {$name in $autosetup(options)} {
+			autosetup-error "Option $name already specified"
+		}
+
+		#puts "$opt => $name $colon $equal $value"
+
+		# Find the corresponding value in the user options
+		# and set the default if necessary
+		if {[string match "-*" $opt]} {
+			# This is a documentation-only option, like "-C <dir>"
+			set opthelp $opt
+		} elseif {$colon eq ""} {
+			# Boolean option
+			lappend autosetup(options) $name
+
+			if {![info exists useropts($name)]} {
+				set useropts($name) $value
+			}
+			if {$value eq "1"} {
+				set opthelp "--disable-$name"
+			} else {
+				set opthelp "--$name"
+			}
+		} else {
+			# String option.
+			lappend autosetup(options) $name
+
+			if {$equal eq "="} {
+				if {[info exists useropts($name)]} {
+					# If the user specified the option with no value, the value will be "1"
+					# Replace with the default
+					if {$useropts($name) eq "1"} {
+						set useropts($name) $value
+					}
+				}
+				set opthelp "--$name?=$value?"
+			} else {
+				set opthelp "--$name=$value"
+			}
+		}
+
+		# Now create the help for this option if appropriate
+		if {[lindex $opts $i+1] eq "=>"} {
+			set desc [lindex $opts $i+2]
+			#string match \n* $desc
+			if {$header ne ""} {
+				lappend autosetup(optionhelp) $header ""
+				set header ""
+			}
+			# A multi-line description
+			lappend autosetup(optionhelp) $opthelp $desc
+			incr i 2
+		}
+	}
+}
+
+# @module-options optionlist
+#
+# Like 'options', but used within a module.
+proc module-options {opts} {
+	set header ""
+	if {$::autosetup(showhelp) > 1 && [llength $opts]} {
+		set header "Module Options:"
+	}
+	options-add $opts $header
+
+	if {$::autosetup(showhelp)} {
+		# Ensure that the module isn't executed on --help
+		# We are running under eval or source, so use break
+		# to prevent further execution
+		#return -code break -level 2
+		return -code break
+	}
+}
+
+proc max {a b} {
+	expr {$a > $b ? $a : $b}
+}
+
+proc options-wrap-desc {text length firstprefix nextprefix initial} {
+	set len $initial
+	set space $firstprefix
+	foreach word [split $text] {
+		set word [string trim $word]
+		if {$word == ""} {
+			continue
+		}
+		if {$len && [string length $space$word] + $len >= $length} {
+			puts ""
+			set len 0
+			set space $nextprefix
+		}
+		incr len [string length $space$word]
+		puts -nonewline $space$word
+		set space " "
+	}
+	if {$len} {
+		puts ""
+	}
+}
+
+proc options-show {} {
+	# Determine the max option width
+	set max 0
+	foreach {opt desc} $::autosetup(optionhelp) {
+		if {[string match =* $opt] || [string match \n* $desc]} {
+			continue
+		}
+		set max [max $max [string length $opt]]
+	}
+	set indent [string repeat " " [expr $max+4]]
+	set cols [getenv COLUMNS 80]
+	catch {
+		lassign [exec stty size] rows cols
+	}
+	incr cols -1
+	# Now output
+	foreach {opt desc} $::autosetup(optionhelp) {
+		if {[string match =* $opt]} {
+			puts [string range $opt 1 end]
+			continue
+		}
+		puts -nonewline "  [format %-${max}s $opt]"
+		if {[string match \n* $desc]} {
+			puts $desc
+		} else {
+			options-wrap-desc [string trim $desc] $cols "  " $indent [expr $max + 2]
+		}
+	}
+}
+
+# @options options-spec
+#
+# Specifies configuration-time options which may be selected by the user
+# and checked with opt-val and opt-bool. The format of options-spec follows.
+#
+# A boolean option is of the form:
+#
+## name[=0|1]  => "Description of this boolean option"
+#
+# The default is name=0, meaning that the option is disabled by default.
+# If name=1 is used to make the option enabled by default, the description should reflect
+# that with text like "Disable support for ...".
+#
+# An argument option (one which takes a parameter) is of the form:
+#
+## name:[=]value  => "Description of this option"
+#
+# If the name:value form is used, the value must be provided with the option (as --name=myvalue).
+# If the name:=value form is used, the value is optional and the given value is used as the default
+# if is not provided.
+#
+# Undocumented options are also supported by omitting the "=> description.
+# These options are not displayed with --help and can be useful for internal options or as aliases.
+#
+# For example, --disable-lfs is an alias for --disable=largefile:
+#
+## lfs=1 largefile=1 => "Disable large file support"
+#
+proc options {optlist} {
+	# Allow options as a list or args
+	options-add $optlist "Local Options:"
+
+	if {$::autosetup(showhelp)} {
+		options-show
+		exit 0
+	}
+
+	# Check for invalid options
+	if {[opt-bool option-checking]} {
+		foreach o [array names ::useropts] {
+			if {$o ni $::autosetup(options)} {
+				user-error "Unknown option --$o"
+			}
+		}
+	}
+}
+
+proc config_guess {} {
+	if {[file-isexec $::autosetup(dir)/config.guess]} {
+		exec-with-stderr sh $::autosetup(dir)/config.guess
+	} else {
+		configlog "No config.guess, so using uname"
+		string tolower [exec uname -p]-unknown-[exec uname -s][exec uname -r]
+	}
+}
+
+proc config_sub {alias} {
+	if {[file-isexec $::autosetup(dir)/config.sub]} {
+		exec-with-stderr sh $::autosetup(dir)/config.sub $alias
+	} else {
+		return $alias
+	}
+}
+
+# @define name ?value=1?
+#
+# Defines the named variable to the given value.
+# These (name, value) pairs represent the results of the configuration check
+# and are available to be checked, modified and substituted.
+#
+proc define {name {value 1}} {
+	set ::define($name) $value
+	#dputs "$name <= $value"
+}
+
+# @define-append name value ...
+#
+# Appends the given value(s) to the given 'defined' variable.
+# If the variable is not defined or empty, it is set to $value.
+# Otherwise the value is appended, separated by a space.
+# Any extra values are similarly appended.
+# If any value is already contained in the variable (as a substring) it is omitted.
+#
+proc define-append {name args} {
+	if {[get-define $name ""] ne ""} {
+		# Make a token attempt to avoid duplicates
+		foreach arg $args {
+			if {[string first $arg $::define($name)] == -1} {
+				append ::define($name) " " $arg
+			}
+		}
+	} else {
+		set ::define($name) [join $args]
+	}
+	#dputs "$name += [join $args] => $::define($name)"
+}
+
+# @get-define name ?default=0?
+#
+# Returns the current value of the 'defined' variable, or $default
+# if not set.
+#
+proc get-define {name {default 0}} {
+	if {[info exists ::define($name)]} {
+		#dputs "$name => $::define($name)"
+		return $::define($name)
+	}
+	#dputs "$name => $default"
+	return $default
+}
+
+# @is-defined name
+#
+# Returns 1 if the given variable is defined.
+#
+proc is-defined {name} {
+	info exists ::define($name)
+}
+
+# @all-defines
+#
+# Returns a dictionary (name value list) of all defined variables.
+#
+# This is suitable for use with 'dict', 'array set' or 'foreach'
+# and allows for arbitrary processing of the defined variables.
+#
+proc all-defines {} {
+	array get ::define
+}
+
+
+# @get-env name default
+#
+# If $name was specified on the command line, return it.
+# If $name was set in the environment, return it.
+# Otherwise return $default.
+#
+proc get-env {name default} {
+	if {[dict exists $::autosetup(cmdline) $name]} {
+		return [dict get $::autosetup(cmdline) $name]
+	}
+	getenv $name $default
+}
+
+# @env-is-set name
+#
+# Returns 1 if the $name was specified on the command line or in the environment.
+# Note that an empty environment variable is not considered to be set.
+#
+proc env-is-set {name} {
+	if {[dict exists $::autosetup(cmdline) $name]} {
+		return 1
+	}
+	if {[getenv $name ""] ne ""} {
+		return 1
+	}
+	return 0
+}
+
+# @readfile filename ?default=""?
+#
+# Return the contents of the file, without the trailing newline.
+# If the doesn't exist or can't be read, returns $default.
+#
+proc readfile {filename {default_value ""}} {
+	set result $default_value
+	catch {
+		set f [open $filename]
+		set result [read -nonewline $f]
+		close $f
+	}
+	return $result
+}
+
+# @writefile filename value
+#
+# Creates the given file containing $value.
+# Does not add an extra newline.
+#
+proc writefile {filename value} {
+	set f [open $filename w]
+	puts -nonewline $f $value
+	close $f
+}
+
+proc quote-if-needed {str} {
+	if {[string match {*[\" ]*} $str]} {
+		return \"[string map [list \" \\" \\ \\\\] $str]\"
+	}
+	return $str
+}
+
+proc quote-argv {argv} {
+	set args {}
+	foreach arg $argv {
+		lappend args [quote-if-needed $arg]
+	}
+	join $args
+}
+
+# @suffix suf list
+#
+# Takes a list and returns a new list with $suf appended
+# to each element
+#
+## suffix .c {a b c} => {a.c b.c c.c}
+#
+proc suffix {suf list} {
+	set result {}
+	foreach p $list {
+		lappend result $p$suf
+	}
+	return $result
+}
+
+# @prefix pre list
+#
+# Takes a list and returns a new list with $pre prepended
+# to each element
+#
+## prefix jim- {a.c b.c} => {jim-a.c jim-b.c}
+#
+proc prefix {pre list} {
+	set result {}
+	foreach p $list {
+		lappend result $pre$p
+	}
+	return $result
+}
+
+# @find-executable name
+#
+# Searches the path for an executable with the given name.
+# Note that the name may include some parameters, e.g. "cc -mbig-endian",
+# in which case the parameters are ignored.
+# Returns 1 if found, or 0 if not.
+#
+proc find-executable {name} {
+	# Ignore any parameters
+	set name [lindex $name 0]
+	if {$name eq ""} {
+		# The empty string is never a valid executable
+		return 0
+	}
+	foreach p [split-path] {
+		dputs "Looking for $name in $p"
+		set exec [file join $p $name]
+		if {[file-isexec $exec]} {
+			dputs "Found $name -> $exec"
+			return 1
+		}
+	}
+	return 0
+}
+
+# @find-an-executable ?-required? name ...
+#
+# Given a list of possible executable names,
+# searches for one of these on the path.
+#
+# Returns the name found, or "" if none found.
+# If the first parameter is '-required', an error is generated
+# if no executable is found.
+#
+proc find-an-executable {args} {
+	set required 0
+	if {[lindex $args 0] eq "-required"} {
+		set args [lrange $args 1 end]
+		incr required
+	}
+	foreach name $args {
+		if {[find-executable $name]} {
+			return $name
+		}
+	}
+	if {$required} {
+		if {[llength $args] == 1} {
+			user-error "failed to find: [join $args]"
+		} else {
+			user-error "failed to find one of: [join $args]"
+		}
+	}
+	return ""
+}
+
+# @configlog msg
+#
+# Writes the given message to the configuration log, config.log
+#
+proc configlog {msg} {
+	if {![info exists ::autosetup(logfh)]} {
+		set ::autosetup(logfh) [open config.log w]
+	}
+	puts $::autosetup(logfh) $msg
+}
+
+# @msg-checking msg
+#
+# Writes the message with no newline to stdout.
+#
+proc msg-checking {msg} {
+	if {$::autosetup(msg-quiet) == 0} {
+		maybe-show-timestamp
+		puts -nonewline $msg
+		set ::autosetup(msg-checking) 1
+	}
+}
+
+# @msg-result msg
+#
+# Writes the message to stdout.
+#
+proc msg-result {msg} {
+	if {$::autosetup(msg-quiet) == 0} {
+		maybe-show-timestamp
+		puts $msg
+		set ::autosetup(msg-checking) 0
+		show-notices
+	}
+}
+
+# @msg-quiet command ...
+#
+# msg-quiet evaluates it's arguments as a command with output
+# from msg-checking and msg-result suppressed.
+#
+# This is useful if a check needs to run a subcheck which isn't
+# of interest to the user.
+proc msg-quiet {args} {
+	incr ::autosetup(msg-quiet)
+	set rc [uplevel 1 $args]
+	incr ::autosetup(msg-quiet) -1
+	return $rc
+}
+
+# Will be overridden by 'use misc'
+proc error-stacktrace {msg} {
+	return $msg
+}
+
+proc error-location {msg} {
+	return $msg
+}
+
+##################################################################
+#
+# Debugging output
+#
+proc dputs {msg} {
+	if {$::autosetup(debug)} {
+		puts $msg
+	}
+}
+
+##################################################################
+#
+# User and system warnings and errors
+#
+# Usage errors such as wrong command line options
+
+# @user-error msg
+#
+# Indicate incorrect usage to the user, including if required components
+# or features are not found.
+# autosetup exits with a non-zero return code.
+#
+proc user-error {msg} {
+	show-notices
+	puts stderr "Error: $msg"
+	puts stderr "Try: '[file tail $::autosetup(exe)] --help' for options"
+	exit 1
+}
+
+# @user-notice msg
+#
+# Output the given message to stderr.
+#
+proc user-notice {msg} {
+	lappend ::autosetup(notices) $msg
+}
+
+# Incorrect usage in the auto.def file. Identify the location.
+proc autosetup-error {msg} {
+	show-notices
+	puts stderr [error-location $msg]
+	exit 1
+}
+
+proc show-notices {} {
+	if {$::autosetup(msg-checking)} {
+		puts ""
+		set ::autosetup(msg-checking) 0
+	}
+	flush stdout
+	if {[info exists ::autosetup(notices)]} {
+		puts stderr [join $::autosetup(notices) \n]
+		unset ::autosetup(notices)
+	}
+}
+
+proc maybe-show-timestamp {} {
+	if {$::autosetup(msg-timing) && $::autosetup(msg-checking) == 0} {
+		puts -nonewline [format {[%6.2f] } [expr {([clock millis] - $::autosetup(start)) % 10000 / 1000.0}]]
+	}
+}
+
+proc autosetup_version {} {
+	return "autosetup v$::autosetup(version)"
+}
+
+##################################################################
+#
+# Directory/path handling
+#
+
+proc realdir {dir} {
+	set oldpwd [pwd]
+	cd $dir
+	set pwd [pwd]
+	cd $oldpwd
+	return $pwd
+}
+
+# Follow symlinks until we get to something which is not a symlink
+proc realpath {path} {
+	while {1} {
+		if {[catch {
+			set path [file link $path]
+		}]} {
+			# Not a link
+			break
+		}
+	}
+	return $path
+}
+
+# Convert absolute path, $path into a path relative
+# to the given directory (or the current dir, if not given).
+#
+proc relative-path {path {pwd {}}} {
+	set diff 0
+	set same 0
+	set newf {}
+	set prefix {}
+	set path [file-normalize $path]
+	if {$pwd eq ""} {
+		set pwd [pwd]
+	} else {
+		set pwd [file-normalize $pwd]
+	}
+
+	if {$path eq $pwd} {
+		return .
+	}
+
+	# Try to make the filename relative to the current dir
+	foreach p [split $pwd /] f [split $path /] {
+		if {$p ne $f} {
+			incr diff
+		} elseif {!$diff} {
+			incr same
+		}
+		if {$diff} {
+			if {$p ne ""} {
+				# Add .. for sibling or parent dir
+				lappend prefix ..
+			}
+			if {$f ne ""} {
+				lappend newf $f
+			}
+		}
+	}
+	if {$same == 1 || [llength $prefix] > 3} {
+		return $path
+	}
+
+	file join [join $prefix /] [join $newf /]
+}
+
+# Add filename as a dependency to rerun autosetup
+# The name will be normalised (converted to a full path)
+#
+proc autosetup_add_dep {filename} {
+	lappend ::autosetup(deps) [file-normalize $filename]
+}
+
+##################################################################
+#
+# Library module support
+#
+
+# @use module ...
+#
+# Load the given library modules.
+# e.g. use cc cc-shared
+#
+proc use {args} {
+	foreach m $args {
+		if {[info exists ::libmodule($m)]} {
+			continue
+		}
+		set ::libmodule($m) 1
+		if {[info exists ::modsource($m)]} {
+			uplevel #0 eval $::modsource($m)
+		} else {
+			set source $::autosetup(libdir)/${m}.tcl
+			if {[file exists $source]} {
+				uplevel #0 [list source $source]
+				autosetup_add_dep $source
+			} else {
+				puts "Looking for $source"
+				autosetup-error "use: No such module: $m"
+			}
+		}
+	}
+}
+
+# Initial settings
+set autosetup(exe) $::argv0
+set autosetup(istcl) 1
+set autosetup(start) [clock millis]
+set autosetup(installed) 0
+set autosetup(msg-checking) 0
+set autosetup(msg-quiet) 0
+
+# Embedded modules are inserted below here
+set autosetup(installed) 1
+# ----- module asciidoc-formatting -----
+
+set modsource(asciidoc-formatting) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+# asciidoc format
+
+use formatting
+
+proc para {text} {
+    regsub -all "\[ \t\n\]+" [string trim $text] " "
+}
+proc title {text} {
+    underline [para $text] =
+    nl
+}
+proc p {text} {
+    puts [para $text]
+    nl
+}
+proc code {text} {
+    foreach line [parse_code_block $text] {
+        puts "    $line"
+    }
+    nl
+}
+proc codelines {lines} {
+    foreach line $lines {
+        puts "    $line"
+    }
+    nl
+}
+proc nl {} {
+    puts ""
+}
+proc underline {text char} {
+    regexp "^(\[ \t\]*)(.*)" $text -> indent words
+    puts $text
+    puts $indent[string repeat $char [string length $words]]
+}
+proc section {text} {
+    underline "[para $text]" -
+    nl
+}
+proc subsection {text} {
+    underline "$text" ~
+    nl
+}
+proc bullet {text} {
+    puts "* [para $text]"
+}
+proc indent {text} {
+    puts " :: "
+    puts [para $text]
+}
+proc defn {first args} {
+    set sep ""
+    if {$first ne ""} {
+        puts "${first}::"
+    } else {
+        puts " :: "
+    }
+    set defn [string trim [join $args \n]]
+    regsub -all "\n\n" $defn "\n ::\n" defn
+    puts $defn
+}
+}
+
+# ----- module formatting -----
+
+set modsource(formatting) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides common text formatting
+
+# This is designed for documenation which looks like:
+# code {...}
+# or
+# code {
+#    ...
+#    ...
+# }
+# In the second case, we need to work out the indenting
+# and strip it from all lines but preserve the remaining indenting.
+# Note that all lines need to be indented with the same initial
+# spaces/tabs.
+#
+# Returns a list of lines with the indenting removed.
+#
+proc parse_code_block {text} {
+    # If the text begins with newline, take the following text,
+    # otherwise just return the original
+    if {![regexp "^\n(.*)" $text -> text]} {
+        return [list [string trim $text]]
+    }
+
+    # And trip spaces off the end
+    set text [string trimright $text]
+
+    set min 100
+    # Examine each line to determine the minimum indent
+    foreach line [split $text \n] {
+        if {$line eq ""} {
+            # Ignore empty lines for the indent calculation
+            continue
+        }
+        regexp "^(\[ \t\]*)" $line -> indent
+        set len [string length $indent]
+        if {$len < $min} {
+            set min $len
+        }
+    }
+
+    # Now make a list of lines with this indent removed
+    set lines {}
+    foreach line [split $text \n] {
+        lappend lines [string range $line $min end]
+    }
+
+    # Return the result
+    return $lines
+}
+}
+
+# ----- module getopt -----
+
+set modsource(getopt) {
+# Copyright (c) 2006 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Simple getopt module
+
+# Parse everything out of the argv list which looks like an option
+# Knows about --enable-thing and --disable-thing as alternatives for --thing=0 or --thing=1
+# Everything which doesn't look like an option, or is after --, is left unchanged
+proc getopt {argvname} {
+	upvar $argvname argv
+	set nargv {}
+
+	for {set i 0} {$i < [llength $argv]} {incr i} {
+		set arg [lindex $argv $i]
+
+		#dputs arg=$arg
+
+		if {$arg eq "--"} {
+			# End of options
+			incr i
+			lappend nargv {*}[lrange $argv $i end]
+			break
+		}
+
+		if {[regexp {^--([^=][^=]+)=(.*)$} $arg -> name value]} {
+			lappend opts($name) $value
+		} elseif {[regexp {^--(enable-|disable-)?([^=]*)$} $arg -> prefix name]} {
+			if {$prefix eq "disable-"} {
+				set value 0
+			} else {
+				set value 1
+			}
+			lappend opts($name) $value
+		} else {
+			lappend nargv $arg
+		}
+	}
+
+	#puts "getopt: argv=[join $argv] => [join $nargv]"
+	#parray opts
+
+	set argv $nargv
+
+	return [array get opts]
+}
+
+proc opt_val {optarrayname options {default {}}} {
+	upvar $optarrayname opts
+
+	set result {}
+
+	foreach o $options {
+		if {[info exists opts($o)]} {
+			lappend result {*}$opts($o)
+		}
+	}
+	if {[llength $result] == 0} {
+		return $default
+	}
+	return $result
+}
+
+proc opt_bool {optarrayname args} {
+	upvar $optarrayname opts
+
+	# Support the args being passed as a list
+	if {[llength $args] == 1} {
+		set args [lindex $args 0]
+	}
+
+	foreach o $args {
+		if {[info exists opts($o)]} {
+			if {"1" in $opts($o) || "yes" in $opts($o)} {
+				return 1
+			}
+		}
+	}
+	return 0
+}
+}
+
+# ----- module help -----
+
+set modsource(help) {
+# Copyright (c) 2010 WorkWare Systems http://workware.net.au/
+# All rights reserved
+
+# Module which provides usage, help and the command reference
+
+proc autosetup_help {what} {
+    use_pager
+
+    puts "Usage: [file tail $::autosetup(exe)] \[options\] \[settings\]\n"
+    puts "This is [autosetup_version], a build environment \"autoconfigurator\""
+    puts "See the documentation online at http://msteveb.github.com/autosetup/\n"
+
+    if {$what eq "local"} {
+        if {[file exists $::autosetup(autodef)]} {
+            # This relies on auto.def having a call to 'options'
+            # which will display options and quit
+            source $::autosetup(autodef)
+        } else {
+            options-show
+        }
+    } else {
+        incr ::autosetup(showhelp)
+        if {[catch {use $what}]} {
+            user-error "Unknown module: $what"
+        } else {
+            options-show
+        }
+    }
+    exit 0
+}
+
+# If not already paged and stdout is a tty, pipe the output through the pager
+# This is done by reinvoking autosetup with --nopager added
+proc use_pager {} {
+    if {![opt-bool nopager] && [getenv PAGER ""] ne "" && ![string match "not a tty" [exec tty]]} {
+        catch {
+            exec [info nameofexecutable] $::argv0 --nopager {*}$::argv | [getenv PAGER] >@stdout <@stdin 2>/dev/null
+        }
+        exit 0
+    }
+}
+
+# Outputs the autosetup references in one of several formats
+proc autosetup_reference {{type text}} {
+
+    use_pager
+
+    switch -glob -- $type {
+        wiki {use wiki-formatting}
+        ascii* {use asciidoc-formatting}
+        md - markdown {use markdown-formatting}
+        default {use text-formatting}
+    }
+
+    title "[autosetup_version] -- Command Reference"
+
+    section {Introduction}
+
+    p {
+        See http://msteveb.github.com/autosetup/ for the online documentation for 'autosetup'
+    }
+
+    p {
+        'autosetup' provides a number of built-in commands which
+        are documented below. These may be used from 'auto.def' to test
+        for features, define variables, create files from templates and
+        other similar actions.
+    }
+
+    automf_command_reference
+
+    exit 0
+}
+
+proc autosetup_output_block {type lines} {
+    if {[llength $lines]} {
+        switch $type {
+            code {
+                codelines $lines
+            }
+            p {
+                p [join $lines]
+            }
+            list {
+                foreach line $lines {
+                    bullet $line
+                }
+                nl
+            }
+        }
+    }
+}
+
+# Generate a command reference from inline documentation
+proc automf_command_reference {} {
+    lappend files $::autosetup(prog)
+    lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/*.tcl]]
+
+    section "Core Commands"
+    set type p
+    set lines {}
+    set cmd {}
+
+    foreach file $files {
+        set f [open $file]
+        while {![eof $f]} {
+            set line [gets $f]
+
+            # Find lines starting with "# @*" and continuing through the remaining comment lines
+            if {![regexp {^# @(.*)} $line -> cmd]} {
+                continue
+            }
+
+            # Synopsis or command?
+            if {$cmd eq "synopsis:"} {
+                section "Module: [file rootname [file tail $file]]"
+            } else {
+                subsection $cmd
+            }
+
+            set lines {}
+            set type p
+
+            # Now the description
+            while {![eof $f]} {
+                set line [gets $f]
+
+                if {![regexp {^#(#)? ?(.*)} $line -> hash cmd]} {
+                    break
+                }
+                if {$hash eq "#"} {
+                    set t code
+                } elseif {[regexp {^- (.*)} $cmd -> cmd]} {
+                    set t list
+                } else {
+                    set t p
+                }
+
+                #puts "hash=$hash, oldhash=$oldhash, lines=[llength $lines], cmd=$cmd"
+
+                if {$t ne $type || $cmd eq ""} {
+                    # Finish the current block
+                    autosetup_output_block $type $lines
+                    set lines {}
+                    set type $t
+                }
+                if {$cmd ne ""} {
+                    lappend lines $cmd
+                }
+            }
+
+            autosetup_output_block $type $lines
+        }
+        close $f
+    }
+}
+}
+
+# ----- module init -----
+
+set modsource(init) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module to help create auto.def and configure
+
+proc autosetup_init {} {
+	set create_configure 1
+	if {[file exists configure]} {
+		if {!$::autosetup(force)} {
+			# Could this be an autosetup configure?
+			if {![string match "*\nWRAPPER=*" [readfile configure]]} {
+				puts "I see configure, but not created by autosetup, so I won't overwrite it."
+				puts "Use autosetup --init --force to overwrite."
+				set create_configure 0
+			}
+		} else {
+			puts "I will overwrite the existing configure because you used --force."
+		}
+	} else {
+		puts "I don't see configure, so I will create it."
+	}
+	if {$create_configure} {
+		if {!$::autosetup(installed)} {
+			user-notice "Warning: Initialising from the development version of autosetup"
+
+			writefile configure "#!/bin/sh\nWRAPPER=\"\$0\" exec $::autosetup(dir)/autosetup \"\$@\"\n"
+		} else {
+			writefile configure \
+{#!/bin/sh
+dir="`dirname "$0"`/autosetup"
+WRAPPER="$0" exec "`$dir/find-tclsh`" "$dir/autosetup" "$@"
+}
+		}
+		catch {exec chmod 755 configure}
+	}
+	if {![file exists auto.def]} {
+		puts "I don't see auto.def, so I will create a default one."
+		writefile auto.def {# Initial auto.def created by 'autosetup --init'
+
+use cc
+
+# Add any user options here
+options {
+}
+
+make-config-header config.h
+make-template Makefile.in
+}
+	}
+	if {![file exists Makefile.in]} {
+		puts "Note: I don't see Makefile.in. You will probably need to create one."
+	}
+
+	exit 0
+}
+}
+
+# ----- module install -----
+
+set modsource(install) {
+# Copyright (c) 2006-2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which can install autosetup
+
+proc autosetup_install {dir} {
+	if {[catch {
+		cd $dir
+		file mkdir autosetup
+
+		set f [open autosetup/autosetup w]
+
+		set publicmodules {}
+
+		# First the main script, but only up until "CUT HERE"
+		set in [open $::autosetup(dir)/autosetup]
+		while {[gets $in buf] >= 0} {
+			if {$buf ne "##-- CUT HERE --##"} {
+				puts $f $buf
+				continue
+			}
+
+			# Insert the static modules here
+			# i.e. those which don't contain @synopsis:
+			puts $f "set autosetup(installed) 1"
+			foreach file [lsort [glob $::autosetup(libdir)/*.tcl]] {
+				set buf [readfile $file]
+				if {[string match "*\n# @synopsis:*" $buf]} {
+					lappend publicmodules $file
+					continue
+				}
+				set modname [file rootname [file tail $file]]
+				puts $f "# ----- module $modname -----"
+				puts $f "\nset modsource($modname) \{"
+				puts $f $buf
+				puts $f "\}\n"
+			}
+		}
+		close $in
+		close $f
+		exec chmod 755 autosetup/autosetup
+
+		# Install public modules
+		foreach file $publicmodules {
+			autosetup_install_file $file autosetup
+		}
+
+		# Install support files
+		foreach file {config.guess config.sub jimsh0.c find-tclsh test-tclsh LICENSE} {
+			autosetup_install_file $::autosetup(dir)/$file autosetup
+		}
+		exec chmod 755 autosetup/config.sub autosetup/config.guess autosetup/find-tclsh
+
+		writefile autosetup/README.autosetup \
+			"This is [autosetup_version]. See http://msteveb.github.com/autosetup/\n"
+
+	} error]} {
+		user-error "Failed to install autosetup: $error"
+	}
+	puts "Installed [autosetup_version] to autosetup/"
+	catch {exec [info nameofexecutable] autosetup/autosetup --init >@stdout 2>@stderr}
+
+	exit 0
+}
+
+# Append the contents of $file to filehandle $f
+proc autosetup_install_append {f file} {
+	set in [open $file]
+	puts $f [read $in]
+	close $in
+}
+
+proc autosetup_install_file {file dir} {
+	if {![file exists $file]} {
+		error "Missing installation file '$file'"
+	}
+	writefile [file join $dir [file tail $file]] [readfile $file]\n
+}
+
+if {$::autosetup(installed)} {
+	user-error "autosetup can only be installed from development source, not from installed copy"
+}
+}
+
+# ----- module markdown-formatting -----
+
+set modsource(markdown-formatting) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+# markdown format (kramdown syntax)
+
+use formatting
+
+proc para {text} {
+    regsub -all "\[ \t\n\]+" [string trim $text] " " text
+    regsub -all {([^a-zA-Z])'([^']*)'} $text {\1**`\2`**} text
+    regsub -all {^'([^']*)'} $text {**`\1`**} text
+    regsub -all {(http[^ \t\n]*)} $text {[\1](\1)} text
+    return $text
+}
+proc title {text} {
+    underline [para $text] =
+    nl
+}
+proc p {text} {
+    puts [para $text]
+    nl
+}
+proc codelines {lines} {
+    puts "~~~~~~~~~~~~"
+    foreach line $lines {
+        puts $line
+    }
+    puts "~~~~~~~~~~~~"
+    nl
+}
+proc code {text} {
+    puts "~~~~~~~~~~~~"
+    foreach line [parse_code_block $text] {
+        puts $line
+    }
+    puts "~~~~~~~~~~~~"
+    nl
+}
+proc nl {} {
+    puts ""
+}
+proc underline {text char} {
+    regexp "^(\[ \t\]*)(.*)" $text -> indent words
+    puts $text
+    puts $indent[string repeat $char [string length $words]]
+}
+proc section {text} {
+    underline "[para $text]" -
+    nl
+}
+proc subsection {text} {
+    puts "### `$text`"
+    nl
+}
+proc bullet {text} {
+    puts "* [para $text]"
+}
+proc defn {first args} {
+    puts "^"
+    set defn [string trim [join $args \n]]
+    if {$first ne ""} {
+        puts "**${first}**"
+        puts -nonewline ": "
+        regsub -all "\n\n" $defn "\n: " defn
+    }
+    puts "$defn"
+}
+}
+
+# ----- module misc -----
+
+set modsource(misc) {
+# Copyright (c) 2007-2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module containing misc procs useful to modules
+# Largely for platform compatibility
+
+set autosetup(istcl) [info exists ::tcl_library]
+set autosetup(iswin) [string equal windows $tcl_platform(platform)]
+
+if {$autosetup(iswin)} {
+	# mingw/windows separates $PATH with semicolons
+	# and doesn't have an executable bit
+	proc split-path {} {
+		split [getenv PATH .] {;}
+	}
+	proc file-isexec {exec} {
+		# Basic test for windows. We ignore .bat
+		if {[file isfile $exec] || [file isfile $exec.exe]} {
+			return 1
+		}
+		return 0
+	}
+} else {
+	# unix separates $PATH with colons and has and executable bit
+	proc split-path {} {
+		split [getenv PATH .] :
+	}
+	proc file-isexec {exec} {
+		file executable $exec
+	}
+}
+
+# Assume that exec can return stdout and stderr
+proc exec-with-stderr {args} {
+	exec {*}$args 2>@1
+}
+
+if {$autosetup(istcl)} {
+	# Tcl doesn't have the env command
+	proc getenv {name args} {
+		if {[info exists ::env($name)]} {
+			return $::env($name)
+		}
+		if {[llength $args]} {
+			return [lindex $args 0]
+		}
+		return -code error "environment variable \"$name\" does not exist"
+	}
+} elseif {$autosetup(iswin)} {
+	# On Windows, backslash convert all environment variables
+	# (Assume that Tcl does this for us)
+	proc getenv {name args} {
+		string map {\\ /} [env $name {*}$args]
+	}
+} else {
+	# Jim on unix is simple
+	alias getenv env
+}
+
+# In case 'file normalize' doesn't exist
+#
+proc file-normalize {path} {
+	if {[catch {file normalize $path} result]} {
+		if {$path eq ""} {
+			return ""
+		}
+		set oldpwd [pwd]
+		if {[file isdir $path]} {
+			cd $path
+			set result [pwd]
+		} else {
+			cd [file dirname $path]
+			set result [file join [pwd] [file tail $path]]
+		}
+		cd $oldpwd
+	}
+	return $result
+}
+
+# If everything is working properly, the only errors which occur
+# should be generated in user code (e.g. auto.def).
+# By default, we only want to show the error location in user code.
+# We use [info frame] to achieve this, but it works differently on Tcl and Jim.
+#
+# This is designed to be called for incorrect usage in auto.def, via autosetup-error
+#
+proc error-location {msg} {
+	if {$::autosetup(debug)} {
+		return -code error $msg
+	}
+	# Search back through the stack trace for the first error in a .def file
+	for {set i 1} {$i < [info level]} {incr i} {
+		if {$::autosetup(istcl)} {
+			array set info [info frame -$i]
+		} else {
+			lassign [info frame -$i] info(caller) info(file) info(line)
+		}
+		if {[string match *.def $info(file)]} {
+			return "[relative-path $info(file)]:$info(line): Error: $msg"
+		}
+		#puts "Skipping $info(file):$info(line)"
+	}
+	return $msg
+}
+
+# Similar to error-location, but called when user code generates an error
+# In this case we want to show the stack trace in user code, but not in autosetup code
+# (unless --debug is enabled)
+#
+proc error-stacktrace {msg} {
+	if {$::autosetup(istcl)} {
+		if {[regexp {file "([^ ]*)" line ([0-9]*)} $::errorInfo dummy file line]} {
+			return "[relative-path $file]:$line $msg\n$::errorInfo"
+		}
+		return $::errorInfo
+	} else {
+		# Prepend a live stacktrace to the error stacktrace, omitting the current level
+		set stacktrace [concat [info stacktrace] [lrange [stacktrace] 3 end]]
+
+		if {!$::autosetup(debug)} {
+			# Omit any levels from autosetup or with no file
+			set newstacktrace {}
+			foreach {p f l} $stacktrace {
+				if {[string match "*autosetup" $f] || $f eq ""} {
+					#puts "Skipping $p $f:$l"
+					continue
+				}
+				lappend newstacktrace $p $f $l
+			}
+			set stacktrace $newstacktrace
+		}
+
+		# Convert filenames to relative paths
+		set newstacktrace {}
+		foreach {p f l} $stacktrace {
+			lappend newstacktrace $p [relative-path $f] $l
+		}
+		lassign $newstacktrace p f l
+		if {$f ne ""} {
+			set prefix "$f:$l: "
+		} else {
+			set prefix ""
+		}
+
+		return "${prefix}Error: $msg\n[stackdump $newstacktrace]"
+	}
+}
+}
+
+# ----- module text-formatting -----
+
+set modsource(text-formatting) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+
+use formatting
+
+proc wordwrap {text length {firstprefix ""} {nextprefix ""}} {
+    set len 0
+    set space $firstprefix
+    foreach word [split $text] {
+        set word [string trim $word]
+        if {$word == ""} {
+            continue
+        }
+        if {$len && [string length $space$word] + $len >= $length} {
+            puts ""
+            set len 0
+            set space $nextprefix
+        }
+        incr len [string length $space$word]
+
+        # Use man-page conventions for highlighting 'quoted' and *quoted*
+        # single words.
+        # Use x^Hx for *bold* and _^Hx for 'underline'.
+        #
+        # less and more will both understand this.
+        # Pipe through 'col -b' to remove them.
+        if {[regexp {^'(.*)'([^a-zA-Z0-9_]*)$} $word -> bareword dot]} {
+            regsub -all . $bareword "_\b&" word
+            append word $dot
+        } elseif {[regexp {^[*](.*)[*]([^a-zA-Z0-9_]*)$} $word -> bareword dot]} {
+            regsub -all . $bareword "&\b&" word
+            append word $dot
+        }
+        puts -nonewline $space$word
+        set space " "
+    }
+    if {$len} {
+        puts ""
+    }
+}
+proc title {text} {
+    underline [string trim $text] =
+    nl
+}
+proc p {text} {
+    wordwrap $text 80
+    nl
+}
+proc codelines {lines} {
+    foreach line $lines {
+        puts "    $line"
+    }
+    nl
+}
+proc nl {} {
+    puts ""
+}
+proc underline {text char} {
+    regexp "^(\[ \t\]*)(.*)" $text -> indent words
+    puts $text
+    puts $indent[string repeat $char [string length $words]]
+}
+proc section {text} {
+    underline "[string trim $text]" -
+    nl
+}
+proc subsection {text} {
+    underline "$text" ~
+    nl
+}
+proc bullet {text} {
+    wordwrap $text 76 "  * " "    "
+}
+proc indent {text} {
+    wordwrap $text 76 "    " "    "
+}
+proc defn {first args} {
+    if {$first ne ""} {
+        underline "    $first" ~
+    }
+    foreach p $args {
+        if {$p ne ""} {
+            indent $p
+        }
+    }
+}
+}
+
+# ----- module wiki-formatting -----
+
+set modsource(wiki-formatting) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+# wiki.tcl.tk format output
+
+use formatting
+
+proc joinlines {text} {
+    set lines {}
+    foreach l [split [string trim $text] \n] {
+        lappend lines [string trim $l]
+    }
+    join $lines
+}
+proc p {text} {
+    puts [joinlines $text]
+    puts ""
+}
+proc title {text} {
+    puts "*** [joinlines $text] ***"
+    puts ""
+}
+proc codelines {lines} {
+    puts "======"
+    foreach line $lines {
+        puts "    $line"
+    }
+    puts "======"
+}
+proc code {text} {
+    puts "======"
+    foreach line [parse_code_block $text] {
+        puts "    $line"
+    }
+    puts "======"
+}
+proc nl {} {
+}
+proc section {text} {
+    puts "'''$text'''"
+    puts ""
+}
+proc subsection {text} {
+    puts "''$text''"
+    puts ""
+}
+proc bullet {text} {
+    puts "   * [joinlines $text]"
+}
+proc indent {text} {
+    puts "    :    [joinlines $text]"
+}
+proc defn {first args} {
+    if {$first ne ""} {
+        indent '''$first'''
+    }
+
+    foreach p $args {
+        p $p
+    }
+}
+}
+
+
+##################################################################
+#
+# Entry/Exit
+#
+if {$autosetup(debug)} {
+	main $argv
+}
+if {[catch {main $argv} msg] == 1} {
+	show-notices
+	puts stderr [error-stacktrace $msg]
+	if {!$autosetup(debug) && !$autosetup(istcl)} {
+		puts stderr "Try: '[file tail $autosetup(exe)] --debug' for a full stack trace"
+	}
+	exit 1
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/cc-lib.tcl b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/cc-lib.tcl
new file mode 100755
index 0000000..e8e5e86
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/cc-lib.tcl
@@ -0,0 +1,77 @@
+# Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# Provides a library of common tests on top of the 'cc' module.
+
+use cc
+
+module-options {}
+
+# @cc-check-lfs
+#
+# The equivalent of the AC_SYS_LARGEFILE macro
+# 
+# defines 'HAVE_LFS' if LFS is available,
+# and defines '_FILE_OFFSET_BITS=64' if necessary
+#
+# Returns 1 if 'LFS' is available or 0 otherwise
+#
+proc cc-check-lfs {} {
+	cc-check-includes sys/types.h
+	msg-checking "Checking if -D_FILE_OFFSET_BITS=64 is needed..."
+	set lfs 1
+	if {[msg-quiet cc-with {-includes sys/types.h} {cc-check-sizeof off_t}] == 8} {
+		msg-result no
+	} elseif {[msg-quiet cc-with {-includes sys/types.h -cflags -D_FILE_OFFSET_BITS=64} {cc-check-sizeof off_t}] == 8} {
+		define _FILE_OFFSET_BITS 64
+		msg-result yes
+	} else {
+		set lfs 0
+		msg-result none
+	}
+	define-feature lfs $lfs
+	return $lfs
+}
+
+# @cc-check-endian
+#
+# The equivalent of the AC_C_BIGENDIAN macro
+# 
+# defines 'HAVE_BIG_ENDIAN' if endian is known to be big,
+# or 'HAVE_LITTLE_ENDIAN' if endian is known to be little.
+#
+# Returns 1 if determined, or 0 if not.
+#
+proc cc-check-endian {} {
+	cc-check-includes sys/types.h sys/param.h
+	set rc 0
+	msg-checking "Checking endian..."
+	cc-with {-includes {sys/types.h sys/param.h}} {
+		if {[cctest -code {
+			#if !defined(BIG_ENDIAN) || !defined(BYTE_ORDER)
+				#error unknown
+			#elif BYTE_ORDER != BIG_ENDIAN
+				#error little
+			#endif
+		}]} {
+			define-feature big-endian
+			msg-result "big"
+			set rc 1
+		} elseif {[cctest -code {
+			#if !defined(LITTLE_ENDIAN) || !defined(BYTE_ORDER)
+				#error unknown
+			#elif BYTE_ORDER != LITTLE_ENDIAN
+				#error big
+			#endif
+		}]} {
+			define-feature little-endian
+			msg-result "little"
+			set rc 1
+		} else {
+			msg-result "unknown"
+		}
+	}
+	return $rc
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/cc-shared.tcl b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/cc-shared.tcl
new file mode 100755
index 0000000..1e77440
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/cc-shared.tcl
@@ -0,0 +1,63 @@
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# The 'cc-shared' module provides support for shared libraries and shared objects.
+# It defines the following variables:
+#
+## SH_CFLAGS         Flags to use compiling sources destined for a shared library
+## SH_LDFLAGS        Flags to use linking a shared library
+## SHOBJ_CFLAGS      Flags to use compiling sources destined for a shared object
+## SHOBJ_LDFLAGS     Flags to use linking a shared object
+## SH_LINKFLAGS      Flags to use linking an executable which will load shared objects
+## LD_LIBRARY_PATH   Environment variable which specifies path to shared libraries
+
+module-options {}
+
+foreach i {SH_LINKFLAGS SH_CFLAGS SH_LDFLAGS SHOBJ_CFLAGS SHOBJ_LDFLAGS} {
+	define $i ""
+}
+
+define LD_LIBRARY_PATH LD_LIBRARY_PATH
+
+switch -glob -- [get-define host] {
+	*-*-darwin* {
+		define SH_CFLAGS -dynamic
+		define SH_LDFLAGS "-dynamiclib"
+		define SHOBJ_CFLAGS "-dynamic -fno-common"
+		define SHOBJ_LDFLAGS "-bundle -undefined dynamic_lookup"
+		define LD_LIBRARY_PATH DYLD_LIBRARY_PATH
+	}
+	*-*-ming* {
+		define SH_LDFLAGS -shared
+		define SHOBJ_LDFLAGS -shared
+	}
+	*-*-cygwin {
+		define SH_LDFLAGS -shared
+		define SHOBJ_LDFLAGS -shared
+	}
+	*-*-solaris* {
+		# XXX: These haven't been fully tested. 
+		#define SH_LINKFLAGS -Wl,-export-dynamic
+		define SH_CFLAGS -Kpic
+		define SHOBJ_CFLAGS -Kpic
+		define SHOBJ_LDFLAGS "-G"
+	}
+	*-*-hpux {
+		# XXX: These haven't been tested
+		define SH_LINKFLAGS -Wl,+s
+		define SH_CFLAGS +z
+		define SHOBJ_CFLAGS "+O3 +z"
+		define SHOBJ_LDFLAGS -b
+		define LD_LIBRARY_PATH SHLIB_PATH
+	}
+	* {
+		# Generic Unix settings
+		define SH_LINKFLAGS -rdynamic
+		define SH_CFLAGS -fpic
+		define SH_LDFLAGS -shared
+		define SHOBJ_CFLAGS -fpic
+		define SHOBJ_LDFLAGS "-shared"
+	}
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/cc.tcl b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/cc.tcl
new file mode 100755
index 0000000..707e69c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/cc.tcl
@@ -0,0 +1,660 @@
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# The 'cc' module supports checking various 'features' of the C or C++
+# compiler/linker environment. Common commands are cc-check-includes,
+# cc-check-types, cc-check-functions, cc-with, make-autoconf-h and make-template.
+#
+# The following environment variables are used if set:
+#
+## CC       - C compiler
+## CXX      - C++ compiler
+## CCACHE   - Set to "none" to disable automatic use of ccache
+## CFLAGS   - Additional C compiler flags
+## CXXFLAGS - Additional C++ compiler flags
+## LDFLAGS  - Additional compiler flags during linking
+## LIBS     - Additional libraries to use (for all tests)
+## CROSS    - Tool prefix for cross compilation
+#
+# The following variables are defined from the corresponding
+# environment variables if set.
+#
+## CPPFLAGS
+## LINKFLAGS
+## CC_FOR_BUILD
+## LD
+
+use system
+
+module-options {}
+
+# Note that the return code is not meaningful
+proc cc-check-something {name code} {
+	uplevel 1 $code
+}
+
+# Checks for the existence of the given function by linking
+#
+proc cctest_function {function} {
+	cctest -link 1 -declare "extern void $function\(void);" -code "$function\();"
+}
+
+# Checks for the existence of the given type by compiling
+proc cctest_type {type} {
+	cctest -code "$type _x;"
+}
+
+# Checks for the existence of the given type/structure member.
+# e.g. "struct stat.st_mtime"
+proc cctest_member {struct_member} {
+	lassign [split $struct_member .] struct member
+	cctest -code "static $struct _s; return sizeof(_s.$member);"
+}
+
+# Checks for the existence of the given define by compiling
+#
+proc cctest_define {name} {
+	cctest -code "#ifndef $name\n#error not defined\n#endif"
+}
+
+# Checks for the existence of the given name either as
+# a macro (#define) or an rvalue (such as an enum)
+#
+proc cctest_decl {name} {
+	cctest -code "#ifndef $name\n(void)$name;\n#endif"
+}
+
+# @cc-check-sizeof type ...
+#
+# Checks the size of the given types (between 1 and 32, inclusive).
+# Defines a variable with the size determined, or "unknown" otherwise.
+# e.g. for type 'long long', defines SIZEOF_LONG_LONG.
+# Returns the size of the last type.
+#
+proc cc-check-sizeof {args} {
+	foreach type $args {
+		msg-checking "Checking for sizeof $type..."
+		set size unknown
+		# Try the most common sizes first
+		foreach i {4 8 1 2 16 32} {
+			if {[cctest -code "static int _x\[sizeof($type) == $i ? 1 : -1\] = { 1 };"]} {
+				set size $i
+				break
+			}
+		}
+		msg-result $size
+		set define [feature-define-name $type SIZEOF_]
+		define $define $size
+	}
+	# Return the last result
+	get-define $define
+}
+
+# Checks for each feature in $list by using the given script.
+#
+# When the script is evaluated, $each is set to the feature
+# being checked, and $extra is set to any additional cctest args.
+#
+# Returns 1 if all features were found, or 0 otherwise.
+proc cc-check-some-feature {list script} {
+	set ret 1
+	foreach each $list {
+		if {![check-feature $each $script]} {
+			set ret 0
+		}
+	}
+	return $ret
+}
+
+# @cc-check-includes includes ...
+#
+# Checks that the given include files can be used
+proc cc-check-includes {args} {
+	cc-check-some-feature $args {
+		cctest -includes $each
+	}
+}
+
+# @cc-check-types type ...
+#
+# Checks that the types exist.
+proc cc-check-types {args} {
+	cc-check-some-feature $args {
+		cctest_type $each
+	}
+}
+
+# @cc-check-defines define ...
+#
+# Checks that the given preprocessor symbol is defined
+proc cc-check-defines {args} {
+	cc-check-some-feature $args {
+		cctest_define $each
+	}
+}
+
+# @cc-check-decls name ...
+#
+# Checks that each given name is either a preprocessor symbol or rvalue
+# such as an enum. Note that the define used for a decl is HAVE_DECL_xxx
+# rather than HAVE_xxx
+proc cc-check-decls {args} {
+	set ret 1
+	foreach name $args {
+		msg-checking "Checking for $name..."
+		set r [cctest_decl $name]
+		define-feature "decl $name" $r
+		if {$r} {
+			msg-result "ok"
+		} else {
+			msg-result "not found"
+			set ret 0
+		}
+	}
+	return $ret
+}
+
+# @cc-check-functions function ...
+#
+# Checks that the given functions exist (can be linked)
+proc cc-check-functions {args} {
+	cc-check-some-feature $args {
+		cctest_function $each
+	}
+}
+
+# @cc-check-members type.member ...
+#
+# Checks that the given type/structure members exist.
+# A structure member is of the form "struct stat.st_mtime"
+proc cc-check-members {args} {
+	cc-check-some-feature $args {
+		cctest_member $each
+	}
+}
+
+# @cc-check-function-in-lib function libs ?otherlibs?
+#
+# Checks that the given given function can be found in one of the libs.
+#
+# First checks for no library required, then checks each of the libraries
+# in turn.
+#
+# If the function is found, the feature is defined and lib_$function is defined
+# to -l$lib where the function was found, or "" if no library required.
+# In addition, -l$lib is added to the LIBS define.
+#
+# If additional libraries may be needed for linking, they should be specified
+# as $extralibs as "-lotherlib1 -lotherlib2".
+# These libraries are not automatically added to LIBS.
+#
+# Returns 1 if found or 0 if not.
+# 
+proc cc-check-function-in-lib {function libs {otherlibs {}}} {
+	msg-checking "Checking libs for $function..."
+	set found 0
+	cc-with [list -libs $otherlibs] {
+		if {[cctest_function $function]} {
+			msg-result "none needed"
+			define lib_$function ""
+			incr found
+		} else {
+			foreach lib $libs {
+				cc-with [list -libs -l$lib] {
+					if {[cctest_function $function]} {
+						msg-result -l$lib
+						define lib_$function -l$lib
+						define-append LIBS -l$lib
+						incr found
+						break
+					}
+				}
+			}
+		}
+	}
+	if {$found} {
+		define [feature-define-name $function]
+	} else {
+		msg-result "no"
+	}
+	return $found
+}
+
+# @cc-check-tools tool ...
+#
+# Checks for existence of the given compiler tools, taking
+# into account any cross compilation prefix.
+#
+# For example, when checking for "ar", first AR is checked on the command
+# line and then in the environment. If not found, "${host}-ar" or
+# simply "ar" is assumed depending upon whether cross compiling.
+# The path is searched for this executable, and if found AR is defined
+# to the executable name.
+#
+# It is an error if the executable is not found.
+#
+proc cc-check-tools {args} {
+	foreach tool $args {
+		set TOOL [string toupper $tool]
+		set exe [get-env $TOOL [get-define cross]$tool]
+		if {![find-executable $exe]} {
+			user-error "Failed to find $exe"
+		}
+		define $TOOL $exe
+	}
+}
+
+# @cc-check-progs prog ...
+#
+# Checks for existence of the given executables on the path.
+#
+# For example, when checking for "grep", the path is searched for
+# the executable, 'grep', and if found GREP is defined as "grep".
+#
+# It the executable is not found, the variable is defined as false.
+# Returns 1 if all programs were found, or 0 otherwise.
+#
+proc cc-check-progs {args} {
+	set failed 0
+	foreach prog $args {
+		set PROG [string toupper $prog]
+		msg-checking "Checking for $prog..."
+		if {![find-executable $prog]} {
+			msg-result no
+			define $PROG false
+			incr failed
+		} else {
+			msg-result ok
+			define $PROG $prog
+		}
+	}
+	expr {!$failed}
+}
+
+# Adds the given settings to $::autosetup(ccsettings) and
+# returns the old settings.
+#
+proc cc-add-settings {settings} {
+	if {[llength $settings] % 2} {
+		autosetup-error "settings list is missing a value: $settings"
+	}
+
+	set prev [cc-get-settings]
+	# workaround a bug in some versions of jimsh by forcing
+	# conversion of $prev to a list
+	llength $prev
+
+	array set new $prev
+
+	foreach {name value} $settings {
+		switch -exact -- $name {
+			-cflags - -includes {
+				# These are given as lists
+				lappend new($name) {*}$value
+			}
+			-declare {
+				lappend new($name) $value
+			}
+			-libs {
+				# Note that new libraries are added before previous libraries
+				set new($name) [list {*}$value {*}$new($name)]
+			}
+			-link - -lang {
+				set new($name) $value
+			}
+			-source - -sourcefile - -code {
+				# XXX: These probably are only valid directly from cctest
+				set new($name) $value
+			}
+			default {
+				autosetup-error "unknown cctest setting: $name"
+			}
+		}
+	}
+
+	cc-store-settings [array get new]
+
+	return $prev
+}
+
+proc cc-store-settings {new} {
+	set ::autosetup(ccsettings) $new
+}
+
+proc cc-get-settings {} {
+	return $::autosetup(ccsettings)
+}
+
+# Similar to cc-add-settings, but each given setting
+# simply replaces the existing value.
+#
+# Returns the previous settings
+proc cc-update-settings {args} {
+	set prev [cc-get-settings]
+	cc-store-settings [dict merge $prev $args]
+	return $prev
+}
+
+# @cc-with settings ?{ script }?
+#
+# Sets the given 'cctest' settings and then runs the tests in 'script'.
+# Note that settings such as -lang replace the current setting, while
+# those such as -includes are appended to the existing setting.
+#
+# If no script is given, the settings become the default for the remainder
+# of the auto.def file.
+#
+## cc-with {-lang c++} {
+##   # This will check with the C++ compiler
+##   cc-check-types bool
+##   cc-with {-includes signal.h} {
+##     # This will check with the C++ compiler, signal.h and any existing includes.
+##     ...
+##   }
+##   # back to just the C++ compiler
+## }
+#
+# The -libs setting is special in that newer values are added *before* earlier ones.
+#
+## cc-with {-libs {-lc -lm}} {
+##   cc-with {-libs -ldl} {
+##     cctest -libs -lsocket ...
+##     # libs will be in this order: -lsocket -ldl -lc -lm
+##   }
+## }
+proc cc-with {settings args} {
+	if {[llength $args] == 0} {
+		cc-add-settings $settings
+	} elseif {[llength $args] > 1} {
+		autosetup-error "usage: cc-with settings ?script?"
+	} else {
+		set save [cc-add-settings $settings]
+		set rc [catch {uplevel 1 [lindex $args 0]} result info]
+		cc-store-settings $save
+		if {$rc != 0} {
+			return $result -code [dict get $info -code]
+		}
+		return $result
+	}
+}
+
+# @cctest ?settings?
+# 
+# Low level C compiler checker. Compiles and or links a small C program
+# according to the arguments and returns 1 if OK, or 0 if not.
+#
+# Supported settings are:
+#
+## -cflags cflags      A list of flags to pass to the compiler
+## -includes list      A list of includes, e.g. {stdlib.h stdio.h}
+## -declare code       Code to declare before main()
+## -link 1             Don't just compile, link too
+## -lang c|c++         Use the C (default) or C++ compiler
+## -libs liblist       List of libraries to link, e.g. {-ldl -lm}
+## -code code          Code to compile in the body of main()
+## -source code        Compile a complete program. Ignore -includes, -declare and -code
+## -sourcefile file    Shorthand for -source [readfile [get-define srcdir]/$file]
+#
+# Unless -source or -sourcefile is specified, the C program looks like:
+#
+## #include <firstinclude>   /* same for remaining includes in the list */
+##
+## declare-code              /* any code in -declare, verbatim */
+##
+## int main(void) {
+##   code                    /* any code in -code, verbatim */
+##   return 0;
+## }
+#
+# Any failures are recorded in 'config.log'
+#
+proc cctest {args} {
+	set src conftest__.c
+	set tmp conftest__
+
+	# Easiest way to merge in the settings
+	cc-with $args {
+		array set opts [cc-get-settings]
+	}
+
+	if {[info exists opts(-sourcefile)]} {
+		set opts(-source) [readfile [get-define srcdir]/$opts(-sourcefile) "#error can't find $opts(-sourcefile)"]
+	}
+	if {[info exists opts(-source)]} {
+		set lines $opts(-source)
+	} else {
+		foreach i $opts(-includes) {
+			if {$opts(-code) ne "" && ![feature-checked $i]} {
+				# Compiling real code with an unchecked header file
+				# Quickly (and silently) check for it now
+
+				# Remove all -includes from settings before checking
+				set saveopts [cc-update-settings -includes {}]
+				msg-quiet cc-check-includes $i
+				cc-store-settings $saveopts
+			}
+			if {$opts(-code) eq "" || [have-feature $i]} {
+				lappend source "#include <$i>"
+			}
+		}
+		lappend source {*}$opts(-declare)
+		lappend source "int main(void) {"
+		lappend source $opts(-code)
+		lappend source "return 0;"
+		lappend source "}"
+
+		set lines [join $source \n]
+	}
+
+	# Build the command line
+	set cmdline {}
+	lappend cmdline {*}[get-define CCACHE]
+	switch -exact -- $opts(-lang) {
+		c++ {
+			lappend cmdline {*}[get-define CXX] {*}[get-define CXXFLAGS]
+		}
+		c {
+			lappend cmdline {*}[get-define CC] {*}[get-define CFLAGS]
+		}
+		default {
+			autosetup-error "cctest called with unknown language: $opts(-lang)"
+		}
+	}
+
+	if {!$opts(-link)} {
+		set tmp conftest__.o
+		lappend cmdline -c
+	}
+	lappend cmdline {*}$opts(-cflags)
+
+	switch -glob -- [get-define host] {
+		*-*-darwin* {
+			# Don't generate .dSYM directories
+			lappend cmdline -gstabs
+		}
+	}
+	lappend cmdline $src -o $tmp {*}$opts(-libs)
+
+	# At this point we have the complete command line and the
+	# complete source to be compiled. Get the result from cache if
+	# we can
+	if {[info exists ::cc_cache($cmdline,$lines)]} {
+		msg-checking "(cached) "
+		set ok $::cc_cache($cmdline,$lines)
+		if {$::autosetup(debug)} {
+			configlog "From cache (ok=$ok): [join $cmdline]"
+			configlog "============"
+			configlog $lines
+			configlog "============"
+		}
+		return $ok
+	}
+
+	writefile $src $lines\n
+
+	set ok 1
+	if {[catch {exec-with-stderr {*}$cmdline} result errinfo]} {
+		configlog "Failed: [join $cmdline]"
+		configlog $result
+		configlog "============"
+		configlog "The failed code was:"
+		configlog $lines
+		configlog "============"
+		set ok 0
+	} elseif {$::autosetup(debug)} {
+		configlog "Compiled OK: [join $cmdline]"
+		configlog "============"
+		configlog $lines
+		configlog "============"
+	}
+	file delete $src
+	file delete $tmp
+
+	# cache it
+	set ::cc_cache($cmdline,$lines) $ok
+
+	return $ok
+}
+
+# @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*?
+#
+# Deprecated - see make-config-header
+proc make-autoconf-h {file {autopatterns {HAVE_*}} {barepatterns {SIZEOF_* HAVE_DECL_*}}} {
+	user-notice "*** make-autoconf-h is deprecated -- use make-config-header instead"
+	make-config-header $file -auto $autopatterns -bare $barepatterns
+}
+
+# @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ...
+#
+# Examines all defined variables which match the given patterns
+# and writes an include file, $file, which defines each of these.
+# Variables which match '-auto' are output as follows:
+# - defines which have the value "0" are ignored.
+# - defines which have integer values are defined as the integer value.
+# - any other value is defined as a string, e.g. "value"
+# Variables which match '-bare' are defined as-is.
+# Variables which match '-str' are defined as a string, e.g. "value"
+# Variables which match '-none' are omitted.
+#
+# Note that order is important. The first pattern which matches is selected
+# Default behaviour is:
+#
+#  -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
+#
+# If the file would be unchanged, it is not written.
+proc make-config-header {file args} {
+	set guard _[string toupper [regsub -all {[^a-zA-Z0-9]} [file tail $file] _]]
+	file mkdir [file dirname $file]
+	set lines {}
+	lappend lines "#ifndef $guard"
+	lappend lines "#define $guard"
+
+	# Add some defaults
+	lappend args -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_*
+
+	foreach n [lsort [dict keys [all-defines]]] {
+		set value [get-define $n]
+		set type [calc-define-output-type $n $args]
+		switch -exact -- $type {
+			-bare {
+				# Just output the value unchanged
+			}
+			-none {
+				continue
+			}
+			-str {
+				set value \"$value\"
+			}
+			-auto {
+				# Automatically determine the type
+				if {$value eq "0"} {
+					lappend lines "/* #undef $n */"
+					continue
+				}
+				if {![string is integer -strict $value]} {
+					set value \"$value\"
+				}
+			}
+			"" {
+				continue
+			}
+			default {
+				autosetup-error "Unknown type in make-config-header: $type"
+			}
+		}
+		lappend lines "#define $n $value"
+	}
+	lappend lines "#endif"
+	set buf [join $lines \n]
+	write-if-changed $file $buf {
+		msg-result "Created $file"
+	}
+}
+
+proc calc-define-output-type {name spec} {
+	foreach {type patterns} $spec {
+		foreach pattern $patterns {
+			if {[string match $pattern $name]} {
+				return $type
+			}
+		}
+	}
+	return ""
+}
+
+# Initialise some values from the environment or commandline or default settings
+foreach i {LDFLAGS LIBS CPPFLAGS LINKFLAGS {CFLAGS "-g -O2"}} {
+	lassign $i var default
+	define $var [get-env $var $default]
+}
+
+if {[env-is-set CC]} {
+	# Set by the user, so don't try anything else
+	set try [list [get-env CC ""]]
+} else {
+	# Try some reasonable options
+	set try [list [get-define cross]cc [get-define cross]gcc]
+}
+define CC [find-an-executable {*}$try]
+if {[get-define CC] eq ""} {
+	user-error "Could not find a C compiler. Tried: [join $try ", "]"
+}
+
+define CPP [get-env CPP "[get-define CC] -E"]
+
+# XXX: Could avoid looking for a C++ compiler until requested
+# Note that if CXX isn't found, we just set it to "false". It might not be needed.
+if {[env-is-set CXX]} {
+	define CXX [find-an-executable -required [get-env CXX ""]]
+} else {
+	define CXX [find-an-executable [get-define cross]c++ [get-define cross]g++ false]
+}
+
+# CXXFLAGS default to CFLAGS if not specified
+define CXXFLAGS [get-env CXXFLAGS [get-define CFLAGS]]
+
+cc-check-tools ld
+
+# May need a CC_FOR_BUILD, so look for one
+define CC_FOR_BUILD [find-an-executable [get-env CC_FOR_BUILD ""] cc gcc false]
+
+if {[get-define CC] eq ""} {
+	user-error "Could not find a C compiler. Tried: [join $try ", "]"
+}
+
+define CCACHE [find-an-executable [get-env CCACHE ccache]]
+
+# Initial cctest settings
+cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {}}
+
+msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]"
+if {[get-define CXX] ne "false"} {
+	msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]"
+}
+msg-result "Build C compiler...[get-define CC_FOR_BUILD]"
+
+if {![cc-check-includes stdlib.h]} {
+	user-error "Compiler does not work. See config.log"
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/config.guess b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/config.guess
new file mode 100755
index 0000000..4c8f032
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/config.guess
@@ -0,0 +1,1508 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+#   Free Software Foundation, Inc.
+
+timestamp='2010-09-24'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner.  Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
+Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' HUP INT TERM
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" HUP INT PIPE TERM ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep -q __ELF__
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+	        os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+	        UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+        echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm:riscos:*:*|arm:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+	echo i386-pc-auroraux${UNAME_RELEASE}
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	eval $set_cc_for_build
+	SUN_ARCH="i386"
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH="x86_64"
+	    fi
+	fi
+	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+ 	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[4567])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+              	{
+              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+              	case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+              	    switch (bits)
+              		{
+              		case 64: puts ("hppa2.0w"); break;
+              		case 32: puts ("hppa2.0n"); break;
+              		default: puts ("hppa2.0"); break;
+              		} break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+              	    puts ("hppa2.0"); break;
+              #endif
+              	default: puts ("hppa1.0"); break;
+              	}
+                  exit (0);
+              }
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep -q __LP64__
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit ;;
+    5000:UNIX_System_V:4.*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	case ${UNAME_MACHINE} in
+	    pc98)
+		echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:windows32*:*)
+    	# uname -m includes "-pc" on this system.
+    	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:*)
+    	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    authenticamd | genuineintel | EM64T)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    8664:Windows_NT:*)
+	echo x86_64-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+	objdump --private-headers /bin/sh | grep -q ld.so.1
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-gnu
+	else
+	    echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    cris:Linux:*:*)
+	echo cris-axis-linux-gnu
+	exit ;;
+    crisv32:Linux:*:*)
+	echo crisv32-axis-linux-gnu
+	exit ;;
+    frv:Linux:*:*)
+    	echo frv-unknown-linux-gnu
+	exit ;;
+    i*86:Linux:*:*)
+	LIBC=gnu
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#ifdef __dietlibc__
+	LIBC=dietlibc
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+	echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef ${UNAME_MACHINE}
+	#undef ${UNAME_MACHINE}el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=${UNAME_MACHINE}el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=${UNAME_MACHINE}
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    or32:Linux:*:*)
+	echo or32-unknown-linux-gnu
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-gnu
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit ;;
+    sh64*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    tile*:Linux:*:*)
+	echo ${UNAME_MACHINE}-tilera-linux-gnu
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-gnu
+	exit ;;
+    x86_64:Linux:*:*)
+	echo x86_64-unknown-linux-gnu
+	exit ;;
+    xtensa*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+    	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configury will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+        exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes@openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf@swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+	        echo mips-nec-sysv${UNAME_RELEASE}
+	else
+	        echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+        exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	case $UNAME_PROCESSOR in
+	    i386)
+		eval $set_cc_for_build
+		if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+		  if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		      (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		      grep IS_64BIT_ARCH >/dev/null
+		  then
+		      UNAME_PROCESSOR="x86_64"
+		  fi
+		fi ;;
+	    unknown) UNAME_PROCESSOR=powerpc ;;
+	esac
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NEO-?:NONSTOP_KERNEL:*:*)
+	echo neo-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSE-?:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+    	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+	  ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    c34*)
+	echo c34-convex-bsd
+	exit ;;
+    c38*)
+	echo c38-convex-bsd
+	exit ;;
+    c4*)
+	echo c4-convex-bsd
+	exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/config.sub b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/config.sub
new file mode 100755
index 0000000..320e303
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/config.sub
@@ -0,0 +1,1739 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+#   Free Software Foundation, Inc.
+
+timestamp='2010-09-11'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted GNU ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
+Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+  linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+  knetbsd*-gnu* | netbsd*-gnu* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray | -microblaze)
+		os=
+		basic_machine=$1
+		;;
+        -bluegene*)
+	        os=-cnk
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+ 	-chorusrdb)
+ 		os=-chorusrdb
+		basic_machine=$1
+ 		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+	| bfin \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| lm32 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | mcore | mep | metag \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64octeon | mips64octeonel \
+	| mips64orion | mips64orionel \
+	| mips64r5900 | mips64r5900el \
+	| mips64vr | mips64vrel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| moxie \
+	| mt \
+	| msp430 \
+	| nds32 | nds32le | nds32be \
+	| nios | nios2 \
+	| ns16k | ns32k \
+	| or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| rx \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu | strongarm \
+	| tahoe | thumb | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+	| ubicom32 \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+	| z8k | z80)
+		basic_machine=$basic_machine-unknown
+		;;
+	c54x)
+		basic_machine=tic54x-unknown
+		;;
+	c55x)
+		basic_machine=tic55x-unknown
+		;;
+	c6x)
+		basic_machine=tic6x-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12 | picochip)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* \
+	| clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| lm32-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64octeon-* | mips64octeonel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64r5900-* | mips64r5900el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nds32-* | nds32le-* | nds32be-* \
+	| nios-* | nios2-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* | rx-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tile-* | tilegx-* \
+	| tron-* \
+	| ubicom32-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-* | z80-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+    	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aros)
+		basic_machine=i386-pc
+		os=-aros
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	bluegene*)
+		basic_machine=powerpc-ibm
+		os=-cnk
+		;;
+	c54x-*)
+		basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c55x-*)
+		basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c6x-*)
+		basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+        cegcc)
+		basic_machine=arm-unknown
+		os=-cegcc
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dicos)
+		basic_machine=i686-pc
+		os=-dicos
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+        microblaze)
+		basic_machine=microblaze-xilinx
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+        neo-tandem)
+		basic_machine=neo-tandem
+		;;
+        nse-tandem)
+		basic_machine=nse-tandem
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+		;;
+	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+        # This must be matched before tile*.
+        tilegx*)
+		basic_machine=tilegx-unknown
+		os=-linux-gnu
+		;;
+	tile*)
+		basic_machine=tile-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	z80-*-coff)
+		basic_machine=z80-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+        -auroraux)
+	        os=-auroraux
+		;;
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+	      | -sym* | -kopensolaris* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* | -aros* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -openbsd* | -solidbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* | -cegcc* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -linux-android* \
+	      | -linux-newlib* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+        -os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+        -tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-dicos*)
+		os=-dicos
+		;;
+        -nacl*)
+	        ;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+        score-*)
+		os=-elf
+		;;
+        spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+        c4x-* | tic4x-*)
+        	os=-coff
+		;;
+	tic54x-*)
+		os=-coff
+		;;
+	tic55x-*)
+		os=-coff
+		;;
+	tic6x-*)
+		os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+        mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+    	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-cnk*|-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/find-tclsh b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/find-tclsh
new file mode 100755
index 0000000..7ef152a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/find-tclsh
@@ -0,0 +1,17 @@
+#!/bin/sh
+# Looks for a suitable tclsh or jimsh in the PATH
+# If not found, builds a bootstrap jimsh from source
+d=`dirname "$0"`
+{ "$d/jimsh0" "$d/test-tclsh"; } 2>/dev/null && exit 0
+PATH="$PATH:$d"
+for tclsh in jimsh tclsh tclsh8.5 tclsh8.6; do
+	{ $tclsh "$d/test-tclsh"; } 2>/dev/null && exit 0
+done
+echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
+./make-bootstrap-jim > $d/jimsh0.c
+for cc in ${CC_FOR_BUILD:-cc} gcc; do
+	{ $cc -o "$d/jimsh0" "$d/jimsh0.c"; } 2>/dev/null || continue
+	"$d/jimsh0" "$d/test-tclsh" && exit 0
+done
+echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
+echo false
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/system.tcl b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/system.tcl
new file mode 100755
index 0000000..f05d05b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/system.tcl
@@ -0,0 +1,268 @@
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# This module supports common system interrogation and options
+# such as --host, --build, --prefix, and setting srcdir, builddir, and EXEXT.
+#
+# It also support the 'feature' naming convention, where searching
+# for a feature such as sys/type.h defines HAVE_SYS_TYPES_H
+#
+module-options {
+	host:host-alias =>		{a complete or partial cpu-vendor-opsys for the system where
+							the application will run (defaults to the same value as --build)}
+	build:build-alias =>	{a complete or partial cpu-vendor-opsys for the system
+							where the application will be built (defaults to the
+							result of running config.guess)}
+	prefix:dir =>			{the target directory for the build (defaults to /usr/local)}
+
+	# These (hidden) options are supported for autoconf/automake compatibility
+	exec-prefix:
+	bindir:
+	sbindir:
+	includedir:
+	mandir:
+	infodir:
+	libexecdir:
+	datadir:
+	libdir:
+	sysconfdir:
+	sharedstatedir:
+	localstatedir:
+	maintainer-mode=0
+	dependency-tracking=0
+}
+
+# Returns 1 if exists, or 0 if  not
+#
+proc check-feature {name code} {
+	msg-checking "Checking for $name..."
+	set r [uplevel 1 $code]
+	define-feature $name $r
+	if {$r} {
+		msg-result "ok"
+	} else {
+		msg-result "not found"
+	}
+	return $r
+}
+
+# @have-feature name ?default=0?
+#
+# Returns the value of the feature if defined, or $default if not.
+# See 'feature-define-name' for how the feature name
+# is translated into the define name.
+#
+proc have-feature {name {default 0}} {
+	get-define [feature-define-name $name] $default
+}
+
+# @define-feature name ?value=1?
+#
+# Sets the feature 'define' to the given value.
+# See 'feature-define-name' for how the feature name
+# is translated into the define name.
+#
+proc define-feature {name {value 1}} {
+	define [feature-define-name $name] $value
+}
+
+# @feature-checked name
+#
+# Returns 1 if the feature has been checked, whether true or not
+#
+proc feature-checked {name} {
+	is-defined [feature-define-name $name]
+}
+
+# @feature-define-name name ?prefix=HAVE_?
+#
+# Converts a name to the corresponding define,
+# e.g. sys/stat.h becomes HAVE_SYS_STAT_H.
+#
+# Converts * to P and all non-alphanumeric to underscore.
+#
+proc feature-define-name {name {prefix HAVE_}} {
+	string toupper $prefix[regsub -all {[^a-zA-Z0-9]} [regsub -all {[*]} $name p] _]
+}
+
+# If $file doesn't exist, or it's contents are different than $buf,
+# the file is written and $script is executed.
+# Otherwise a "file is unchanged" message is displayed.
+proc write-if-changed {file buf {script {}}} {
+	set old [readfile $file ""]
+	if {$old eq $buf && [file exists $file]} {
+		msg-result "$file is unchanged"
+	} else {
+		writefile $file $buf\n
+		uplevel 1 $script
+	}
+}
+
+# @make-template template ?outfile?
+#
+# Reads the input file <srcdir>/$template and writes the output file $outfile.
+# If $outfile is blank/omitted, $template should end with ".in" which
+# is removed to create the output file name.
+#
+# Each pattern of the form @define@ is replaced the the corresponding
+# define, if it exists, or left unchanged if not.
+# 
+# The special value @srcdir@ is subsituted with the relative
+# path to the source directory from the directory where the output
+# file is created. Use @top_srcdir@ for the absolute path.
+#
+# Conditional sections may be specified as follows:
+## @if name == value
+## lines
+## @else
+## lines
+## @endif
+#
+# Where 'name' is a defined variable name and @else is optional.
+# If the expression does not match, all lines through '@endif' are ignored.
+#
+# The alternative forms may also be used:
+## @if name
+## @if name != value
+#
+# Where the first form is true if the variable is defined, but not empty or 0
+#
+# Currently these expressions can't be nested.
+#
+proc make-template {template {out {}}} {
+	set infile [file join $::autosetup(srcdir) $template]
+
+	if {![file exists $infile]} {
+		user-error "Template $template is missing"
+	}
+
+	# Define this as late as possible
+	define AUTODEPS $::autosetup(deps)
+
+	if {$out eq ""} {
+		if {[file ext $template] ne ".in"} {
+			autosetup-error "make_template $template has no target file and can't guess"
+		}
+		set out [file rootname $template]
+	}
+
+	set outdir [file dirname $out]
+
+	# Make sure the directory exists
+	file mkdir $outdir
+
+	# Set up srcdir to be relative to the target dir
+	define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir]
+
+	set mapping {}
+	foreach {n v} [array get ::define] {
+		lappend mapping @$n@ $v
+	}
+	set result {}
+	foreach line [split [readfile $infile] \n] {
+		if {[info exists cond]} {
+			set l [string trimright $line]
+			if {$l eq "@endif"} {
+				unset cond
+				continue
+			}
+			if {$l eq "@else"} {
+				set cond [expr {!$cond}]
+				continue
+			}
+			if {$cond} {
+				lappend result $line
+			}
+			continue
+		}
+		if {[regexp {^@if\s+(\w+)(.*)} $line -> name expression]} {
+			lassign $expression equal value
+			set varval [get-define $name ""]
+			if {$equal eq ""} {
+				set cond [expr {$varval ni {"" 0}}]
+			} else {
+				set cond [expr {$varval eq $value}]
+				if {$equal ne "=="} {
+					set cond [expr {!$cond}]
+				}
+			}
+			continue
+		}
+		lappend result $line
+	}
+	writefile $out [string map $mapping [join $result \n]]\n
+
+	msg-result "Created [relative-path $out] from [relative-path $template]"
+}
+
+# build/host tuples and cross-compilation prefix
+set build [opt-val build]
+define build_alias $build
+if {$build eq ""} {
+	define build [config_guess]
+} else {
+	define build [config_sub $build]
+}
+
+set host [opt-val host]
+define host_alias $host
+if {$host eq ""} {
+	define host [get-define build]
+	set cross ""
+} else {
+	define host [config_sub $host]
+	set cross $host-
+}
+define cross [get-env CROSS $cross]
+
+set prefix [opt-val prefix /usr/local]
+
+# These are for compatibility with autoconf
+define target [get-define host]
+define prefix $prefix
+define builddir $autosetup(builddir)
+define srcdir $autosetup(srcdir)
+# Allow this to come from the environment
+define top_srcdir [get-env top_srcdir [get-define srcdir]]
+
+# autoconf supports all of these
+set exec_prefix [opt-val exec-prefix $prefix]
+define exec_prefix $exec_prefix
+foreach {name defpath} {
+	bindir /bin
+	sbindir /sbin
+	libexecdir /libexec
+	libdir /lib
+} {
+	define $name [opt-val $name $exec_prefix$defpath]
+}
+foreach {name defpath} {
+	datadir /share
+	sysconfdir /etc
+	sharedstatedir /com
+	localstatedir /var
+	infodir /share/info
+	mandir /share/man
+	includedir /include
+} {
+	define $name [opt-val $name $prefix$defpath]
+}
+
+define SHELL [get-env SHELL [find-an-executable sh bash ksh]]
+
+# Windows vs. non-Windows
+switch -glob -- [get-define host] {
+	*-*-ming* - *-*-cygwin {
+		define-feature windows
+		define EXEEXT .exe
+	}
+	default {
+		define EXEEXT ""
+	}
+}
+
+# Display
+msg-result "Host System...[get-define host]"
+msg-result "Build System...[get-define build]"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/test-tclsh b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/test-tclsh
new file mode 100755
index 0000000..75126d2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/autosetup/test-tclsh
@@ -0,0 +1,20 @@
+# A small Tcl script to verify that the chosen
+# interpreter works. Sometimes we might e.g. pick up
+# an interpreter for a different arch.
+# Outputs the full path to the interpreter
+
+if {[catch {info version} version] == 0} {
+	# This is Jim Tcl
+	if {$version >= 0.72} {
+		# Ensure that regexp works
+		regexp (a.*?) a
+		puts [info nameofexecutable]
+		exit 0
+	}
+} elseif {[catch {info tclversion} version] == 0} {
+	if {$version >= 8.5 && ![string match 8.5a* [info patchlevel]]} {
+		puts [info nameofexecutable]
+		exit 0
+	}
+}
+exit 1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/bootstrap.tcl b/android/external/usb_modeswitch/usb_modeswitch/jim/bootstrap.tcl
new file mode 100755
index 0000000..e7adf4b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/bootstrap.tcl
@@ -0,0 +1,3 @@
+# No need for package support in the bootstrap jimsh, but
+# Tcl extensions call package require
+proc package {args} {}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/configure b/android/external/usb_modeswitch/usb_modeswitch/jim/configure
new file mode 100755
index 0000000..1c5586f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/configure
@@ -0,0 +1,3 @@
+#!/bin/sh
+dir="`dirname "$0"`/autosetup"
+WRAPPER="$0" exec "`$dir/find-tclsh`" "$dir/autosetup" "$@"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/configure.ac b/android/external/usb_modeswitch/usb_modeswitch/jim/configure.ac
new file mode 100755
index 0000000..b70b5d8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/configure.ac
@@ -0,0 +1 @@
+# Dummy configure.ac to make automake happy
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/andrew.txt b/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/andrew.txt
new file mode 100755
index 0000000..8dbfcfc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/andrew.txt
@@ -0,0 +1,65 @@
+Delivered-To: oyvindharboe@gmail.com
+Received: by 10.100.7.20 with SMTP id 20cs86142ang;
+        Wed, 16 Jul 2008 00:45:59 -0700 (PDT)
+Received: by 10.142.238.12 with SMTP id l12mr5009290wfh.204.1216194359186;
+        Wed, 16 Jul 2008 00:45:59 -0700 (PDT)
+Return-Path: <andrew@lunn.ch>
+Received: from cpanel5.proisp.no (cpanel5.proisp.no [209.85.100.29])
+        by mx.google.com with ESMTP id 31si6762736wff.16.2008.07.16.00.45.57;
+        Wed, 16 Jul 2008 00:45:59 -0700 (PDT)
+Received-SPF: fail (google.com: domain of andrew@lunn.ch does not designate 209.85.100.29 as permitted sender) client-ip=209.85.100.29;
+Authentication-Results: mx.google.com; spf=hardfail (google.com: domain of andrew@lunn.ch does not designate 209.85.100.29 as permitted sender) smtp.mail=andrew@lunn.ch
+Received: from londo.lunn.ch ([80.238.139.98]:48839 ident=mail)
+	by cpanel5.proisp.no with esmtp (Exim 4.69)
+	(envelope-from <andrew@lunn.ch>)
+	id 1KJ1ht-00085G-Ng
+	for oyvind.harboe@zylin.com; Wed, 16 Jul 2008 09:45:52 +0200
+Received: from lunn by londo.lunn.ch with local (Exim 3.36 #1 (Debian))
+	id 1KJ1hq-0005ss-00; Wed, 16 Jul 2008 09:45:46 +0200
+Date: Wed, 16 Jul 2008 09:45:46 +0200
+From: Andrew Lunn <andrew@lunn.ch>
+To: ?yvind Harboe <oyvind.harboe@zylin.com>
+Cc: jim-devel@lists.berlios.de, antirez@gmail.com, patthoyts@users.sf.net,
+	andrew@lunn.ch, openocd@duaneellis.com, uklein@klein-messgeraete.de,
+	ml-jim@qiao.in-berlin.de
+Subject: Re: Change Jim Tcl license
+Message-ID: <20080716074546.GC24771@lunn.ch>
+References: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+In-Reply-To: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+User-Agent: Mutt/1.5.18 (2008-05-17)
+X-Spam-Status: No, score=-2.6
+X-Spam-Score: -25
+X-Spam-Bar: --
+X-Spam-Flag: NO
+X-AntiAbuse: This header was added to track abuse, please include it with any abuse report
+X-AntiAbuse: Primary Hostname - cpanel5.proisp.no
+X-AntiAbuse: Original Domain - zylin.com
+X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12]
+X-AntiAbuse: Sender Address Domain - lunn.ch
+X-Source: 
+X-Source-Args: 
+X-Source-Dir: 
+
+On Wed, Jul 16, 2008 at 09:34:14AM +0200, ?yvind Harboe wrote:
+> Hi all,
+> 
+> I'm currently the maintainer of Jim Tcl trying as best as I can
+> to fill Salvatore's shoes.
+> 
+> Short story:
+> 
+> If you have contributed to Jim Tcl, please reply to this email
+> that you agree that we can switch Jim Tcl to a FreeBSD license.
+
+I've no problems with this, but my contributions are very minimal.
+
+Do you want this written down, in blood, to keep the lawyers happy?
+
+At a minimum i think everybody's agreement needs to be posted to a
+public email list which is publicly archived etc so there is a
+record of the agreement...
+
+       Andrew
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/clemens.txt b/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/clemens.txt
new file mode 100755
index 0000000..806f7ed
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/clemens.txt
@@ -0,0 +1,87 @@
+                                                                                                                                                                                                                                                               
+Delivered-To: oyvindharboe@gmail.com
+Received: by 10.100.7.20 with SMTP id 20cs114742ang;
+        Wed, 16 Jul 2008 08:58:18 -0700 (PDT)
+Received: by 10.114.137.2 with SMTP id k2mr325372wad.95.1216223896673;
+        Wed, 16 Jul 2008 08:58:16 -0700 (PDT)
+Return-Path: <ml-jim@qiao.in-berlin.de>
+Received: from cpanel5.proisp.no (cpanel5.proisp.no [209.85.100.29])
+        by mx.google.com with ESMTP id m28si10145125waf.16.2008.07.16.08.58.15;
+        Wed, 16 Jul 2008 08:58:16 -0700 (PDT)
+Received-SPF: neutral (google.com: 209.85.100.29 is neither permitted nor denied by best guess record for domain of ml-jim@qiao.in-berlin.de) client-ip=209.85.100.29;
+Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.100.29 is neither permitted nor denied by best guess record for domain of ml-jim@qiao.in-berlin.de) smtp.mail=ml-jim@qiao.in-berlin.de
+Received: from gnu.in-berlin.de ([192.109.42.4]:58401)
+	by cpanel5.proisp.no with esmtps (TLSv1:AES256-SHA:256)
+	(Exim 4.69)
+	(envelope-from <ml-jim@qiao.in-berlin.de>)
+	id 1KJ9OG-0006Hf-8y
+	for oyvind.harboe@zylin.com; Wed, 16 Jul 2008 17:58:07 +0200
+X-Envelope-From: ml-jim@qiao.in-berlin.de
+X-Envelope-To: <oyvind.harboe@zylin.com>
+Received: from qiao.in-berlin.de (qiao.in-berlin.de [217.197.85.72])
+	by gnu.in-berlin.de (8.13.8/8.13.8/Debian-2) with ESMTP id m6GFvxio009504
+	for <oyvind.harboe@zylin.com>; Wed, 16 Jul 2008 17:58:02 +0200
+Received: from [192.168.0.10] ([::ffff:192.168.0.10])
+  by qiao.in-berlin.de with esmtp; Wed, 16 Jul 2008 18:00:04 +0200
+  id 0001D68D.487E1B04.000042E7
+In-Reply-To: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+References: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+Mime-Version: 1.0 (Apple Message framework v753.1)
+Content-Type: text/plain; charset=ISO-8859-1; delsp=yes; format=flowed
+Message-Id: <E112D7A6-89D1-40C8-913C-7DAF7303E7EC@qiao.in-berlin.de>
+Cc: jim-devel@lists.berlios.de, antirez@gmail.com, patthoyts@users.sf.net,
+        andrew@lunn.ch, openocd@duaneellis.com, uklein@klein-messgeraete.de
+Content-Transfer-Encoding: quoted-printable
+From: Clemens Hintze <ml-jim@qiao.in-berlin.de>
+Subject: Re: Change Jim Tcl license
+Date: Wed, 16 Jul 2008 17:58:14 +0200
+To: "=?ISO-8859-1?Q?\"=D8yvind_Harboe\"?=" <oyvind.harboe@zylin.com>
+X-Mailer: Apple Mail (2.753.1)
+X-Spam-Score:  (0.101) BAYES_50,RDNS_NONE
+X-Scanned-By: MIMEDefang_at_IN-Berlin_e.V. on 192.109.42.4
+X-Spam-Status: No, score=-2.6
+X-Spam-Score: -25
+X-Spam-Bar: --
+X-Spam-Flag: NO
+X-AntiAbuse: This header was added to track abuse, please include it with any abuse report
+X-AntiAbuse: Primary Hostname - cpanel5.proisp.no
+X-AntiAbuse: Original Domain - zylin.com
+X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12]
+X-AntiAbuse: Sender Address Domain - qiao.in-berlin.de
+X-Source: 
+X-Source-Args: 
+X-Source-Dir: 
+
+
+Am 16.07.2008 um 09:34 schrieb =D8yvind Harboe:
+
+> Hi all,
+
+Hi =D8yvind,
+
+(...)
+
+> If you have contributed to Jim Tcl, please reply to this email
+> that you agree that we can switch Jim Tcl to a FreeBSD license.
+>
+> Once I have a record of all contributors agreeing to switch
+> to a FreeBSD license, I'll update CVS.
+
+No problem with me: I agree to permit my contributions to the Jim =20
+project to be
+re-licensed under a BSD compatible license.
+
+(...)
+
+> Please let me know if any of the emails below are wrong(chi is
+> missing) or the list is not complete.
+
+After consultation with the voices in my head, I can ensure you, =20
+'chi' is also agreeing with the re-licensing, because its me too ;-)
+
+Thank you very much to revive Jim! :-)
+
+Best regards,
+Clemens Hintze.
+
+(...)=
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/duane.txt b/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/duane.txt
new file mode 100755
index 0000000..56f962c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/duane.txt
@@ -0,0 +1,65 @@
+Delivered-To: oyvindharboe@gmail.com
+Received: by 10.100.7.20 with SMTP id 20cs93801ang;
+        Wed, 16 Jul 2008 03:40:02 -0700 (PDT)
+Received: by 10.142.148.10 with SMTP id v10mr5070849wfd.317.1216204801306;
+        Wed, 16 Jul 2008 03:40:01 -0700 (PDT)
+Return-Path: <openocd@duaneellis.com>
+Received: from cpanel5.proisp.no (cpanel5.proisp.no [209.85.100.29])
+        by mx.google.com with ESMTP id 27si9313433wff.3.2008.07.16.03.40.00;
+        Wed, 16 Jul 2008 03:40:01 -0700 (PDT)
+Received-SPF: neutral (google.com: 209.85.100.29 is neither permitted nor denied by best guess record for domain of openocd@duaneellis.com) client-ip=209.85.100.29;
+Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.100.29 is neither permitted nor denied by best guess record for domain of openocd@duaneellis.com) smtp.mail=openocd@duaneellis.com
+Received: from smtpout10-04.prod.mesa1.secureserver.net ([64.202.165.238]:48803 helo=smtpout10.prod.mesa1.secureserver.net)
+	by cpanel5.proisp.no with smtp (Exim 4.69)
+	(envelope-from <openocd@duaneellis.com>)
+	id 1KJ4QL-0005cq-GB
+	for oyvind.harboe@zylin.com; Wed, 16 Jul 2008 12:39:54 +0200
+Received: (qmail 2305 invoked from network); 16 Jul 2008 10:39:56 -0000
+Received: from unknown (68.37.53.103)
+  by smtpout10-04.prod.mesa1.secureserver.net (64.202.165.238) with ESMTP; 16 Jul 2008 10:39:55 -0000
+Message-ID: <487DCFEC.4010104@duaneellis.com>
+Date: Wed, 16 Jul 2008 06:39:40 -0400
+From: Duane Ellis <openocd@duaneellis.com>
+Reply-To: openocd@duaneellis.com
+User-Agent: Thunderbird 2.0.0.14 (Windows/20080421)
+MIME-Version: 1.0
+To: =?ISO-8859-1?Q?=D8yvind_Harboe?= <oyvind.harboe@zylin.com>
+CC: jim-devel@lists.berlios.de, antirez@gmail.com, 
+ patthoyts@users.sf.net, andrew@lunn.ch, uklein@klein-messgeraete.de, 
+ ml-jim@qiao.in-berlin.de
+Subject: Re: Change Jim Tcl license
+References: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+In-Reply-To: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 8bit
+X-Spam-Status: No, score=-2.6
+X-Spam-Score: -25
+X-Spam-Bar: --
+X-Spam-Flag: NO
+X-AntiAbuse: This header was added to track abuse, please include it with any abuse report
+X-AntiAbuse: Primary Hostname - cpanel5.proisp.no
+X-AntiAbuse: Original Domain - zylin.com
+X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12]
+X-AntiAbuse: Sender Address Domain - duaneellis.com
+X-Source: 
+X-Source-Args: 
+X-Source-Dir: 
+
+Oyvind Harboe wrote:
+> Short story:
+>
+> If you have contributed to Jim Tcl, please reply to this email
+> that you agree that we can switch Jim Tcl to a FreeBSD license.
+>
+> Once I have a record of all contributors agreeing to switch
+> to a FreeBSD license, I'll update CVS.
+>
+>   
+OK - from me
+
+    --Duane.
+
+-Duane.
+
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/oharboe.txt b/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/oharboe.txt
new file mode 100755
index 0000000..af4a8e8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/oharboe.txt
@@ -0,0 +1,85 @@
+                                                                                                                                                                                                                                                            
+Received: by 10.100.7.20 with HTTP; Wed, 16 Jul 2008 10:12:05 -0700 (PDT)
+Message-ID: <c09652430807161012m178c5fbesef9a3f831e4d1dac@mail.gmail.com>
+Date: Wed, 16 Jul 2008 19:12:05 +0200
+From: "=?ISO-8859-1?Q?=D8yvind_Harboe?=" <oyvind.harboe@zylin.com>
+Sender: oyvindharboe@gmail.com
+To: jim-devel@lists.berlios.de
+Subject: Re: Change Jim Tcl license
+In-Reply-To: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=ISO-8859-1
+Content-Transfer-Encoding: quoted-printable
+Content-Disposition: inline
+References: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+Delivered-To: oyvindharboe@gmail.com
+X-Google-Sender-Auth: fc18e85532eee8f2
+
+For the record:
+
+I would like my contributions  to Jim Tcl to be under a FreeBSD license too=
+.
+
+On Wed, Jul 16, 2008 at 9:34 AM, =D8yvind Harboe <oyvind.harboe@zylin.com> =
+wrote:
+> Hi all,
+>
+> I'm currently the maintainer of Jim Tcl trying as best as I can
+> to fill Salvatore's shoes.
+>
+> Short story:
+>
+> If you have contributed to Jim Tcl, please reply to this email
+> that you agree that we can switch Jim Tcl to a FreeBSD license.
+>
+> Once I have a record of all contributors agreeing to switch
+> to a FreeBSD license, I'll update CVS.
+>
+> Long story:
+>
+> The current Jim Tcl license has a problem with GPL. If you
+> link GPL code and Jim Tcl, the result is no license at all.
+>
+> This prevents Jim Tcl from being used in GPL projects.
+>
+> Lately Jim Tcl has been used with OpenOCD, a GPL project,
+> and the license issue must be resolved one way or another.
+>
+> Upon conferring with Jonathan Larmour <jifl@ecoscentric.com>, who
+> has kindly helped out with his knowledge on the topic, I have
+> concluded that the best way to rectify this is to change the
+> Jim Tcl license to a FreeBSD license. See OpenOCD mailing
+> list for a discussion on this if you want details.
+>
+> http://www.fsf.org/licensing/licenses/index_html#FreeBSD
+>
+> As far as I can determine, below is the complete list of contributors.
+>
+>
+> antirez - Salvatore Sanfilippo <antirez@gmail.com>
+> patthoyts - ?? Pat Thoyts <patthoyts@users.sf.net>
+> oharboe - =D8yvind Harboe - soyvind.harboe@zylin.com
+> chi - ??
+> Andrew Lunn <andrew@lunn.ch>
+> Duane Ellis <openocd@duaneellis.com>
+> Uwe Klein <uklein@klein-messgeraete.de>
+> Clemens Hintze ml-jim@qiao.in-berlin.de
+>
+> Please let me know if any of the emails below are wrong(chi is
+> missing) or the list is not complete.
+>
+>
+> --
+> =D8yvind Harboe
+> http://www.zylin.com/zy1000.html
+> ARM7 ARM9 XScale Cortex
+> JTAG debugger and flash programmer
+>
+
+
+
+--=20
+=D8yvind Harboe
+http://www.zylin.com/zy1000.html
+ARM7 ARM9 XScale Cortex
+JTAG debugger and flash programmer
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/pat.txt b/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/pat.txt
new file mode 100755
index 0000000..988a599
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/pat.txt
@@ -0,0 +1,84 @@
+                                                                                                                                                                                                                                                             
+Delivered-To: oyvindharboe@gmail.com
+Received: by 10.100.7.20 with SMTP id 20cs108097ang;
+        Wed, 16 Jul 2008 07:49:02 -0700 (PDT)
+Received: by 10.142.232.20 with SMTP id e20mr80874wfh.138.1216219741865;
+        Wed, 16 Jul 2008 07:49:01 -0700 (PDT)
+Return-Path: <patthoyts@users.sourceforge.net>
+Received: from cpanel5.proisp.no (cpanel5.proisp.no [209.85.100.29])
+        by mx.google.com with ESMTP id 30si10551683wff.18.2008.07.16.07.49.01;
+        Wed, 16 Jul 2008 07:49:01 -0700 (PDT)
+Received-SPF: neutral (google.com: 209.85.100.29 is neither permitted nor denied by best guess record for domain of patthoyts@users.sourceforge.net) client-ip=209.85.100.29;
+Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.100.29 is neither permitted nor denied by best guess record for domain of patthoyts@users.sourceforge.net) smtp.mail=patthoyts@users.sourceforge.net
+Received: from smtp-out4.blueyonder.co.uk ([195.188.213.7]:38596)
+	by cpanel5.proisp.no with esmtp (Exim 4.69)
+	(envelope-from <patthoyts@users.sourceforge.net>)
+	id 1KJ8JH-0000Vd-OT
+	for oyvind.harboe@zylin.com; Wed, 16 Jul 2008 16:48:52 +0200
+Received: from [172.23.170.141] (helo=anti-virus02-08)
+	by smtp-out4.blueyonder.co.uk with smtp (Exim 4.52)
+	id 1KJ8JO-0007r0-Cy; Wed, 16 Jul 2008 15:48:58 +0100
+Received: from [77.102.249.21] (helo=badger.patthoyts.tk)
+	by asmtp-out4.blueyonder.co.uk with esmtp (Exim 4.52)
+	id 1KJ8J6-0000gY-VY; Wed, 16 Jul 2008 15:48:41 +0100
+Received: by badger.patthoyts.tk (Postfix, from userid 1000)
+	id 810535184F; Wed, 16 Jul 2008 15:48:40 +0100 (BST)
+Sender: pat@badger.patthoyts.tk
+To: =?iso-8859-1?q?=D8yvind_Harboe?= <oyvind.harboe@zylin.com>
+Cc: jim-devel@lists.berlios.de
+Subject: Re: Change Jim Tcl license
+References: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+X-Face:  .`d#euqz@6H{";Ysmx2IVe_7M3vA+2w1X[QLk?ZO&QRauXQL{*L'$3getx}9+zK.-KWDx3.
+ qrlR)76MFb`6bgoGvLpLtcQKB=X~;*<JKLtwLBM(IA'?rVjs1*tq\VHn?WMNsB,3XXWF@5.)4SRFa+
+ '?a?.s#@hl7CiTo'F"O!fvbL0
+X-Url: http://www.patthoyts.tk/
+From: Pat Thoyts <patthoyts@users.sourceforge.net>
+Date: 16 Jul 2008 15:48:39 +0100
+In-Reply-To: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+Message-ID: <87fxq97um0.fsf@badger.patthoyts.tk>
+Lines: 27
+User-Agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.3
+MIME-Version: 1.0
+Content-Type: text/plain; charset=iso-8859-1
+Content-Transfer-Encoding: quoted-printable
+X-Spam-Status: No, score=-2.6
+X-Spam-Score: -25
+X-Spam-Bar: --
+X-Spam-Flag: NO
+X-AntiAbuse: This header was added to track abuse, please include it with any abuse report
+X-AntiAbuse: Primary Hostname - cpanel5.proisp.no
+X-AntiAbuse: Original Domain - zylin.com
+X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12]
+X-AntiAbuse: Sender Address Domain - users.sourceforge.net
+X-Source: 
+X-Source-Args: 
+X-Source-Dir: 
+
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+"=D8yvind Harboe" <oyvind.harboe@zylin.com> writes:
+
+>If you have contributed to Jim Tcl, please reply to this email
+>that you agree that we can switch Jim Tcl to a FreeBSD license.
+>
+>Once I have a record of all contributors agreeing to switch
+>to a FreeBSD license, I'll update CVS.
+
+I hereby agree to permit my contributions to the Jim project to be
+re-licensed under a BSD compatible license.
+
+- --=20
+Pat Thoyts                            http://www.patthoyts.tk/
+PGP fingerprint 2C 6E 98 07 2C 59 C8 97  10 CE 11 E6 04 E0 B9 DD
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.8 (SunOS)
+Comment: Processed by Mailcrypt 3.5.8 <http://mailcrypt.sourceforge.net/>
+
+iQCVAwUBSH4KO2B90JXwhOSJAQKtqQP9ERwSXpbP69l4JSrunG29Rhu2F3r83zu3
+GAKpFu4HwkVnIStLQ4o3tsqG9uKrVDbRMa187eSwHmlXXIMwDlkCKNsDFxvdLDZz
+kbTYDibspYSw6CjwOUSTXifK9P7ho4Q7PtsRnJ8T1IMlGJlwg39Rxd+mpEO/if3q
+ExIwM1aBbAs=3D
+=3Du8si
+-----END PGP SIGNATURE-----
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/salvatore.txt b/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/salvatore.txt
new file mode 100755
index 0000000..5bbf973
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/salvatore.txt
@@ -0,0 +1,88 @@
+                                                                                                                                                                                                                                                             
+Delivered-To: oyvindharboe@gmail.com
+Received: by 10.100.7.20 with SMTP id 20cs113143ang;
+        Wed, 16 Jul 2008 08:41:11 -0700 (PDT)
+Received: by 10.142.140.15 with SMTP id n15mr127048wfd.84.1216222870242;
+        Wed, 16 Jul 2008 08:41:10 -0700 (PDT)
+Return-Path: <antirez@gmail.com>
+Received: from cpanel5.proisp.no (cpanel5.proisp.no [209.85.100.29])
+        by mx.google.com with ESMTP id 29si7397124wfg.0.2008.07.16.08.41.08;
+        Wed, 16 Jul 2008 08:41:10 -0700 (PDT)
+Received-SPF: neutral (google.com: 209.85.100.29 is neither permitted nor denied by domain of antirez@gmail.com) client-ip=209.85.100.29;
+Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.100.29 is neither permitted nor denied by domain of antirez@gmail.com) smtp.mail=antirez@gmail.com; dkim=pass (test mode) header.i=@gmail.com
+Received: from fg-out-1718.google.com ([72.14.220.155]:16058)
+	by cpanel5.proisp.no with esmtp (Exim 4.69)
+	(envelope-from <antirez@gmail.com>)
+	id 1KJ97g-0004yX-1W
+	for oyvind.harboe@zylin.com; Wed, 16 Jul 2008 17:40:59 +0200
+Received: by fg-out-1718.google.com with SMTP id l27so3985052fgb.19
+        for <oyvind.harboe@zylin.com>; Wed, 16 Jul 2008 08:40:59 -0700 (PDT)
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+        d=gmail.com; s=gamma;
+        h=domainkey-signature:received:received:message-id:date:from:to
+         :subject:cc:in-reply-to:mime-version:content-type
+         :content-transfer-encoding:content-disposition:references;
+        bh=/aWDZQfgMBPqomYWZ2AUKOhhGMju+bwnSBbKL8MBonA=;
+        b=i0P3OKDopn/vHfa5ZrUvBjuPBnj43GMw8FOXKjxM/IfvywJParYqBS2Vmlw8RTndFg
+         J5wwxXf5056cZu/GbKbj8xLfylFfSInVaO7OnDutA3CeX1iU35my1DU6l9W6ILkLiT1P
+         Azi3L27rFQrzau/s53VU/UVELc3WckWdu1a1k=
+DomainKey-Signature: a=rsa-sha1; c=nofws;
+        d=gmail.com; s=gamma;
+        h=message-id:date:from:to:subject:cc:in-reply-to:mime-version
+         :content-type:content-transfer-encoding:content-disposition
+         :references;
+        b=ww2MIz9svJttgS8mTRBhEX8Isveugn2hl3sMcgh0hZ1+ln8YbiysxYxZkdddewWm02
+         WXsWgSgwy7MIPAUK1tNjzgkZ2l789SdrAtBCmqmRWJJI+ESTqbHMz8cqW+QRVP/A9Dfm
+         8+AR85DHi7SOB0mdHtq9fsavZReUdaSIgy6F4=
+Received: by 10.86.80.5 with SMTP id d5mr2284433fgb.19.1216222858224;
+        Wed, 16 Jul 2008 08:40:58 -0700 (PDT)
+Received: by 10.86.50.18 with HTTP; Wed, 16 Jul 2008 08:40:58 -0700 (PDT)
+Message-ID: <c6114db60807160840n62186f46w7cdc1bbec91186ca@mail.gmail.com>
+Date: Wed, 16 Jul 2008 17:40:58 +0200
+From: "Salvatore Sanfilippo" <antirez@gmail.com>
+To: "=?ISO-8859-1?Q?=D8yvind_Harboe?=" <oyvind.harboe@zylin.com>
+Subject: Re: Change Jim Tcl license
+Cc: jim-devel@lists.berlios.de, patthoyts@users.sf.net, andrew@lunn.ch, 
+	openocd@duaneellis.com, uklein@klein-messgeraete.de, 
+	ml-jim@qiao.in-berlin.de
+In-Reply-To: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=ISO-8859-1
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline
+References: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+X-Spam-Status: No, score=-2.6
+X-Spam-Score: -25
+X-Spam-Bar: --
+X-Spam-Flag: NO
+X-AntiAbuse: This header was added to track abuse, please include it with any abuse report
+X-AntiAbuse: Primary Hostname - cpanel5.proisp.no
+X-AntiAbuse: Original Domain - zylin.com
+X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12]
+X-AntiAbuse: Sender Address Domain - gmail.com
+X-Source: 
+X-Source-Args: 
+X-Source-Dir: 
+
+I agree to permit my contributions to the Jim project to be
+re-licensed under a BSD compatible license.
+
+Since I'm currently the top contributor if it's safer from
+the legal point of view I can also put a tar.gz of the current
+Jim source code with a BSD "LICENSE" file on my website.
+
+Otherwise I can sign by hand a letter and send a digitalized
+image here.
+
+Ciao,
+Salvatore
+
+-- 
+Salvatore 'antirez' Sanfilippo
+http://antirez.com
+
+Organizations which design systems are constrained to produce designs
+which are copies of the communication structures of these
+organizations.
+
+Conway's Law
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/uwe.txt b/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/uwe.txt
new file mode 100755
index 0000000..035ca32
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/freebsd/uwe.txt
@@ -0,0 +1,73 @@
+Delivered-To: oyvindharboe@gmail.com
+Received: by 10.100.7.20 with SMTP id 20cs89014ang;
+        Wed, 16 Jul 2008 01:58:32 -0700 (PDT)
+Received: by 10.142.125.9 with SMTP id x9mr5028534wfc.123.1216198711465;
+        Wed, 16 Jul 2008 01:58:31 -0700 (PDT)
+Return-Path: <wiederling@googlemail.com>
+Received: from cpanel5.proisp.no (cpanel5.proisp.no [209.85.100.29])
+        by mx.google.com with ESMTP id 30si6756166wfa.10.2008.07.16.01.58.29;
+        Wed, 16 Jul 2008 01:58:31 -0700 (PDT)
+Received-SPF: neutral (google.com: 209.85.100.29 is neither permitted nor denied by domain of wiederling@googlemail.com) client-ip=209.85.100.29;
+Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.100.29 is neither permitted nor denied by domain of wiederling@googlemail.com) smtp.mail=wiederling@googlemail.com; dkim=pass (test mode) header.i=@googlemail.com
+Received: from wr-out-0506.google.com ([64.233.184.233]:51225)
+	by cpanel5.proisp.no with esmtp (Exim 4.69)
+	(envelope-from <wiederling@googlemail.com>)
+	id 1KJ2q7-00057b-IR
+	for oyvind.harboe@zylin.com; Wed, 16 Jul 2008 10:58:24 +0200
+Received: by wr-out-0506.google.com with SMTP id c8so2209154wra.27
+        for <oyvind.harboe@zylin.com>; Wed, 16 Jul 2008 01:58:25 -0700 (PDT)
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+        d=googlemail.com; s=gamma;
+        h=domainkey-signature:received:received:message-id:date:from:to
+         :subject:cc:in-reply-to:mime-version:content-type
+         :content-transfer-encoding:content-disposition:references;
+        bh=VxcH0g2H5iLUo27gqJiqrlY4uVbN1NFE4skyMKqysPM=;
+        b=JPK53r6LQ6GqBCG1kfVYyTPuPuVhlBrbzQ8oSBwpwuwwB7t3CSv+c75jRjb/n3y8mi
+         gN1r6noZucK9ZpRZiHxYZpHVhYFcWbZ+ZXM75H2qIFfl4YDzfgg/Ub7CzoR2LskuBsRk
+         DMH2LnyAYf+Om2YAKJdkoMnGbPMDMFSrNHeIc=
+DomainKey-Signature: a=rsa-sha1; c=nofws;
+        d=googlemail.com; s=gamma;
+        h=message-id:date:from:to:subject:cc:in-reply-to:mime-version
+         :content-type:content-transfer-encoding:content-disposition
+         :references;
+        b=VAGlxpb1YGbex/eaS0tQgWvH/lWHzgD5R/rxjshVSwZJOStwqMA1F5jNQgybQFIn1F
+         zWoiAV81uWMzBEGYab7SGsStWLxovcBSgi9NL+XqwAkhBdrWjgFPvpBHn5PvgOOXEhGH
+         EGhjrY8qp2LSxhFcW3/DvgObhBBKtY1J+qzvA=
+Received: by 10.90.115.17 with SMTP id n17mr1231758agc.90.1216198705850;
+        Wed, 16 Jul 2008 01:58:25 -0700 (PDT)
+Received: by 10.90.105.18 with HTTP; Wed, 16 Jul 2008 01:58:25 -0700 (PDT)
+Message-ID: <1af31b6f0807160158o295303adh43abdd34fbe8ec99@mail.gmail.com>
+Date: Wed, 16 Jul 2008 10:58:25 +0200
+From: "Uwe Klein" <wiederling@googlemail.com>
+To: "=?ISO-8859-1?Q?=D8yvind_Harboe?=" <oyvind.harboe@zylin.com>
+Subject: Re: [Jim-devel] Change Jim Tcl license
+Cc: jim-devel@lists.berlios.de, patthoyts@users.sf.net, andrew@lunn.ch, 
+	uklein@klein-messgeraete.de, antirez@gmail.com, 
+	openocd@duaneellis.com, ml-jim@qiao.in-berlin.de
+In-Reply-To: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=ISO-8859-1
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline
+References: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+X-Spam-Status: No, score=-2.6
+X-Spam-Score: -25
+X-Spam-Bar: --
+X-Spam-Flag: NO
+X-AntiAbuse: This header was added to track abuse, please include it with any abuse report
+X-AntiAbuse: Primary Hostname - cpanel5.proisp.no
+X-AntiAbuse: Original Domain - zylin.com
+X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12]
+X-AntiAbuse: Sender Address Domain - googlemail.com
+X-Source: 
+X-Source-Args: 
+X-Source-Dir: 
+
+>  If you have contributed to Jim Tcl, please reply to this email
+>  that you agree that we can switch Jim Tcl to a FreeBSD license.
+
+For Uwe Klein <uklein@klein-messgeraete.de>
+
+This is OK with me.
+
+uwe
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/glob.tcl b/android/external/usb_modeswitch/usb_modeswitch/jim/glob.tcl
new file mode 100755
index 0000000..cd94d8d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/glob.tcl
@@ -0,0 +1,129 @@
+# Implements a Tcl-compatible glob command based on readdir
+#
+# (c) 2008 Steve Bennett <steveb@workware.net.au>
+#
+# See LICENCE in this directory for licensing.
+
+package require readdir
+
+# Implements the Tcl glob command
+#
+# Usage: glob ?-nocomplain? pattern ...
+#
+# Patterns use 'string match' (glob) pattern matching for each
+# directory level, plus support for braced alternations.
+#
+# e.g. glob "te[a-e]*/*.{c,tcl}"
+#
+# Note: files starting with . will only be returned if matching component
+#       of the pattern starts with .
+proc glob {args} {
+
+	# If $dir is a directory, return a list of all entries
+	# it contains which match $pattern
+	#
+	local proc glob.readdir_pattern {dir pattern} {
+		set result {}
+
+		# readdir doesn't return . or .., so simulate it here
+		if {$pattern in {. ..}} {
+			return $pattern
+		}
+
+		# If the pattern isn't actually a pattern...
+		if {[string match {*[*?]*} $pattern]} {
+			# Use -nocomplain here to return nothing if $dir is not a directory
+			set files [readdir -nocomplain $dir]
+		} elseif {[file isdir $dir] && [file exists $dir/$pattern]} {
+			set files [list $pattern]
+		} else {
+			set files ""
+		}
+
+		foreach name $files {
+			if {[string match $pattern $name]} {
+				# Only include entries starting with . if the pattern starts with .
+				if {[string index $name 0] eq "." && [string index $pattern 0] ne "."} {
+					continue
+				}
+				lappend result $name
+			}
+		}
+
+		return $result
+	}
+
+	# If the pattern contains a braced expression, return a list of
+	# patterns with the braces expanded. {c,b}* => c* b*
+	# Otherwise just return the pattern
+	# Note: Only supports one braced expression. i.e. not {a,b}*{c,d}*
+	proc glob.expandbraces {pattern} {
+		# Avoid regexp for dependency reasons.
+		# XXX: Doesn't handle backslashed braces
+		if {[set fb [string first "\{" $pattern]] < 0} {
+			return $pattern
+		}
+		if {[set nb [string first "\}" $pattern $fb]] < 0} {
+			return $pattern
+		}
+		set before [string range $pattern 0 $fb-1]
+		set braced [string range $pattern $fb+1 $nb-1]
+		set after [string range $pattern $nb+1 end]
+
+		lmap part [split $braced ,] {
+			set pat $before$part$after
+		}
+	}
+
+	# Core glob implementation. Returns a list of files/directories matching the pattern
+	proc glob.glob {pattern} {
+		set dir [file dirname $pattern]
+		if {$dir eq $pattern} {
+			# At the top level
+			return [list $dir]
+		}
+
+		# Recursively expand the parent directory
+		set dirlist [glob.glob $dir]
+		set pattern [file tail $pattern]
+
+		# Now collect the fiels/directories
+		set result {}
+		foreach dir $dirlist {
+			set globdir $dir
+			if {[string match "*/" $dir]} {
+				set sep ""
+			} elseif {$dir eq "."} {
+				set globdir ""
+				set sep ""
+			} else {
+				set sep /
+			}
+			foreach pat [glob.expandbraces $pattern] {
+				foreach name [glob.readdir_pattern $dir $pat] {
+					lappend result $globdir$sep$name
+				}
+			}
+		}
+		return $result
+	}
+
+	# Start of main glob
+	set nocomplain 0
+
+	if {[lindex $args 0] eq "-nocomplain"} {
+		set nocomplain 1
+		set args [lrange $args 1 end]
+	}
+
+	set result {}
+	foreach pattern $args {
+		lappend result {*}[glob.glob $pattern]
+	}
+
+	if {$nocomplain == 0 && [llength $result] == 0} {
+		return -code error "no files matched glob patterns"
+	}
+
+	return $result
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/initjimsh.tcl b/android/external/usb_modeswitch/usb_modeswitch/jim/initjimsh.tcl
new file mode 100755
index 0000000..a764f3a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/initjimsh.tcl
@@ -0,0 +1,27 @@
+# This pseudo-package is loaded from jimsh to add additional
+# paths to $auto_path and to source ~/.jimrc
+
+proc _jimsh_init {} {
+	rename _jimsh_init {}
+
+	# Add to the standard auto_path
+	lappend p {*}[split [env JIMLIB {}] $::tcl_platform(pathSeparator)]
+	lappend p {*}$::auto_path
+	lappend p [file dirname [info nameofexecutable]]
+	set ::auto_path $p
+
+	if {$::tcl_interactive && [env HOME {}] ne ""} {
+		foreach src {.jimrc jimrc.tcl} {
+			if {[file exists [env HOME]/$src]} {
+				uplevel #0 source [env HOME]/$src
+				break
+			}
+		}
+	}
+}
+
+if {$tcl_platform(platform) eq "windows"} {
+	set jim_argv0 [string map {\\ /} $jim_argv0]
+}
+
+_jimsh_init
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-aio.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-aio.c
new file mode 100755
index 0000000..710a47d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-aio.c
@@ -0,0 +1,1353 @@
+
+/* Jim - A small embeddable Tcl interpreter
+ *
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
+ * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
+ * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
+ * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
+ * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
+ * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ **/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+
+#if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#else
+#define JIM_ANSIC
+#endif
+
+#include "jim-eventloop.h"
+#include "jim-subcmd.h"
+
+#define AIO_CMD_LEN 32      /* e.g. aio.handleXXXXXX */
+#define AIO_BUF_LEN 256     /* Can keep this small and rely on stdio buffering */
+
+#define AIO_KEEPOPEN 1
+
+#if defined(JIM_IPV6)
+#define IPV6 1
+#else
+#define IPV6 0
+#ifndef PF_INET6
+#define PF_INET6 0
+#endif
+#endif
+
+#if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP)
+union sockaddr_any {
+    struct sockaddr sa;
+    struct sockaddr_in sin;
+#if IPV6
+    struct sockaddr_in6 sin6;
+#endif
+};
+
+#ifndef HAVE_INET_NTOP
+const char *inet_ntop(int af, const void *src, char *dst, int size)
+{
+    if (af != PF_INET) {
+        return NULL;
+    }
+    snprintf(dst, size, "%s", inet_ntoa(((struct sockaddr_in *)src)->sin_addr));
+    return dst;
+}
+#endif
+#endif /* JIM_BOOTSTRAP */
+
+typedef struct AioFile
+{
+    FILE *fp;
+    Jim_Obj *filename;
+    int type;
+    int OpenFlags;              /* AIO_KEEPOPEN? keep FILE* */
+    int fd;
+#ifdef O_NDELAY
+    int flags;
+#endif
+    Jim_Obj *rEvent;
+    Jim_Obj *wEvent;
+    Jim_Obj *eEvent;
+    int addr_family;
+} AioFile;
+
+static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+static int JimMakeChannel(Jim_Interp *interp, FILE *fh, int fd, Jim_Obj *filename,
+    const char *hdlfmt, int family, const char *mode);
+
+#if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP)
+static int JimParseIPv6Address(Jim_Interp *interp, const char *hostport, union sockaddr_any *sa, int *salen)
+{
+#if IPV6
+    /*
+     * An IPv6 addr/port looks like:
+     *   [::1]
+     *   [::1]:2000
+     *   [fe80::223:6cff:fe95:bdc0%en1]:2000
+     *   [::]:2000
+     *   2000
+     *
+     *   Note that the "any" address is ::, which is the same as when no address is specified.
+     */
+     char *sthost = NULL;
+     const char *stport;
+     int ret = JIM_OK;
+     struct addrinfo req;
+     struct addrinfo *ai;
+
+    stport = strrchr(hostport, ':');
+    if (!stport) {
+        /* No : so, the whole thing is the port */
+        stport = hostport;
+        hostport = "::";
+        sthost = Jim_StrDup(hostport);
+    }
+    else {
+        stport++;
+    }
+
+    if (*hostport == '[') {
+        /* This is a numeric ipv6 address */
+        char *pt = strchr(++hostport, ']');
+        if (pt) {
+            sthost = Jim_StrDupLen(hostport, pt - hostport);
+        }
+    }
+
+    if (!sthost) {
+        sthost = Jim_StrDupLen(hostport, stport - hostport - 1);
+    }
+
+    memset(&req, '\0', sizeof(req));
+    req.ai_family = PF_INET6;
+
+    if (getaddrinfo(sthost, NULL, &req, &ai)) {
+        Jim_SetResultFormatted(interp, "Not a valid address: %s", hostport);
+        ret = JIM_ERR;
+    }
+    else {
+        memcpy(&sa->sin, ai->ai_addr, ai->ai_addrlen);
+        *salen = ai->ai_addrlen;
+
+        sa->sin.sin_port = htons(atoi(stport));
+
+        freeaddrinfo(ai);
+    }
+    Jim_Free(sthost);
+
+    return ret;
+#else
+    Jim_SetResultString(interp, "ipv6 not supported", -1);
+    return JIM_ERR;
+#endif
+}
+
+static int JimParseIpAddress(Jim_Interp *interp, const char *hostport, union sockaddr_any *sa, int *salen)
+{
+    /* An IPv4 addr/port looks like:
+     *   192.168.1.5
+     *   192.168.1.5:2000
+     *   2000
+     *
+     * If the address is missing, INADDR_ANY is used.
+     * If the port is missing, 0 is used (only useful for server sockets).
+     */
+    char *sthost = NULL;
+    const char *stport;
+    int ret = JIM_OK;
+
+    stport = strrchr(hostport, ':');
+    if (!stport) {
+        /* No : so, the whole thing is the port */
+        stport = hostport;
+        sthost = Jim_StrDup("0.0.0.0");
+    }
+    else {
+        sthost = Jim_StrDupLen(hostport, stport - hostport);
+        stport++;
+    }
+
+    {
+#ifdef HAVE_GETADDRINFO
+        struct addrinfo req;
+        struct addrinfo *ai;
+        memset(&req, '\0', sizeof(req));
+        req.ai_family = PF_INET;
+
+        if (getaddrinfo(sthost, NULL, &req, &ai)) {
+            ret = JIM_ERR;
+        }
+        else {
+            memcpy(&sa->sin, ai->ai_addr, ai->ai_addrlen);
+            *salen = ai->ai_addrlen;
+            freeaddrinfo(ai);
+        }
+#else
+        struct hostent *he;
+
+        ret = JIM_ERR;
+
+        if ((he = gethostbyname(sthost)) != NULL) {
+            if (he->h_length == sizeof(sa->sin.sin_addr)) {
+                *salen = sizeof(sa->sin);
+                sa->sin.sin_family= he->h_addrtype;
+                memcpy(&sa->sin.sin_addr, he->h_addr, he->h_length); /* set address */
+                ret = JIM_OK;
+            }
+        }
+#endif
+
+        sa->sin.sin_port = htons(atoi(stport));
+    }
+    Jim_Free(sthost);
+
+    if (ret != JIM_OK) {
+        Jim_SetResultFormatted(interp, "Not a valid address: %s", hostport);
+    }
+
+    return ret;
+}
+
+#ifdef HAVE_SYS_UN_H
+static int JimParseDomainAddress(Jim_Interp *interp, const char *path, struct sockaddr_un *sa)
+{
+    sa->sun_family = PF_UNIX;
+    snprintf(sa->sun_path, sizeof(sa->sun_path), "%s", path);
+
+    return JIM_OK;
+}
+#endif
+#endif /* JIM_BOOTSTRAP */
+
+static void JimAioSetError(Jim_Interp *interp, Jim_Obj *name)
+{
+    if (name) {
+        Jim_SetResultFormatted(interp, "%#s: %s", name, strerror(errno));
+    }
+    else {
+        Jim_SetResultString(interp, strerror(errno), -1);
+    }
+}
+
+static void JimAioDelProc(Jim_Interp *interp, void *privData)
+{
+    AioFile *af = privData;
+
+    JIM_NOTUSED(interp);
+
+    Jim_DecrRefCount(interp, af->filename);
+
+    if (!(af->OpenFlags & AIO_KEEPOPEN)) {
+        fclose(af->fp);
+    }
+#ifdef jim_ext_eventloop
+    /* remove existing EventHandlers */
+    if (af->rEvent) {
+        Jim_DeleteFileHandler(interp, af->fp);
+    }
+    if (af->wEvent) {
+        Jim_DeleteFileHandler(interp, af->fp);
+    }
+    if (af->eEvent) {
+        Jim_DeleteFileHandler(interp, af->fp);
+    }
+#endif
+    Jim_Free(af);
+}
+
+static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    char buf[AIO_BUF_LEN];
+    Jim_Obj *objPtr;
+    int nonewline = 0;
+    int neededLen = -1;         /* -1 is "read as much as possible" */
+
+    if (argc && Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) {
+        nonewline = 1;
+        argv++;
+        argc--;
+    }
+    if (argc == 1) {
+        jim_wide wideValue;
+
+        if (Jim_GetWide(interp, argv[0], &wideValue) != JIM_OK)
+            return JIM_ERR;
+        if (wideValue < 0) {
+            Jim_SetResultString(interp, "invalid parameter: negative len", -1);
+            return JIM_ERR;
+        }
+        neededLen = (int)wideValue;
+    }
+    else if (argc) {
+        return -1;
+    }
+    objPtr = Jim_NewStringObj(interp, NULL, 0);
+    while (neededLen != 0) {
+        int retval;
+        int readlen;
+
+        if (neededLen == -1) {
+            readlen = AIO_BUF_LEN;
+        }
+        else {
+            readlen = (neededLen > AIO_BUF_LEN ? AIO_BUF_LEN : neededLen);
+        }
+        retval = fread(buf, 1, readlen, af->fp);
+        if (retval > 0) {
+            Jim_AppendString(interp, objPtr, buf, retval);
+            if (neededLen != -1) {
+                neededLen -= retval;
+            }
+        }
+        if (retval != readlen)
+            break;
+    }
+    /* Check for error conditions */
+    if (ferror(af->fp)) {
+        clearerr(af->fp);
+        /* eof and EAGAIN are not error conditions */
+        if (!feof(af->fp) && errno != EAGAIN) {
+            /* I/O error */
+            Jim_FreeNewObj(interp, objPtr);
+            JimAioSetError(interp, af->filename);
+            return JIM_ERR;
+        }
+    }
+    if (nonewline) {
+        int len;
+        const char *s = Jim_GetString(objPtr, &len);
+
+        if (len > 0 && s[len - 1] == '\n') {
+            objPtr->length--;
+            objPtr->bytes[objPtr->length] = '\0';
+        }
+    }
+    Jim_SetResult(interp, objPtr);
+    return JIM_OK;
+}
+
+static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    long count = 0;
+    long maxlen = LONG_MAX;
+    FILE *outfh = Jim_AioFilehandle(interp, argv[0]);
+
+    if (outfh == NULL) {
+        return JIM_ERR;
+    }
+
+    if (argc == 2) {
+        if (Jim_GetLong(interp, argv[1], &maxlen) != JIM_OK) {
+            return JIM_ERR;
+        }
+    }
+
+    while (count < maxlen) {
+        int ch = fgetc(af->fp);
+
+        if (ch == EOF || fputc(ch, outfh) == EOF) {
+            break;
+        }
+        count++;
+    }
+
+    if (ferror(af->fp)) {
+        Jim_SetResultFormatted(interp, "error while reading: %s", strerror(errno));
+        clearerr(af->fp);
+        return JIM_ERR;
+    }
+
+    if (ferror(outfh)) {
+        Jim_SetResultFormatted(interp, "error while writing: %s", strerror(errno));
+        clearerr(outfh);
+        return JIM_ERR;
+    }
+
+    Jim_SetResultInt(interp, count);
+
+    return JIM_OK;
+}
+
+static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    char buf[AIO_BUF_LEN];
+    Jim_Obj *objPtr;
+    int len;
+
+    errno = 0;
+
+    objPtr = Jim_NewStringObj(interp, NULL, 0);
+    while (1) {
+        buf[AIO_BUF_LEN - 1] = '_';
+        if (fgets(buf, AIO_BUF_LEN, af->fp) == NULL)
+            break;
+
+        if (buf[AIO_BUF_LEN - 1] == '\0' && buf[AIO_BUF_LEN - 2] != '\n') {
+            Jim_AppendString(interp, objPtr, buf, AIO_BUF_LEN - 1);
+        }
+        else {
+            len = strlen(buf);
+
+            if (len && (buf[len - 1] == '\n')) {
+                /* strip "\n" */
+                len--;
+            }
+
+            Jim_AppendString(interp, objPtr, buf, len);
+            break;
+        }
+    }
+    if (ferror(af->fp) && errno != EAGAIN && errno != EINTR) {
+        /* I/O error */
+        Jim_FreeNewObj(interp, objPtr);
+        JimAioSetError(interp, af->filename);
+        clearerr(af->fp);
+        return JIM_ERR;
+    }
+
+    if (argc) {
+        if (Jim_SetVariable(interp, argv[0], objPtr) != JIM_OK) {
+            Jim_FreeNewObj(interp, objPtr);
+            return JIM_ERR;
+        }
+
+        len = Jim_Length(objPtr);
+
+        if (len == 0 && feof(af->fp)) {
+            /* On EOF returns -1 if varName was specified */
+            len = -1;
+        }
+        Jim_SetResultInt(interp, len);
+    }
+    else {
+        Jim_SetResult(interp, objPtr);
+    }
+    return JIM_OK;
+}
+
+static int aio_cmd_puts(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    int wlen;
+    const char *wdata;
+    Jim_Obj *strObj;
+
+    if (argc == 2) {
+        if (!Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) {
+            return -1;
+        }
+        strObj = argv[1];
+    }
+    else {
+        strObj = argv[0];
+    }
+
+    wdata = Jim_GetString(strObj, &wlen);
+    if (fwrite(wdata, 1, wlen, af->fp) == (unsigned)wlen) {
+        if (argc == 2 || putc('\n', af->fp) != EOF) {
+            return JIM_OK;
+        }
+    }
+    JimAioSetError(interp, af->filename);
+    return JIM_ERR;
+}
+
+#if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP)
+static int aio_cmd_recvfrom(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    char *buf;
+    union sockaddr_any sa;
+    long len;
+    socklen_t salen = sizeof(sa);
+    int rlen;
+
+    if (Jim_GetLong(interp, argv[0], &len) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    buf = Jim_Alloc(len + 1);
+
+    rlen = recvfrom(fileno(af->fp), buf, len, 0, &sa.sa, &salen);
+    if (rlen < 0) {
+        Jim_Free(buf);
+        JimAioSetError(interp, NULL);
+        return JIM_ERR;
+    }
+    buf[rlen] = 0;
+    Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, rlen));
+
+    if (argc > 1) {
+        /* INET6_ADDRSTRLEN is 46. Add some for [] and port */
+        char addrbuf[60];
+
+#if IPV6
+        if (sa.sa.sa_family == PF_INET6) {
+            addrbuf[0] = '[';
+            /* Allow 9 for []:65535\0 */
+            inet_ntop(sa.sa.sa_family, &sa.sin6.sin6_addr, addrbuf + 1, sizeof(addrbuf) - 9);
+            snprintf(addrbuf + strlen(addrbuf), 8, "]:%d", ntohs(sa.sin.sin_port));
+        }
+        else
+#endif
+        {
+            /* Allow 7 for :65535\0 */
+            inet_ntop(sa.sa.sa_family, &sa.sin.sin_addr, addrbuf, sizeof(addrbuf) - 7);
+            snprintf(addrbuf + strlen(addrbuf), 7, ":%d", ntohs(sa.sin.sin_port));
+        }
+
+        if (Jim_SetVariable(interp, argv[1], Jim_NewStringObj(interp, addrbuf, -1)) != JIM_OK) {
+            return JIM_ERR;
+        }
+    }
+
+    return JIM_OK;
+}
+
+
+static int aio_cmd_sendto(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    int wlen;
+    int len;
+    const char *wdata;
+    union sockaddr_any sa;
+    const char *addr = Jim_String(argv[1]);
+    int salen;
+
+    if (IPV6 && af->addr_family == PF_INET6) {
+        if (JimParseIPv6Address(interp, addr, &sa, &salen) != JIM_OK) {
+            return JIM_ERR;
+        }
+    }
+    else if (JimParseIpAddress(interp, addr, &sa, &salen) != JIM_OK) {
+        return JIM_ERR;
+    }
+    wdata = Jim_GetString(argv[0], &wlen);
+
+    /* Note that we don't validate the socket type. Rely on sendto() failing if appropriate */
+    len = sendto(fileno(af->fp), wdata, wlen, 0, &sa.sa, salen);
+    if (len < 0) {
+        JimAioSetError(interp, NULL);
+        return JIM_ERR;
+    }
+    Jim_SetResultInt(interp, len);
+    return JIM_OK;
+}
+
+static int aio_cmd_accept(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    int sock;
+    union sockaddr_any sa;
+    socklen_t addrlen = sizeof(sa);
+
+    sock = accept(af->fd, &sa.sa, &addrlen);
+    if (sock < 0) {
+        JimAioSetError(interp, NULL);
+        return JIM_ERR;
+    }
+
+    /* Create the file command */
+    return JimMakeChannel(interp, NULL, sock, Jim_NewStringObj(interp, "accept", -1),
+        "aio.sockstream%ld", af->addr_family, "r+");
+}
+
+static int aio_cmd_listen(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    long backlog;
+
+    if (Jim_GetLong(interp, argv[0], &backlog) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    if (listen(af->fd, backlog)) {
+        JimAioSetError(interp, NULL);
+        return JIM_ERR;
+    }
+
+    return JIM_OK;
+}
+#endif /* JIM_BOOTSTRAP */
+
+static int aio_cmd_flush(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    if (fflush(af->fp) == EOF) {
+        JimAioSetError(interp, af->filename);
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+static int aio_cmd_eof(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    Jim_SetResultInt(interp, feof(af->fp));
+    return JIM_OK;
+}
+
+static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_DeleteCommand(interp, Jim_String(argv[0]));
+    return JIM_OK;
+}
+
+static int aio_cmd_seek(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    int orig = SEEK_SET;
+    long offset;
+
+    if (argc == 2) {
+        if (Jim_CompareStringImmediate(interp, argv[1], "start"))
+            orig = SEEK_SET;
+        else if (Jim_CompareStringImmediate(interp, argv[1], "current"))
+            orig = SEEK_CUR;
+        else if (Jim_CompareStringImmediate(interp, argv[1], "end"))
+            orig = SEEK_END;
+        else {
+            return -1;
+        }
+    }
+    if (Jim_GetLong(interp, argv[0], &offset) != JIM_OK) {
+        return JIM_ERR;
+    }
+    if (fseek(af->fp, offset, orig) == -1) {
+        JimAioSetError(interp, af->filename);
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+static int aio_cmd_tell(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    Jim_SetResultInt(interp, ftell(af->fp));
+    return JIM_OK;
+}
+
+static int aio_cmd_filename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    Jim_SetResult(interp, af->filename);
+    return JIM_OK;
+}
+
+#ifdef O_NDELAY
+static int aio_cmd_ndelay(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    int fmode = af->flags;
+
+    if (argc) {
+        long nb;
+
+        if (Jim_GetLong(interp, argv[0], &nb) != JIM_OK) {
+            return JIM_ERR;
+        }
+        if (nb) {
+            fmode |= O_NDELAY;
+        }
+        else {
+            fmode &= ~O_NDELAY;
+        }
+        fcntl(af->fd, F_SETFL, fmode);
+        af->flags = fmode;
+    }
+    Jim_SetResultInt(interp, (fmode & O_NONBLOCK) ? 1 : 0);
+    return JIM_OK;
+}
+#endif
+
+static int aio_cmd_buffering(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    static const char * const options[] = {
+        "none",
+        "line",
+        "full",
+        NULL
+    };
+    enum
+    {
+        OPT_NONE,
+        OPT_LINE,
+        OPT_FULL,
+    };
+    int option;
+
+    if (Jim_GetEnum(interp, argv[0], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+        return JIM_ERR;
+    }
+    switch (option) {
+        case OPT_NONE:
+            setvbuf(af->fp, NULL, _IONBF, 0);
+            break;
+        case OPT_LINE:
+            setvbuf(af->fp, NULL, _IOLBF, BUFSIZ);
+            break;
+        case OPT_FULL:
+            setvbuf(af->fp, NULL, _IOFBF, BUFSIZ);
+            break;
+    }
+    return JIM_OK;
+}
+
+#ifdef jim_ext_eventloop
+static void JimAioFileEventFinalizer(Jim_Interp *interp, void *clientData)
+{
+    Jim_Obj *objPtr = clientData;
+
+    Jim_DecrRefCount(interp, objPtr);
+}
+
+static int JimAioFileEventHandler(Jim_Interp *interp, void *clientData, int mask)
+{
+    Jim_Obj *objPtr = clientData;
+
+    return Jim_EvalObjBackground(interp, objPtr);
+}
+
+static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask, Jim_Obj **scriptHandlerObj,
+    int argc, Jim_Obj * const *argv)
+{
+    int scriptlen = 0;
+
+    if (argc == 0) {
+        /* Return current script */
+        if (*scriptHandlerObj) {
+            Jim_SetResult(interp, *scriptHandlerObj);
+        }
+        return JIM_OK;
+    }
+
+    if (*scriptHandlerObj) {
+        /* Delete old handler */
+        Jim_DeleteFileHandler(interp, af->fp);
+        *scriptHandlerObj = NULL;
+    }
+
+    /* Now possibly add the new script(s) */
+    Jim_GetString(argv[0], &scriptlen);
+    if (scriptlen == 0) {
+        /* Empty script, so done */
+        return JIM_OK;
+    }
+
+    /* A new script to add */
+    Jim_IncrRefCount(argv[0]);
+    *scriptHandlerObj = argv[0];
+
+    Jim_CreateFileHandler(interp, af->fp, mask,
+        JimAioFileEventHandler, *scriptHandlerObj, JimAioFileEventFinalizer);
+
+    return JIM_OK;
+}
+
+static int aio_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    return aio_eventinfo(interp, af, JIM_EVENT_READABLE, &af->rEvent, argc, argv);
+}
+
+static int aio_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    return aio_eventinfo(interp, af, JIM_EVENT_WRITABLE, &af->wEvent, argc, argv);
+}
+
+static int aio_cmd_onexception(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, &af->wEvent, argc, argv);
+}
+#endif
+
+static const jim_subcmd_type aio_command_table[] = {
+    {   .cmd = "read",
+        .args = "?-nonewline? ?len?",
+        .function = aio_cmd_read,
+        .minargs = 0,
+        .maxargs = 2,
+        .description = "Read and return bytes from the stream. To eof if no len."
+    },
+    {   .cmd = "copyto",
+        .args = "handle ?size?",
+        .function = aio_cmd_copy,
+        .minargs = 1,
+        .maxargs = 2,
+        .description = "Copy up to 'size' bytes to the given filehandle, or to eof if no size."
+    },
+    {   .cmd = "gets",
+        .args = "?var?",
+        .function = aio_cmd_gets,
+        .minargs = 0,
+        .maxargs = 1,
+        .description = "Read one line and return it or store it in the var"
+    },
+    {   .cmd = "puts",
+        .args = "?-nonewline? str",
+        .function = aio_cmd_puts,
+        .minargs = 1,
+        .maxargs = 2,
+        .description = "Write the string, with newline unless -nonewline"
+    },
+#if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP)
+    {   .cmd = "recvfrom",
+        .args = "len ?addrvar?",
+        .function = aio_cmd_recvfrom,
+        .minargs = 1,
+        .maxargs = 2,
+        .description = "Receive up to 'len' bytes on the socket. Sets 'addrvar' with receive address, if set"
+    },
+    {   .cmd = "sendto",
+        .args = "str address",
+        .function = aio_cmd_sendto,
+        .minargs = 2,
+        .maxargs = 2,
+        .description = "Send 'str' to the given address (dgram only)"
+    },
+    {   .cmd = "accept",
+        .function = aio_cmd_accept,
+        .description = "Server socket only: Accept a connection and return stream"
+    },
+    {   .cmd = "listen",
+        .args = "backlog",
+        .function = aio_cmd_listen,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Set the listen backlog for server socket"
+    },
+#endif /* JIM_BOOTSTRAP */
+    {   .cmd = "flush",
+        .function = aio_cmd_flush,
+        .description = "Flush the stream"
+    },
+    {   .cmd = "eof",
+        .function = aio_cmd_eof,
+        .description = "Returns 1 if stream is at eof"
+    },
+    {   .cmd = "close",
+        .flags = JIM_MODFLAG_FULLARGV,
+        .function = aio_cmd_close,
+        .description = "Closes the stream"
+    },
+    {   .cmd = "seek",
+        .args = "offset ?start|current|end",
+        .function = aio_cmd_seek,
+        .minargs = 1,
+        .maxargs = 2,
+        .description = "Seeks in the stream (default 'current')"
+    },
+    {   .cmd = "tell",
+        .function = aio_cmd_tell,
+        .description = "Returns the current seek position"
+    },
+    {   .cmd = "filename",
+        .function = aio_cmd_filename,
+        .description = "Returns the original filename"
+    },
+#ifdef O_NDELAY
+    {   .cmd = "ndelay",
+        .args = "?0|1?",
+        .function = aio_cmd_ndelay,
+        .minargs = 0,
+        .maxargs = 1,
+        .description = "Set O_NDELAY (if arg). Returns current/new setting."
+    },
+#endif
+    {   .cmd = "buffering",
+        .args = "none|line|full",
+        .function = aio_cmd_buffering,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Sets buffering"
+    },
+#ifdef jim_ext_eventloop
+    {   .cmd = "readable",
+        .args = "?readable-script?",
+        .minargs = 0,
+        .maxargs = 1,
+        .function = aio_cmd_readable,
+        .description = "Returns script, or invoke readable-script when readable, {} to remove",
+    },
+    {   .cmd = "writable",
+        .args = "?writable-script?",
+        .minargs = 0,
+        .maxargs = 1,
+        .function = aio_cmd_writable,
+        .description = "Returns script, or invoke writable-script when writable, {} to remove",
+    },
+    {   .cmd = "onexception",
+        .args = "?exception-script?",
+        .minargs = 0,
+        .maxargs = 1,
+        .function = aio_cmd_onexception,
+        .description = "Returns script, or invoke exception-script when oob data, {} to remove",
+    },
+#endif
+    { 0 }
+};
+
+static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return Jim_CallSubCmd(interp, Jim_ParseSubCmd(interp, aio_command_table, argc, argv), argc, argv);
+}
+
+static int JimAioOpenCommand(Jim_Interp *interp, int argc,
+        Jim_Obj *const *argv)
+{
+    FILE *fp;
+    const char *hdlfmt;
+    const char *mode;
+
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "filename ?mode?");
+        return JIM_ERR;
+    }
+
+    mode = (argc == 3) ? Jim_String(argv[2]) : "r";
+    hdlfmt = Jim_String(argv[1]);
+    if (Jim_CompareStringImmediate(interp, argv[1], "stdin")) {
+        fp = stdin;
+    }
+    else if (Jim_CompareStringImmediate(interp, argv[1], "stdout")) {
+        fp = stdout;
+    }
+    else if (Jim_CompareStringImmediate(interp, argv[1], "stderr")) {
+        fp = stderr;
+    }
+    else {
+        const char *filename = Jim_String(argv[1]);
+
+
+#ifdef jim_ext_tclcompat
+        /* If the filename starts with '|', use popen instead */
+        if (*filename == '|') {
+            Jim_Obj *evalObj[3];
+
+            evalObj[0] = Jim_NewStringObj(interp, "popen", -1);
+            evalObj[1] = Jim_NewStringObj(interp, filename + 1, -1);
+            evalObj[2] = Jim_NewStringObj(interp, mode, -1);
+
+            return Jim_EvalObjVector(interp, 3, evalObj);
+        }
+#endif
+        hdlfmt = "aio.handle%ld";
+        fp = NULL;
+    }
+
+    /* Create the file command */
+    return JimMakeChannel(interp, fp, -1, argv[1], hdlfmt, 0, mode);
+}
+
+/**
+ * Creates a channel for fh/fd/filename.
+ *
+ * If fh is not NULL, uses that as the channel (and set AIO_KEEPOPEN).
+ * Otherwise, if fd is >= 0, uses that as the chanel.
+ * Otherwise opens 'filename' with mode 'mode'.
+ *
+ * hdlfmt is a sprintf format for the filehandle. Anything with %ld at the end will do.
+ * mode is used for open or fdopen.
+ *
+ * Creates the command and sets the name as the current result.
+ */
+static int JimMakeChannel(Jim_Interp *interp, FILE *fh, int fd, Jim_Obj *filename,
+    const char *hdlfmt, int family, const char *mode)
+{
+    AioFile *af;
+    char buf[AIO_CMD_LEN];
+    int OpenFlags = 0;
+
+    Jim_IncrRefCount(filename);
+
+    if (fh == NULL) {
+        if (fd < 0) {
+            fh = fopen(Jim_String(filename), mode);
+        }
+        else {
+            fh = fdopen(fd, mode);
+        }
+    }
+    else {
+        OpenFlags = AIO_KEEPOPEN;
+    }
+
+    if (fh == NULL) {
+        JimAioSetError(interp, filename);
+        close(fd);
+        Jim_DecrRefCount(interp, filename);
+        return JIM_ERR;
+    }
+
+    /* Create the file command */
+    af = Jim_Alloc(sizeof(*af));
+    memset(af, 0, sizeof(*af));
+    af->fp = fh;
+    af->fd = fileno(fh);
+    af->filename = filename;
+#ifdef FD_CLOEXEC
+    if ((OpenFlags & AIO_KEEPOPEN) == 0) {
+        fcntl(af->fd, F_SETFD, FD_CLOEXEC);
+        af->OpenFlags = OpenFlags;
+    }
+#endif
+#ifdef O_NDELAY
+    af->flags = fcntl(af->fd, F_GETFL);
+#endif
+    af->addr_family = family;
+    snprintf(buf, sizeof(buf), hdlfmt, Jim_GetId(interp));
+    Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc);
+
+    Jim_SetResultString(interp, buf, -1);
+
+    return JIM_OK;
+}
+
+#if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP)
+
+static int JimAioSockCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *hdlfmt = "aio.unknown%ld";
+    const char *socktypes[] = {
+        "unix",
+        "unix.server",
+        "dgram",
+        "dgram.server",
+        "stream",
+        "stream.server",
+        "pipe",
+        NULL
+    };
+    enum
+    {
+        SOCK_UNIX,
+        SOCK_UNIX_SERVER,
+        SOCK_DGRAM_CLIENT,
+        SOCK_DGRAM_SERVER,
+        SOCK_STREAM_CLIENT,
+        SOCK_STREAM_SERVER,
+        SOCK_STREAM_PIPE,
+        SOCK_DGRAM6_CLIENT,
+        SOCK_DGRAM6_SERVER,
+        SOCK_STREAM6_CLIENT,
+        SOCK_STREAM6_SERVER,
+    };
+    int socktype;
+    int sock;
+    const char *hostportarg = NULL;
+    int res;
+    int on = 1;
+    const char *mode = "r+";
+    int family = PF_INET;
+    Jim_Obj *argv0 = argv[0];
+    int ipv6 = 0;
+
+    if (argc > 1 && Jim_CompareStringImmediate(interp, argv[1], "-ipv6")) {
+        if (!IPV6) {
+            Jim_SetResultString(interp, "ipv6 not supported", -1);
+            return JIM_ERR;
+        }
+        ipv6 = 1;
+        family = PF_INET6;
+    }
+    argc -= ipv6;
+    argv += ipv6;
+
+    if (argc < 2) {
+      wrongargs:
+        Jim_WrongNumArgs(interp, 1, &argv0, "?-ipv6? type ?address?");
+        return JIM_ERR;
+    }
+
+    if (Jim_GetEnum(interp, argv[1], socktypes, &socktype, "socket type", JIM_ERRMSG) != JIM_OK)
+        return JIM_ERR;
+
+    Jim_SetEmptyResult(interp);
+
+    hdlfmt = "aio.sock%ld";
+
+    if (argc > 2) {
+        hostportarg = Jim_String(argv[2]);
+    }
+
+    switch (socktype) {
+        case SOCK_DGRAM_CLIENT:
+            if (argc == 2) {
+                /* No address, so an unconnected dgram socket */
+                sock = socket(family, SOCK_DGRAM, 0);
+                if (sock < 0) {
+                    JimAioSetError(interp, NULL);
+                    return JIM_ERR;
+                }
+                break;
+            }
+            /* fall through */
+        case SOCK_STREAM_CLIENT:
+            {
+                union sockaddr_any sa;
+                int salen;
+
+                if (argc != 3) {
+                    goto wrongargs;
+                }
+
+                if (ipv6) {
+                    if (JimParseIPv6Address(interp, hostportarg, &sa, &salen) != JIM_OK) {
+                        return JIM_ERR;
+                    }
+                }
+                else if (JimParseIpAddress(interp, hostportarg, &sa, &salen) != JIM_OK) {
+                    return JIM_ERR;
+                }
+                sock = socket(family, (socktype == SOCK_DGRAM_CLIENT) ? SOCK_DGRAM : SOCK_STREAM, 0);
+                if (sock < 0) {
+                    JimAioSetError(interp, NULL);
+                    return JIM_ERR;
+                }
+                res = connect(sock, &sa.sa, salen);
+                if (res) {
+                    JimAioSetError(interp, argv[2]);
+                    close(sock);
+                    return JIM_ERR;
+                }
+            }
+            break;
+
+        case SOCK_STREAM_SERVER:
+        case SOCK_DGRAM_SERVER:
+            {
+                union sockaddr_any sa;
+                int salen;
+
+                if (argc != 3) {
+                    goto wrongargs;
+                }
+
+                if (ipv6) {
+                    if (JimParseIPv6Address(interp, hostportarg, &sa, &salen) != JIM_OK) {
+                        return JIM_ERR;
+                    }
+                }
+                else if (JimParseIpAddress(interp, hostportarg, &sa, &salen) != JIM_OK) {
+                    return JIM_ERR;
+                }
+                sock = socket(family, (socktype == SOCK_DGRAM_SERVER) ? SOCK_DGRAM : SOCK_STREAM, 0);
+                if (sock < 0) {
+                    JimAioSetError(interp, NULL);
+                    return JIM_ERR;
+                }
+
+                /* Enable address reuse */
+                setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
+
+                res = bind(sock, &sa.sa, salen);
+                if (res) {
+                    JimAioSetError(interp, argv[2]);
+                    close(sock);
+                    return JIM_ERR;
+                }
+                if (socktype == SOCK_STREAM_SERVER) {
+                    res = listen(sock, 5);
+                    if (res) {
+                        JimAioSetError(interp, NULL);
+                        close(sock);
+                        return JIM_ERR;
+                    }
+                }
+                hdlfmt = "aio.socksrv%ld";
+            }
+            break;
+
+#ifdef HAVE_SYS_UN_H
+        case SOCK_UNIX:
+            {
+                struct sockaddr_un sa;
+                socklen_t len;
+
+                if (argc != 3 || ipv6) {
+                    goto wrongargs;
+                }
+
+                if (JimParseDomainAddress(interp, hostportarg, &sa) != JIM_OK) {
+                    JimAioSetError(interp, argv[2]);
+                    return JIM_ERR;
+                }
+                family = PF_UNIX;
+                sock = socket(PF_UNIX, SOCK_STREAM, 0);
+                if (sock < 0) {
+                    JimAioSetError(interp, NULL);
+                    return JIM_ERR;
+                }
+                len = strlen(sa.sun_path) + 1 + sizeof(sa.sun_family);
+                res = connect(sock, (struct sockaddr *)&sa, len);
+                if (res) {
+                    JimAioSetError(interp, argv[2]);
+                    close(sock);
+                    return JIM_ERR;
+                }
+                hdlfmt = "aio.sockunix%ld";
+                break;
+            }
+
+        case SOCK_UNIX_SERVER:
+            {
+                struct sockaddr_un sa;
+                socklen_t len;
+
+                if (argc != 3 || ipv6) {
+                    goto wrongargs;
+                }
+
+                if (JimParseDomainAddress(interp, hostportarg, &sa) != JIM_OK) {
+                    JimAioSetError(interp, argv[2]);
+                    return JIM_ERR;
+                }
+                family = PF_UNIX;
+                sock = socket(PF_UNIX, SOCK_STREAM, 0);
+                if (sock < 0) {
+                    JimAioSetError(interp, NULL);
+                    return JIM_ERR;
+                }
+                len = strlen(sa.sun_path) + 1 + sizeof(sa.sun_family);
+                res = bind(sock, (struct sockaddr *)&sa, len);
+                if (res) {
+                    JimAioSetError(interp, argv[2]);
+                    close(sock);
+                    return JIM_ERR;
+                }
+                res = listen(sock, 5);
+                if (res) {
+                    JimAioSetError(interp, NULL);
+                    close(sock);
+                    return JIM_ERR;
+                }
+                hdlfmt = "aio.sockunixsrv%ld";
+                break;
+            }
+#endif
+
+#ifdef HAVE_PIPE
+        case SOCK_STREAM_PIPE:
+            {
+                int p[2];
+
+                if (argc != 2 || ipv6) {
+                    goto wrongargs;
+                }
+
+                if (pipe(p) < 0) {
+                    JimAioSetError(interp, NULL);
+                    return JIM_ERR;
+                }
+
+                if (JimMakeChannel(interp, NULL, p[0], argv[1], "aio.pipe%ld", 0, "r") == JIM_OK) {
+                    Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
+                    Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
+
+                    if (JimMakeChannel(interp, NULL, p[1], argv[1], "aio.pipe%ld", 0, "w") == JIM_OK) {
+                        Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
+                        Jim_SetResult(interp, objPtr);
+                        return JIM_OK;
+                    }
+                }
+                /* Can only be here if fdopen() failed */
+                close(p[0]);
+                close(p[1]);
+                JimAioSetError(interp, NULL);
+                return JIM_ERR;
+            }
+            break;
+#endif
+        default:
+            Jim_SetResultString(interp, "Unsupported socket type", -1);
+            return JIM_ERR;
+    }
+
+    return JimMakeChannel(interp, NULL, sock, argv[1], hdlfmt, family, mode);
+}
+#endif /* JIM_BOOTSTRAP */
+
+FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command)
+{
+    Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG);
+
+    if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) {
+        return ((AioFile *) cmdPtr->u.native.privData)->fp;
+    }
+    Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command);
+    return NULL;
+}
+
+int Jim_aioInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "aio", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    Jim_CreateCommand(interp, "open", JimAioOpenCommand, NULL, NULL);
+#ifndef JIM_ANSIC
+    Jim_CreateCommand(interp, "socket", JimAioSockCommand, NULL, NULL);
+#endif
+
+    /* Takeover stdin, stdout and stderr */
+    Jim_EvalGlobal(interp, "open stdin; open stdout; open stderr");
+
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-array.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-array.c
new file mode 100755
index 0000000..89a86f0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-array.c
@@ -0,0 +1,274 @@
+
+/*
+ * Implements the array command for jim
+ *
+ * (c) 2008 Steve Bennett <steveb@workware.net.au>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ *
+ * Based on code originally from Tcl 6.7:
+ *
+ * Copyright 1987-1991 Regents of the University of California
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies.  The University of California
+ * makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "jim-subcmd.h"
+
+static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    /* Just a regular [info exists] */
+    Jim_SetResultInt(interp, Jim_GetVariable(interp, argv[0], 0) != 0);
+    return JIM_OK;
+}
+
+static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int i;
+    int len;
+    int all = 0;
+    Jim_Obj *resultObj;
+    Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+    Jim_Obj *dictObj;
+    Jim_Obj **dictValuesObj;
+
+    if (!objPtr) {
+        return JIM_OK;
+    }
+
+    if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
+        all = 1;
+    }
+
+    /* If it is a dictionary or list with an even number of elements, nothing else to do */
+    if (all) {
+        if (Jim_IsDict(objPtr) || (Jim_IsList(objPtr) && Jim_ListLength(interp, objPtr) % 2 == 0)) {
+            Jim_SetResult(interp, objPtr);
+            return JIM_OK;
+        }
+    }
+
+    if (Jim_DictKeysVector(interp, objPtr, NULL, 0, &dictObj, JIM_ERRMSG) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    if (Jim_DictPairs(interp, dictObj, &dictValuesObj, &len) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    if (all) {
+        /* Return the whole array */
+        Jim_SetResult(interp, dictObj);
+    }
+    else {
+        /* Only return the matching values */
+        resultObj = Jim_NewListObj(interp, NULL, 0);
+
+        for (i = 0; i < len; i += 2) {
+            if (Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) {
+                Jim_ListAppendElement(interp, resultObj, dictValuesObj[i]);
+                Jim_ListAppendElement(interp, resultObj, dictValuesObj[i + 1]);
+            }
+        }
+
+        Jim_SetResult(interp, resultObj);
+    }
+    Jim_Free(dictValuesObj);
+    return JIM_OK;
+
+}
+
+static int array_cmd_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+
+    if (!objPtr) {
+        return JIM_OK;
+    }
+
+    return Jim_DictKeys(interp, objPtr, argc == 1 ? NULL : argv[1]);
+}
+
+static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int i;
+    int len;
+    Jim_Obj *resultObj;
+    Jim_Obj *objPtr;
+    Jim_Obj *dictObj;
+    Jim_Obj **dictValuesObj;
+
+    if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
+        /* Unset the whole array */
+        Jim_UnsetVariable(interp, argv[0], JIM_NONE);
+        return JIM_OK;
+    }
+
+    objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+
+    if (Jim_DictKeysVector(interp, objPtr, NULL, 0, &dictObj, JIM_ERRMSG) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    if (Jim_DictPairs(interp, dictObj, &dictValuesObj, &len) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    /* Create a new object with the values which don't match */
+    resultObj = Jim_NewDictObj(interp, NULL, 0);
+
+    for (i = 0; i < len; i += 2) {
+        if (!Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) {
+            Jim_DictAddElement(interp, resultObj, dictValuesObj[i], dictValuesObj[i + 1]);
+        }
+    }
+    Jim_Free(dictValuesObj);
+
+    Jim_SetVariable(interp, argv[0], resultObj);
+    return JIM_OK;
+}
+
+static int array_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr;
+    int len = 0;
+
+    /* Not found means zero length */
+    objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+    if (objPtr) {
+        len = Jim_DictSize(interp, objPtr);
+        if (len < 0) {
+            return JIM_ERR;
+        }
+    }
+
+    Jim_SetResultInt(interp, len);
+
+    return JIM_OK;
+}
+
+static int array_cmd_set(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int i;
+    int len;
+    int rc = JIM_OK;
+    Jim_Obj *listObj = argv[1];
+
+    if (Jim_GetVariable(interp, argv[0], JIM_NONE) == NULL) {
+        /* Doesn't exist, so just set the list directly */
+        return Jim_SetVariable(interp, argv[0], listObj);
+    }
+
+    len = Jim_ListLength(interp, listObj);
+    if (len % 2) {
+        Jim_SetResultString(interp, "list must have an even number of elements", -1);
+        return JIM_ERR;
+    }
+    for (i = 0; i < len && rc == JIM_OK; i += 2) {
+        Jim_Obj *nameObj;
+        Jim_Obj *valueObj;
+
+        Jim_ListIndex(interp, listObj, i, &nameObj, JIM_NONE);
+        Jim_ListIndex(interp, listObj, i + 1, &valueObj, JIM_NONE);
+
+        rc = Jim_SetDictKeysVector(interp, argv[0], &nameObj, 1, valueObj, JIM_ERRMSG);
+    }
+
+    return rc;
+}
+
+static const jim_subcmd_type array_command_table[] = {
+        {       .cmd = "exists",
+                .args = "arrayName",
+                .function = array_cmd_exists,
+                .minargs = 1,
+                .maxargs = 1,
+                .description = "Does array exist?"
+        },
+        {       .cmd = "get",
+                .args = "arrayName ?pattern?",
+                .function = array_cmd_get,
+                .minargs = 1,
+                .maxargs = 2,
+                .description = "Array contents as name value list"
+        },
+        {       .cmd = "names",
+                .args = "arrayName ?pattern?",
+                .function = array_cmd_names,
+                .minargs = 1,
+                .maxargs = 2,
+                .description = "Array keys as a list"
+        },
+        {       .cmd = "set",
+                .args = "arrayName list",
+                .function = array_cmd_set,
+                .minargs = 2,
+                .maxargs = 2,
+                .description = "Set array from list"
+        },
+        {       .cmd = "size",
+                .args = "arrayName",
+                .function = array_cmd_size,
+                .minargs = 1,
+                .maxargs = 1,
+                .description = "Number of elements in array"
+        },
+        {       .cmd = "unset",
+                .args = "arrayName ?pattern?",
+                .function = array_cmd_unset,
+                .minargs = 1,
+                .maxargs = 2,
+                .description = "Unset elements of an array"
+        },
+        {       .cmd = 0,
+        }
+};
+
+int Jim_arrayInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "array", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    Jim_CreateCommand(interp, "array", Jim_SubCmdProc, (void *)array_command_table, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-clock.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-clock.c
new file mode 100755
index 0000000..51ffb51
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-clock.c
@@ -0,0 +1,159 @@
+
+/*
+ * tcl_clock.c
+ *
+ * Implements the clock command
+ */
+
+/* For strptime() */
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 500
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "jim-subcmd.h"
+
+static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    /* How big is big enough? */
+    char buf[100];
+    time_t t;
+    long seconds;
+
+    const char *format = "%a %b  %d %H:%M:%S %Z %Y";
+
+    if (argc == 2 || (argc == 3 && !Jim_CompareStringImmediate(interp, argv[1], "-format"))) {
+        return -1;
+    }
+
+    if (argc == 3) {
+        format = Jim_String(argv[2]);
+    }
+
+    if (Jim_GetLong(interp, argv[0], &seconds) != JIM_OK) {
+        return JIM_ERR;
+    }
+    t = seconds;
+
+    strftime(buf, sizeof(buf), format, localtime(&t));
+
+    Jim_SetResultString(interp, buf, -1);
+
+    return JIM_OK;
+}
+
+#ifdef HAVE_STRPTIME
+static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    char *pt;
+    struct tm tm;
+    time_t now = time(0);
+
+    if (!Jim_CompareStringImmediate(interp, argv[1], "-format")) {
+        return -1;
+    }
+
+    /* Initialise with the current date/time */
+    localtime_r(&now, &tm);
+
+    pt = strptime(Jim_String(argv[0]), Jim_String(argv[2]), &tm);
+    if (pt == 0 || *pt != 0) {
+        Jim_SetResultString(interp, "Failed to parse time according to format", -1);
+        return JIM_ERR;
+    }
+
+    /* Now convert into a time_t */
+    Jim_SetResultInt(interp, mktime(&tm));
+
+    return JIM_OK;
+}
+#endif
+
+static int clock_cmd_seconds(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_SetResultInt(interp, time(NULL));
+
+    return JIM_OK;
+}
+
+static int clock_cmd_micros(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, NULL);
+
+    Jim_SetResultInt(interp, (jim_wide) tv.tv_sec * 1000000 + tv.tv_usec);
+
+    return JIM_OK;
+}
+
+static int clock_cmd_millis(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, NULL);
+
+    Jim_SetResultInt(interp, (jim_wide) tv.tv_sec * 1000 + tv.tv_usec / 1000);
+
+    return JIM_OK;
+}
+
+static const jim_subcmd_type clock_command_table[] = {
+    {   .cmd = "seconds",
+        .function = clock_cmd_seconds,
+        .minargs = 0,
+        .maxargs = 0,
+        .description = "Returns the current time as seconds since the epoch"
+    },
+    {   .cmd = "clicks",
+        .function = clock_cmd_micros,
+        .minargs = 0,
+        .maxargs = 0,
+        .description = "Returns the current time in 'clicks'"
+    },
+    {   .cmd = "microseconds",
+        .function = clock_cmd_micros,
+        .minargs = 0,
+        .maxargs = 0,
+        .description = "Returns the current time in microseconds"
+    },
+    {   .cmd = "milliseconds",
+        .function = clock_cmd_millis,
+        .minargs = 0,
+        .maxargs = 0,
+        .description = "Returns the current time in milliseconds"
+    },
+    {   .cmd = "format",
+        .args = "seconds ?-format format?",
+        .function = clock_cmd_format,
+        .minargs = 1,
+        .maxargs = 3,
+        .description = "Format the given time"
+    },
+#ifdef HAVE_STRPTIME
+    {   .cmd = "scan",
+        .args = "str -format format",
+        .function = clock_cmd_scan,
+        .minargs = 3,
+        .maxargs = 3,
+        .description = "Determine the time according to the given format"
+    },
+#endif
+    { 0 }
+};
+
+int Jim_clockInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "clock", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    Jim_CreateCommand(interp, "clock", Jim_SubCmdProc, (void *)clock_command_table, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-config.h.in b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-config.h.in
new file mode 100755
index 0000000..2394bc5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-config.h.in
@@ -0,0 +1,2 @@
+/* Public autoconf settings */
+@DEFINE_HAVE_LONG_LONG@
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-eventloop.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-eventloop.c
new file mode 100755
index 0000000..a7efdc2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-eventloop.c
@@ -0,0 +1,760 @@
+
+/* Jim - A small embeddable Tcl interpreter
+ *
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
+ * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
+ * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
+ * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
+ * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
+ * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ **/
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "jim-eventloop.h"
+
+/* POSIX includes */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#if defined(__MINGW32__)
+#include <windows.h>
+#include <winsock.h>
+#define msleep Sleep
+#ifndef HAVE_USLEEP
+#define usleep(US) msleep((US) / 1000)
+#endif
+#else
+#include <sys/select.h>
+
+#ifndef HAVE_USLEEP
+/* XXX: Implement this in terms of select() or nanosleep() */
+#define usleep(US)
+#endif
+#define msleep(MS) sleep((MS) / 1000); usleep(((MS) % 1000) * 1000);
+#endif
+
+/* --- */
+
+/* File event structure */
+typedef struct Jim_FileEvent
+{
+    FILE *handle;
+    int mask;                   /* one of JIM_EVENT_(READABLE|WRITABLE|EXCEPTION) */
+    Jim_FileProc *fileProc;
+    Jim_EventFinalizerProc *finalizerProc;
+    void *clientData;
+    struct Jim_FileEvent *next;
+} Jim_FileEvent;
+
+/* Time event structure */
+typedef struct Jim_TimeEvent
+{
+    jim_wide id;                /* time event identifier. */
+    int mode;                   /* restart, repetitive .. UK */
+    long initialms;             /* initial relativ timer value UK */
+    long when_sec;              /* seconds */
+    long when_ms;               /* milliseconds */
+    Jim_TimeProc *timeProc;
+    Jim_EventFinalizerProc *finalizerProc;
+    void *clientData;
+    struct Jim_TimeEvent *next;
+} Jim_TimeEvent;
+
+/* Per-interp stucture containing the state of the event loop */
+typedef struct Jim_EventLoop
+{
+    jim_wide timeEventNextId;
+    Jim_FileEvent *fileEventHead;
+    Jim_TimeEvent *timeEventHead;
+    int suppress_bgerror; /* bgerror returned break, so don't call it again */
+} Jim_EventLoop;
+
+static void JimAfterTimeHandler(Jim_Interp *interp, void *clientData);
+static void JimAfterTimeEventFinalizer(Jim_Interp *interp, void *clientData);
+
+int Jim_EvalObjBackground(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
+{
+    Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop");
+    Jim_CallFrame *savedFramePtr;
+    int retval;
+
+    savedFramePtr = interp->framePtr;
+    interp->framePtr = interp->topFramePtr;
+    retval = Jim_EvalObj(interp, scriptObjPtr);
+    interp->framePtr = savedFramePtr;
+    /* Try to report the error (if any) via the bgerror proc */
+    if (retval != JIM_OK && !eventLoop->suppress_bgerror) {
+        Jim_Obj *objv[2];
+        int rc = JIM_ERR;
+
+        objv[0] = Jim_NewStringObj(interp, "bgerror", -1);
+        objv[1] = Jim_GetResult(interp);
+        Jim_IncrRefCount(objv[0]);
+        Jim_IncrRefCount(objv[1]);
+        if (Jim_GetCommand(interp, objv[0], JIM_NONE) == NULL || (rc = Jim_EvalObjVector(interp, 2, objv)) != JIM_OK) {
+            if (rc == JIM_BREAK) {
+                /* No more bgerror calls */
+                eventLoop->suppress_bgerror++;
+            }
+            else {
+                /* Report the error to stderr. */
+                Jim_MakeErrorMessage(interp);
+                fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
+                /* And reset the result */
+                Jim_SetResultString(interp, "", -1);
+            }
+        }
+        Jim_DecrRefCount(interp, objv[0]);
+        Jim_DecrRefCount(interp, objv[1]);
+    }
+    return retval;
+}
+
+
+void Jim_CreateFileHandler(Jim_Interp *interp, FILE * handle, int mask,
+    Jim_FileProc * proc, void *clientData, Jim_EventFinalizerProc * finalizerProc)
+{
+    Jim_FileEvent *fe;
+    Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop");
+
+    fe = Jim_Alloc(sizeof(*fe));
+    fe->handle = handle;
+    fe->mask = mask;
+    fe->fileProc = proc;
+    fe->finalizerProc = finalizerProc;
+    fe->clientData = clientData;
+    fe->next = eventLoop->fileEventHead;
+    eventLoop->fileEventHead = fe;
+}
+
+void Jim_DeleteFileHandler(Jim_Interp *interp, FILE * handle)
+{
+    Jim_FileEvent *fe, *prev = NULL;
+    Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop");
+
+    fe = eventLoop->fileEventHead;
+    while (fe) {
+        if (fe->handle == handle) {
+            if (prev == NULL)
+                eventLoop->fileEventHead = fe->next;
+            else
+                prev->next = fe->next;
+            if (fe->finalizerProc)
+                fe->finalizerProc(interp, fe->clientData);
+            Jim_Free(fe);
+            return;
+        }
+        prev = fe;
+        fe = fe->next;
+    }
+}
+
+static void JimGetTime(long *seconds, long *milliseconds)
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, NULL);
+    *seconds = tv.tv_sec;
+    *milliseconds = tv.tv_usec / 1000;
+}
+
+jim_wide Jim_CreateTimeHandler(Jim_Interp *interp, jim_wide milliseconds,
+    Jim_TimeProc * proc, void *clientData, Jim_EventFinalizerProc * finalizerProc)
+{
+    Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop");
+    jim_wide id = eventLoop->timeEventNextId++;
+    Jim_TimeEvent *te, *e, *prev;
+    long cur_sec, cur_ms;
+
+    JimGetTime(&cur_sec, &cur_ms);
+
+    te = Jim_Alloc(sizeof(*te));
+    te->id = id;
+    te->mode = 0;
+    te->initialms = milliseconds;
+    te->when_sec = cur_sec + milliseconds / 1000;
+    te->when_ms = cur_ms + milliseconds % 1000;
+    if (te->when_ms >= 1000) {
+        te->when_sec++;
+        te->when_ms -= 1000;
+    }
+    te->timeProc = proc;
+    te->finalizerProc = finalizerProc;
+    te->clientData = clientData;
+
+    /* Add to the appropriate place in the list */
+    if (eventLoop->timeEventHead) {
+        prev = NULL;
+        for (e = eventLoop->timeEventHead; e; e = e->next) {
+            if (te->when_sec < e->when_sec || (te->when_sec == e->when_sec && te->when_ms < e->when_ms)) {
+                break;
+            }
+            prev = e;
+        }
+        if (prev) {
+            te->next = prev->next;
+            prev->next = te;
+            return id;
+        }
+    }
+
+    te->next = eventLoop->timeEventHead;
+    eventLoop->timeEventHead = te;
+
+    return id;
+}
+
+static jim_wide JimParseAfterId(Jim_Obj *idObj)
+{
+    int len;
+    const char *tok = Jim_GetString(idObj, &len);
+    jim_wide id;
+
+    if (strncmp(tok, "after#", 6) == 0 && Jim_StringToWide(tok + 6, &id, 10) == JIM_OK) {
+        /* Got an event by id */
+        return id;
+    }
+    return -1;
+}
+
+static jim_wide JimFindAfterByScript(Jim_EventLoop *eventLoop, Jim_Obj *scriptObj)
+{
+    Jim_TimeEvent *te;
+
+    for (te = eventLoop->timeEventHead; te; te = te->next) {
+        /* Is this an 'after' event? */
+        if (te->timeProc == JimAfterTimeHandler) {
+            if (Jim_StringEqObj(scriptObj, te->clientData)) {
+                return te->id;
+            }
+        }
+    }
+    return -1;                  /* NO event with the specified ID found */
+}
+
+static Jim_TimeEvent *JimFindTimeHandlerById(Jim_EventLoop *eventLoop, jim_wide id)
+{
+    Jim_TimeEvent *te;
+
+    for (te = eventLoop->timeEventHead; te; te = te->next) {
+        if (te->id == id) {
+            return te;
+        }
+    }
+    return NULL;
+}
+
+static Jim_TimeEvent *Jim_RemoveTimeHandler(Jim_EventLoop *eventLoop, jim_wide id)
+{
+    Jim_TimeEvent *te, *prev = NULL;
+
+    for (te = eventLoop->timeEventHead; te; te = te->next) {
+        if (te->id == id) {
+            if (prev == NULL)
+                eventLoop->timeEventHead = te->next;
+            else
+                prev->next = te->next;
+            return te;
+        }
+        prev = te;
+    }
+    return NULL;
+}
+
+static void Jim_FreeTimeHandler(Jim_Interp *interp, Jim_TimeEvent *te)
+{
+    if (te->finalizerProc)
+        te->finalizerProc(interp, te->clientData);
+    Jim_Free(te);
+}
+
+jim_wide Jim_DeleteTimeHandler(Jim_Interp *interp, jim_wide id)
+{
+    Jim_TimeEvent *te;
+    Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop");
+
+    if (id >= eventLoop->timeEventNextId) {
+        return -2;              /* wrong event ID */
+    }
+
+    te = Jim_RemoveTimeHandler(eventLoop, id);
+    if (te) {
+        jim_wide remain;
+        long cur_sec, cur_ms;
+
+        JimGetTime(&cur_sec, &cur_ms);
+
+        remain = (te->when_sec - cur_sec) * 1000;
+        remain += (te->when_ms - cur_ms);
+        remain = (remain < 0) ? 0 : remain;
+
+        Jim_FreeTimeHandler(interp, te);
+        return remain;
+    }
+    return -1;                  /* NO event with the specified ID found */
+}
+
+/* --- POSIX version of Jim_ProcessEvents, for now the only available --- */
+
+/* Process every pending time event, then every pending file event
+ * (that may be registered by time event callbacks just processed).
+ * Without special flags the function sleeps until some file event
+ * fires, or when the next time event occurrs (if any).
+ *
+ * If flags is 0, the function does nothing and returns.
+ * if flags has JIM_ALL_EVENTS set, all the kind of events are processed.
+ * if flags has JIM_FILE_EVENTS set, file events are processed.
+ * if flags has JIM_TIME_EVENTS set, time events are processed.
+ * if flags has JIM_DONT_WAIT set the function returns ASAP until all
+ * the events that's possible to process without to wait are processed.
+ *
+ * The function returns the number of events processed or -1 if
+ * there are no matching handlers, or -2 on error.
+ */
+int Jim_ProcessEvents(Jim_Interp *interp, int flags)
+{
+    jim_wide sleep_ms = -1;
+    int processed = 0;
+    Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop");
+    Jim_FileEvent *fe = eventLoop->fileEventHead;
+    Jim_TimeEvent *te;
+    jim_wide maxId;
+
+    if ((flags & JIM_FILE_EVENTS) == 0 || fe == NULL) {
+        /* No file events */
+        if ((flags & JIM_TIME_EVENTS) == 0 || eventLoop->timeEventHead == NULL) {
+            /* No time events */
+            return -1;
+        }
+    }
+
+    /* Note that we want call select() even if there are no
+     * file events to process as long as we want to process time
+     * events, in order to sleep until the next time event is ready
+     * to fire. */
+
+    if (flags & JIM_DONT_WAIT) {
+        /* Wait no time */
+        sleep_ms = 0;
+    }
+    else if (flags & JIM_TIME_EVENTS) {
+        /* The nearest timer is always at the head of the list */
+        if (eventLoop->timeEventHead) {
+            Jim_TimeEvent *shortest = eventLoop->timeEventHead;
+            long now_sec, now_ms;
+
+            /* Calculate the time missing for the nearest
+             * timer to fire. */
+            JimGetTime(&now_sec, &now_ms);
+            sleep_ms = 1000 * (shortest->when_sec - now_sec) + (shortest->when_ms - now_ms);
+            if (sleep_ms < 0) {
+                sleep_ms = 1;
+            }
+        }
+        else {
+            /* Wait forever */
+            sleep_ms = -1;
+        }
+    }
+
+#ifdef HAVE_SELECT
+    if (flags & JIM_FILE_EVENTS) {
+        int retval;
+        struct timeval tv, *tvp = NULL;
+        fd_set rfds, wfds, efds;
+        int maxfd = -1;
+
+        FD_ZERO(&rfds);
+        FD_ZERO(&wfds);
+        FD_ZERO(&efds);
+
+        /* Check file events */
+        while (fe != NULL) {
+            int fd = fileno(fe->handle);
+
+            if (fe->mask & JIM_EVENT_READABLE)
+                FD_SET(fd, &rfds);
+            if (fe->mask & JIM_EVENT_WRITABLE)
+                FD_SET(fd, &wfds);
+            if (fe->mask & JIM_EVENT_EXCEPTION)
+                FD_SET(fd, &efds);
+            if (maxfd < fd)
+                maxfd = fd;
+            fe = fe->next;
+        }
+
+        if (sleep_ms >= 0) {
+            tvp = &tv;
+            tvp->tv_sec = sleep_ms / 1000;
+            tvp->tv_usec = 1000 * (sleep_ms % 1000);
+        }
+
+        retval = select(maxfd + 1, &rfds, &wfds, &efds, tvp);
+
+        if (retval < 0) {
+            if (errno == EINVAL) {
+                /* This can happen on mingw32 if a non-socket filehandle is passed */
+                Jim_SetResultString(interp, "non-waitable filehandle", -1);
+                return -2;
+            }
+            /* XXX: What about EINTR? */
+        }
+        else if (retval > 0) {
+            fe = eventLoop->fileEventHead;
+            while (fe != NULL) {
+                int fd = fileno(fe->handle);
+                int mask = 0;
+
+                if ((fe->mask & JIM_EVENT_READABLE) && FD_ISSET(fd, &rfds))
+                    mask |= JIM_EVENT_READABLE;
+                if (fe->mask & JIM_EVENT_WRITABLE && FD_ISSET(fd, &wfds))
+                    mask |= JIM_EVENT_WRITABLE;
+                if (fe->mask & JIM_EVENT_EXCEPTION && FD_ISSET(fd, &efds))
+                    mask |= JIM_EVENT_EXCEPTION;
+
+                if (mask) {
+                    if (fe->fileProc(interp, fe->clientData, mask) != JIM_OK) {
+                        /* Remove the element on handler error */
+                        Jim_DeleteFileHandler(interp, fe->handle);
+                    }
+                    processed++;
+                    /* After an event is processed our file event list
+                     * may no longer be the same, so what we do
+                     * is to clear the bit for this file descriptor and
+                     * restart again from the head. */
+                    fe = eventLoop->fileEventHead;
+                    FD_CLR(fd, &rfds);
+                    FD_CLR(fd, &wfds);
+                    FD_CLR(fd, &efds);
+                }
+                else {
+                    fe = fe->next;
+                }
+            }
+        }
+    }
+#else
+    if (sleep_ms > 0) {
+        msleep(sleep_ms);
+    }
+#endif
+
+    /* Check time events */
+    te = eventLoop->timeEventHead;
+    maxId = eventLoop->timeEventNextId - 1;
+    while (te) {
+        long now_sec, now_ms;
+        jim_wide id;
+
+        if (te->id > maxId) {
+            te = te->next;
+            continue;
+        }
+        JimGetTime(&now_sec, &now_ms);
+        if (now_sec > te->when_sec || (now_sec == te->when_sec && now_ms >= te->when_ms)) {
+            id = te->id;
+            /* Remove from the list before executing */
+            Jim_RemoveTimeHandler(eventLoop, id);
+            te->timeProc(interp, te->clientData);
+            /* After an event is processed our time event list may
+             * no longer be the same, so we restart from head.
+             * Still we make sure to don't process events registered
+             * by event handlers itself in order to don't loop forever
+             * even in case an [after 0] that continuously register
+             * itself. To do so we saved the max ID we want to handle. */
+            Jim_FreeTimeHandler(interp, te);
+
+            te = eventLoop->timeEventHead;
+            processed++;
+        }
+        else {
+            te = te->next;
+        }
+    }
+
+    return processed;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void JimELAssocDataDeleProc(Jim_Interp *interp, void *data)
+{
+    void *next;
+    Jim_FileEvent *fe;
+    Jim_TimeEvent *te;
+    Jim_EventLoop *eventLoop = data;
+
+    fe = eventLoop->fileEventHead;
+    while (fe) {
+        next = fe->next;
+        if (fe->finalizerProc)
+            fe->finalizerProc(interp, fe->clientData);
+        Jim_Free(fe);
+        fe = next;
+    }
+
+    te = eventLoop->timeEventHead;
+    while (te) {
+        next = te->next;
+        if (te->finalizerProc)
+            te->finalizerProc(interp, te->clientData);
+        Jim_Free(te);
+        te = next;
+    }
+    Jim_Free(data);
+}
+
+static int JimELVwaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_EventLoop *eventLoop = Jim_CmdPrivData(interp);
+    Jim_Obj *oldValue;
+    int rc;
+
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "name");
+        return JIM_ERR;
+    }
+
+    oldValue = Jim_GetGlobalVariable(interp, argv[1], JIM_NONE);
+    if (oldValue) {
+        Jim_IncrRefCount(oldValue);
+    }
+    else {
+        /* If a result was left, it is an error */
+        int len;
+        Jim_GetString(interp->result, &len);
+        if (len) {
+            return JIM_ERR;
+        }
+    }
+
+    eventLoop->suppress_bgerror = 0;
+
+    while ((rc = Jim_ProcessEvents(interp, JIM_ALL_EVENTS)) >= 0) {
+        Jim_Obj *currValue;
+        currValue = Jim_GetGlobalVariable(interp, argv[1], JIM_NONE);
+        /* Stop the loop if the vwait-ed variable changed value,
+         * or if was unset and now is set (or the contrary). */
+        if ((oldValue && !currValue) ||
+            (!oldValue && currValue) ||
+            (oldValue && currValue && !Jim_StringEqObj(oldValue, currValue)))
+            break;
+    }
+    if (oldValue)
+        Jim_DecrRefCount(interp, oldValue);
+
+
+    if (rc == -2) {
+        return JIM_ERR;
+    }
+
+    Jim_SetEmptyResult(interp);
+    return JIM_OK;
+}
+
+static int JimELUpdateCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_EventLoop *eventLoop = Jim_CmdPrivData(interp);
+    static const char * const options[] = {
+        "idletasks", NULL
+    };
+    enum { UPDATE_IDLE, UPDATE_NONE };
+    int option = UPDATE_NONE;
+    int flags = JIM_TIME_EVENTS;
+
+    if (argc == 1) {
+        flags = JIM_ALL_EVENTS;
+    }
+    else if (argc > 2 || Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+        Jim_WrongNumArgs(interp, 1, argv, "?idletasks?");
+        return JIM_ERR;
+    }
+
+    eventLoop->suppress_bgerror = 0;
+
+    while (Jim_ProcessEvents(interp, flags | JIM_DONT_WAIT) > 0) {
+    }
+
+    return JIM_OK;
+}
+
+static void JimAfterTimeHandler(Jim_Interp *interp, void *clientData)
+{
+    Jim_Obj *objPtr = clientData;
+
+    Jim_EvalObjBackground(interp, objPtr);
+}
+
+static void JimAfterTimeEventFinalizer(Jim_Interp *interp, void *clientData)
+{
+    Jim_Obj *objPtr = clientData;
+
+    Jim_DecrRefCount(interp, objPtr);
+}
+
+static int JimELAfterCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_EventLoop *eventLoop = Jim_CmdPrivData(interp);
+    jim_wide ms = 0, id;
+    Jim_Obj *objPtr, *idObjPtr;
+    static const char * const options[] = {
+        "cancel", "info", "idle", NULL
+    };
+    enum
+    { AFTER_CANCEL, AFTER_INFO, AFTER_IDLE, AFTER_RESTART, AFTER_EXPIRE, AFTER_CREATE };
+    int option = AFTER_CREATE;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "option ?arg ...?");
+        return JIM_ERR;
+    }
+    if (Jim_GetWide(interp, argv[1], &ms) != JIM_OK) {
+        if (Jim_GetEnum(interp, argv[1], options, &option, "argument", JIM_ERRMSG) != JIM_OK) {
+            return JIM_ERR;
+        }
+        Jim_SetEmptyResult(interp);
+    }
+    else if (argc == 2) {
+        /* Simply a sleep */
+        msleep(ms);
+        return JIM_OK;
+    }
+
+    switch (option) {
+        case AFTER_IDLE:
+            if (argc < 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "script ?script ...?");
+                return JIM_ERR;
+            }
+            /* fall through */
+        case AFTER_CREATE: {
+            Jim_Obj *scriptObj = Jim_ConcatObj(interp, argc - 2, argv + 2);
+            Jim_IncrRefCount(scriptObj);
+            id = Jim_CreateTimeHandler(interp, ms, JimAfterTimeHandler, scriptObj,
+                JimAfterTimeEventFinalizer);
+            objPtr = Jim_NewStringObj(interp, NULL, 0);
+            Jim_AppendString(interp, objPtr, "after#", -1);
+            idObjPtr = Jim_NewIntObj(interp, id);
+            Jim_IncrRefCount(idObjPtr);
+            Jim_AppendObj(interp, objPtr, idObjPtr);
+            Jim_DecrRefCount(interp, idObjPtr);
+            Jim_SetResult(interp, objPtr);
+            return JIM_OK;
+        }
+        case AFTER_CANCEL:
+            if (argc < 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "id|command");
+                return JIM_ERR;
+            }
+            else {
+                jim_wide remain = 0;
+
+                id = JimParseAfterId(argv[2]);
+                if (id < 0) {
+                    /* Not an event id, so search by script */
+                    Jim_Obj *scriptObj = Jim_ConcatObj(interp, argc - 2, argv + 2);
+                    id = JimFindAfterByScript(eventLoop, scriptObj);
+                    Jim_FreeNewObj(interp, scriptObj);
+                    if (id < 0) {
+                        /* Not found */
+                        break;
+                    }
+                }
+                remain = Jim_DeleteTimeHandler(interp, id);
+                if (remain >= 0) {
+                    Jim_SetResultInt(interp, remain);
+                }
+            }
+            break;
+
+        case AFTER_INFO:
+            if (argc == 2) {
+                Jim_TimeEvent *te = eventLoop->timeEventHead;
+                Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+                char buf[30];
+                const char *fmt = "after#%" JIM_WIDE_MODIFIER;
+
+                while (te) {
+                    snprintf(buf, sizeof(buf), fmt, te->id);
+                    Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, buf, -1));
+                    te = te->next;
+                }
+                Jim_SetResult(interp, listObj);
+            }
+            else if (argc == 3) {
+                id = JimParseAfterId(argv[2]);
+                if (id >= 0) {
+                    Jim_TimeEvent *e = JimFindTimeHandlerById(eventLoop, id);
+                    if (e && e->timeProc == JimAfterTimeHandler) {
+                        Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+                        Jim_ListAppendElement(interp, listObj, e->clientData);
+                        Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, e->initialms ? "timer" : "idle", -1));
+                        Jim_SetResult(interp, listObj);
+                        return JIM_OK;
+                    }
+                }
+                Jim_SetResultFormatted(interp, "event \"%#s\" doesn't exist", argv[2]);
+                return JIM_ERR;
+            }
+            else {
+                Jim_WrongNumArgs(interp, 2, argv, "?id?");
+                return JIM_ERR;
+            }
+            break;
+    }
+    return JIM_OK;
+}
+
+int Jim_eventloopInit(Jim_Interp *interp)
+{
+    Jim_EventLoop *eventLoop;
+
+    if (Jim_PackageProvide(interp, "eventloop", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    eventLoop = Jim_Alloc(sizeof(*eventLoop));
+    eventLoop->fileEventHead = NULL;
+    eventLoop->timeEventHead = NULL;
+    eventLoop->timeEventNextId = 1;
+    eventLoop->suppress_bgerror = 0;
+    Jim_SetAssocData(interp, "eventloop", JimELAssocDataDeleProc, eventLoop);
+
+    Jim_CreateCommand(interp, "vwait", JimELVwaitCommand, eventLoop, NULL);
+    Jim_CreateCommand(interp, "update", JimELUpdateCommand, eventLoop, NULL);
+    Jim_CreateCommand(interp, "after", JimELAfterCommand, eventLoop, NULL);
+
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-eventloop.h b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-eventloop.h
new file mode 100755
index 0000000..4da5408
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-eventloop.h
@@ -0,0 +1,87 @@
+/* Jim - A small embeddable Tcl interpreter
+ *
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
+ * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
+ * Copyright 2008 oharboe - �yvind Harboe - oyvind.harboe@zylin.com
+ * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
+ * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
+ * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ **/
+/* ------ USAGE -------
+ *
+ * In order to use this file from other extensions include it in every
+ * file where you need to call the eventloop API, also in the init
+ * function of your extension call Jim_ImportEventloopAPI(interp)
+ * after the Jim_InitExtension() call.
+ *
+ * See the UDP extension as example.
+ */
+
+
+#ifndef __JIM_EVENTLOOP_H__
+#define __JIM_EVENTLOOP_H__
+
+#include <stdio.h>
+
+typedef int Jim_FileProc(Jim_Interp *interp, void *clientData, int mask);
+typedef int Jim_SignalProc(Jim_Interp *interp, void *clientData, void *msg);
+typedef void Jim_TimeProc(Jim_Interp *interp, void *clientData);
+typedef void Jim_EventFinalizerProc(Jim_Interp *interp, void *clientData);
+
+/* File event structure */
+#define JIM_EVENT_READABLE 1
+#define JIM_EVENT_WRITABLE 2
+#define JIM_EVENT_EXCEPTION 4
+
+JIM_EXPORT void Jim_CreateFileHandler (Jim_Interp *interp,
+        FILE *handle, int mask,
+        Jim_FileProc *proc, void *clientData,
+        Jim_EventFinalizerProc *finalizerProc);
+JIM_EXPORT void Jim_DeleteFileHandler (Jim_Interp *interp,
+        FILE *handle);
+JIM_EXPORT jim_wide Jim_CreateTimeHandler (Jim_Interp *interp,
+        jim_wide milliseconds,
+        Jim_TimeProc *proc, void *clientData,
+        Jim_EventFinalizerProc *finalizerProc);
+JIM_EXPORT jim_wide Jim_DeleteTimeHandler (Jim_Interp *interp, jim_wide id);
+
+#define JIM_FILE_EVENTS 1
+#define JIM_TIME_EVENTS 2
+#define JIM_ALL_EVENTS (JIM_FILE_EVENTS|JIM_TIME_EVENTS)
+#define JIM_DONT_WAIT 4
+
+JIM_EXPORT int Jim_ProcessEvents (Jim_Interp *interp, int flags);
+JIM_EXPORT int Jim_EvalObjBackground (Jim_Interp *interp, Jim_Obj *scriptObjPtr);
+
+int Jim_eventloopInit(Jim_Interp *interp);
+
+#endif /* __JIM_EVENTLOOP_H__ */
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-exec.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-exec.c
new file mode 100755
index 0000000..9088156
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-exec.c
@@ -0,0 +1,1619 @@
+/*
+ * (c) 2008 Steve Bennett <steveb@workware.net.au>
+ *
+ * Implements the exec command for Jim
+ *
+ * Based on code originally from Tcl 6.7 by John Ousterhout.
+ * From that code:
+ *
+ * The Tcl_Fork and Tcl_WaitPids procedures are based on code
+ * contributed by Karl Lehenbauer, Mark Diekhans and Peter
+ * da Silva.
+ *
+ * Copyright 1987-1991 Regents of the University of California
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies.  The University of California
+ * makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+
+#if (!defined(HAVE_VFORK) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
+/* Poor man's implementation of exec with system()
+ * The system() call *may* do command line redirection, etc.
+ * The standard output is not available.
+ * Can't redirect filehandles.
+ */
+static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp);
+    int i, j;
+    int rc;
+
+    /* Create a quoted command line */
+    for (i = 1; i < argc; i++) {
+        int len;
+        const char *arg = Jim_GetString(argv[i], &len);
+
+        if (i > 1) {
+            Jim_AppendString(interp, cmdlineObj, " ", 1);
+        }
+        if (strpbrk(arg, "\\\" ") == NULL) {
+            /* No quoting required */
+            Jim_AppendString(interp, cmdlineObj, arg, len);
+            continue;
+        }
+
+        Jim_AppendString(interp, cmdlineObj, "\"", 1);
+        for (j = 0; j < len; j++) {
+            if (arg[j] == '\\' || arg[j] == '"') {
+                Jim_AppendString(interp, cmdlineObj, "\\", 1);
+            }
+            Jim_AppendString(interp, cmdlineObj, &arg[j], 1);
+        }
+        Jim_AppendString(interp, cmdlineObj, "\"", 1);
+    }
+    rc = system(Jim_String(cmdlineObj));
+
+    Jim_FreeNewObj(interp, cmdlineObj);
+
+    if (rc) {
+        Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
+        Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, 0));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, rc));
+        Jim_SetGlobalVariableStr(interp, "errorCode", errorCode);
+        return JIM_ERR;
+    }
+
+    return JIM_OK;
+}
+
+int Jim_execInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+    Jim_CreateCommand(interp, "exec", Jim_ExecCmd, NULL, NULL);
+    return JIM_OK;
+}
+#else
+/* Full exec implementation for unix and mingw */
+
+#include <errno.h>
+#include <signal.h>
+
+#define XXX printf("@%s:%d\n", __FILE__, __LINE__); fflush(stdout);
+
+#if defined(__MINGW32__)
+    /* XXX: Should we use this implementation for cygwin too? */
+    #include <fcntl.h>
+
+    typedef HANDLE fdtype;
+    typedef HANDLE pidtype;
+    #define JIM_BAD_FD INVALID_HANDLE_VALUE
+    #define JIM_BAD_PID INVALID_HANDLE_VALUE
+    #define JimCloseFd CloseHandle
+
+    #define WIFEXITED(STATUS) 1
+    #define WEXITSTATUS(STATUS) (STATUS)
+    #define WIFSIGNALED(STATUS) 0
+    #define WTERMSIG(STATUS) 0
+    #define WNOHANG 1
+
+    static fdtype JimFileno(FILE *fh);
+    static pidtype JimWaitPid(pidtype pid, int *status, int nohang);
+    static fdtype JimDupFd(fdtype infd);
+    static fdtype JimOpenForRead(const char *filename);
+    static FILE *JimFdOpenForRead(fdtype fd);
+    static int JimPipe(fdtype pipefd[2]);
+    static pidtype JimStartWinProcess(Jim_Interp *interp, char **argv, char *env,
+        fdtype inputId, fdtype outputId, fdtype errorId);
+    static int JimErrno(void);
+#else
+    #include "jim-signal.h"
+    #include <unistd.h>
+    #include <fcntl.h>
+    #include <sys/wait.h>
+
+    typedef int fdtype;
+    typedef int pidtype;
+    #define JimPipe pipe
+    #define JimErrno() errno
+    #define JIM_BAD_FD -1
+    #define JIM_BAD_PID -1
+    #define JimFileno fileno
+    #define JimReadFd read
+    #define JimCloseFd close
+    #define JimWaitPid waitpid
+    #define JimDupFd dup
+    #define JimFdOpenForRead(FD) fdopen((FD), "r")
+    #define JimOpenForRead(NAME) open((NAME), O_RDONLY, 0)
+#endif
+
+static const char *JimStrError(void);
+static char **JimSaveEnv(char **env);
+static void JimRestoreEnv(char **env);
+static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv,
+    pidtype **pidArrayPtr, fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr);
+static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr);
+static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, fdtype errorId);
+static fdtype JimCreateTemp(Jim_Interp *interp, const char *contents);
+static fdtype JimOpenForWrite(const char *filename, int append);
+static int JimRewindFd(fdtype fd);
+
+static void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
+{
+    Jim_SetResultFormatted(interp, "%s: %s", msg, JimStrError());
+}
+
+static const char *JimStrError(void)
+{
+    return strerror(JimErrno());
+}
+
+static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr)
+{
+    int len;
+    const char *s = Jim_GetString(objPtr, &len);
+
+    if (len > 0 && s[len - 1] == '\n') {
+        objPtr->length--;
+        objPtr->bytes[objPtr->length] = '\0';
+    }
+}
+
+/**
+ * Read from 'fd', append the data to strObj and close 'fd'.
+ * Returns JIM_OK if OK, or JIM_ERR on error.
+ */
+static int JimAppendStreamToString(Jim_Interp *interp, fdtype fd, Jim_Obj *strObj)
+{
+    char buf[256];
+    FILE *fh = JimFdOpenForRead(fd);
+    if (fh == NULL) {
+        return JIM_ERR;
+    }
+
+    while (1) {
+        int retval = fread(buf, 1, sizeof(buf), fh);
+        if (retval > 0) {
+            Jim_AppendString(interp, strObj, buf, retval);
+        }
+        if (retval != sizeof(buf)) {
+            break;
+        }
+    }
+    Jim_RemoveTrailingNewline(strObj);
+    fclose(fh);
+    return JIM_OK;
+}
+
+/*
+ * If the last character of the result is a newline, then remove
+ * the newline character (the newline would just confuse things).
+ *
+ * Note: Ideally we could do this by just reducing the length of stringrep
+ *       by 1, but there is no API for this :-(
+ */
+static void JimTrimTrailingNewline(Jim_Interp *interp)
+{
+    int len;
+    const char *p = Jim_GetString(Jim_GetResult(interp), &len);
+
+    if (len > 0 && p[len - 1] == '\n') {
+        Jim_SetResultString(interp, p, len - 1);
+    }
+}
+
+/**
+ * Builds the environment array from $::env
+ *
+ * If $::env is not set, simply returns environ.
+ *
+ * Otherwise allocates the environ array from the contents of $::env
+ *
+ * If the exec fails, memory can be freed via JimFreeEnv()
+ */
+static char **JimBuildEnv(Jim_Interp *interp)
+{
+#if defined(jim_ext_tclcompat)
+    int i;
+    int size;
+    int num;
+    int n;
+    char **envptr;
+    char *envdata;
+
+    Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, "env", JIM_NONE);
+
+    if (!objPtr) {
+        return Jim_GetEnviron();
+    }
+
+    /* We build the array as a single block consisting of the pointers followed by
+     * the strings. This has the advantage of being easy to allocate/free and being
+     * compatible with both unix and windows
+     */
+
+    /* Calculate the required size */
+    num = Jim_ListLength(interp, objPtr);
+    if (num % 2) {
+        num--;
+    }
+    size = Jim_Length(objPtr);
+    /* We need one \0 and one equal sign for each element.
+     * A list has at least one space for each element except the first.
+     * We only need one extra char for the extra null terminator.
+     */
+    size++;
+
+    envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size);
+    envdata = (char *)&envptr[num / 2 + 1];
+
+    n = 0;
+    for (i = 0; i < num; i += 2) {
+        const char *s1, *s2;
+        Jim_Obj *elemObj;
+
+        Jim_ListIndex(interp, objPtr, i, &elemObj, JIM_NONE);
+        s1 = Jim_String(elemObj);
+        Jim_ListIndex(interp, objPtr, i + 1, &elemObj, JIM_NONE);
+        s2 = Jim_String(elemObj);
+
+        envptr[n] = envdata;
+        envdata += sprintf(envdata, "%s=%s", s1, s2);
+        envdata++;
+        n++;
+    }
+    envptr[n] = NULL;
+    *envdata = 0;
+
+    return envptr;
+#else
+    return Jim_GetEnviron();
+#endif
+}
+
+/**
+ * Frees the environment allocated by JimBuildEnv()
+ *
+ * Must pass original_environ.
+ */
+static void JimFreeEnv(char **env, char **original_environ)
+{
+#ifdef jim_ext_tclcompat
+    if (env != original_environ) {
+        Jim_Free(env);
+    }
+#endif
+}
+
+/*
+ * Create error messages for unusual process exits.  An
+ * extra newline gets appended to each error message, but
+ * it gets removed below (in the same fashion that an
+ * extra newline in the command's output is removed).
+ */
+static int JimCheckWaitStatus(Jim_Interp *interp, pidtype pid, int waitStatus)
+{
+    Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
+    int rc = JIM_ERR;
+
+    if (WIFEXITED(waitStatus)) {
+        if (WEXITSTATUS(waitStatus) == 0) {
+            Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "NONE", -1));
+            rc = JIM_OK;
+        }
+        else {
+            Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
+            Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
+            Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WEXITSTATUS(waitStatus)));
+        }
+    }
+    else {
+        const char *type;
+        const char *action;
+
+        if (WIFSIGNALED(waitStatus)) {
+            type = "CHILDKILLED";
+            action = "killed";
+        }
+        else {
+            type = "CHILDSUSP";
+            action = "suspended";
+        }
+
+        Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, type, -1));
+
+#ifdef jim_ext_signal
+        Jim_SetResultFormatted(interp, "child %s by signal %s", action, Jim_SignalId(WTERMSIG(waitStatus)));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, Jim_SignalId(WTERMSIG(waitStatus)), -1));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, Jim_SignalName(WTERMSIG(waitStatus)), -1));
+#else
+        Jim_SetResultFormatted(interp, "child %s by signal %d", action, WTERMSIG(waitStatus));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WTERMSIG(waitStatus)));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WTERMSIG(waitStatus)));
+#endif
+    }
+    Jim_SetGlobalVariableStr(interp, "errorCode", errorCode);
+    return rc;
+}
+
+/*
+ * Data structures of the following type are used by JimFork and
+ * JimWaitPids to keep track of child processes.
+ */
+
+struct WaitInfo
+{
+    pidtype pid;                    /* Process id of child. */
+    int status;                 /* Status returned when child exited or suspended. */
+    int flags;                  /* Various flag bits;  see below for definitions. */
+};
+
+struct WaitInfoTable {
+    struct WaitInfo *info;
+    int size;
+    int used;
+};
+
+/*
+ * Flag bits in WaitInfo structures:
+ *
+ * WI_DETACHED -        Non-zero means no-one cares about the
+ *                      process anymore.  Ignore it until it
+ *                      exits, then forget about it.
+ */
+
+#define WI_DETACHED 2
+
+#define WAIT_TABLE_GROW_BY 4
+
+static void JimFreeWaitInfoTable(struct Jim_Interp *interp, void *privData)
+{
+    struct WaitInfoTable *table = privData;
+
+    Jim_Free(table->info);
+    Jim_Free(table);
+}
+
+static struct WaitInfoTable *JimAllocWaitInfoTable(void)
+{
+    struct WaitInfoTable *table = Jim_Alloc(sizeof(*table));
+    table->info = NULL;
+    table->size = table->used = 0;
+
+    return table;
+}
+
+/*
+ * The main [exec] command
+ */
+static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    fdtype outputId;               /* File id for output pipe.  -1
+                                 * means command overrode. */
+    fdtype errorId;                /* File id for temporary file
+                                 * containing error output. */
+    pidtype *pidPtr;
+    int numPids, result;
+
+    /*
+     * See if the command is to be run in background;  if so, create
+     * the command, detach it, and return.
+     */
+    if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) {
+        Jim_Obj *listObj;
+        int i;
+
+        argc--;
+        numPids = JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, NULL, NULL);
+        if (numPids < 0) {
+            return JIM_ERR;
+        }
+        /* The return value is a list of the pids */
+        listObj = Jim_NewListObj(interp, NULL, 0);
+        for (i = 0; i < numPids; i++) {
+            Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, (long)pidPtr[i]));
+        }
+        Jim_SetResult(interp, listObj);
+        JimDetachPids(interp, numPids, pidPtr);
+        Jim_Free(pidPtr);
+        return JIM_OK;
+    }
+
+    /*
+     * Create the command's pipeline.
+     */
+    numPids =
+        JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, &outputId, &errorId);
+
+    if (numPids < 0) {
+        return JIM_ERR;
+    }
+
+    /*
+     * Read the child's output (if any) and put it into the result.
+     */
+    Jim_SetResultString(interp, "", 0);
+
+    result = JIM_OK;
+    if (outputId != JIM_BAD_FD) {
+        result = JimAppendStreamToString(interp, outputId, Jim_GetResult(interp));
+        if (result < 0) {
+            Jim_SetResultErrno(interp, "error reading from output pipe");
+        }
+    }
+
+    if (JimCleanupChildren(interp, numPids, pidPtr, errorId) != JIM_OK) {
+        result = JIM_ERR;
+    }
+    return result;
+}
+
+static void JimReapDetachedPids(struct WaitInfoTable *table)
+{
+    struct WaitInfo *waitPtr;
+    int count;
+
+    if (!table) {
+        return;
+    }
+
+    for (waitPtr = table->info, count = table->used; count > 0; waitPtr++, count--) {
+        if (waitPtr->flags & WI_DETACHED) {
+            int status;
+            pidtype pid = JimWaitPid(waitPtr->pid, &status, WNOHANG);
+            if (pid != JIM_BAD_PID) {
+                if (waitPtr != &table->info[table->used - 1]) {
+                    *waitPtr = table->info[table->used - 1];
+                }
+                table->used--;
+            }
+        }
+    }
+}
+
+/**
+ * Does waitpid() on the given pid, and then removes the
+ * entry from the wait table.
+ *
+ * Returns the pid if OK and updates *statusPtr with the status,
+ * or JIM_BAD_PID if the pid was not in the table.
+ */
+static pidtype JimWaitForProcess(struct WaitInfoTable *table, pidtype pid, int *statusPtr)
+{
+    int i;
+
+    /* Find it in the table */
+    for (i = 0; i < table->used; i++) {
+        if (pid == table->info[i].pid) {
+            /* wait for it */
+            JimWaitPid(pid, statusPtr, 0);
+
+            /* Remove it from the table */
+            if (i != table->used - 1) {
+                table->info[i] = table->info[table->used - 1];
+            }
+            table->used--;
+            return pid;
+        }
+    }
+
+    /* Not found */
+    return JIM_BAD_PID;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * JimDetachPids --
+ *
+ *  This procedure is called to indicate that one or more child
+ *  processes have been placed in background and are no longer
+ *  cared about.  These children can be cleaned up with JimReapDetachedPids().
+ *
+ * Results:
+ *  None.
+ *
+ * Side effects:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr)
+{
+    int j;
+    struct WaitInfoTable *table = Jim_CmdPrivData(interp);
+
+    for (j = 0; j < numPids; j++) {
+        /* Find it in the table */
+        int i;
+        for (i = 0; i < table->used; i++) {
+            if (pidPtr[j] == table->info[i].pid) {
+                table->info[i].flags |= WI_DETACHED;
+                break;
+            }
+        }
+    }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * JimCreatePipeline --
+ *
+ *  Given an argc/argv array, instantiate a pipeline of processes
+ *  as described by the argv.
+ *
+ * Results:
+ *  The return value is a count of the number of new processes
+ *  created, or -1 if an error occurred while creating the pipeline.
+ *  *pidArrayPtr is filled in with the address of a dynamically
+ *  allocated array giving the ids of all of the processes.  It
+ *  is up to the caller to free this array when it isn't needed
+ *  anymore.  If inPipePtr is non-NULL, *inPipePtr is filled in
+ *  with the file id for the input pipe for the pipeline (if any):
+ *  the caller must eventually close this file.  If outPipePtr
+ *  isn't NULL, then *outPipePtr is filled in with the file id
+ *  for the output pipe from the pipeline:  the caller must close
+ *  this file.  If errFilePtr isn't NULL, then *errFilePtr is filled
+ *  with a file id that may be used to read error output after the
+ *  pipeline completes.
+ *
+ * Side effects:
+ *  Processes and pipes are created.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, pidtype **pidArrayPtr,
+    fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr)
+{
+    pidtype *pidPtr = NULL;         /* Points to malloc-ed array holding all
+                                 * the pids of child processes. */
+    int numPids = 0;            /* Actual number of processes that exist
+                                 * at *pidPtr right now. */
+    int cmdCount;               /* Count of number of distinct commands
+                                 * found in argc/argv. */
+    const char *input = NULL;   /* Describes input for pipeline, depending
+                                 * on "inputFile".  NULL means take input
+                                 * from stdin/pipe. */
+
+#define FILE_NAME   0           /* input/output: filename */
+#define FILE_APPEND 1           /* output only:  filename, append */
+#define FILE_HANDLE 2           /* input/output: filehandle */
+#define FILE_TEXT   3           /* input only:   input is actual text */
+
+    int inputFile = FILE_NAME;  /* 1 means input is name of input file.
+                                 * 2 means input is filehandle name.
+                                 * 0 means input holds actual
+                                 * text to be input to command. */
+
+    int outputFile = FILE_NAME; /* 0 means output is the name of output file.
+                                 * 1 means output is the name of output file, and append.
+                                 * 2 means output is filehandle name.
+                                 * All this is ignored if output is NULL
+                                 */
+    int errorFile = FILE_NAME;  /* 0 means error is the name of error file.
+                                 * 1 means error is the name of error file, and append.
+                                 * 2 means error is filehandle name.
+                                 * All this is ignored if error is NULL
+                                 */
+    const char *output = NULL;  /* Holds name of output file to pipe to,
+                                 * or NULL if output goes to stdout/pipe. */
+    const char *error = NULL;   /* Holds name of stderr file to pipe to,
+                                 * or NULL if stderr goes to stderr/pipe. */
+    fdtype inputId = JIM_BAD_FD;
+                                 /* Readable file id input to current command in
+                                 * pipeline (could be file or pipe).  JIM_BAD_FD
+                                 * means use stdin. */
+    fdtype outputId = JIM_BAD_FD;
+                                 /* Writable file id for output from current
+                                 * command in pipeline (could be file or pipe).
+                                 * JIM_BAD_FD means use stdout. */
+    fdtype errorId = JIM_BAD_FD;
+                                 /* Writable file id for all standard error
+                                 * output from all commands in pipeline.  JIM_BAD_FD
+                                 * means use stderr. */
+    fdtype lastOutputId = JIM_BAD_FD;
+                                 /* Write file id for output from last command
+                                 * in pipeline (could be file or pipe).
+                                 * -1 means use stdout. */
+    fdtype pipeIds[2];           /* File ids for pipe that's being created. */
+    int firstArg, lastArg;      /* Indexes of first and last arguments in
+                                 * current command. */
+    int lastBar;
+    int i;
+    pidtype pid;
+    char **save_environ;
+    struct WaitInfoTable *table = Jim_CmdPrivData(interp);
+
+    /* Holds the args which will be used to exec */
+    char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1));
+    int arg_count = 0;
+
+    JimReapDetachedPids(table);
+
+    if (inPipePtr != NULL) {
+        *inPipePtr = JIM_BAD_FD;
+    }
+    if (outPipePtr != NULL) {
+        *outPipePtr = JIM_BAD_FD;
+    }
+    if (errFilePtr != NULL) {
+        *errFilePtr = JIM_BAD_FD;
+    }
+    pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
+
+    /*
+     * First, scan through all the arguments to figure out the structure
+     * of the pipeline.  Count the number of distinct processes (it's the
+     * number of "|" arguments).  If there are "<", "<<", or ">" arguments
+     * then make note of input and output redirection and remove these
+     * arguments and the arguments that follow them.
+     */
+    cmdCount = 1;
+    lastBar = -1;
+    for (i = 0; i < argc; i++) {
+        const char *arg = Jim_String(argv[i]);
+
+        if (arg[0] == '<') {
+            inputFile = FILE_NAME;
+            input = arg + 1;
+            if (*input == '<') {
+                inputFile = FILE_TEXT;
+                input++;
+            }
+            else if (*input == '@') {
+                inputFile = FILE_HANDLE;
+                input++;
+            }
+
+            if (!*input && ++i < argc) {
+                input = Jim_String(argv[i]);
+            }
+        }
+        else if (arg[0] == '>') {
+            int dup_error = 0;
+
+            outputFile = FILE_NAME;
+
+            output = arg + 1;
+            if (*output == '>') {
+                outputFile = FILE_APPEND;
+                output++;
+            }
+            if (*output == '&') {
+                /* Redirect stderr too */
+                output++;
+                dup_error = 1;
+            }
+            if (*output == '@') {
+                outputFile = FILE_HANDLE;
+                output++;
+            }
+            if (!*output && ++i < argc) {
+                output = Jim_String(argv[i]);
+            }
+            if (dup_error) {
+                errorFile = outputFile;
+                error = output;
+            }
+        }
+        else if (arg[0] == '2' && arg[1] == '>') {
+            error = arg + 2;
+            errorFile = FILE_NAME;
+
+            if (*error == '@') {
+                errorFile = FILE_HANDLE;
+                error++;
+            }
+            else if (*error == '>') {
+                errorFile = FILE_APPEND;
+                error++;
+            }
+            if (!*error && ++i < argc) {
+                error = Jim_String(argv[i]);
+            }
+        }
+        else {
+            if (strcmp(arg, "|") == 0 || strcmp(arg, "|&") == 0) {
+                if (i == lastBar + 1 || i == argc - 1) {
+                    Jim_SetResultString(interp, "illegal use of | or |& in command", -1);
+                    goto badargs;
+                }
+                lastBar = i;
+                cmdCount++;
+            }
+            /* Either |, |& or a "normal" arg, so store it in the arg array */
+            arg_array[arg_count++] = (char *)arg;
+            continue;
+        }
+
+        if (i >= argc) {
+            Jim_SetResultFormatted(interp, "can't specify \"%s\" as last word in command", arg);
+            goto badargs;
+        }
+    }
+
+    if (arg_count == 0) {
+        Jim_SetResultString(interp, "didn't specify command to execute", -1);
+badargs:
+        Jim_Free(arg_array);
+        return -1;
+    }
+
+    /* Must do this before vfork(), so do it now */
+    save_environ = JimSaveEnv(JimBuildEnv(interp));
+
+    /*
+     * Set up the redirected input source for the pipeline, if
+     * so requested.
+     */
+    if (input != NULL) {
+        if (inputFile == FILE_TEXT) {
+            /*
+             * Immediate data in command.  Create temporary file and
+             * put data into file.
+             */
+            inputId = JimCreateTemp(interp, input);
+            if (inputId == JIM_BAD_FD) {
+                goto error;
+            }
+        }
+        else if (inputFile == FILE_HANDLE) {
+            /* Should be a file descriptor */
+            Jim_Obj *fhObj = Jim_NewStringObj(interp, input, -1);
+            FILE *fh = Jim_AioFilehandle(interp, fhObj);
+
+            Jim_FreeNewObj(interp, fhObj);
+            if (fh == NULL) {
+                goto error;
+            }
+            inputId = JimDupFd(JimFileno(fh));
+        }
+        else {
+            /*
+             * File redirection.  Just open the file.
+             */
+            inputId = JimOpenForRead(input);
+            if (inputId == JIM_BAD_FD) {
+                Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", input, JimStrError());
+                goto error;
+            }
+        }
+    }
+    else if (inPipePtr != NULL) {
+        if (JimPipe(pipeIds) != 0) {
+            Jim_SetResultErrno(interp, "couldn't create input pipe for command");
+            goto error;
+        }
+        inputId = pipeIds[0];
+        *inPipePtr = pipeIds[1];
+        pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
+    }
+
+    /*
+     * Set up the redirected output sink for the pipeline from one
+     * of two places, if requested.
+     */
+    if (output != NULL) {
+        if (outputFile == FILE_HANDLE) {
+            Jim_Obj *fhObj = Jim_NewStringObj(interp, output, -1);
+            FILE *fh = Jim_AioFilehandle(interp, fhObj);
+
+            Jim_FreeNewObj(interp, fhObj);
+            if (fh == NULL) {
+                goto error;
+            }
+            fflush(fh);
+            lastOutputId = JimDupFd(JimFileno(fh));
+        }
+        else {
+            /*
+             * Output is to go to a file.
+             */
+            lastOutputId = JimOpenForWrite(output, outputFile == FILE_APPEND);
+            if (lastOutputId == JIM_BAD_FD) {
+                Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", output, JimStrError());
+                goto error;
+            }
+        }
+    }
+    else if (outPipePtr != NULL) {
+        /*
+         * Output is to go to a pipe.
+         */
+        if (JimPipe(pipeIds) != 0) {
+            Jim_SetResultErrno(interp, "couldn't create output pipe");
+            goto error;
+        }
+        lastOutputId = pipeIds[1];
+        *outPipePtr = pipeIds[0];
+        pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
+    }
+    /* If we are redirecting stderr with 2>filename or 2>@fileId, then we ignore errFilePtr */
+    if (error != NULL) {
+        if (errorFile == FILE_HANDLE) {
+            if (strcmp(error, "1") == 0) {
+                /* Special 2>@1 */
+                if (lastOutputId != JIM_BAD_FD) {
+                    errorId = JimDupFd(lastOutputId);
+                }
+                else {
+                    /* No redirection of stdout, so just use 2>@stdout */
+                    error = "stdout";
+                }
+            }
+            if (errorId == JIM_BAD_FD) {
+                Jim_Obj *fhObj = Jim_NewStringObj(interp, error, -1);
+                FILE *fh = Jim_AioFilehandle(interp, fhObj);
+
+                Jim_FreeNewObj(interp, fhObj);
+                if (fh == NULL) {
+                    goto error;
+                }
+                fflush(fh);
+                errorId = JimDupFd(JimFileno(fh));
+            }
+        }
+        else {
+            /*
+             * Output is to go to a file.
+             */
+            errorId = JimOpenForWrite(error, errorFile == FILE_APPEND);
+            if (errorId == JIM_BAD_FD) {
+                Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", error, JimStrError());
+                goto error;
+            }
+        }
+    }
+    else if (errFilePtr != NULL) {
+        /*
+         * Set up the standard error output sink for the pipeline, if
+         * requested.  Use a temporary file which is opened, then deleted.
+         * Could potentially just use pipe, but if it filled up it could
+         * cause the pipeline to deadlock:  we'd be waiting for processes
+         * to complete before reading stderr, and processes couldn't complete
+         * because stderr was backed up.
+         */
+        errorId = JimCreateTemp(interp, NULL);
+        if (errorId == JIM_BAD_FD) {
+            goto error;
+        }
+        *errFilePtr = JimDupFd(errorId);
+    }
+
+    /*
+     * Scan through the argc array, forking off a process for each
+     * group of arguments between "|" arguments.
+     */
+
+    pidPtr = Jim_Alloc(cmdCount * sizeof(*pidPtr));
+    for (i = 0; i < numPids; i++) {
+        pidPtr[i] = JIM_BAD_PID;
+    }
+    for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg + 1) {
+        int pipe_dup_err = 0;
+        fdtype origErrorId = errorId;
+
+        for (lastArg = firstArg; lastArg < arg_count; lastArg++) {
+            if (arg_array[lastArg][0] == '|') {
+                if (arg_array[lastArg][1] == '&') {
+                    pipe_dup_err = 1;
+                }
+                break;
+            }
+        }
+        /* Replace | with NULL for execv() */
+        arg_array[lastArg] = NULL;
+        if (lastArg == arg_count) {
+            outputId = lastOutputId;
+        }
+        else {
+            if (JimPipe(pipeIds) != 0) {
+                Jim_SetResultErrno(interp, "couldn't create pipe");
+                goto error;
+            }
+            outputId = pipeIds[1];
+        }
+
+        /* Now fork the child */
+
+#ifdef __MINGW32__
+        pid = JimStartWinProcess(interp, &arg_array[firstArg], save_environ ? save_environ[0] : NULL, inputId, outputId, errorId);
+        if (pid == JIM_BAD_PID) {
+            Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]);
+            goto error;
+        }
+#else
+        /*
+         * Disable SIGPIPE signals:  if they were allowed, this process
+         * might go away unexpectedly if children misbehave.  This code
+         * can potentially interfere with other application code that
+         * expects to handle SIGPIPEs;  what's really needed is an
+         * arbiter for signals to allow them to be "shared".
+         */
+        if (table->info == NULL) {
+            (void)signal(SIGPIPE, SIG_IGN);
+        }
+
+        /* Need to do this befor vfork() */
+        if (pipe_dup_err) {
+            errorId = outputId;
+        }
+
+        /*
+         * Make a new process and enter it into the table if the fork
+         * is successful.
+         */
+        pid = vfork();
+        if (pid < 0) {
+            Jim_SetResultErrno(interp, "couldn't fork child process");
+            goto error;
+        }
+        if (pid == 0) {
+            /* Child */
+
+            if (inputId != -1) dup2(inputId, 0);
+            if (outputId != -1) dup2(outputId, 1);
+            if (errorId != -1) dup2(errorId, 2);
+
+            for (i = 3; (i <= outputId) || (i <= inputId) || (i <= errorId); i++) {
+                close(i);
+            }
+
+            execvp(arg_array[firstArg], &arg_array[firstArg]);
+
+            /* Need to prep an error message before vfork(), just in case */
+            fprintf(stderr, "couldn't exec \"%s\"", arg_array[firstArg]);
+            _exit(127);
+        }
+#endif
+
+        /* parent */
+
+        /*
+         * Enlarge the wait table if there isn't enough space for a new
+         * entry.
+         */
+        if (table->used == table->size) {
+            table->size += WAIT_TABLE_GROW_BY;
+            table->info = Jim_Realloc(table->info, table->size * sizeof(*table->info));
+        }
+
+        table->info[table->used].pid = pid;
+        table->info[table->used].flags = 0;
+        table->used++;
+
+        pidPtr[numPids] = pid;
+
+        /* Restore in case of pipe_dup_err */
+        errorId = origErrorId;
+
+        /*
+         * Close off our copies of file descriptors that were set up for
+         * this child, then set up the input for the next child.
+         */
+
+        if (inputId != JIM_BAD_FD) {
+            JimCloseFd(inputId);
+        }
+        if (outputId != JIM_BAD_FD) {
+            JimCloseFd(outputId);
+        }
+        inputId = pipeIds[0];
+        pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
+    }
+    *pidArrayPtr = pidPtr;
+
+    /*
+     * All done.  Cleanup open files lying around and then return.
+     */
+
+  cleanup:
+    if (inputId != JIM_BAD_FD) {
+        JimCloseFd(inputId);
+    }
+    if (lastOutputId != JIM_BAD_FD) {
+        JimCloseFd(lastOutputId);
+    }
+    if (errorId != JIM_BAD_FD) {
+        JimCloseFd(errorId);
+    }
+    Jim_Free(arg_array);
+
+    JimRestoreEnv(save_environ);
+
+    return numPids;
+
+    /*
+     * An error occurred.  There could have been extra files open, such
+     * as pipes between children.  Clean them all up.  Detach any child
+     * processes that have been created.
+     */
+
+  error:
+    if ((inPipePtr != NULL) && (*inPipePtr != JIM_BAD_FD)) {
+        JimCloseFd(*inPipePtr);
+        *inPipePtr = JIM_BAD_FD;
+    }
+    if ((outPipePtr != NULL) && (*outPipePtr != JIM_BAD_FD)) {
+        JimCloseFd(*outPipePtr);
+        *outPipePtr = JIM_BAD_FD;
+    }
+    if ((errFilePtr != NULL) && (*errFilePtr != JIM_BAD_FD)) {
+        JimCloseFd(*errFilePtr);
+        *errFilePtr = JIM_BAD_FD;
+    }
+    if (pipeIds[0] != JIM_BAD_FD) {
+        JimCloseFd(pipeIds[0]);
+    }
+    if (pipeIds[1] != JIM_BAD_FD) {
+        JimCloseFd(pipeIds[1]);
+    }
+    if (pidPtr != NULL) {
+        for (i = 0; i < numPids; i++) {
+            if (pidPtr[i] != JIM_BAD_PID) {
+                JimDetachPids(interp, 1, &pidPtr[i]);
+            }
+        }
+        Jim_Free(pidPtr);
+    }
+    numPids = -1;
+    goto cleanup;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * JimCleanupChildren --
+ *
+ *  This is a utility procedure used to wait for child processes
+ *  to exit, record information about abnormal exits, and then
+ *  collect any stderr output generated by them.
+ *
+ * Results:
+ *  The return value is a standard Tcl result.  If anything at
+ *  weird happened with the child processes, JIM_ERROR is returned
+ *  and a message is left in interp->result.
+ *
+ * Side effects:
+ *  If the last character of interp->result is a newline, then it
+ *  is removed.  File errorId gets closed, and pidPtr is freed
+ *  back to the storage allocator.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, fdtype errorId)
+{
+    struct WaitInfoTable *table = Jim_CmdPrivData(interp);
+    int result = JIM_OK;
+    int i;
+
+    for (i = 0; i < numPids; i++) {
+        int waitStatus = 0;
+        if (JimWaitForProcess(table, pidPtr[i], &waitStatus) != JIM_BAD_PID) {
+            if (JimCheckWaitStatus(interp, pidPtr[i], waitStatus) != JIM_OK) {
+                result = JIM_ERR;
+            }
+        }
+    }
+    Jim_Free(pidPtr);
+
+    /*
+     * Read the standard error file.  If there's anything there,
+     * then add the file's contents to the result
+     * string.
+     */
+    if (errorId != JIM_BAD_FD) {
+        JimRewindFd(errorId);
+        if (JimAppendStreamToString(interp, errorId, Jim_GetResult(interp)) != JIM_OK) {
+            result = JIM_ERR;
+        }
+    }
+
+    JimTrimTrailingNewline(interp);
+
+    return result;
+}
+
+int Jim_execInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+    Jim_CreateCommand(interp, "exec", Jim_ExecCmd, JimAllocWaitInfoTable(), JimFreeWaitInfoTable);
+    return JIM_OK;
+}
+
+#if defined(__MINGW32__)
+/* Windows-specific (mingw) implementation */
+
+static SECURITY_ATTRIBUTES *JimStdSecAttrs(void)
+{
+    static SECURITY_ATTRIBUTES secAtts;
+
+    secAtts.nLength = sizeof(SECURITY_ATTRIBUTES);
+    secAtts.lpSecurityDescriptor = NULL;
+    secAtts.bInheritHandle = TRUE;
+    return &secAtts;
+}
+
+static int JimErrno(void)
+{
+    switch (GetLastError()) {
+    case ERROR_FILE_NOT_FOUND: return ENOENT;
+    case ERROR_PATH_NOT_FOUND: return ENOENT;
+    case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
+    case ERROR_ACCESS_DENIED: return EACCES;
+    case ERROR_INVALID_HANDLE: return EBADF;
+    case ERROR_BAD_ENVIRONMENT: return E2BIG;
+    case ERROR_BAD_FORMAT: return ENOEXEC;
+    case ERROR_INVALID_ACCESS: return EACCES;
+    case ERROR_INVALID_DRIVE: return ENOENT;
+    case ERROR_CURRENT_DIRECTORY: return EACCES;
+    case ERROR_NOT_SAME_DEVICE: return EXDEV;
+    case ERROR_NO_MORE_FILES: return ENOENT;
+    case ERROR_WRITE_PROTECT: return EROFS;
+    case ERROR_BAD_UNIT: return ENXIO;
+    case ERROR_NOT_READY: return EBUSY;
+    case ERROR_BAD_COMMAND: return EIO;
+    case ERROR_CRC: return EIO;
+    case ERROR_BAD_LENGTH: return EIO;
+    case ERROR_SEEK: return EIO;
+    case ERROR_WRITE_FAULT: return EIO;
+    case ERROR_READ_FAULT: return EIO;
+    case ERROR_GEN_FAILURE: return EIO;
+    case ERROR_SHARING_VIOLATION: return EACCES;
+    case ERROR_LOCK_VIOLATION: return EACCES;
+    case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE;
+    case ERROR_HANDLE_DISK_FULL: return ENOSPC;
+    case ERROR_NOT_SUPPORTED: return ENODEV;
+    case ERROR_REM_NOT_LIST: return EBUSY;
+    case ERROR_DUP_NAME: return EEXIST;
+    case ERROR_BAD_NETPATH: return ENOENT;
+    case ERROR_NETWORK_BUSY: return EBUSY;
+    case ERROR_DEV_NOT_EXIST: return ENODEV;
+    case ERROR_TOO_MANY_CMDS: return EAGAIN;
+    case ERROR_ADAP_HDW_ERR: return EIO;
+    case ERROR_BAD_NET_RESP: return EIO;
+    case ERROR_UNEXP_NET_ERR: return EIO;
+    case ERROR_NETNAME_DELETED: return ENOENT;
+    case ERROR_NETWORK_ACCESS_DENIED: return EACCES;
+    case ERROR_BAD_DEV_TYPE: return ENODEV;
+    case ERROR_BAD_NET_NAME: return ENOENT;
+    case ERROR_TOO_MANY_NAMES: return ENFILE;
+    case ERROR_TOO_MANY_SESS: return EIO;
+    case ERROR_SHARING_PAUSED: return EAGAIN;
+    case ERROR_REDIR_PAUSED: return EAGAIN;
+    case ERROR_FILE_EXISTS: return EEXIST;
+    case ERROR_CANNOT_MAKE: return ENOSPC;
+    case ERROR_OUT_OF_STRUCTURES: return ENFILE;
+    case ERROR_ALREADY_ASSIGNED: return EEXIST;
+    case ERROR_INVALID_PASSWORD: return EPERM;
+    case ERROR_NET_WRITE_FAULT: return EIO;
+    case ERROR_NO_PROC_SLOTS: return EAGAIN;
+    case ERROR_DISK_CHANGE: return EXDEV;
+    case ERROR_BROKEN_PIPE: return EPIPE;
+    case ERROR_OPEN_FAILED: return ENOENT;
+    case ERROR_DISK_FULL: return ENOSPC;
+    case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE;
+    case ERROR_INVALID_TARGET_HANDLE: return EBADF;
+    case ERROR_INVALID_NAME: return ENOENT;
+    case ERROR_PROC_NOT_FOUND: return ESRCH;
+    case ERROR_WAIT_NO_CHILDREN: return ECHILD;
+    case ERROR_CHILD_NOT_COMPLETE: return ECHILD;
+    case ERROR_DIRECT_ACCESS_HANDLE: return EBADF;
+    case ERROR_SEEK_ON_DEVICE: return ESPIPE;
+    case ERROR_BUSY_DRIVE: return EAGAIN;
+    case ERROR_DIR_NOT_EMPTY: return EEXIST;
+    case ERROR_NOT_LOCKED: return EACCES;
+    case ERROR_BAD_PATHNAME: return ENOENT;
+    case ERROR_LOCK_FAILED: return EACCES;
+    case ERROR_ALREADY_EXISTS: return EEXIST;
+    case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG;
+    case ERROR_BAD_PIPE: return EPIPE;
+    case ERROR_PIPE_BUSY: return EAGAIN;
+    case ERROR_PIPE_NOT_CONNECTED: return EPIPE;
+    case ERROR_DIRECTORY: return ENOTDIR;
+    }
+    return EINVAL;
+}
+
+static int JimPipe(fdtype pipefd[2])
+{
+    if (CreatePipe(&pipefd[0], &pipefd[1], NULL, 0)) {
+        return 0;
+    }
+    return -1;
+}
+
+static fdtype JimDupFd(fdtype infd)
+{
+    fdtype dupfd;
+    pidtype pid = GetCurrentProcess();
+
+    if (DuplicateHandle(pid, infd, pid, &dupfd, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
+        return dupfd;
+    }
+    return JIM_BAD_FD;
+}
+
+static int JimRewindFd(fdtype fd)
+{
+    return SetFilePointer(fd, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER ? -1 : 0;
+}
+
+#if 0
+static int JimReadFd(fdtype fd, char *buffer, size_t len)
+{
+    DWORD num;
+
+    if (ReadFile(fd, buffer, len, &num, NULL)) {
+        return num;
+    }
+    if (GetLastError() == ERROR_HANDLE_EOF || GetLastError() == ERROR_BROKEN_PIPE) {
+        return 0;
+    }
+    return -1;
+}
+#endif
+
+static FILE *JimFdOpenForRead(fdtype fd)
+{
+    return _fdopen(_open_osfhandle((int)fd, _O_RDONLY | _O_TEXT), "r");
+}
+
+static fdtype JimFileno(FILE *fh)
+{
+    return (fdtype)_get_osfhandle(_fileno(fh));
+}
+
+static fdtype JimOpenForRead(const char *filename)
+{
+    return CreateFile(filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+        JimStdSecAttrs(), OPEN_EXISTING, 0, NULL);
+}
+
+static fdtype JimOpenForWrite(const char *filename, int append)
+{
+    return CreateFile(filename, append ? FILE_APPEND_DATA : GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+        JimStdSecAttrs(), append ? OPEN_ALWAYS : CREATE_ALWAYS, 0, (HANDLE) NULL);
+}
+
+static FILE *JimFdOpenForWrite(fdtype fd)
+{
+    return _fdopen(_open_osfhandle((int)fd, _O_TEXT), "w");
+}
+
+static pidtype JimWaitPid(pidtype pid, int *status, int nohang)
+{
+    DWORD ret = WaitForSingleObject(pid, nohang ? 0 : INFINITE);
+    if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) {
+        /* WAIT_TIMEOUT can only happend with WNOHANG */
+        return JIM_BAD_PID;
+    }
+    GetExitCodeProcess(pid, &ret);
+    *status = ret;
+    CloseHandle(pid);
+    return pid;
+}
+
+static HANDLE JimCreateTemp(Jim_Interp *interp, const char *contents)
+{
+    char name[MAX_PATH];
+    HANDLE handle;
+
+    if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, "JIM", 0, name)) {
+        return JIM_BAD_FD;
+    }
+
+    handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, JimStdSecAttrs(),
+            CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
+            NULL);
+
+    if (handle == INVALID_HANDLE_VALUE) {
+        goto error;
+    }
+
+    if (contents != NULL) {
+        /* Use fdopen() to get automatic text-mode translation */
+        FILE *fh = JimFdOpenForWrite(JimDupFd(handle));
+        if (fh == NULL) {
+            goto error;
+        }
+
+        if (fwrite(contents, strlen(contents), 1, fh) != 1) {
+            fclose(fh);
+            goto error;
+        }
+        fseek(fh, 0, SEEK_SET);
+        fclose(fh);
+    }
+    return handle;
+
+  error:
+    Jim_SetResultErrno(interp, "failed to create temp file");
+    CloseHandle(handle);
+    DeleteFile(name);
+    return JIM_BAD_FD;
+}
+
+static int
+JimWinFindExecutable(const char *originalName, char fullPath[MAX_PATH])
+{
+    int i;
+    static char extensions[][5] = {".exe", "", ".bat"};
+
+    for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) {
+        lstrcpyn(fullPath, originalName, MAX_PATH - 5);
+        lstrcat(fullPath, extensions[i]);
+
+        if (SearchPath(NULL, fullPath, NULL, MAX_PATH, fullPath, NULL) == 0) {
+            continue;
+        }
+        if (GetFileAttributes(fullPath) & FILE_ATTRIBUTE_DIRECTORY) {
+            continue;
+        }
+        return 0;
+    }
+
+    return -1;
+}
+
+static char **JimSaveEnv(char **env)
+{
+    return env;
+}
+
+static void JimRestoreEnv(char **env)
+{
+    JimFreeEnv(env, NULL);
+}
+
+static Jim_Obj *
+JimWinBuildCommandLine(Jim_Interp *interp, char **argv)
+{
+    char *start, *special;
+    int quote, i;
+
+    Jim_Obj *strObj = Jim_NewStringObj(interp, "", 0);
+
+    for (i = 0; argv[i]; i++) {
+        if (i > 0) {
+            Jim_AppendString(interp, strObj, " ", 1);
+        }
+
+        if (argv[i][0] == '\0') {
+            quote = 1;
+        }
+        else {
+            quote = 0;
+            for (start = argv[i]; *start != '\0'; start++) {
+                if (isspace(UCHAR(*start))) {
+                    quote = 1;
+                    break;
+                }
+            }
+        }
+        if (quote) {
+            Jim_AppendString(interp, strObj, "\"" , 1);
+        }
+
+        start = argv[i];
+        for (special = argv[i]; ; ) {
+            if ((*special == '\\') && (special[1] == '\\' ||
+                    special[1] == '"' || (quote && special[1] == '\0'))) {
+                Jim_AppendString(interp, strObj, start, special - start);
+                start = special;
+                while (1) {
+                    special++;
+                    if (*special == '"' || (quote && *special == '\0')) {
+                        /*
+                         * N backslashes followed a quote -> insert
+                         * N * 2 + 1 backslashes then a quote.
+                         */
+
+                        Jim_AppendString(interp, strObj, start, special - start);
+                        break;
+                    }
+                    if (*special != '\\') {
+                        break;
+                    }
+                }
+                Jim_AppendString(interp, strObj, start, special - start);
+                start = special;
+            }
+            if (*special == '"') {
+        if (special == start) {
+            Jim_AppendString(interp, strObj, "\"", 1);
+        }
+        else {
+            Jim_AppendString(interp, strObj, start, special - start);
+        }
+                Jim_AppendString(interp, strObj, "\\\"", 2);
+                start = special + 1;
+            }
+            if (*special == '\0') {
+                break;
+            }
+            special++;
+        }
+        Jim_AppendString(interp, strObj, start, special - start);
+        if (quote) {
+            Jim_AppendString(interp, strObj, "\"", 1);
+        }
+    }
+    return strObj;
+}
+
+static pidtype
+JimStartWinProcess(Jim_Interp *interp, char **argv, char *env, fdtype inputId, fdtype outputId, fdtype errorId)
+{
+    STARTUPINFO startInfo;
+    PROCESS_INFORMATION procInfo;
+    HANDLE hProcess, h;
+    char execPath[MAX_PATH];
+    char *originalName;
+    pidtype pid = JIM_BAD_PID;
+    Jim_Obj *cmdLineObj;
+
+    if (JimWinFindExecutable(argv[0], execPath) < 0) {
+        return JIM_BAD_PID;
+    }
+    originalName = argv[0];
+    argv[0] = execPath;
+
+    hProcess = GetCurrentProcess();
+    cmdLineObj = JimWinBuildCommandLine(interp, argv);
+
+    /*
+     * STARTF_USESTDHANDLES must be used to pass handles to child process.
+     * Using SetStdHandle() and/or dup2() only works when a console mode
+     * parent process is spawning an attached console mode child process.
+     */
+
+    ZeroMemory(&startInfo, sizeof(startInfo));
+    startInfo.cb = sizeof(startInfo);
+    startInfo.dwFlags   = STARTF_USESTDHANDLES;
+    startInfo.hStdInput	= INVALID_HANDLE_VALUE;
+    startInfo.hStdOutput= INVALID_HANDLE_VALUE;
+    startInfo.hStdError = INVALID_HANDLE_VALUE;
+
+    /*
+     * Duplicate all the handles which will be passed off as stdin, stdout
+     * and stderr of the child process. The duplicate handles are set to
+     * be inheritable, so the child process can use them.
+     */
+    if (inputId == JIM_BAD_FD) {
+        if (CreatePipe(&startInfo.hStdInput, &h, JimStdSecAttrs(), 0) != FALSE) {
+            CloseHandle(h);
+        }
+    } else {
+        DuplicateHandle(hProcess, inputId, hProcess, &startInfo.hStdInput,
+                0, TRUE, DUPLICATE_SAME_ACCESS);
+    }
+    if (startInfo.hStdInput == JIM_BAD_FD) {
+        goto end;
+    }
+
+    if (outputId == JIM_BAD_FD) {
+        startInfo.hStdOutput = CreateFile("NUL:", GENERIC_WRITE, 0,
+                JimStdSecAttrs(), OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    } else {
+        DuplicateHandle(hProcess, outputId, hProcess, &startInfo.hStdOutput,
+                0, TRUE, DUPLICATE_SAME_ACCESS);
+    }
+    if (startInfo.hStdOutput == JIM_BAD_FD) {
+        goto end;
+    }
+
+    if (errorId == JIM_BAD_FD) {
+        /*
+         * If handle was not set, errors should be sent to an infinitely
+         * deep sink.
+         */
+
+        startInfo.hStdError = CreateFile("NUL:", GENERIC_WRITE, 0,
+                JimStdSecAttrs(), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    } else {
+        DuplicateHandle(hProcess, errorId, hProcess, &startInfo.hStdError,
+                0, TRUE, DUPLICATE_SAME_ACCESS);
+    }
+    if (startInfo.hStdError == JIM_BAD_FD) {
+        goto end;
+    }
+
+    if (!CreateProcess(NULL, (char *)Jim_String(cmdLineObj), NULL, NULL, TRUE,
+            0, env, NULL, &startInfo, &procInfo)) {
+        goto end;
+    }
+
+    /*
+     * "When an application spawns a process repeatedly, a new thread
+     * instance will be created for each process but the previous
+     * instances may not be cleaned up.  This results in a significant
+     * virtual memory loss each time the process is spawned.  If there
+     * is a WaitForInputIdle() call between CreateProcess() and
+     * CloseHandle(), the problem does not occur." PSS ID Number: Q124121
+     */
+
+    WaitForInputIdle(procInfo.hProcess, 5000);
+    CloseHandle(procInfo.hThread);
+
+    pid = procInfo.hProcess;
+
+    end:
+    Jim_FreeNewObj(interp, cmdLineObj);
+    if (startInfo.hStdInput != JIM_BAD_FD) {
+        CloseHandle(startInfo.hStdInput);
+    }
+    if (startInfo.hStdOutput != JIM_BAD_FD) {
+        CloseHandle(startInfo.hStdOutput);
+    }
+    if (startInfo.hStdError != JIM_BAD_FD) {
+        CloseHandle(startInfo.hStdError);
+    }
+    return pid;
+}
+#else
+/* Unix-specific implementation */
+static int JimOpenForWrite(const char *filename, int append)
+{
+    return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666);
+}
+
+static int JimRewindFd(int fd)
+{
+    return lseek(fd, 0L, SEEK_SET);
+}
+
+static int JimCreateTemp(Jim_Interp *interp, const char *contents)
+{
+    char inName[] = "/tmp/tcl.tmp.XXXXXX";
+
+    int fd = mkstemp(inName);
+    if (fd == JIM_BAD_FD) {
+        Jim_SetResultErrno(interp, "couldn't create temp file");
+        return -1;
+    }
+    unlink(inName);
+    if (contents) {
+        int length = strlen(contents);
+        if (write(fd, contents, length) != length) {
+            Jim_SetResultErrno(interp, "couldn't write temp file");
+            close(fd);
+            return -1;
+        }
+        lseek(fd, 0L, SEEK_SET);
+    }
+    return fd;
+}
+
+static char **JimSaveEnv(char **env)
+{
+    char **saveenv = Jim_GetEnviron();
+    Jim_SetEnviron(env);
+    return saveenv;
+}
+
+static void JimRestoreEnv(char **env)
+{
+    JimFreeEnv(Jim_GetEnviron(), env);
+    Jim_SetEnviron(env);
+}
+#endif
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-file.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-file.c
new file mode 100755
index 0000000..7b48368
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-file.c
@@ -0,0 +1,929 @@
+/*
+ * Implements the file command for jim
+ *
+ * (c) 2008 Steve Bennett <steveb@workware.net.au>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ *
+ * Based on code originally from Tcl 6.7:
+ *
+ * Copyright 1987-1991 Regents of the University of California
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies.  The University of California
+ * makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "jim-subcmd.h"
+
+# ifndef MAXPATHLEN
+# define MAXPATHLEN JIM_PATH_LEN
+# endif
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * JimGetFileType --
+ *
+ *  Given a mode word, returns a string identifying the type of a
+ *  file.
+ *
+ * Results:
+ *  A static text string giving the file type from mode.
+ *
+ * Side effects:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static const char *JimGetFileType(int mode)
+{
+    if (S_ISREG(mode)) {
+        return "file";
+    }
+    else if (S_ISDIR(mode)) {
+        return "directory";
+    }
+    else if (S_ISCHR(mode)) {
+        return "characterSpecial";
+    }
+    else if (S_ISBLK(mode)) {
+        return "blockSpecial";
+    }
+    else if (S_ISFIFO(mode)) {
+        return "fifo";
+#ifdef S_ISLNK
+    }
+    else if (S_ISLNK(mode)) {
+        return "link";
+#endif
+#ifdef S_ISSOCK
+    }
+    else if (S_ISSOCK(mode)) {
+        return "socket";
+#endif
+    }
+    return "unknown";
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * StoreStatData --
+ *
+ *  This is a utility procedure that breaks out the fields of a
+ *  "stat" structure and stores them in textual form into the
+ *  elements of an associative array.
+ *
+ * Results:
+ *  Returns a standard Tcl return value.  If an error occurs then
+ *  a message is left in interp->result.
+ *
+ * Side effects:
+ *  Elements of the associative array given by "varName" are modified.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int set_array_int_value(Jim_Interp *interp, Jim_Obj *container, const char *key,
+    jim_wide value)
+{
+    Jim_Obj *nameobj = Jim_NewStringObj(interp, key, -1);
+    Jim_Obj *valobj = Jim_NewWideObj(interp, value);
+
+    if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj, JIM_ERRMSG) != JIM_OK) {
+        Jim_FreeObj(interp, nameobj);
+        Jim_FreeObj(interp, valobj);
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+static int set_array_string_value(Jim_Interp *interp, Jim_Obj *container, const char *key,
+    const char *value)
+{
+    Jim_Obj *nameobj = Jim_NewStringObj(interp, key, -1);
+    Jim_Obj *valobj = Jim_NewStringObj(interp, value, -1);
+
+    if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj, JIM_ERRMSG) != JIM_OK) {
+        Jim_FreeObj(interp, nameobj);
+        Jim_FreeObj(interp, valobj);
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+static int StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat *sb)
+{
+    if (set_array_int_value(interp, varName, "dev", sb->st_dev) != JIM_OK) {
+        Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variables isn't array", varName);
+        return JIM_ERR;
+    }
+    set_array_int_value(interp, varName, "ino", sb->st_ino);
+    set_array_int_value(interp, varName, "mode", sb->st_mode);
+    set_array_int_value(interp, varName, "nlink", sb->st_nlink);
+    set_array_int_value(interp, varName, "uid", sb->st_uid);
+    set_array_int_value(interp, varName, "gid", sb->st_gid);
+    set_array_int_value(interp, varName, "size", sb->st_size);
+    set_array_int_value(interp, varName, "atime", sb->st_atime);
+    set_array_int_value(interp, varName, "mtime", sb->st_mtime);
+    set_array_int_value(interp, varName, "ctime", sb->st_ctime);
+    set_array_string_value(interp, varName, "type", JimGetFileType((int)sb->st_mode));
+
+    /* And also return the value */
+    Jim_SetResult(interp, Jim_GetVariable(interp, varName, 0));
+
+    return JIM_OK;
+}
+
+static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *path = Jim_String(argv[0]);
+    const char *p = strrchr(path, '/');
+
+    if (!p) {
+        Jim_SetResultString(interp, ".", -1);
+    }
+    else if (p == path) {
+        Jim_SetResultString(interp, "/", -1);
+    }
+#if defined(__MINGW32__)
+    else if (p[-1] == ':') {
+        /* z:/dir => z:/ */
+        Jim_SetResultString(interp, path, p - path + 1);
+    }
+#endif
+    else {
+        Jim_SetResultString(interp, path, p - path);
+    }
+    return JIM_OK;
+}
+
+static int file_cmd_rootname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *path = Jim_String(argv[0]);
+    const char *lastSlash = strrchr(path, '/');
+    const char *p = strrchr(path, '.');
+
+    if (p == NULL || (lastSlash != NULL && lastSlash > p)) {
+        Jim_SetResult(interp, argv[0]);
+    }
+    else {
+        Jim_SetResultString(interp, path, p - path);
+    }
+    return JIM_OK;
+}
+
+static int file_cmd_extension(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *path = Jim_String(argv[0]);
+    const char *lastSlash = strrchr(path, '/');
+    const char *p = strrchr(path, '.');
+
+    if (p == NULL || (lastSlash != NULL && lastSlash >= p)) {
+        p = "";
+    }
+    Jim_SetResultString(interp, p, -1);
+    return JIM_OK;
+}
+
+static int file_cmd_tail(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *path = Jim_String(argv[0]);
+    const char *lastSlash = strrchr(path, '/');
+
+    if (lastSlash) {
+        Jim_SetResultString(interp, lastSlash + 1, -1);
+    }
+    else {
+        Jim_SetResult(interp, argv[0]);
+    }
+    return JIM_OK;
+}
+
+static int file_cmd_normalize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+#ifdef HAVE_REALPATH
+    const char *path = Jim_String(argv[0]);
+    char *newname = Jim_Alloc(MAXPATHLEN + 1);
+
+    if (realpath(path, newname)) {
+        Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, -1));
+    }
+    else {
+        Jim_Free(newname);
+        Jim_SetResult(interp, argv[0]);
+    }
+    return JIM_OK;
+#else
+    Jim_SetResultString(interp, "Not implemented", -1);
+    return JIM_ERR;
+#endif
+}
+
+static int file_cmd_join(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int i;
+    char *newname = Jim_Alloc(MAXPATHLEN + 1);
+    char *last = newname;
+
+    *newname = 0;
+
+    /* Simple implementation for now */
+    for (i = 0; i < argc; i++) {
+        int len;
+        const char *part = Jim_GetString(argv[i], &len);
+
+        if (*part == '/') {
+            /* Absolute component, so go back to the start */
+            last = newname;
+        }
+#if defined(__MINGW32__)
+        else if (strchr(part, ':')) {
+            /* Absolute compontent on mingw, so go back to the start */
+            last = newname;
+        }
+#endif
+        else if (part[0] == '.') {
+            if (part[1] == '/') {
+                part += 2;
+                len -= 2;
+            }
+            else if (part[1] == 0 && last != newname) {
+                /* Adding '.' to an existing path does nothing */
+                continue;
+            }
+        }
+
+        /* Add a slash if needed */
+        if (last != newname && last[-1] != '/') {
+            *last++ = '/';
+        }
+
+        if (len) {
+            if (last + len - newname >= MAXPATHLEN) {
+                Jim_Free(newname);
+                Jim_SetResultString(interp, "Path too long", -1);
+                return JIM_ERR;
+            }
+            memcpy(last, part, len);
+            last += len;
+        }
+
+        /* Remove a slash if needed */
+        if (last > newname + 1 && last[-1] == '/') {
+            *--last = 0;
+        }
+    }
+
+    *last = 0;
+
+    /* Probably need to handle some special cases ... */
+
+    Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, last - newname));
+
+    return JIM_OK;
+}
+
+static int file_access(Jim_Interp *interp, Jim_Obj *filename, int mode)
+{
+    const char *path = Jim_String(filename);
+    int rc = access(path, mode);
+
+    Jim_SetResultBool(interp, rc != -1);
+
+    return JIM_OK;
+}
+
+static int file_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return file_access(interp, argv[0], R_OK);
+}
+
+static int file_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return file_access(interp, argv[0], W_OK);
+}
+
+static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return file_access(interp, argv[0], X_OK);
+}
+
+static int file_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return file_access(interp, argv[0], F_OK);
+}
+
+static int file_cmd_delete(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int force = Jim_CompareStringImmediate(interp, argv[0], "-force");
+
+    if (force || Jim_CompareStringImmediate(interp, argv[0], "--")) {
+        argc++;
+        argv--;
+    }
+
+    while (argc--) {
+        const char *path = Jim_String(argv[0]);
+
+        if (unlink(path) == -1 && errno != ENOENT) {
+            if (rmdir(path) == -1) {
+                /* Maybe try using the script helper */
+                if (!force || Jim_EvalPrefix(interp, "file delete force", 1, argv) != JIM_OK) {
+                    Jim_SetResultFormatted(interp, "couldn't delete file \"%s\": %s", path,
+                        strerror(errno));
+                    return JIM_ERR;
+                }
+            }
+        }
+        argv++;
+    }
+    return JIM_OK;
+}
+
+#ifdef HAVE_MKDIR_ONE_ARG
+#define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME)
+#else
+#define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755)
+#endif
+
+/**
+ * Create directory, creating all intermediate paths if necessary.
+ *
+ * Returns 0 if OK or -1 on failure (and sets errno)
+ *
+ * Note: The path may be modified.
+ */
+static int mkdir_all(char *path)
+{
+    int ok = 1;
+
+    /* First time just try to make the dir */
+    goto first;
+
+    while (ok--) {
+        /* Must have failed the first time, so recursively make the parent and try again */
+        char *slash = strrchr(path, '/');
+
+        if (slash && slash != path) {
+            *slash = 0;
+            if (mkdir_all(path) != 0) {
+                return -1;
+            }
+            *slash = '/';
+        }
+      first:
+        if (MKDIR_DEFAULT(path) == 0) {
+            return 0;
+        }
+        if (errno == ENOENT) {
+            /* Create the parent and try again */
+            continue;
+        }
+        /* Maybe it already exists as a directory */
+        if (errno == EEXIST) {
+            struct stat sb;
+
+            if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
+                return 0;
+            }
+            /* Restore errno */
+            errno = EEXIST;
+        }
+        /* Failed */
+        break;
+    }
+    return -1;
+}
+
+static int file_cmd_mkdir(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    while (argc--) {
+        char *path = Jim_StrDup(Jim_String(argv[0]));
+        int rc = mkdir_all(path);
+
+        Jim_Free(path);
+        if (rc != 0) {
+            Jim_SetResultFormatted(interp, "can't create directory \"%#s\": %s", argv[0],
+                strerror(errno));
+            return JIM_ERR;
+        }
+        argv++;
+    }
+    return JIM_OK;
+}
+
+#ifdef HAVE_MKSTEMP
+static int file_cmd_tempfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int fd;
+    char *filename;
+    const char *template = "/tmp/tcl.tmp.XXXXXX";
+
+    if (argc >= 1) {
+        template = Jim_String(argv[0]);
+    }
+    filename = Jim_StrDup(template);
+
+    fd = mkstemp(filename);
+    if (fd < 0) {
+        Jim_SetResultString(interp, "Failed to create tempfile", -1);
+        return JIM_ERR;
+    }
+    close(fd);
+
+    Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, filename, -1));
+    return JIM_OK;
+}
+#endif
+
+static int file_cmd_rename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *source;
+    const char *dest;
+    int force = 0;
+
+    if (argc == 3) {
+        if (!Jim_CompareStringImmediate(interp, argv[0], "-force")) {
+            return -1;
+        }
+        force++;
+        argv++;
+        argc--;
+    }
+
+    source = Jim_String(argv[0]);
+    dest = Jim_String(argv[1]);
+
+    if (!force && access(dest, F_OK) == 0) {
+        Jim_SetResultFormatted(interp, "error renaming \"%#s\" to \"%#s\": target exists", argv[0],
+            argv[1]);
+        return JIM_ERR;
+    }
+
+    if (rename(source, dest) != 0) {
+        Jim_SetResultFormatted(interp, "error renaming \"%#s\" to \"%#s\": %s", argv[0], argv[1],
+            strerror(errno));
+        return JIM_ERR;
+    }
+
+    return JIM_OK;
+}
+
+static int file_stat(Jim_Interp *interp, Jim_Obj *filename, struct stat *sb)
+{
+    const char *path = Jim_String(filename);
+
+    if (stat(path, sb) == -1) {
+        Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+#ifndef HAVE_LSTAT
+#define lstat stat
+#endif
+
+static int file_lstat(Jim_Interp *interp, Jim_Obj *filename, struct stat *sb)
+{
+    const char *path = Jim_String(filename);
+
+    if (lstat(path, sb) == -1) {
+        Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+static int file_cmd_atime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+
+    if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+        return JIM_ERR;
+    }
+    Jim_SetResultInt(interp, sb.st_atime);
+    return JIM_OK;
+}
+
+static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+
+    if (argc == 2) {
+#ifdef HAVE_UTIMES
+        jim_wide newtime;
+        struct timeval times[2];
+
+        if (Jim_GetWide(interp, argv[1], &newtime) != JIM_OK) {
+            return JIM_ERR;
+        }
+
+        times[1].tv_sec = times[0].tv_sec = newtime;
+        times[1].tv_usec = times[0].tv_usec = 0;
+
+        if (utimes(Jim_String(argv[0]), times) != 0) {
+            Jim_SetResultFormatted(interp, "can't set time on \"%#s\": %s", argv[0], strerror(errno));
+            return JIM_ERR;
+        }
+#else
+        Jim_SetResultString(interp, "Not implemented", -1);
+        return JIM_ERR;
+#endif
+    }
+    if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+        return JIM_ERR;
+    }
+    Jim_SetResultInt(interp, sb.st_mtime);
+    return JIM_OK;
+}
+
+static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return Jim_EvalPrefix(interp, "file copy", argc, argv);
+}
+
+static int file_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+
+    if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+        return JIM_ERR;
+    }
+    Jim_SetResultInt(interp, sb.st_size);
+    return JIM_OK;
+}
+
+static int file_cmd_isdirectory(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+    int ret = 0;
+
+    if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+        ret = S_ISDIR(sb.st_mode);
+    }
+    Jim_SetResultInt(interp, ret);
+    return JIM_OK;
+}
+
+static int file_cmd_isfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+    int ret = 0;
+
+    if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+        ret = S_ISREG(sb.st_mode);
+    }
+    Jim_SetResultInt(interp, ret);
+    return JIM_OK;
+}
+
+#ifdef HAVE_GETEUID
+static int file_cmd_owned(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+    int ret = 0;
+
+    if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+        ret = (geteuid() == sb.st_uid);
+    }
+    Jim_SetResultInt(interp, ret);
+    return JIM_OK;
+}
+#endif
+
+#if defined(HAVE_READLINK)
+static int file_cmd_readlink(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *path = Jim_String(argv[0]);
+    char *linkValue = Jim_Alloc(MAXPATHLEN + 1);
+
+    int linkLength = readlink(path, linkValue, MAXPATHLEN);
+
+    if (linkLength == -1) {
+        Jim_Free(linkValue);
+        Jim_SetResultFormatted(interp, "couldn't readlink \"%#s\": %s", argv[0], strerror(errno));
+        return JIM_ERR;
+    }
+    linkValue[linkLength] = 0;
+    Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, linkValue, linkLength));
+    return JIM_OK;
+}
+#endif
+
+static int file_cmd_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+
+    if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
+        return JIM_ERR;
+    }
+    Jim_SetResultString(interp, JimGetFileType((int)sb.st_mode), -1);
+    return JIM_OK;
+}
+
+static int file_cmd_lstat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+
+    if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
+        return JIM_ERR;
+    }
+    return StoreStatData(interp, argv[1], &sb);
+}
+
+static int file_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+
+    if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+        return JIM_ERR;
+    }
+    return StoreStatData(interp, argv[1], &sb);
+}
+
+static const jim_subcmd_type file_command_table[] = {
+    {   .cmd = "atime",
+        .args = "name",
+        .function = file_cmd_atime,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Last access time"
+    },
+    {   .cmd = "mtime",
+        .args = "name ?time?",
+        .function = file_cmd_mtime,
+        .minargs = 1,
+        .maxargs = 2,
+        .description = "Get or set last modification time"
+    },
+    {   .cmd = "copy",
+        .args = "?-force? source dest",
+        .function = file_cmd_copy,
+        .minargs = 2,
+        .maxargs = 3,
+        .description = "Copy source file to destination file"
+    },
+    {   .cmd = "dirname",
+        .args = "name",
+        .function = file_cmd_dirname,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Directory part of the name"
+    },
+    {   .cmd = "rootname",
+        .args = "name",
+        .function = file_cmd_rootname,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Name without any extension"
+    },
+    {   .cmd = "extension",
+        .args = "name",
+        .function = file_cmd_extension,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Last extension including the dot"
+    },
+    {   .cmd = "tail",
+        .args = "name",
+        .function = file_cmd_tail,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Last component of the name"
+    },
+    {   .cmd = "normalize",
+        .args = "name",
+        .function = file_cmd_normalize,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Normalized path of name"
+    },
+    {   .cmd = "join",
+        .args = "name ?name ...?",
+        .function = file_cmd_join,
+        .minargs = 1,
+        .maxargs = -1,
+        .description = "Join multiple path components"
+    },
+    {   .cmd = "readable",
+        .args = "name",
+        .function = file_cmd_readable,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Is file readable"
+    },
+    {   .cmd = "writable",
+        .args = "name",
+        .function = file_cmd_writable,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Is file writable"
+    },
+    {   .cmd = "executable",
+        .args = "name",
+        .function = file_cmd_executable,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Is file executable"
+    },
+    {   .cmd = "exists",
+        .args = "name",
+        .function = file_cmd_exists,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Does file exist"
+    },
+    {   .cmd = "delete",
+        .args = "?-force|--? name ...",
+        .function = file_cmd_delete,
+        .minargs = 1,
+        .maxargs = -1,
+        .description = "Deletes the files or directories (must be empty unless -force)"
+    },
+    {   .cmd = "mkdir",
+        .args = "dir ...",
+        .function = file_cmd_mkdir,
+        .minargs = 1,
+        .maxargs = -1,
+        .description = "Creates the directories"
+    },
+#ifdef HAVE_MKSTEMP
+    {   .cmd = "tempfile",
+        .args = "?template?",
+        .function = file_cmd_tempfile,
+        .minargs = 0,
+        .maxargs = 1,
+        .description = "Creates a temporary filename"
+    },
+#endif
+    {   .cmd = "rename",
+        .args = "?-force? source dest",
+        .function = file_cmd_rename,
+        .minargs = 2,
+        .maxargs = 3,
+        .description = "Renames a file"
+    },
+#if defined(HAVE_READLINK)
+    {   .cmd = "readlink",
+        .args = "name",
+        .function = file_cmd_readlink,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Value of the symbolic link"
+    },
+#endif
+    {   .cmd = "size",
+        .args = "name",
+        .function = file_cmd_size,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Size of file"
+    },
+    {   .cmd = "stat",
+        .args = "name var",
+        .function = file_cmd_stat,
+        .minargs = 2,
+        .maxargs = 2,
+        .description = "Stores results of stat in var array"
+    },
+    {   .cmd = "lstat",
+        .args = "name var",
+        .function = file_cmd_lstat,
+        .minargs = 2,
+        .maxargs = 2,
+        .description = "Stores results of lstat in var array"
+    },
+    {   .cmd = "type",
+        .args = "name",
+        .function = file_cmd_type,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Returns type of the file"
+    },
+#ifdef HAVE_GETEUID
+    {   .cmd = "owned",
+        .args = "name",
+        .function = file_cmd_owned,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Returns 1 if owned by the current owner"
+    },
+#endif
+    {   .cmd = "isdirectory",
+        .args = "name",
+        .function = file_cmd_isdirectory,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Returns 1 if name is a directory"
+    },
+    {   .cmd = "isfile",
+        .args = "name",
+        .function = file_cmd_isfile,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Returns 1 if name is a file"
+    },
+    {
+        .cmd = 0
+    }
+};
+
+static int Jim_CdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *path;
+
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "dirname");
+        return JIM_ERR;
+    }
+
+    path = Jim_String(argv[1]);
+
+    if (chdir(path) != 0) {
+        Jim_SetResultFormatted(interp, "couldn't change working directory to \"%s\": %s", path,
+            strerror(errno));
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+static int Jim_PwdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const int cwd_len = 2048;
+    char *cwd = malloc(cwd_len);
+
+    if (getcwd(cwd, cwd_len) == NULL) {
+        Jim_SetResultString(interp, "Failed to get pwd", -1);
+        return JIM_ERR;
+    }
+#if defined(__MINGW32__)
+    {
+        /* Try to keep backlashes out of paths */
+        char *p = cwd;
+        while ((p = strchr(p, '\\')) != NULL) {
+            *p++ = '/';
+        }
+    }
+#endif
+
+    Jim_SetResultString(interp, cwd, -1);
+
+    free(cwd);
+    return JIM_OK;
+}
+
+int Jim_fileInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "file", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    Jim_CreateCommand(interp, "file", Jim_SubCmdProc, (void *)file_command_table, NULL);
+    Jim_CreateCommand(interp, "pwd", Jim_PwdCmd, NULL, NULL);
+    Jim_CreateCommand(interp, "cd", Jim_CdCmd, NULL, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-format.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-format.c
new file mode 100755
index 0000000..c9cde89
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-format.c
@@ -0,0 +1,433 @@
+/*
+ * Implements the internals of the format command for jim
+ *
+ * The FreeBSD license
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ *
+ * Based on code originally from Tcl 8.5:
+ *
+ * Copyright (c) 1995-1997 Sun Microsystems, Inc.
+ * Copyright (c) 1999 by Scriptics Corporation.
+ *
+ * See the file "tcl.license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ */
+#include <ctype.h>
+#include <string.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "utf8.h"
+
+#define JIM_UTF_MAX 3
+#define JIM_INTEGER_SPACE 24
+#define MAX_FLOAT_WIDTH 320
+
+/**
+ * Apply the printf-like format in fmtObjPtr with the given arguments.
+ *
+ * Returns a new object with zero reference count if OK, or NULL on error.
+ */
+Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv)
+{
+    const char *span, *format, *formatEnd, *msg;
+    int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0;
+    static const char * const mixedXPG =
+	    "cannot mix \"%\" and \"%n$\" conversion specifiers";
+    static const char * const badIndex[2] = {
+	"not enough arguments for all format specifiers",
+	"\"%n$\" argument index out of range"
+    };
+    int formatLen;
+    Jim_Obj *resultPtr;
+
+    /* A single buffer is used to store numeric fields (with sprintf())
+     * This buffer is allocated/reallocated as necessary
+     */
+    char *num_buffer = NULL;
+    int num_buffer_size = 0;
+
+    span = format = Jim_GetString(fmtObjPtr, &formatLen);
+    formatEnd = format + formatLen;
+    resultPtr = Jim_NewStringObj(interp, "", 0);
+
+    while (format != formatEnd) {
+	char *end;
+	int gotMinus, sawFlag;
+	int gotPrecision, useShort;
+	long width, precision;
+	int newXpg;
+	int ch;
+	int step;
+	int doubleType;
+	char pad = ' ';
+	char spec[2*JIM_INTEGER_SPACE + 12];
+	char *p;
+
+	int formatted_chars;
+	int formatted_bytes;
+	const char *formatted_buf;
+
+	step = utf8_tounicode(format, &ch);
+	format += step;
+	if (ch != '%') {
+	    numBytes += step;
+	    continue;
+	}
+	if (numBytes) {
+	    Jim_AppendString(interp, resultPtr, span, numBytes);
+	    numBytes = 0;
+	}
+
+	/*
+	 * Saw a % : process the format specifier.
+	 *
+	 * Step 0. Handle special case of escaped format marker (i.e., %%).
+	 */
+
+	step = utf8_tounicode(format, &ch);
+	if (ch == '%') {
+	    span = format;
+	    numBytes = step;
+	    format += step;
+	    continue;
+	}
+
+	/*
+	 * Step 1. XPG3 position specifier
+	 */
+
+	newXpg = 0;
+	if (isdigit(ch)) {
+	    int position = strtoul(format, &end, 10);
+	    if (*end == '$') {
+		newXpg = 1;
+		objIndex = position - 1;
+		format = end + 1;
+		step = utf8_tounicode(format, &ch);
+	    }
+	}
+	if (newXpg) {
+	    if (gotSequential) {
+		msg = mixedXPG;
+		goto errorMsg;
+	    }
+	    gotXpg = 1;
+	} else {
+	    if (gotXpg) {
+		msg = mixedXPG;
+		goto errorMsg;
+	    }
+	    gotSequential = 1;
+	}
+	if ((objIndex < 0) || (objIndex >= objc)) {
+	    msg = badIndex[gotXpg];
+	    goto errorMsg;
+	}
+
+	/*
+	 * Step 2. Set of flags. Also build up the sprintf spec.
+	 */
+	p = spec;
+	*p++ = '%';
+
+	gotMinus = 0;
+	sawFlag = 1;
+	do {
+	    switch (ch) {
+	    case '-':
+		gotMinus = 1;
+		break;
+	    case '0':
+		pad = ch;
+		break;
+	    case ' ':
+	    case '+':
+	    case '#':
+		break;
+	    default:
+		sawFlag = 0;
+		continue;
+	    }
+	    *p++ = ch;
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	} while (sawFlag);
+
+	/*
+	 * Step 3. Minimum field width.
+	 */
+
+	width = 0;
+	if (isdigit(ch)) {
+	    width = strtoul(format, &end, 10);
+	    format = end;
+	    step = utf8_tounicode(format, &ch);
+	} else if (ch == '*') {
+	    if (objIndex >= objc - 1) {
+		msg = badIndex[gotXpg];
+		goto errorMsg;
+	    }
+	    if (Jim_GetLong(interp, objv[objIndex], &width) != JIM_OK) {
+		goto error;
+	    }
+	    if (width < 0) {
+		width = -width;
+		if (!gotMinus) {
+		    *p++ = '-';
+		    gotMinus = 1;
+		}
+	    }
+	    objIndex++;
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	}
+
+	/*
+	 * Step 4. Precision.
+	 */
+
+	gotPrecision = precision = 0;
+	if (ch == '.') {
+	    gotPrecision = 1;
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	}
+	if (isdigit(ch)) {
+	    precision = strtoul(format, &end, 10);
+	    format = end;
+	    step = utf8_tounicode(format, &ch);
+	} else if (ch == '*') {
+	    if (objIndex >= objc - 1) {
+		msg = badIndex[gotXpg];
+		goto errorMsg;
+	    }
+	    if (Jim_GetLong(interp, objv[objIndex], &precision) != JIM_OK) {
+		goto error;
+	    }
+
+	    /*
+	     * TODO: Check this truncation logic.
+	     */
+
+	    if (precision < 0) {
+		precision = 0;
+	    }
+	    objIndex++;
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	}
+
+	/*
+	 * Step 5. Length modifier.
+	 */
+
+	useShort = 0;
+	if (ch == 'h') {
+	    useShort = 1;
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	} else if (ch == 'l') {
+	    /* Just for compatibility. All non-short integers are wide. */
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	    if (ch == 'l') {
+		format += step;
+		step = utf8_tounicode(format, &ch);
+	    }
+	}
+
+	format += step;
+	span = format;
+
+	/*
+	 * Step 6. The actual conversion character.
+	 */
+
+	if (ch == 'i') {
+	    ch = 'd';
+	}
+
+	doubleType = 0;
+
+	/* Each valid conversion will set:
+	 * formatted_buf   - the result to be added
+	 * formatted_chars - the length of formatted_buf in characters
+	 * formatted_bytes - the length of formatted_buf in bytes
+	 */
+	switch (ch) {
+	case '\0':
+	    msg = "format string ended in middle of field specifier";
+	    goto errorMsg;
+	case 's': {
+	    formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes);
+	    formatted_chars = Jim_Utf8Length(interp, objv[objIndex]);
+	    if (gotPrecision && (precision < formatted_chars)) {
+		/* Need to build a (null terminated) truncated string */
+		formatted_chars = precision;
+		formatted_bytes = utf8_index(formatted_buf, precision);
+	    }
+	    break;
+	}
+	case 'c': {
+	    jim_wide code;
+
+	    if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) {
+		goto error;
+	    }
+	    /* Just store the value in the 'spec' buffer */
+	    formatted_bytes = utf8_fromunicode(spec, code);
+	    formatted_buf = spec;
+	    formatted_chars = 1;
+	    break;
+	}
+
+	case 'e':
+	case 'E':
+	case 'f':
+	case 'g':
+	case 'G':
+	    doubleType = 1;
+	    /* fall through */
+	case 'd':
+	case 'u':
+	case 'o':
+	case 'x':
+	case 'X': {
+	    jim_wide w;
+	    double d;
+	    int length;
+
+	    /* Fill in the width and precision */
+	    if (width) {
+		p += sprintf(p, "%ld", width);
+	    }
+	    if (gotPrecision) {
+		p += sprintf(p, ".%ld", precision);
+	    }
+
+	    /* Now the modifier, and get the actual value here */
+	    if (doubleType) {
+		if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) {
+		    goto error;
+		}
+		length = MAX_FLOAT_WIDTH;
+	    }
+	    else {
+		if (Jim_GetWide(interp, objv[objIndex], &w) != JIM_OK) {
+		    goto error;
+		}
+		length = JIM_INTEGER_SPACE;
+		if (useShort) {
+		    *p++ = 'h';
+		    if (ch == 'd') {
+			w = (short)w;
+		    }
+		    else {
+			w = (unsigned short)w;
+		    }
+		}
+		else {
+		    *p++ = 'l';
+#ifdef HAVE_LONG_LONG
+		    if (sizeof(long long) == sizeof(jim_wide)) {
+			*p++ = 'l';
+		    }
+#endif
+		}
+	    }
+
+	    *p++ = (char) ch;
+	    *p = '\0';
+
+	    /* Adjust length for width and precision */
+	    if (width > length) {
+		length = width;
+	    }
+	    if (gotPrecision) {
+		length += precision;
+	    }
+
+	    /* Increase the size of the buffer if needed */
+	    if (num_buffer_size < length + 1) {
+		num_buffer_size = length + 1;
+		num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
+	    }
+
+	    if (doubleType) {
+		snprintf(num_buffer, length + 1, spec, d);
+	    }
+	    else {
+		formatted_bytes = snprintf(num_buffer, length + 1, spec, w);
+	    }
+	    formatted_chars = formatted_bytes = strlen(num_buffer);
+	    formatted_buf = num_buffer;
+	    break;
+	}
+
+	default: {
+	    /* Just reuse the 'spec' buffer */
+	    spec[0] = ch;
+	    spec[1] = '\0';
+	    Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec);
+	    goto error;
+	}
+	}
+
+	if (!gotMinus) {
+	    while (formatted_chars < width) {
+		Jim_AppendString(interp, resultPtr, &pad, 1);
+		formatted_chars++;
+	    }
+	}
+
+	Jim_AppendString(interp, resultPtr, formatted_buf, formatted_bytes);
+
+	while (formatted_chars < width) {
+	    Jim_AppendString(interp, resultPtr, &pad, 1);
+	    formatted_chars++;
+	}
+
+	objIndex += gotSequential;
+    }
+    if (numBytes) {
+	Jim_AppendString(interp, resultPtr, span, numBytes);
+    }
+
+    Jim_Free(num_buffer);
+    return resultPtr;
+
+  errorMsg:
+    Jim_SetResultString(interp, msg, -1);
+  error:
+    Jim_FreeNewObj(interp, resultPtr);
+    Jim_Free(num_buffer);
+    return NULL;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-interactive.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-interactive.c
new file mode 100755
index 0000000..658e8d8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-interactive.c
@@ -0,0 +1,137 @@
+#include <errno.h>
+#include <string.h>
+#include "jim.h"
+#include "jimautoconf.h"
+
+#ifdef USE_LINENOISE
+#include <unistd.h>
+#include "linenoise.h"
+#else
+
+#define MAX_LINE_LEN 512
+
+static char *linenoise(const char *prompt)
+{
+    char *line = malloc(MAX_LINE_LEN);
+
+    fputs(prompt, stdout);
+    fflush(stdout);
+
+    if (fgets(line, MAX_LINE_LEN, stdin) == NULL) {
+        free(line);
+        return NULL;
+    }
+    return line;
+}
+#endif
+
+int Jim_InteractivePrompt(Jim_Interp *interp)
+{
+    int retcode = JIM_OK;
+    char *history_file = NULL;
+#ifdef USE_LINENOISE
+    const char *home;
+
+    home = getenv("HOME");
+    if (home && isatty(STDIN_FILENO)) {
+        int history_len = strlen(home) + sizeof("/.jim_history");
+        history_file = Jim_Alloc(history_len);
+        snprintf(history_file, history_len, "%s/.jim_history", home);
+        linenoiseHistoryLoad(history_file);
+    }
+#endif
+
+    printf("Welcome to Jim version %d.%d" JIM_NL,
+        JIM_VERSION / 100, JIM_VERSION % 100);
+    Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1");
+
+    while (1) {
+        Jim_Obj *scriptObjPtr;
+        const char *result;
+        int reslen;
+        char prompt[20];
+        const char *str;
+
+        if (retcode != 0) {
+            const char *retcodestr = Jim_ReturnCode(retcode);
+
+            if (*retcodestr == '?') {
+                snprintf(prompt, sizeof(prompt) - 3, "[%d] ", retcode);
+            }
+            else {
+                snprintf(prompt, sizeof(prompt) - 3, "[%s] ", retcodestr);
+            }
+        }
+        else {
+            prompt[0] = '\0';
+        }
+        strcat(prompt, ". ");
+
+        scriptObjPtr = Jim_NewStringObj(interp, "", 0);
+        Jim_IncrRefCount(scriptObjPtr);
+        while (1) {
+            char state;
+            int len;
+            char *line;
+
+            line = linenoise(prompt);
+            if (line == NULL) {
+                if (errno == EINTR) {
+                    continue;
+                }
+                Jim_DecrRefCount(interp, scriptObjPtr);
+                goto out;
+            }
+            if (Jim_Length(scriptObjPtr) != 0) {
+                Jim_AppendString(interp, scriptObjPtr, "\n", 1);
+            }
+            Jim_AppendString(interp, scriptObjPtr, line, -1);
+            free(line);
+            str = Jim_GetString(scriptObjPtr, &len);
+            if (len == 0) {
+                continue;
+            }
+            if (Jim_ScriptIsComplete(str, len, &state))
+                break;
+
+            snprintf(prompt, sizeof(prompt), "%c> ", state);
+        }
+#ifdef USE_LINENOISE
+        if (strcmp(str, "h") == 0) {
+            /* built-in history command */
+            int i;
+            int len;
+            char **history = linenoiseHistory(&len);
+            for (i = 0; i < len; i++) {
+                printf("%4d %s\n", i + 1, history[i]);
+            }
+            Jim_DecrRefCount(interp, scriptObjPtr);
+            continue;
+        }
+
+        linenoiseHistoryAdd(Jim_String(scriptObjPtr));
+        if (history_file) {
+            linenoiseHistorySave(history_file);
+        }
+#endif
+        retcode = Jim_EvalObj(interp, scriptObjPtr);
+        Jim_DecrRefCount(interp, scriptObjPtr);
+
+
+
+        if (retcode == JIM_EXIT) {
+            Jim_Free(history_file);
+            return JIM_EXIT;
+        }
+        if (retcode == JIM_ERR) {
+            Jim_MakeErrorMessage(interp);
+        }
+        result = Jim_GetString(Jim_GetResult(interp), &reslen);
+        if (reslen) {
+            printf("%s\n", result);
+        }
+    }
+  out:
+    Jim_Free(history_file);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-load.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-load.c
new file mode 100755
index 0000000..4dc6ed2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-load.c
@@ -0,0 +1,126 @@
+#include "jim.h"
+#include "jimautoconf.h"
+#include <string.h>
+
+/* -----------------------------------------------------------------------------
+ * Dynamic libraries support (WIN32 not supported)
+ * ---------------------------------------------------------------------------*/
+
+#if defined(HAVE_DLOPEN) || defined(HAVE_DLOPEN_COMPAT)
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#ifndef RTLD_NOW
+    #define RTLD_NOW 0
+#endif
+#ifndef RTLD_LOCAL
+    #define RTLD_LOCAL 0
+#endif
+
+/**
+ * Note that Jim_LoadLibrary() requires a path to an existing file.
+ *
+ * If it is necessary to search JIM_LIBPATH, use Jim_PackageRequire() instead.
+ */
+int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName)
+{
+    void *handle = dlopen(pathName, RTLD_NOW | RTLD_LOCAL);
+    if (handle == NULL) {
+        Jim_SetResultFormatted(interp, "error loading extension \"%s\": %s", pathName,
+            dlerror());
+    }
+    else {
+        /* We use a unique init symbol depending on the extension name.
+         * This is done for compatibility between static and dynamic extensions.
+         * For extension readline.so, the init symbol is "Jim_readlineInit"
+         */
+        const char *pt;
+        const char *pkgname;
+        int pkgnamelen;
+        char initsym[40];
+        int (*onload) (Jim_Interp *);
+
+        pt = strrchr(pathName, '/');
+        if (pt) {
+            pkgname = pt + 1;
+        }
+        else {
+            pkgname = pathName;
+        }
+        pt = strchr(pkgname, '.');
+        if (pt) {
+            pkgnamelen = pt - pkgname;
+        }
+        else {
+            pkgnamelen = strlen(pkgname);
+        }
+        snprintf(initsym, sizeof(initsym), "Jim_%.*sInit", pkgnamelen, pkgname);
+
+        if ((onload = dlsym(handle, initsym)) == NULL) {
+            Jim_SetResultFormatted(interp,
+                "No %s symbol found in extension %s", initsym, pathName);
+        }
+        else if (onload(interp) != JIM_ERR) {
+            /* Add this handle to the stack of handles to be freed */
+            if (!interp->loadHandles) {
+                interp->loadHandles = Jim_Alloc(sizeof(*interp->loadHandles));
+                Jim_InitStack(interp->loadHandles);
+            }
+            Jim_StackPush(interp->loadHandles, handle);
+
+            Jim_SetEmptyResult(interp);
+
+            return JIM_OK;
+        }
+    }
+    if (handle) {
+        dlclose(handle);
+    }
+    return JIM_ERR;
+}
+
+static void JimFreeOneLoadHandle(void *handle)
+{
+    dlclose(handle);
+}
+
+void Jim_FreeLoadHandles(Jim_Interp *interp)
+{
+    if (interp->loadHandles) {
+        Jim_FreeStackElements(interp->loadHandles, JimFreeOneLoadHandle);
+        Jim_Free(interp->loadHandles);
+    }
+}
+
+#else /* JIM_DYNLIB */
+int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName)
+{
+    JIM_NOTUSED(interp);
+    JIM_NOTUSED(pathName);
+
+    Jim_SetResultString(interp, "the Jim binary has no support for [load]", -1);
+    return JIM_ERR;
+}
+
+void Jim_FreeLoadHandles(Jim_Interp *interp)
+{
+}
+#endif /* JIM_DYNLIB */
+
+/* [load] */
+static int Jim_LoadCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "libaryFile");
+        return JIM_ERR;
+    }
+    return Jim_LoadLibrary(interp, Jim_String(argv[1]));
+}
+
+int Jim_loadInit(Jim_Interp *interp)
+{
+    Jim_CreateCommand(interp, "load", Jim_LoadCoreCommand, NULL, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-nvp.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-nvp.c
new file mode 100755
index 0000000..be94f15
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-nvp.c
@@ -0,0 +1,338 @@
+#include <string.h>
+#include <jim-nvp.h>
+
+int Jim_GetNvp(Jim_Interp *interp,
+    Jim_Obj *objPtr, const Jim_Nvp * nvp_table, const Jim_Nvp ** result)
+{
+    Jim_Nvp *n;
+    int e;
+
+    e = Jim_Nvp_name2value_obj(interp, nvp_table, objPtr, &n);
+    if (e == JIM_ERR) {
+        return e;
+    }
+
+    /* Success? found? */
+    if (n->name) {
+        /* remove const */
+        *result = (Jim_Nvp *) n;
+        return JIM_OK;
+    }
+    else {
+        return JIM_ERR;
+    }
+}
+
+Jim_Nvp *Jim_Nvp_name2value_simple(const Jim_Nvp * p, const char *name)
+{
+    while (p->name) {
+        if (0 == strcmp(name, p->name)) {
+            break;
+        }
+        p++;
+    }
+    return ((Jim_Nvp *) (p));
+}
+
+Jim_Nvp *Jim_Nvp_name2value_nocase_simple(const Jim_Nvp * p, const char *name)
+{
+    while (p->name) {
+        if (0 == strcasecmp(name, p->name)) {
+            break;
+        }
+        p++;
+    }
+    return ((Jim_Nvp *) (p));
+}
+
+int Jim_Nvp_name2value_obj(Jim_Interp *interp, const Jim_Nvp * p, Jim_Obj *o, Jim_Nvp ** result)
+{
+    return Jim_Nvp_name2value(interp, p, Jim_String(o), result);
+}
+
+
+int Jim_Nvp_name2value(Jim_Interp *interp, const Jim_Nvp * _p, const char *name, Jim_Nvp ** result)
+{
+    const Jim_Nvp *p;
+
+    p = Jim_Nvp_name2value_simple(_p, name);
+
+    /* result */
+    if (result) {
+        *result = (Jim_Nvp *) (p);
+    }
+
+    /* found? */
+    if (p->name) {
+        return JIM_OK;
+    }
+    else {
+        return JIM_ERR;
+    }
+}
+
+int
+Jim_Nvp_name2value_obj_nocase(Jim_Interp *interp, const Jim_Nvp * p, Jim_Obj *o, Jim_Nvp ** puthere)
+{
+    return Jim_Nvp_name2value_nocase(interp, p, Jim_String(o), puthere);
+}
+
+int
+Jim_Nvp_name2value_nocase(Jim_Interp *interp, const Jim_Nvp * _p, const char *name,
+    Jim_Nvp ** puthere)
+{
+    const Jim_Nvp *p;
+
+    p = Jim_Nvp_name2value_nocase_simple(_p, name);
+
+    if (puthere) {
+        *puthere = (Jim_Nvp *) (p);
+    }
+    /* found */
+    if (p->name) {
+        return JIM_OK;
+    }
+    else {
+        return JIM_ERR;
+    }
+}
+
+
+int Jim_Nvp_value2name_obj(Jim_Interp *interp, const Jim_Nvp * p, Jim_Obj *o, Jim_Nvp ** result)
+{
+    int e;;
+    jim_wide w;
+
+    e = Jim_GetWide(interp, o, &w);
+    if (e != JIM_OK) {
+        return e;
+    }
+
+    return Jim_Nvp_value2name(interp, p, w, result);
+}
+
+Jim_Nvp *Jim_Nvp_value2name_simple(const Jim_Nvp * p, int value)
+{
+    while (p->name) {
+        if (value == p->value) {
+            break;
+        }
+        p++;
+    }
+    return ((Jim_Nvp *) (p));
+}
+
+
+int Jim_Nvp_value2name(Jim_Interp *interp, const Jim_Nvp * _p, int value, Jim_Nvp ** result)
+{
+    const Jim_Nvp *p;
+
+    p = Jim_Nvp_value2name_simple(_p, value);
+
+    if (result) {
+        *result = (Jim_Nvp *) (p);
+    }
+
+    if (p->name) {
+        return JIM_OK;
+    }
+    else {
+        return JIM_ERR;
+    }
+}
+
+
+int Jim_GetOpt_Setup(Jim_GetOptInfo * p, Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    memset(p, 0, sizeof(*p));
+    p->interp = interp;
+    p->argc = argc;
+    p->argv = argv;
+
+    return JIM_OK;
+}
+
+void Jim_GetOpt_Debug(Jim_GetOptInfo * p)
+{
+    int x;
+
+    fprintf(stderr, "---args---\n");
+    for (x = 0; x < p->argc; x++) {
+        fprintf(stderr, "%2d) %s\n", x, Jim_String(p->argv[x]));
+    }
+    fprintf(stderr, "-------\n");
+}
+
+
+int Jim_GetOpt_Obj(Jim_GetOptInfo * goi, Jim_Obj **puthere)
+{
+    Jim_Obj *o;
+
+    o = NULL;                   // failure
+    if (goi->argc) {
+        // success
+        o = goi->argv[0];
+        goi->argc -= 1;
+        goi->argv += 1;
+    }
+    if (puthere) {
+        *puthere = o;
+    }
+    if (o != NULL) {
+        return JIM_OK;
+    }
+    else {
+        return JIM_ERR;
+    }
+}
+
+int Jim_GetOpt_String(Jim_GetOptInfo * goi, char **puthere, int *len)
+{
+    int r;
+    Jim_Obj *o;
+    const char *cp;
+
+
+    r = Jim_GetOpt_Obj(goi, &o);
+    if (r == JIM_OK) {
+        cp = Jim_GetString(o, len);
+        if (puthere) {
+            /* remove const */
+            *puthere = (char *)(cp);
+        }
+    }
+    return r;
+}
+
+int Jim_GetOpt_Double(Jim_GetOptInfo * goi, double *puthere)
+{
+    int r;
+    Jim_Obj *o;
+    double _safe;
+
+    if (puthere == NULL) {
+        puthere = &_safe;
+    }
+
+    r = Jim_GetOpt_Obj(goi, &o);
+    if (r == JIM_OK) {
+        r = Jim_GetDouble(goi->interp, o, puthere);
+        if (r != JIM_OK) {
+            Jim_SetResultFormatted(goi->interp, "not a number: %#s", o);
+        }
+    }
+    return r;
+}
+
+int Jim_GetOpt_Wide(Jim_GetOptInfo * goi, jim_wide * puthere)
+{
+    int r;
+    Jim_Obj *o;
+    jim_wide _safe;
+
+    if (puthere == NULL) {
+        puthere = &_safe;
+    }
+
+    r = Jim_GetOpt_Obj(goi, &o);
+    if (r == JIM_OK) {
+        r = Jim_GetWide(goi->interp, o, puthere);
+    }
+    return r;
+}
+
+int Jim_GetOpt_Nvp(Jim_GetOptInfo * goi, const Jim_Nvp * nvp, Jim_Nvp ** puthere)
+{
+    Jim_Nvp *_safe;
+    Jim_Obj *o;
+    int e;
+
+    if (puthere == NULL) {
+        puthere = &_safe;
+    }
+
+    e = Jim_GetOpt_Obj(goi, &o);
+    if (e == JIM_OK) {
+        e = Jim_Nvp_name2value_obj(goi->interp, nvp, o, puthere);
+    }
+
+    return e;
+}
+
+void Jim_GetOpt_NvpUnknown(Jim_GetOptInfo * goi, const Jim_Nvp * nvptable, int hadprefix)
+{
+    if (hadprefix) {
+        Jim_SetResult_NvpUnknown(goi->interp, goi->argv[-2], goi->argv[-1], nvptable);
+    }
+    else {
+        Jim_SetResult_NvpUnknown(goi->interp, NULL, goi->argv[-1], nvptable);
+    }
+}
+
+
+int Jim_GetOpt_Enum(Jim_GetOptInfo * goi, const char *const *lookup, int *puthere)
+{
+    int _safe;
+    Jim_Obj *o;
+    int e;
+
+    if (puthere == NULL) {
+        puthere = &_safe;
+    }
+    e = Jim_GetOpt_Obj(goi, &o);
+    if (e == JIM_OK) {
+        e = Jim_GetEnum(goi->interp, o, lookup, puthere, "option", JIM_ERRMSG);
+    }
+    return e;
+}
+
+void
+Jim_SetResult_NvpUnknown(Jim_Interp *interp,
+    Jim_Obj *param_name, Jim_Obj *param_value, const Jim_Nvp * nvp)
+{
+    if (param_name) {
+        Jim_SetResultFormatted(interp, "%#s: Unknown: %#s, try one of: ", param_name, param_value);
+    }
+    else {
+        Jim_SetResultFormatted(interp, "Unknown param: %#s, try one of: ", param_value);
+    }
+    while (nvp->name) {
+        const char *a;
+        const char *b;
+
+        if ((nvp + 1)->name) {
+            a = nvp->name;
+            b = ", ";
+        }
+        else {
+            a = "or ";
+            b = nvp->name;
+        }
+        Jim_AppendStrings(interp, Jim_GetResult(interp), a, b, NULL);
+        nvp++;
+    }
+}
+
+const char *Jim_Debug_ArgvString(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    static Jim_Obj *debug_string_obj;
+
+    int x;
+
+    if (debug_string_obj) {
+        Jim_FreeObj(interp, debug_string_obj);
+    }
+
+    debug_string_obj = Jim_NewEmptyStringObj(interp);
+    for (x = 0; x < argc; x++) {
+        Jim_AppendStrings(interp, debug_string_obj, Jim_String(argv[x]), " ", NULL);
+    }
+
+    return Jim_String(debug_string_obj);
+}
+
+int Jim_nvpInit(Jim_Interp *interp)
+{
+    /* This is really a helper library, not an extension, but this is the easy way */
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-nvp.h b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-nvp.h
new file mode 100755
index 0000000..12ff889
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-nvp.h
@@ -0,0 +1,275 @@
+#ifndef JIM_NVP_H
+#define JIM_NVP_H
+
+#include <jim.h>
+
+/** Name Value Pairs, aka: NVP
+ *   -  Given a string - return the associated int.
+ *   -  Given a number - return the associated string.
+ *   .
+ *
+ * Very useful when the number is not a simple index into an array of
+ * known string, or there may be multiple strings (aliases) that mean then same
+ * thing.
+ *
+ * An NVP Table is terminated with ".name = NULL".
+ *
+ * During the 'name2value' operation, if no matching string is found
+ * the pointer to the terminal element (with p->name == NULL) is returned.
+ *
+ * Example:
+ * \code
+ *      const Jim_Nvp yn[] = {
+ *          { "yes", 1 },
+ *          { "no" , 0 },
+ *          { "yep", 1 },
+ *          { "nope", 0 },
+ *          { NULL, -1 },
+ *      };
+ *
+ *  Jim_Nvp *result
+ *  e = Jim_Nvp_name2value(interp, yn, "y", &result);
+ *         returns &yn[0];
+ *  e = Jim_Nvp_name2value(interp, yn, "n", &result);
+ *         returns &yn[1];
+ *  e = Jim_Nvp_name2value(interp, yn, "Blah", &result);
+ *         returns &yn[4];
+ * \endcode
+ *
+ * During the number2name operation, the first matching value is returned.
+ */
+typedef struct {
+	const char *name;
+	int         value;
+} Jim_Nvp;
+
+
+int Jim_GetNvp (Jim_Interp *interp,
+									Jim_Obj *objPtr,
+									const Jim_Nvp *nvp_table,
+									const Jim_Nvp **result);
+
+/* Name Value Pairs Operations */
+Jim_Nvp *Jim_Nvp_name2value_simple(const Jim_Nvp *nvp_table, const char *name);
+Jim_Nvp *Jim_Nvp_name2value_nocase_simple(const Jim_Nvp *nvp_table, const char *name);
+Jim_Nvp *Jim_Nvp_value2name_simple(const Jim_Nvp *nvp_table, int v);
+
+int Jim_Nvp_name2value(Jim_Interp *interp, const Jim_Nvp *nvp_table, const char *name, Jim_Nvp **result);
+int Jim_Nvp_name2value_nocase(Jim_Interp *interp, const Jim_Nvp *nvp_table, const char *name, Jim_Nvp **result);
+int Jim_Nvp_value2name(Jim_Interp *interp, const Jim_Nvp *nvp_table, int value, Jim_Nvp **result);
+
+int Jim_Nvp_name2value_obj(Jim_Interp *interp, const Jim_Nvp *nvp_table, Jim_Obj *name_obj, Jim_Nvp **result);
+int Jim_Nvp_name2value_obj_nocase(Jim_Interp *interp, const Jim_Nvp *nvp_table, Jim_Obj *name_obj, Jim_Nvp **result);
+int Jim_Nvp_value2name_obj(Jim_Interp *interp, const Jim_Nvp *nvp_table, Jim_Obj *value_obj, Jim_Nvp **result);
+
+/** prints a nice 'unknown' parameter error message to the 'result' */
+void Jim_SetResult_NvpUnknown(Jim_Interp *interp,
+												   Jim_Obj *param_name,
+												   Jim_Obj *param_value,
+												   const Jim_Nvp *nvp_table);
+
+
+/** Debug: convert argc/argv into a printable string for printf() debug
+ *
+ * \param interp - the interpeter
+ * \param argc   - arg count
+ * \param argv   - the objects
+ *
+ * \returns string pointer holding the text.
+ *
+ * Note, next call to this function will free the old (last) string.
+ *
+ * For example might want do this:
+ * \code
+ *     fp = fopen("some.file.log", "a");
+ *     fprintf(fp, "PARAMS are: %s\n", Jim_DebugArgvString(interp, argc, argv));
+ *     fclose(fp);
+ * \endcode
+ */
+const char *Jim_Debug_ArgvString(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
+
+/** A TCL -ish GetOpt like code.
+ *
+ * Some TCL objects have various "configuration" values.
+ * For example - in Tcl/Tk the "buttons" have many options.
+ *
+ * Usefull when dealing with command options.
+ * that may come in any order...
+ *
+ * Does not support "-foo = 123" type options.
+ * Only supports tcl type options, like "-foo 123"
+ */
+
+typedef struct jim_getopt {
+	Jim_Interp     *interp;
+	int            argc;
+	Jim_Obj        * const * argv;
+	int            isconfigure; /* non-zero if configure */
+} Jim_GetOptInfo;
+
+/** GetOpt - how to.
+ *
+ * Example (short and incomplete):
+ * \code
+ *   Jim_GetOptInfo goi;
+ *
+ *   Jim_GetOpt_Setup(&goi, interp, argc, argv);
+ *
+ *   while (goi.argc) {
+ *         e = Jim_GetOpt_Nvp(&goi, nvp_options, &n);
+ *         if (e != JIM_OK) {
+ *               Jim_GetOpt_NvpUnknown(&goi, nvp_options, 0);
+ *               return e;
+ *         }
+ *
+ *         switch (n->value) {
+ *         case ALIVE:
+ *             printf("Option ALIVE specified\n");
+ *             break;
+ *         case FIRST:
+ *             if (goi.argc < 1) {
+ *                     .. not enough args error ..
+ *             }
+ *             Jim_GetOpt_String(&goi, &cp, NULL);
+ *             printf("FIRSTNAME: %s\n", cp);
+ *         case AGE:
+ *             Jim_GetOpt_Wide(&goi, &w);
+ *             printf("AGE: %d\n", (int)(w));
+ *             break;
+ *         case POLITICS:
+ *             e = Jim_GetOpt_Nvp(&goi, nvp_politics, &n);
+ *             if (e != JIM_OK) {
+ *                 Jim_GetOpt_NvpUnknown(&goi, nvp_politics, 1);
+ *                 return e;
+ *             }
+ *         }
+ *  }
+ *
+ * \endcode
+ *
+ */
+
+/** Setup GETOPT
+ *
+ * \param goi    - get opt info to be initialized
+ * \param interp - jim interp
+ * \param argc   - argc count.
+ * \param argv   - argv (will be copied)
+ *
+ * \code
+ *     Jim_GetOptInfo  goi;
+ *
+ *     Jim_GetOptSetup(&goi, interp, argc, argv);
+ * \endcode
+ */
+
+int Jim_GetOpt_Setup(Jim_GetOptInfo *goi,
+											Jim_Interp *interp,
+											int argc,
+											Jim_Obj * const *  argv);
+
+
+/** Debug - Dump parameters to stderr
+ * \param goi - current parameters
+ */
+void Jim_GetOpt_Debug(Jim_GetOptInfo *goi);
+
+
+
+/** Remove argv[0] from the list.
+ *
+ * \param goi - get opt info
+ * \param puthere - where param is put
+ *
+ */
+int Jim_GetOpt_Obj(Jim_GetOptInfo *goi, Jim_Obj **puthere);
+
+/** Remove argv[0] as string.
+ *
+ * \param goi     - get opt info
+ * \param puthere - where param is put
+ * \param len     - return its length
+ */
+int Jim_GetOpt_String(Jim_GetOptInfo *goi, char **puthere, int *len);
+
+/** Remove argv[0] as double.
+ *
+ * \param goi     - get opt info
+ * \param puthere - where param is put.
+ *
+ */
+int Jim_GetOpt_Double(Jim_GetOptInfo *goi, double *puthere);
+
+/** Remove argv[0] as wide.
+ *
+ * \param goi     - get opt info
+ * \param puthere - where param is put.
+ */
+int Jim_GetOpt_Wide(Jim_GetOptInfo *goi, jim_wide *puthere);
+
+/** Remove argv[0] as NVP.
+ *
+ * \param goi     - get opt info
+ * \param lookup  - nvp lookup table
+ * \param puthere - where param is put.
+ *
+ */
+int Jim_GetOpt_Nvp(Jim_GetOptInfo *goi, const Jim_Nvp *lookup, Jim_Nvp **puthere);
+
+/** Create an appropriate error message for an NVP.
+ *
+ * \param goi - options info
+ * \param lookup - the NVP table that was used.
+ * \param hadprefix - 0 or 1 if the option had a prefix.
+ *
+ * This function will set the "interp->result" to a human readable
+ * error message listing the available options.
+ *
+ * This function assumes the previous option argv[-1] is the unknown string.
+ *
+ * If this option had some prefix, then pass "hadprefix = 1" else pass "hadprefix = 0"
+ *
+ * Example:
+ * \code
+ *
+ *  while (goi.argc) {
+ *     // Get the next option
+ *     e = Jim_GetOpt_Nvp(&goi, cmd_options, &n);
+ *     if (e != JIM_OK) {
+ *          // option was not recognized
+ *          // pass 'hadprefix = 0' because there is no prefix
+ *          Jim_GetOpt_NvpUnknown(&goi, cmd_options, 0);
+ *          return e;
+ *     }
+ *
+ *     switch (n->value) {
+ *     case OPT_SEX:
+ *          // handle:  --sex male | female | lots | needmore
+ *          e = Jim_GetOpt_Nvp(&goi, &nvp_sex, &n);
+ *          if (e != JIM_OK) {
+ *               Jim_GetOpt_NvpUnknown(&ogi, nvp_sex, 1);
+ *               return e;
+ *          }
+ *          printf("Code: (%d) is %s\n", n->value, n->name);
+ *          break;
+ *     case ...:
+ *          [snip]
+ *     }
+ * }
+ * \endcode
+ *
+ */
+void Jim_GetOpt_NvpUnknown(Jim_GetOptInfo *goi, const Jim_Nvp *lookup, int hadprefix);
+
+
+/** Remove argv[0] as Enum
+ *
+ * \param goi     - get opt info
+ * \param lookup  - lookup table.
+ * \param puthere - where param is put.
+ *
+ */
+int Jim_GetOpt_Enum(Jim_GetOptInfo *goi, const char * const *  lookup, int *puthere);
+
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-pack.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-pack.c
new file mode 100755
index 0000000..88bf2c1
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-pack.c
@@ -0,0 +1,380 @@
+#include <string.h>
+#include <jim.h>
+
+/* Provides the [pack] and [unpack] commands to pack and unpack
+ * a binary string to/from arbitrary width integers and strings.
+ *
+ * This may be used to implement the [binary] command.
+ */
+
+/**
+ * Big endian bit test.
+ *
+ * Considers 'bitvect' as a big endian bit stream and returns
+ * bit 'b' as zero or non-zero.
+ */
+static int JimTestBitBigEndian(const unsigned char *bitvec, int b)
+{
+    div_t pos = div(b, 8);
+    return bitvec[pos.quot] & (1 << (7 - pos.rem));
+}
+
+/**
+ * Little endian bit test.
+ *
+ * Considers 'bitvect' as a little endian bit stream and returns
+ * bit 'b' as zero or non-zero.
+ */
+static int JimTestBitLittleEndian(const unsigned char *bitvec, int b)
+{
+    div_t pos = div(b, 8);
+    return bitvec[pos.quot] & (1 << pos.rem);
+}
+
+/**
+ * Sign extends the given value, 'n' of width 'width' bits.
+ *
+ * For example, sign extending 0x80 with a width of 8, produces -128
+ */
+static jim_wide JimSignExtend(jim_wide n, int width)
+{
+    if (width == sizeof(jim_wide) * 8) {
+        /* Can't sign extend the maximum size integer */
+        return n;
+    }
+    if (n & ((jim_wide)1 << (width - 1))) {
+        /* Need to extend */
+        n -= ((jim_wide)1 << width);
+    }
+
+    return n;
+}
+
+/**
+ * Big endian integer extraction.
+ *
+ * Considers 'bitvect' as a big endian bit stream.
+ * Returns an integer of the given width (in bits)
+ * starting at the given position (in bits).
+ *
+ * The pos/width must represent bits inside bitvec,
+ * and the width be no more than the width of jim_wide.
+ */
+static jim_wide JimBitIntBigEndian(const unsigned char *bitvec, int pos, int width)
+{
+    jim_wide result = 0;
+    int i;
+
+    /* Aligned, byte extraction */
+    if (pos % 8 == 0 && width % 8 == 0) {
+        for (i = 0; i < width; i += 8) {
+            result = (result << 8) + bitvec[(pos + i) / 8];
+        }
+        return result;
+    }
+
+    /* Unaligned */
+    for (i = 0; i < width; i++) {
+        if (JimTestBitBigEndian(bitvec, pos + width - i - 1)) {
+            result |= ((jim_wide)1 << i);
+        }
+    }
+
+    return result;
+}
+
+/**
+ * Little endian integer extraction.
+ *
+ * Like JimBitIntBigEndian() but considers 'bitvect' as a little endian bit stream.
+ */
+static jim_wide JimBitIntLittleEndian(const unsigned char *bitvec, int pos, int width)
+{
+    jim_wide result = 0;
+    int i;
+
+    /* Aligned, byte extraction */
+    if (pos % 8 == 0 && width % 8 == 0) {
+        for (i = 0; i < width; i += 8) {
+            result += (jim_wide)bitvec[(pos + i) / 8] << i;
+        }
+        return result;
+    }
+
+    /* Unaligned */
+    for (i = 0; i < width; i++) {
+        if (JimTestBitLittleEndian(bitvec, pos + i)) {
+            result |= ((jim_wide)1 << i);
+        }
+    }
+
+    return result;
+}
+
+/**
+ * Big endian bit set.
+ *
+ * Considers 'bitvect' as a big endian bit stream and sets
+ * bit 'b' to 'bit'
+ */
+static void JimSetBitBigEndian(unsigned char *bitvec, int b, int bit)
+{
+    div_t pos = div(b, 8);
+    if (bit) {
+        bitvec[pos.quot] |= (1 << (7 - pos.rem));
+    }
+    else {
+        bitvec[pos.quot] &= ~(1 << (7 - pos.rem));
+    }
+}
+
+/**
+ * Little endian bit set.
+ *
+ * Considers 'bitvect' as a little endian bit stream and sets
+ * bit 'b' to 'bit'
+ */
+static void JimSetBitLittleEndian(unsigned char *bitvec, int b, int bit)
+{
+    div_t pos = div(b, 8);
+    if (bit) {
+        bitvec[pos.quot] |= (1 << pos.rem);
+    }
+    else {
+        bitvec[pos.quot] &= ~(1 << pos.rem);
+    }
+}
+
+/**
+ * Big endian integer packing.
+ *
+ * Considers 'bitvect' as a big endian bit stream.
+ * Packs integer 'value' of the given width (in bits)
+ * starting at the given position (in bits).
+ *
+ * The pos/width must represent bits inside bitvec,
+ * and the width be no more than the width of jim_wide.
+ */
+static void JimSetBitsIntBigEndian(unsigned char *bitvec, jim_wide value, int pos, int width)
+{
+    int i;
+
+    /* Common fast option */
+    if (pos % 8 == 0 && width == 8) {
+        bitvec[pos / 8] = value;
+        return;
+    }
+
+    for (i = 0; i < width; i++) {
+        int bit = !!(value & ((jim_wide)1 << i));
+        JimSetBitBigEndian(bitvec, pos + width - i - 1, bit);
+    }
+}
+
+/**
+ * Little endian version of JimSetBitsIntBigEndian()
+ */
+static void JimSetBitsIntLittleEndian(unsigned char *bitvec, jim_wide value, int pos, int width)
+{
+    int i;
+
+    /* Common fast option */
+    if (pos % 8 == 0 && width == 8) {
+        bitvec[pos / 8] = value;
+        return;
+    }
+
+    for (i = 0; i < width; i++) {
+        int bit = !!(value & ((jim_wide)1 << i));
+        JimSetBitLittleEndian(bitvec, pos + i, bit);
+    }
+}
+
+/**
+ * [unpack]
+ *
+ * Usage: unpack binvalue -intbe|-intle|-uintbe|-uintle|-str bitpos bitwidth
+ *
+ * Unpacks bits from $binvalue at bit position $bitpos and with $bitwidth.
+ * Interprets the value according to the type and returns it.
+ */
+static int Jim_UnpackCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int option;
+    static const char * const options[] = { "-intbe", "-intle", "-uintbe", "-uintle", "-str", NULL };
+    enum { OPT_INTBE, OPT_INTLE, OPT_UINTBE, OPT_UINTLE, OPT_STR, };
+    jim_wide pos;
+    jim_wide width;
+
+    if (argc != 5) {
+        Jim_WrongNumArgs(interp, 1, argv, "binvalue -intbe|-intle|-uintbe|-uintle|-str bitpos bitwidth");
+        return JIM_ERR;
+    }
+    if (Jim_GetEnum(interp, argv[2], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    if (Jim_GetWide(interp, argv[3], &pos) != JIM_OK) {
+        return JIM_ERR;
+    }
+    if (Jim_GetWide(interp, argv[4], &width) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    if (option == OPT_STR) {
+        int len;
+        const char *str = Jim_GetString(argv[1], &len);
+
+        if (width % 8 || pos % 8) {
+            Jim_SetResultString(interp, "string field is not on a byte boundary", -1);
+            return JIM_ERR;
+        }
+
+        if (pos >= 0 && width > 0 && pos < len * 8) {
+            if (pos + width > len * 8) {
+                width = len * 8 - pos;
+            }
+            Jim_SetResultString(interp, str + pos / 8, width / 8);
+        }
+        return JIM_OK;
+    }
+    else {
+        int len;
+        const unsigned char *str = (const unsigned char *)Jim_GetString(argv[1], &len);
+        jim_wide result = 0;
+
+        if (width > sizeof(jim_wide) * 8) {
+            Jim_SetResultFormatted(interp, "int field is too wide: %#s", argv[4]);
+            return JIM_ERR;
+        }
+
+        if (pos >= 0 && width > 0 && pos < len * 8) {
+            if (pos + width > len * 8) {
+                width = len * 8 - pos;
+            }
+            if (option == OPT_INTBE || option == OPT_UINTBE) {
+                result = JimBitIntBigEndian(str, pos, width);
+            }
+            else {
+                result = JimBitIntLittleEndian(str, pos, width);
+            }
+            if (option == OPT_INTBE || option == OPT_INTLE) {
+                result = JimSignExtend(result, width);
+            }
+        }
+        Jim_SetResultInt(interp, result);
+        return JIM_OK;
+    }
+}
+
+/**
+ * [pack]
+ *
+ * Usage: pack varname value -intle|-intbe|-str width ?bitoffset?
+ *
+ * Packs the binary representation of 'value' into the variable of the given name.
+ * The value is packed according to the given type, width and bitoffset.
+ * The variable is created if necessary (like [append])
+ * Ihe variable is expanded if necessary
+ */
+static int Jim_PackCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int option;
+    static const char * const options[] = { "-intle", "-intbe", "-str", NULL };
+    enum { OPT_LE, OPT_BE, OPT_STR };
+    jim_wide pos = 0;
+    jim_wide width;
+    jim_wide value;
+    Jim_Obj *stringObjPtr;
+    int len;
+    int freeobj = 0;
+
+    if (argc != 5 && argc != 6) {
+        Jim_WrongNumArgs(interp, 1, argv, "varName value -intle|-intbe|-str bitwidth ?bitoffset?");
+        return JIM_ERR;
+    }
+    if (Jim_GetEnum(interp, argv[3], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+        return JIM_ERR;
+    }
+    if (option != OPT_STR && Jim_GetWide(interp, argv[2], &value) != JIM_OK) {
+        return JIM_ERR;
+    }
+    if (Jim_GetWide(interp, argv[4], &width) != JIM_OK) {
+        return JIM_ERR;
+    }
+    if (width <= 0 || (option == OPT_STR && width % 8) || (option != OPT_STR && width > sizeof(jim_wide) * 8)) {
+        Jim_SetResultFormatted(interp, "bad bitwidth: %#s", argv[5]);
+        return JIM_ERR;
+    }
+    if (argc == 6) {
+        if (Jim_GetWide(interp, argv[5], &pos) != JIM_OK) {
+            return JIM_ERR;
+        }
+        if (pos < 0 || (option == OPT_STR && pos % 8)) {
+            Jim_SetResultFormatted(interp, "bad bitoffset: %#s", argv[5]);
+            return JIM_ERR;
+        }
+    }
+
+    stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
+    if (!stringObjPtr) {
+        /* Create the string if it doesn't exist */
+        stringObjPtr = Jim_NewEmptyStringObj(interp);
+        freeobj = 1;
+    }
+    else if (Jim_IsShared(stringObjPtr)) {
+        freeobj = 1;
+        stringObjPtr = Jim_DuplicateObj(interp, stringObjPtr);
+    }
+
+    len = Jim_Length(stringObjPtr) * 8;
+
+    /* Extend the string as necessary first */
+    while (len < pos + width) {
+        Jim_AppendString(interp, stringObjPtr, "", 1);
+        len += 8;
+    }
+
+    Jim_SetResultInt(interp, pos + width);
+
+    /* Now set the bits. Note that the the string *must* have no non-string rep
+     * since we are writing the bytes directly.
+     */
+    Jim_AppendString(interp, stringObjPtr, "", 0);
+
+    if (option == OPT_BE) {
+        JimSetBitsIntBigEndian((unsigned char *)stringObjPtr->bytes, value, pos, width);
+    }
+    else if (option == OPT_LE) {
+        JimSetBitsIntLittleEndian((unsigned char *)stringObjPtr->bytes, value, pos, width);
+    }
+    else {
+        pos /= 8;
+        width /= 8;
+
+        if (width > Jim_Length(argv[2])) {
+            width = Jim_Length(argv[2]);
+        }
+        memcpy(stringObjPtr->bytes + pos, Jim_GetString(argv[2], NULL), width);
+        /* No padding is needed since the string is already extended */
+    }
+
+    if (Jim_SetVariable(interp, argv[1], stringObjPtr) != JIM_OK) {
+        if (freeobj) {
+            Jim_FreeNewObj(interp, stringObjPtr);
+            return JIM_ERR;
+        }
+    }
+    return JIM_OK;
+}
+
+int Jim_packInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "pack", "1.0", JIM_ERRMSG)) {
+        return JIM_ERR;
+    }
+
+    Jim_CreateCommand(interp, "unpack", Jim_UnpackCmd, NULL, NULL);
+    Jim_CreateCommand(interp, "pack", Jim_PackCmd, NULL, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-package.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-package.c
new file mode 100755
index 0000000..9caec0d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-package.c
@@ -0,0 +1,259 @@
+#include <unistd.h>
+#include <string.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "jim-subcmd.h"
+
+/* -----------------------------------------------------------------------------
+ * Packages handling
+ * ---------------------------------------------------------------------------*/
+
+int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
+{
+    /* If the package was already provided returns an error. */
+    Jim_HashEntry *he = Jim_FindHashEntry(&interp->packages, name);
+
+    /* An empty result means the automatic entry. This can be replaced */
+    if (he && *(const char *)he->u.val) {
+        if (flags & JIM_ERRMSG) {
+            Jim_SetResultFormatted(interp, "package \"%s\" was already provided", name);
+        }
+        return JIM_ERR;
+    }
+    if (he) {
+        Jim_DeleteHashEntry(&interp->packages, name);
+    }
+    Jim_AddHashEntry(&interp->packages, name, (char *)ver);
+    return JIM_OK;
+}
+
+static char *JimFindPackage(Jim_Interp *interp, char **prefixes, int prefixc, const char *pkgName)
+{
+    int i;
+    char *buf = Jim_Alloc(JIM_PATH_LEN);
+
+    for (i = 0; i < prefixc; i++) {
+        if (prefixes[i] == NULL)
+            continue;
+
+        /* Loadable modules are tried first */
+#ifdef jim_ext_load
+        snprintf(buf, JIM_PATH_LEN, "%s/%s.so", prefixes[i], pkgName);
+        if (access(buf, R_OK) == 0) {
+            return buf;
+        }
+#endif
+        if (strcmp(prefixes[i], ".") == 0) {
+            snprintf(buf, JIM_PATH_LEN, "%s.tcl", pkgName);
+        }
+        else {
+            snprintf(buf, JIM_PATH_LEN, "%s/%s.tcl", prefixes[i], pkgName);
+        }
+
+        if (access(buf, R_OK) == 0) {
+            return buf;
+        }
+    }
+    Jim_Free(buf);
+    return NULL;
+}
+
+/* Search for a suitable package under every dir specified by JIM_LIBPATH,
+ * and load it if possible. If a suitable package was loaded with success
+ * JIM_OK is returned, otherwise JIM_ERR is returned. */
+static int JimLoadPackage(Jim_Interp *interp, const char *name, int flags)
+{
+    Jim_Obj *libPathObjPtr;
+    char **prefixes, *path;
+    int prefixc, i, retCode = JIM_ERR;
+
+    libPathObjPtr = Jim_GetGlobalVariableStr(interp, JIM_LIBPATH, JIM_NONE);
+    if (libPathObjPtr == NULL) {
+        prefixc = 0;
+        libPathObjPtr = NULL;
+    }
+    else {
+        Jim_IncrRefCount(libPathObjPtr);
+        prefixc = Jim_ListLength(interp, libPathObjPtr);
+    }
+
+    prefixes = Jim_Alloc(sizeof(char *) * prefixc);
+    for (i = 0; i < prefixc; i++) {
+        Jim_Obj *prefixObjPtr;
+
+        if (Jim_ListIndex(interp, libPathObjPtr, i, &prefixObjPtr, JIM_NONE) != JIM_OK) {
+            prefixes[i] = NULL;
+            continue;
+        }
+        prefixes[i] = Jim_StrDup(Jim_String(prefixObjPtr));
+    }
+
+    /* Scan every directory for the the first match */
+    path = JimFindPackage(interp, prefixes, prefixc, name);
+    if (path != NULL) {
+        char *p = strrchr(path, '.');
+
+        /* Note: Even if the file fails to load, we consider the package loaded.
+         *       This prevents issues with recursion.
+         *       Use a dummy version of "" to signify this case.
+         */
+        Jim_PackageProvide(interp, name, "", 0);
+
+        /* Try to load/source it */
+        if (p && strcmp(p, ".tcl") == 0) {
+            retCode = Jim_EvalFileGlobal(interp, path);
+        }
+#ifdef jim_ext_load
+        else {
+            retCode = Jim_LoadLibrary(interp, path);
+        }
+#endif
+        if (retCode != JIM_OK) {
+            /* Upon failure, remove the dummy entry */
+            Jim_DeleteHashEntry(&interp->packages, name);
+        }
+        Jim_Free(path);
+    }
+    for (i = 0; i < prefixc; i++)
+        Jim_Free(prefixes[i]);
+    Jim_Free(prefixes);
+    if (libPathObjPtr)
+        Jim_DecrRefCount(interp, libPathObjPtr);
+    return retCode;
+}
+
+int Jim_PackageRequire(Jim_Interp *interp, const char *name, int flags)
+{
+    Jim_HashEntry *he;
+
+    /* Start with an empty error string */
+    Jim_SetResultString(interp, "", 0);
+
+    he = Jim_FindHashEntry(&interp->packages, name);
+    if (he == NULL) {
+        /* Try to load the package. */
+        int retcode = JimLoadPackage(interp, name, flags);
+        if (retcode != JIM_OK) {
+            if (flags & JIM_ERRMSG) {
+                int len;
+
+                Jim_GetString(Jim_GetResult(interp), &len);
+                Jim_SetResultFormatted(interp, "%#s%sCan't load package %s",
+                    Jim_GetResult(interp), len ? "\n" : "", name);
+            }
+            return retcode;
+        }
+
+        /* In case the package did no 'package provide' */
+        Jim_PackageProvide(interp, name, "1.0", 0);
+
+        /* Now it must exist */
+        he = Jim_FindHashEntry(&interp->packages, name);
+    }
+
+    Jim_SetResultString(interp, he->u.val, -1);
+    return JIM_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * package provide name ?version?
+ *
+ *      This procedure is invoked to declare that a particular version
+ *      of a particular package is now present in an interpreter.  There
+ *      must not be any other version of this package already
+ *      provided in the interpreter.
+ *
+ * Results:
+ *      Returns JIM_OK and sets the package version (or 1.0 if not specified).
+ *
+ *----------------------------------------------------------------------
+ */
+static int package_cmd_provide(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *version = "1.0";
+
+    if (argc == 2) {
+        version = Jim_String(argv[1]);
+    }
+    return Jim_PackageProvide(interp, Jim_String(argv[0]), version, JIM_ERRMSG);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * package require name ?version?
+ *
+ *      This procedure is load a given package.
+ *      Note that the version is ignored.
+ *
+ * Results:
+ *      Returns JIM_OK and sets the package version.
+ *
+ *----------------------------------------------------------------------
+ */
+static int package_cmd_require(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    /* package require failing is important enough to add to the stack */
+    interp->addStackTrace++;
+
+    return Jim_PackageRequire(interp, Jim_String(argv[0]), JIM_ERRMSG);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * package list
+ *
+ *      Returns a list of known packages
+ *
+ * Results:
+ *      Returns JIM_OK and sets a list of known packages.
+ *
+ *----------------------------------------------------------------------
+ */
+static int package_cmd_list(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_HashTableIterator *htiter;
+    Jim_HashEntry *he;
+    Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+    htiter = Jim_GetHashTableIterator(&interp->packages);
+    while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+        Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, he->key, -1));
+    }
+    Jim_FreeHashTableIterator(htiter);
+
+    Jim_SetResult(interp, listObjPtr);
+
+    return JIM_OK;
+}
+
+static const jim_subcmd_type package_command_table[] = {
+    {.cmd = "provide",
+            .args = "name ?version?",
+            .function = package_cmd_provide,
+            .minargs = 1,
+            .maxargs = 2,
+        .description = "Indicates that the current script provides the given package"},
+    {.cmd = "require",
+            .args = "name ?version?",
+            .function = package_cmd_require,
+            .minargs = 1,
+            .maxargs = 2,
+        .description = "Loads the given package by looking in standard places"},
+    {.cmd = "list",
+            .function = package_cmd_list,
+            .minargs = 0,
+            .maxargs = 0,
+        .description = "Lists all known packages"},
+    {0}
+};
+
+int Jim_packageInit(Jim_Interp *interp)
+{
+    Jim_CreateCommand(interp, "package", Jim_SubCmdProc, (void *)package_command_table, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-posix.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-posix.c
new file mode 100755
index 0000000..0cf3604
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-posix.c
@@ -0,0 +1,231 @@
+
+/* Jim - POSIX extension
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ *
+ * 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
+ *
+ * A copy of the license is also included in the source distribution
+ * of Jim, as a TXT file name called LICENSE.
+ *
+ * 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 <sys/types.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+
+#ifdef HAVE_SYS_SYSINFO_H
+#include <sys/sysinfo.h>
+#endif
+
+static void Jim_PosixSetError(Jim_Interp *interp)
+{
+    Jim_SetResultString(interp, strerror(errno), -1);
+}
+
+#if defined(HAVE_FORK)
+static int Jim_PosixForkCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    pid_t pid;
+
+    JIM_NOTUSED(argv);
+
+    if (argc != 1) {
+        Jim_WrongNumArgs(interp, 1, argv, "");
+        return JIM_ERR;
+    }
+    if ((pid = fork()) == -1) {
+        Jim_PosixSetError(interp);
+        return JIM_ERR;
+    }
+    Jim_SetResultInt(interp, (jim_wide) pid);
+    return JIM_OK;
+}
+#endif
+
+/*
+ * os.wait ?-nohang? pid
+ *
+ * An interface to waitpid(2)
+ *
+ * Returns a 3 element list.
+ *
+ * If -nohang is specified, and the process is still alive, returns
+ *
+ *   {0 none 0}
+ *
+ * If the process does not exist or has already been waited for, returns:
+ *
+ *   {-1 error <error-description>}
+ *
+ * If the process exited normally, returns:
+ *
+ *   {<pid> exit <exit-status>}
+ *
+ * If the process terminated on a signal, returns:
+ *
+ *   {<pid> signal <signal-number>}
+ *
+ * Otherwise (core dump, stopped, continued, ...), returns:
+ *
+ *   {<pid> other 0}
+ */
+static int Jim_PosixWaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int nohang = 0;
+    long pid;
+    int status;
+    Jim_Obj *listObj;
+    const char *type;
+    int value;
+
+    if (argc > 1 && Jim_CompareStringImmediate(interp, argv[1], "-nohang")) {
+        nohang = 1;
+    }
+    if (argc != nohang + 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "?-nohang? pid");
+        return JIM_ERR;
+    }
+    if (Jim_GetLong(interp, argv[nohang + 1], &pid) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    pid = waitpid(pid, &status, nohang ? WNOHANG : 0);
+    listObj = Jim_NewListObj(interp, NULL, 0);
+    Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, pid));
+    if (pid < 0) {
+        type = "error";
+        value = errno;
+    }
+    else if (pid == 0) {
+        type = "none";
+        value = 0;
+    }
+    else if (WIFEXITED(status)) {
+        type = "exit";
+        value = WEXITSTATUS(status);
+    }
+    else if (WIFSIGNALED(status)) {
+        type = "signal";
+        value = WTERMSIG(status);
+    }
+    else {
+        type = "other";
+        value = 0;
+    }
+
+    Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, type, -1));
+    if (pid < 0) {
+        Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, strerror(value), -1));
+    }
+    else {
+        Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value));
+    }
+    Jim_SetResult(interp, listObj);
+    return JIM_OK;
+}
+
+static int Jim_PosixGetidsCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objv[8];
+
+    if (argc != 1) {
+        Jim_WrongNumArgs(interp, 1, argv, "");
+        return JIM_ERR;
+    }
+    objv[0] = Jim_NewStringObj(interp, "uid", -1);
+    objv[1] = Jim_NewIntObj(interp, getuid());
+    objv[2] = Jim_NewStringObj(interp, "euid", -1);
+    objv[3] = Jim_NewIntObj(interp, geteuid());
+    objv[4] = Jim_NewStringObj(interp, "gid", -1);
+    objv[5] = Jim_NewIntObj(interp, getgid());
+    objv[6] = Jim_NewStringObj(interp, "egid", -1);
+    objv[7] = Jim_NewIntObj(interp, getegid());
+    Jim_SetResult(interp, Jim_NewListObj(interp, objv, 8));
+    return JIM_OK;
+}
+
+#define JIM_HOST_NAME_MAX 1024
+static int Jim_PosixGethostnameCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    char *buf;
+    int rc = JIM_OK;
+
+    if (argc != 1) {
+        Jim_WrongNumArgs(interp, 1, argv, "");
+        return JIM_ERR;
+    }
+    buf = Jim_Alloc(JIM_HOST_NAME_MAX);
+    if (gethostname(buf, JIM_HOST_NAME_MAX) == -1) {
+        Jim_PosixSetError(interp);
+        rc = JIM_ERR;
+    }
+    else {
+        Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, -1));
+    }
+    return rc;
+}
+
+static int Jim_PosixUptimeCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+#ifdef HAVE_STRUCT_SYSINFO_UPTIME
+    struct sysinfo info;
+
+    if (argc != 1) {
+        Jim_WrongNumArgs(interp, 1, argv, "");
+        return JIM_ERR;
+    }
+
+    if (sysinfo(&info) == -1) {
+        Jim_PosixSetError(interp);
+        return JIM_ERR;
+    }
+
+    Jim_SetResultInt(interp, info.uptime);
+#else
+    Jim_SetResultInt(interp, (long)time(NULL));
+#endif
+    return JIM_OK;
+}
+
+static int Jim_PosixPidCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 1) {
+        Jim_WrongNumArgs(interp, 1, argv, "");
+        return JIM_ERR;
+    }
+
+    Jim_SetResultInt(interp, getpid());
+    return JIM_OK;
+}
+
+int Jim_posixInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "posix", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+#ifdef HAVE_FORK
+    Jim_CreateCommand(interp, "os.fork", Jim_PosixForkCommand, NULL, NULL);
+#endif
+    Jim_CreateCommand(interp, "os.wait", Jim_PosixWaitCommand, NULL, NULL);
+    Jim_CreateCommand(interp, "os.getids", Jim_PosixGetidsCommand, NULL, NULL);
+    Jim_CreateCommand(interp, "os.gethostname", Jim_PosixGethostnameCommand, NULL, NULL);
+    Jim_CreateCommand(interp, "os.uptime", Jim_PosixUptimeCommand, NULL, NULL);
+    Jim_CreateCommand(interp, "pid", Jim_PosixPidCommand, NULL, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-readdir.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-readdir.c
new file mode 100755
index 0000000..67fc956
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-readdir.c
@@ -0,0 +1,119 @@
+
+/*
+ * Tcl readdir command.
+ *
+ * (c) 2008 Steve Bennett <steveb@worware.net.au>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ *
+ * Based on original work by:
+ *-----------------------------------------------------------------------------
+ * Copyright 1991-1994 Karl Lehenbauer and Mark Diekhans.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies.  Karl Lehenbauer and
+ * Mark Diekhans make no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or
+ * implied warranty.
+ *-----------------------------------------------------------------------------
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Jim_ReaddirCmd --
+ *     Implements the rename TCL command:
+ *         readdir ?-nocomplain? dirPath
+ *
+ * Results:
+ *      Standard TCL result.
+ *-----------------------------------------------------------------------------
+ */
+int Jim_ReaddirCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *dirPath;
+    DIR *dirPtr;
+    struct dirent *entryPtr;
+    int nocomplain = 0;
+
+    if (argc == 3 && Jim_CompareStringImmediate(interp, argv[1], "-nocomplain")) {
+        nocomplain = 1;
+    }
+    if (argc != 2 && !nocomplain) {
+        Jim_WrongNumArgs(interp, 1, argv, "?-nocomplain? dirPath");
+        return JIM_ERR;
+    }
+
+    dirPath = Jim_String(argv[1 + nocomplain]);
+
+    dirPtr = opendir(dirPath);
+    if (dirPtr == NULL) {
+        if (nocomplain) {
+            return JIM_OK;
+        }
+        Jim_SetResultString(interp, strerror(errno), -1);
+        return JIM_ERR;
+    }
+    Jim_SetResultString(interp, strerror(errno), -1);
+
+    Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
+
+    while ((entryPtr = readdir(dirPtr)) != NULL) {
+        if (entryPtr->d_name[0] == '.') {
+            if (entryPtr->d_name[1] == '\0') {
+                continue;
+            }
+            if ((entryPtr->d_name[1] == '.') && (entryPtr->d_name[2] == '\0'))
+                continue;
+        }
+        Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp,
+                entryPtr->d_name, -1));
+    }
+    closedir(dirPtr);
+
+    return JIM_OK;
+}
+
+int Jim_readdirInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "readdir", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    Jim_CreateCommand(interp, "readdir", Jim_ReaddirCmd, NULL, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-readline.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-readline.c
new file mode 100755
index 0000000..3990d0c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-readline.c
@@ -0,0 +1,61 @@
+
+/* Jim - Readline bindings for Jim
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ *
+ * 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
+ *
+ * A copy of the license is also included in the source distribution
+ * of Jim, as a TXT file name called LICENSE.
+ *
+ * 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 "jim.h"
+#include "jimautoconf.h"
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+static int JimRlReadlineCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    char *line;
+
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "prompt");
+        return JIM_ERR;
+    }
+    line = readline(Jim_String(argv[1]));
+    if (!line) {
+        return JIM_EXIT;
+    }
+    Jim_SetResult(interp, Jim_NewStringObj(interp, line, -1));
+    return JIM_OK;
+}
+
+static int JimRlAddHistoryCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "string");
+        return JIM_ERR;
+    }
+    add_history(Jim_String(argv[1]));
+    return JIM_OK;
+}
+
+int Jim_readlineInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "readline", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    Jim_CreateCommand(interp, "readline.readline", JimRlReadlineCommand, NULL, NULL);
+    Jim_CreateCommand(interp, "readline.addhistory", JimRlAddHistoryCommand, NULL, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-regexp.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-regexp.c
new file mode 100755
index 0000000..2ccd996
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-regexp.c
@@ -0,0 +1,566 @@
+/*
+ * Implements the regexp and regsub commands for Jim
+ *
+ * (c) 2008 Steve Bennett <steveb@workware.net.au>
+ *
+ * Uses C library regcomp()/regexec() for the matching.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ *
+ * Based on code originally from Tcl 6.7:
+ *
+ * Copyright 1987-1991 Regents of the University of California
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies.  The University of California
+ * makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "jimregexp.h"
+
+static void FreeRegexpInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    regfree(objPtr->internalRep.regexpValue.compre);
+    Jim_Free(objPtr->internalRep.regexpValue.compre);
+}
+
+static const Jim_ObjType regexpObjType = {
+    "regexp",
+    FreeRegexpInternalRep,
+    NULL,
+    NULL,
+    JIM_TYPE_NONE
+};
+
+static regex_t *SetRegexpFromAny(Jim_Interp *interp, Jim_Obj *objPtr, unsigned flags)
+{
+    regex_t *compre;
+    const char *pattern;
+    int ret;
+
+    /* Check if the object is already an uptodate variable */
+    if (objPtr->typePtr == &regexpObjType &&
+        objPtr->internalRep.regexpValue.compre && objPtr->internalRep.regexpValue.flags == flags) {
+        /* nothing to do */
+        return objPtr->internalRep.regexpValue.compre;
+    }
+
+    /* Not a regexp or the flags do not match */
+
+    /* Get the string representation */
+    pattern = Jim_String(objPtr);
+    compre = Jim_Alloc(sizeof(regex_t));
+
+    if ((ret = regcomp(compre, pattern, REG_EXTENDED | flags)) != 0) {
+        char buf[100];
+
+        regerror(ret, compre, buf, sizeof(buf));
+        Jim_SetResultFormatted(interp, "couldn't compile regular expression pattern: %s", buf);
+        regfree(compre);
+        Jim_Free(compre);
+        return NULL;
+    }
+
+    Jim_FreeIntRep(interp, objPtr);
+
+    objPtr->typePtr = &regexpObjType;
+    objPtr->internalRep.regexpValue.flags = flags;
+    objPtr->internalRep.regexpValue.compre = compre;
+
+    return compre;
+}
+
+int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int opt_indices = 0;
+    int opt_all = 0;
+    int opt_inline = 0;
+    regex_t *regex;
+    int match, i, j;
+    int offset = 0;
+    regmatch_t *pmatch = NULL;
+    int source_len;
+    int result = JIM_OK;
+    const char *pattern;
+    const char *source_str;
+    int num_matches = 0;
+    int num_vars;
+    Jim_Obj *resultListObj = NULL;
+    int regcomp_flags = 0;
+    int eflags = 0;
+    int option;
+    enum {
+        OPT_INDICES,  OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_INLINE, OPT_START, OPT_END
+    };
+    static const char * const options[] = {
+        "-indices", "-nocase", "-line", "-all", "-inline", "-start", "--", NULL
+    };
+
+    if (argc < 3) {
+      wrongNumArgs:
+        Jim_WrongNumArgs(interp, 1, argv,
+            "?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?");
+        return JIM_ERR;
+    }
+
+    for (i = 1; i < argc; i++) {
+        const char *opt = Jim_String(argv[i]);
+
+        if (*opt != '-') {
+            break;
+        }
+        if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+            return JIM_ERR;
+        }
+        if (option == OPT_END) {
+            i++;
+            break;
+        }
+        switch (option) {
+            case OPT_INDICES:
+                opt_indices = 1;
+                break;
+
+            case OPT_NOCASE:
+                regcomp_flags |= REG_ICASE;
+                break;
+
+            case OPT_LINE:
+                regcomp_flags |= REG_NEWLINE;
+                break;
+
+            case OPT_ALL:
+                opt_all = 1;
+                break;
+
+            case OPT_INLINE:
+                opt_inline = 1;
+                break;
+
+            case OPT_START:
+                if (++i == argc) {
+                    goto wrongNumArgs;
+                }
+                if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
+                    return JIM_ERR;
+                }
+                break;
+        }
+    }
+    if (argc - i < 2) {
+        goto wrongNumArgs;
+    }
+
+    regex = SetRegexpFromAny(interp, argv[i], regcomp_flags);
+    if (!regex) {
+        return JIM_ERR;
+    }
+
+    pattern = Jim_String(argv[i]);
+    source_str = Jim_GetString(argv[i + 1], &source_len);
+
+    num_vars = argc - i - 2;
+
+    if (opt_inline) {
+        if (num_vars) {
+            Jim_SetResultString(interp, "regexp match variables not allowed when using -inline",
+                -1);
+            result = JIM_ERR;
+            goto done;
+        }
+        num_vars = regex->re_nsub + 1;
+    }
+
+    pmatch = Jim_Alloc((num_vars + 1) * sizeof(*pmatch));
+
+    /* If an offset has been specified, adjust for that now.
+     * If it points past the end of the string, point to the terminating null
+     */
+    if (offset) {
+        if (offset < 0) {
+            offset += source_len + 1;
+        }
+        if (offset > source_len) {
+            source_str += source_len;
+        }
+        else if (offset > 0) {
+            source_str += offset;
+        }
+        eflags |= REG_NOTBOL;
+    }
+
+    if (opt_inline) {
+        resultListObj = Jim_NewListObj(interp, NULL, 0);
+    }
+
+  next_match:
+    match = regexec(regex, source_str, num_vars + 1, pmatch, eflags);
+    if (match >= REG_BADPAT) {
+        char buf[100];
+
+        regerror(match, regex, buf, sizeof(buf));
+        Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
+        result = JIM_ERR;
+        goto done;
+    }
+
+    if (match == REG_NOMATCH) {
+        goto done;
+    }
+
+    num_matches++;
+
+    if (opt_all && !opt_inline) {
+        /* Just count the number of matches, so skip the substitution h */
+        goto try_next_match;
+    }
+
+    /*
+     * If additional variable names have been specified, return
+     * index information in those variables.
+     */
+
+    j = 0;
+    for (i += 2; opt_inline ? j < num_vars : i < argc; i++, j++) {
+        Jim_Obj *resultObj;
+
+        if (opt_indices) {
+            resultObj = Jim_NewListObj(interp, NULL, 0);
+        }
+        else {
+            resultObj = Jim_NewStringObj(interp, "", 0);
+        }
+
+        if (pmatch[j].rm_so == -1) {
+            if (opt_indices) {
+                Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1));
+                Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1));
+            }
+        }
+        else {
+            int len = pmatch[j].rm_eo - pmatch[j].rm_so;
+
+            if (opt_indices) {
+                Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp,
+                        offset + pmatch[j].rm_so));
+                Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp,
+                        offset + pmatch[j].rm_so + len - 1));
+            }
+            else {
+                Jim_AppendString(interp, resultObj, source_str + pmatch[j].rm_so, len);
+            }
+        }
+
+        if (opt_inline) {
+            Jim_ListAppendElement(interp, resultListObj, resultObj);
+        }
+        else {
+            /* And now set the result variable */
+            result = Jim_SetVariable(interp, argv[i], resultObj);
+
+            if (result != JIM_OK) {
+                Jim_FreeObj(interp, resultObj);
+                break;
+            }
+        }
+    }
+
+  try_next_match:
+    if (opt_all && (pattern[0] != '^' || (regcomp_flags & REG_NEWLINE)) && *source_str) {
+        if (pmatch[0].rm_eo) {
+            offset += pmatch[0].rm_eo;
+            source_str += pmatch[0].rm_eo;
+        }
+        else {
+            source_str++;
+            offset++;
+        }
+        if (*source_str) {
+            eflags = REG_NOTBOL;
+            goto next_match;
+        }
+    }
+
+  done:
+    if (result == JIM_OK) {
+        if (opt_inline) {
+            Jim_SetResult(interp, resultListObj);
+        }
+        else {
+            Jim_SetResultInt(interp, num_matches);
+        }
+    }
+
+    Jim_Free(pmatch);
+    return result;
+}
+
+#define MAX_SUB_MATCHES 50
+
+int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int regcomp_flags = 0;
+    int regexec_flags = 0;
+    int opt_all = 0;
+    int offset = 0;
+    regex_t *regex;
+    const char *p;
+    int result;
+    regmatch_t pmatch[MAX_SUB_MATCHES + 1];
+    int num_matches = 0;
+
+    int i, j, n;
+    Jim_Obj *varname;
+    Jim_Obj *resultObj;
+    const char *source_str;
+    int source_len;
+    const char *replace_str;
+    int replace_len;
+    const char *pattern;
+    int option;
+    enum {
+        OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_START, OPT_END
+    };
+    static const char * const options[] = {
+        "-nocase", "-line", "-all", "-start", "--", NULL
+    };
+
+    if (argc < 4) {
+      wrongNumArgs:
+        Jim_WrongNumArgs(interp, 1, argv,
+            "?switches? exp string subSpec ?varName?");
+        return JIM_ERR;
+    }
+
+    for (i = 1; i < argc; i++) {
+        const char *opt = Jim_String(argv[i]);
+
+        if (*opt != '-') {
+            break;
+        }
+        if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+            return JIM_ERR;
+        }
+        if (option == OPT_END) {
+            i++;
+            break;
+        }
+        switch (option) {
+            case OPT_NOCASE:
+                regcomp_flags |= REG_ICASE;
+                break;
+
+            case OPT_LINE:
+                regcomp_flags |= REG_NEWLINE;
+                break;
+
+            case OPT_ALL:
+                opt_all = 1;
+                break;
+
+            case OPT_START:
+                if (++i == argc) {
+                    goto wrongNumArgs;
+                }
+                if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
+                    return JIM_ERR;
+                }
+                break;
+        }
+    }
+    if (argc - i != 3 && argc - i != 4) {
+        goto wrongNumArgs;
+    }
+
+    regex = SetRegexpFromAny(interp, argv[i], regcomp_flags);
+    if (!regex) {
+        return JIM_ERR;
+    }
+    pattern = Jim_String(argv[i]);
+
+    source_str = Jim_GetString(argv[i + 1], &source_len);
+    replace_str = Jim_GetString(argv[i + 2], &replace_len);
+    varname = argv[i + 3];
+
+    /* Create the result string */
+    resultObj = Jim_NewStringObj(interp, "", 0);
+
+    /* If an offset has been specified, adjust for that now.
+     * If it points past the end of the string, point to the terminating null
+     */
+    if (offset) {
+        if (offset < 0) {
+            offset += source_len + 1;
+        }
+        if (offset > source_len) {
+            offset = source_len;
+        }
+        else if (offset < 0) {
+            offset = 0;
+        }
+    }
+
+    /* Copy the part before -start */
+    Jim_AppendString(interp, resultObj, source_str, offset);
+
+    /*
+     * The following loop is to handle multiple matches within the
+     * same source string;  each iteration handles one match and its
+     * corresponding substitution.  If "-all" hasn't been specified
+     * then the loop body only gets executed once.
+     */
+
+    n = source_len - offset;
+    p = source_str + offset;
+    do {
+        int match = regexec(regex, p, MAX_SUB_MATCHES, pmatch, regexec_flags);
+
+        if (match >= REG_BADPAT) {
+            char buf[100];
+
+            regerror(match, regex, buf, sizeof(buf));
+            Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
+            return JIM_ERR;
+        }
+        if (match == REG_NOMATCH) {
+            break;
+        }
+
+        num_matches++;
+
+        /*
+         * Copy the portion of the source string before the match to the
+         * result variable.
+         */
+        Jim_AppendString(interp, resultObj, p, pmatch[0].rm_so);
+
+        /*
+         * Append the subSpec (replace_str) argument to the variable, making appropriate
+         * substitutions.  This code is a bit hairy because of the backslash
+         * conventions and because the code saves up ranges of characters in
+         * subSpec to reduce the number of calls to Jim_SetVar.
+         */
+
+        for (j = 0; j < replace_len; j++) {
+            int idx;
+            int c = replace_str[j];
+
+            if (c == '&') {
+                idx = 0;
+            }
+            else if (c == '\\' && j < replace_len) {
+                c = replace_str[++j];
+                if ((c >= '0') && (c <= '9')) {
+                    idx = c - '0';
+                }
+                else if ((c == '\\') || (c == '&')) {
+                    Jim_AppendString(interp, resultObj, replace_str + j, 1);
+                    continue;
+                }
+                else {
+                    Jim_AppendString(interp, resultObj, replace_str + j - 1, 2);
+                    continue;
+                }
+            }
+            else {
+                Jim_AppendString(interp, resultObj, replace_str + j, 1);
+                continue;
+            }
+            if ((idx < MAX_SUB_MATCHES) && pmatch[idx].rm_so != -1 && pmatch[idx].rm_eo != -1) {
+                Jim_AppendString(interp, resultObj, p + pmatch[idx].rm_so,
+                    pmatch[idx].rm_eo - pmatch[idx].rm_so);
+            }
+        }
+
+        p += pmatch[0].rm_eo;
+        n -= pmatch[0].rm_eo;
+
+        /* If -all is not specified, or there is no source left, we are done */
+        if (!opt_all || n == 0) {
+            break;
+        }
+
+        /* An anchored pattern without -line must be done */
+        if ((regcomp_flags & REG_NEWLINE) == 0 && pattern[0] == '^') {
+            break;
+        }
+
+        /* If the pattern is empty, need to step forwards */
+        if (pattern[0] == '\0' && n) {
+            /* Need to copy the char we are moving over */
+            Jim_AppendString(interp, resultObj, p, 1);
+            p++;
+            n--;
+        }
+
+        regexec_flags |= REG_NOTBOL;
+    } while (n);
+
+    /*
+     * Copy the portion of the string after the last match to the
+     * result variable.
+     */
+    Jim_AppendString(interp, resultObj, p, -1);
+
+    /* And now set or return the result variable */
+    if (argc - i == 4) {
+        result = Jim_SetVariable(interp, varname, resultObj);
+
+        if (result == JIM_OK) {
+            Jim_SetResultInt(interp, num_matches);
+        }
+        else {
+            Jim_FreeObj(interp, resultObj);
+        }
+    }
+    else {
+        Jim_SetResult(interp, resultObj);
+        result = JIM_OK;
+    }
+
+    return result;
+}
+
+int Jim_regexpInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "regexp", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    Jim_CreateCommand(interp, "regexp", Jim_RegexpCmd, NULL, NULL);
+    Jim_CreateCommand(interp, "regsub", Jim_RegsubCmd, NULL, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-sdl.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-sdl.c
new file mode 100755
index 0000000..2e700eb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-sdl.c
@@ -0,0 +1,234 @@
+
+/* Jim - SDL extension
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ *
+ * 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
+ *
+ * A copy of the license is also included in the source distribution
+ * of Jim, as a TXT file name called LICENSE.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <SDL/SDL.h>
+#include <SDL/SDL_gfxPrimitives.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+
+#define AIO_CMD_LEN 128
+
+typedef struct JimSdlSurface
+{
+    SDL_Surface *screen;
+} JimSdlSurface;
+
+static void JimSdlSetError(Jim_Interp *interp)
+{
+    Jim_SetResultString(interp, SDL_GetError(), -1);
+}
+
+static void JimSdlDelProc(Jim_Interp *interp, void *privData)
+{
+    JimSdlSurface *jss = privData;
+
+    JIM_NOTUSED(interp);
+
+    SDL_FreeSurface(jss->screen);
+    Jim_Free(jss);
+}
+
+/* Calls to commands created via [sdl.surface] are implemented by this
+ * C command. */
+static int JimSdlHandlerCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    JimSdlSurface *jss = Jim_CmdPrivData(interp);
+    int option;
+    static const char * const options[] = {
+        "free", "flip", "pixel", "rectangle", "box", "line", "aaline",
+        "circle", "aacircle", "fcircle", NULL
+    };
+    enum
+    { OPT_FREE, OPT_FLIP, OPT_PIXEL, OPT_RECTANGLE, OPT_BOX, OPT_LINE,
+        OPT_AALINE, OPT_CIRCLE, OPT_AACIRCLE, OPT_FCIRCLE
+    };
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "method ?args ...?");
+        return JIM_ERR;
+    }
+    if (Jim_GetEnum(interp, argv[1], options, &option, "SDL surface method", JIM_ERRMSG) != JIM_OK)
+        return JIM_ERR;
+    if (option == OPT_PIXEL) {
+        /* PIXEL */
+        long x, y, red, green, blue, alpha = 255;
+
+        if (argc != 7 && argc != 8) {
+            Jim_WrongNumArgs(interp, 2, argv, "x y red green blue ?alpha?");
+            return JIM_ERR;
+        }
+        if (Jim_GetLong(interp, argv[2], &x) != JIM_OK ||
+            Jim_GetLong(interp, argv[3], &y) != JIM_OK ||
+            Jim_GetLong(interp, argv[4], &red) != JIM_OK ||
+            Jim_GetLong(interp, argv[5], &green) != JIM_OK ||
+            Jim_GetLong(interp, argv[6], &blue) != JIM_OK) {
+            return JIM_ERR;
+        }
+        if (argc == 8 && Jim_GetLong(interp, argv[7], &alpha) != JIM_OK)
+            return JIM_ERR;
+        pixelRGBA(jss->screen, x, y, red, green, blue, alpha);
+        return JIM_OK;
+    }
+    else if (option == OPT_RECTANGLE || option == OPT_BOX ||
+        option == OPT_LINE || option == OPT_AALINE) {
+        /* RECTANGLE, BOX, LINE, AALINE */
+        long x1, y1, x2, y2, red, green, blue, alpha = 255;
+
+        if (argc != 9 && argc != 10) {
+            Jim_WrongNumArgs(interp, 2, argv, "x y red green blue ?alpha?");
+            return JIM_ERR;
+        }
+        if (Jim_GetLong(interp, argv[2], &x1) != JIM_OK ||
+            Jim_GetLong(interp, argv[3], &y1) != JIM_OK ||
+            Jim_GetLong(interp, argv[4], &x2) != JIM_OK ||
+            Jim_GetLong(interp, argv[5], &y2) != JIM_OK ||
+            Jim_GetLong(interp, argv[6], &red) != JIM_OK ||
+            Jim_GetLong(interp, argv[7], &green) != JIM_OK ||
+            Jim_GetLong(interp, argv[8], &blue) != JIM_OK) {
+            return JIM_ERR;
+        }
+        if (argc == 10 && Jim_GetLong(interp, argv[9], &alpha) != JIM_OK)
+            return JIM_ERR;
+        switch (option) {
+            case OPT_RECTANGLE:
+                rectangleRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha);
+                break;
+            case OPT_BOX:
+                boxRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha);
+                break;
+            case OPT_LINE:
+                lineRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha);
+                break;
+            case OPT_AALINE:
+                aalineRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha);
+                break;
+        }
+        return JIM_OK;
+    }
+    else if (option == OPT_CIRCLE || option == OPT_AACIRCLE || option == OPT_FCIRCLE) {
+        /* CIRCLE, AACIRCLE, FCIRCLE */
+        long x, y, radius, red, green, blue, alpha = 255;
+
+        if (argc != 8 && argc != 9) {
+            Jim_WrongNumArgs(interp, 2, argv, "x y radius red green blue ?alpha?");
+            return JIM_ERR;
+        }
+        if (Jim_GetLong(interp, argv[2], &x) != JIM_OK ||
+            Jim_GetLong(interp, argv[3], &y) != JIM_OK ||
+            Jim_GetLong(interp, argv[4], &radius) != JIM_OK ||
+            Jim_GetLong(interp, argv[5], &red) != JIM_OK ||
+            Jim_GetLong(interp, argv[6], &green) != JIM_OK ||
+            Jim_GetLong(interp, argv[7], &blue) != JIM_OK) {
+            return JIM_ERR;
+        }
+        if (argc == 9 && Jim_GetLong(interp, argv[8], &alpha) != JIM_OK)
+            return JIM_ERR;
+        switch (option) {
+            case OPT_CIRCLE:
+                circleRGBA(jss->screen, x, y, radius, red, green, blue, alpha);
+                break;
+            case OPT_AACIRCLE:
+                aacircleRGBA(jss->screen, x, y, radius, red, green, blue, alpha);
+                break;
+            case OPT_FCIRCLE:
+                filledCircleRGBA(jss->screen, x, y, radius, red, green, blue, alpha);
+                break;
+        }
+        return JIM_OK;
+    }
+    else if (option == OPT_FREE) {
+        /* FREE */
+        if (argc != 2) {
+            Jim_WrongNumArgs(interp, 2, argv, "");
+            return JIM_ERR;
+        }
+        Jim_DeleteCommand(interp, Jim_String(argv[0]));
+        return JIM_OK;
+    }
+    else if (option == OPT_FLIP) {
+        /* FLIP */
+        if (argc != 2) {
+            Jim_WrongNumArgs(interp, 2, argv, "");
+            return JIM_ERR;
+        }
+        SDL_Flip(jss->screen);
+        return JIM_OK;
+    }
+    return JIM_OK;
+}
+
+static int JimSdlSurfaceCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    JimSdlSurface *jss;
+    char buf[AIO_CMD_LEN];
+    Jim_Obj *objPtr;
+    long screenId, xres, yres;
+    SDL_Surface *screen;
+
+    if (argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "xres yres");
+        return JIM_ERR;
+    }
+    if (Jim_GetLong(interp, argv[1], &xres) != JIM_OK ||
+        Jim_GetLong(interp, argv[2], &yres) != JIM_OK)
+        return JIM_ERR;
+
+    /* Try to create the surface */
+    screen = SDL_SetVideoMode(xres, yres, 32, SDL_SWSURFACE | SDL_ANYFORMAT);
+    if (screen == NULL) {
+        JimSdlSetError(interp);
+        return JIM_ERR;
+    }
+    /* Get the next file id */
+    if (Jim_EvalGlobal(interp, "if {[catch {incr sdl.surfaceId}]} {set sdl.surfaceId 0}") != JIM_OK)
+        return JIM_ERR;
+    objPtr = Jim_GetVariableStr(interp, "sdl.surfaceId", JIM_ERRMSG);
+    if (objPtr == NULL)
+        return JIM_ERR;
+    if (Jim_GetLong(interp, objPtr, &screenId) != JIM_OK)
+        return JIM_ERR;
+
+    /* Create the SDL screen command */
+    jss = Jim_Alloc(sizeof(*jss));
+    jss->screen = screen;
+    sprintf(buf, "sdl.surface%ld", screenId);
+    Jim_CreateCommand(interp, buf, JimSdlHandlerCommand, jss, JimSdlDelProc);
+    Jim_SetResultString(interp, buf, -1);
+    return JIM_OK;
+}
+
+int Jim_sdlInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "sdl", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+        JimSdlSetError(interp);
+        return JIM_ERR;
+    }
+    atexit(SDL_Quit);
+    Jim_CreateCommand(interp, "sdl.screen", JimSdlSurfaceCommand, NULL, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-signal.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-signal.c
new file mode 100755
index 0000000..6a2a2be
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-signal.c
@@ -0,0 +1,514 @@
+
+/*
+ * jim-signal.c
+ *
+ */
+
+#include <signal.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "jim-subcmd.h"
+#include "jim-signal.h"
+
+#define MAX_SIGNALS (sizeof(jim_wide) * 8)
+
+static jim_wide *sigloc;
+static jim_wide sigsblocked;
+static struct sigaction *sa_old;
+static int signal_handling[MAX_SIGNALS];
+
+/* Make sure to do this as a wide, not int */
+#define sig_to_bit(SIG) ((jim_wide)1 << (SIG))
+
+static void signal_handler(int sig)
+{
+    /* We just remember which signals occurred. Jim_Eval() will
+     * notice this as soon as it can and throw an error
+     */
+    *sigloc |= sig_to_bit(sig);
+}
+
+static void signal_ignorer(int sig)
+{
+    /* We just remember which signals occurred */
+    sigsblocked |= sig_to_bit(sig);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SignalId --
+ *
+ *      Return a textual identifier for a signal number.
+ *
+ * Results:
+ *      This procedure returns a machine-readable textual identifier
+ *      that corresponds to sig.  The identifier is the same as the
+ *      #define name in signal.h.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------
+ */
+#define CHECK_SIG(NAME) if (sig == NAME) return #NAME
+
+const char *Jim_SignalId(int sig)
+{
+    CHECK_SIG(SIGABRT);
+    CHECK_SIG(SIGALRM);
+    CHECK_SIG(SIGBUS);
+    CHECK_SIG(SIGCHLD);
+    CHECK_SIG(SIGCONT);
+    CHECK_SIG(SIGFPE);
+    CHECK_SIG(SIGHUP);
+    CHECK_SIG(SIGILL);
+    CHECK_SIG(SIGINT);
+#ifdef SIGIO
+    CHECK_SIG(SIGIO);
+#endif
+    CHECK_SIG(SIGKILL);
+    CHECK_SIG(SIGPIPE);
+    CHECK_SIG(SIGPROF);
+    CHECK_SIG(SIGQUIT);
+    CHECK_SIG(SIGSEGV);
+    CHECK_SIG(SIGSTOP);
+    CHECK_SIG(SIGSYS);
+    CHECK_SIG(SIGTERM);
+    CHECK_SIG(SIGTRAP);
+    CHECK_SIG(SIGTSTP);
+    CHECK_SIG(SIGTTIN);
+    CHECK_SIG(SIGTTOU);
+    CHECK_SIG(SIGURG);
+    CHECK_SIG(SIGUSR1);
+    CHECK_SIG(SIGUSR2);
+    CHECK_SIG(SIGVTALRM);
+    CHECK_SIG(SIGWINCH);
+    CHECK_SIG(SIGXCPU);
+    CHECK_SIG(SIGXFSZ);
+#ifdef SIGPWR
+    CHECK_SIG(SIGPWR);
+#endif
+#ifdef SIGCLD
+    CHECK_SIG(SIGCLD);
+#endif
+#ifdef SIGEMT
+    CHECK_SIG(SIGEMT);
+#endif
+#ifdef SIGLOST
+    CHECK_SIG(SIGLOST);
+#endif
+#ifdef SIGPOLL
+    CHECK_SIG(SIGPOLL);
+#endif
+#ifdef SIGINFO
+    CHECK_SIG(SIGINFO);
+#endif
+    return "unknown signal";
+}
+
+const char *Jim_SignalName(int sig)
+{
+#ifdef HAVE_SYS_SIGLIST
+    if (sig >= 0 && sig < NSIG) {
+        return sys_siglist[sig];
+    }
+#endif
+    return Jim_SignalId(sig);
+}
+
+/**
+ * Given the name of a signal, returns the signal value if found,
+ * or returns -1 (and sets an error) if not found.
+ * We accept -SIGINT, SIGINT, INT or any lowercase version or a number,
+ * either positive or negative.
+ */
+static int find_signal_by_name(Jim_Interp *interp, const char *name)
+{
+    int i;
+    const char *pt = name;
+
+    /* Remove optional - and SIG from the front of the name */
+    if (*pt == '-') {
+        pt++;
+    }
+    if (strncasecmp(name, "sig", 3) == 0) {
+        pt += 3;
+    }
+    if (isdigit(UCHAR(pt[0]))) {
+        i = atoi(pt);
+        if (i > 0 && i < MAX_SIGNALS) {
+            return i;
+        }
+    }
+    else {
+        for (i = 1; i < MAX_SIGNALS; i++) {
+            /* Jim_SignalId() returns names such as SIGINT, and
+             * returns "unknown signal id" if unknown, so this will work
+             */
+            if (strcasecmp(Jim_SignalId(i) + 3, pt) == 0) {
+                return i;
+            }
+        }
+    }
+    Jim_SetResultString(interp, "unknown signal ", -1);
+    Jim_AppendString(interp, Jim_GetResult(interp), name, -1);
+
+    return -1;
+}
+
+#define SIGNAL_ACTION_HANDLE 1
+#define SIGNAL_ACTION_IGNORE -1
+#define SIGNAL_ACTION_DEFAULT 0
+
+static int do_signal_cmd(Jim_Interp *interp, int action, int argc, Jim_Obj *const *argv)
+{
+    struct sigaction sa;
+    int i;
+
+    if (argc == 0) {
+        Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
+        for (i = 1; i < MAX_SIGNALS; i++) {
+            if (signal_handling[i] == action) {
+                /* Add signal name to the list  */
+                Jim_ListAppendElement(interp, Jim_GetResult(interp),
+                    Jim_NewStringObj(interp, Jim_SignalId(i), -1));
+            }
+        }
+        return JIM_OK;
+    }
+
+    /* Catch all the signals we care about */
+    if (action != SIGNAL_ACTION_DEFAULT) {
+        sa.sa_flags = 0;
+        sigemptyset(&sa.sa_mask);
+        if (action == SIGNAL_ACTION_HANDLE) {
+            sa.sa_handler = signal_handler;
+        }
+        else {
+            sa.sa_handler = signal_ignorer;
+        }
+    }
+
+    /* Iterate through the provided signals */
+    for (i = 0; i < argc; i++) {
+        int sig = find_signal_by_name(interp, Jim_String(argv[i]));
+
+        if (sig < 0) {
+            return JIM_ERR;
+        }
+        if (action != signal_handling[sig]) {
+            /* Need to change the action for this signal */
+            switch (action) {
+                case SIGNAL_ACTION_HANDLE:
+                case SIGNAL_ACTION_IGNORE:
+                    if (signal_handling[sig] == SIGNAL_ACTION_DEFAULT) {
+                        if (!sa_old) {
+                            /* Allocate the structure the first time through */
+                            sa_old = Jim_Alloc(sizeof(*sa_old) * MAX_SIGNALS);
+                        }
+                        sigaction(sig, &sa, &sa_old[sig]);
+                    }
+                    else {
+                        sigaction(sig, &sa, 0);
+                    }
+                    break;
+
+                case SIGNAL_ACTION_DEFAULT:
+                    /* Restore old handler */
+                    if (sa_old) {
+                        sigaction(sig, &sa_old[sig], 0);
+                    }
+            }
+            signal_handling[sig] = action;
+        }
+    }
+
+    return JIM_OK;
+}
+
+static int signal_cmd_handle(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return do_signal_cmd(interp, SIGNAL_ACTION_HANDLE, argc, argv);
+}
+
+static int signal_cmd_ignore(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return do_signal_cmd(interp, SIGNAL_ACTION_IGNORE, argc, argv);
+}
+
+static int signal_cmd_default(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return do_signal_cmd(interp, SIGNAL_ACTION_DEFAULT, argc, argv);
+}
+
+static int signal_set_sigmask_result(Jim_Interp *interp, jim_wide sigmask)
+{
+    int i;
+    Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
+    for (i = 0; i < MAX_SIGNALS; i++) {
+        if (sigmask & sig_to_bit(i)) {
+            Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, Jim_SignalId(i), -1));
+        }
+    }
+    Jim_SetResult(interp, listObj);
+    return JIM_OK;
+}
+
+static int signal_cmd_check(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int clear = 0;
+    jim_wide mask = 0;
+    jim_wide blocked;
+
+    if (argc > 0 && Jim_CompareStringImmediate(interp, argv[0], "-clear")) {
+        clear++;
+    }
+    if (argc > clear) {
+        int i;
+
+        /* Signals specified */
+        for (i = clear; i < argc; i++) {
+            int sig = find_signal_by_name(interp, Jim_String(argv[i]));
+
+            if (sig < 0 || sig >= MAX_SIGNALS) {
+                return -1;
+            }
+            mask |= sig_to_bit(sig);
+        }
+    }
+    else {
+        /* No signals specified, so check/clear all */
+        mask = ~mask;
+    }
+
+    if ((sigsblocked & mask) == 0) {
+        /* No matching signals, so empty result and nothing to do */
+        return JIM_OK;
+    }
+    /* Be careful we don't have a race condition where signals are cleared but not returned */
+    blocked = sigsblocked & mask;
+    if (clear) {
+        sigsblocked &= ~blocked;
+    }
+    /* Set the result */
+    signal_set_sigmask_result(interp, blocked);
+    return JIM_OK;
+}
+
+static int signal_cmd_throw(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int sig = SIGINT;
+
+    if (argc == 1) {
+        if ((sig = find_signal_by_name(interp, Jim_String(argv[0]))) < 0) {
+            return JIM_ERR;
+        }
+    }
+
+    /* If the signal is ignored (blocked) ... */
+    if (signal_handling[sig] == SIGNAL_ACTION_IGNORE) {
+        sigsblocked |= sig_to_bit(sig);
+        return JIM_OK;
+    }
+
+    /* Just set the signal */
+    interp->sigmask |= sig_to_bit(sig);
+
+    /* Set the canonical name of the signal as the result */
+    Jim_SetResultString(interp, Jim_SignalId(sig), -1);
+
+    /* And simply say we caught the signal */
+    return JIM_SIGNAL;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Jim_SignalCmd --
+ *     Implements the TCL signal command:
+ *         signal handle|ignore|default|throw ?signals ...?
+ *         signal throw signal
+ *
+ *     Specifies which signals are handled by Tcl code.
+ *     If the one of the given signals is caught, it causes a JIM_SIGNAL
+ *     exception to be thrown which can be caught by catch.
+ *
+ *     Use 'signal ignore' to ignore the signal(s)
+ *     Use 'signal default' to go back to the default behaviour
+ *     Use 'signal throw signal' to raise the given signal
+ *
+ *     If no arguments are given, returns the list of signals which are being handled
+ *
+ * Results:
+ *      Standard TCL results.
+ *
+ *-----------------------------------------------------------------------------
+ */
+static const jim_subcmd_type signal_command_table[] = {
+    {   .cmd = "handle",
+        .args = "?signals ...?",
+        .function = signal_cmd_handle,
+        .minargs = 0,
+        .maxargs = -1,
+        .description = "Lists handled signals, or adds to handled signals"
+    },
+    {   .cmd = "ignore",
+        .args = "?signals ...?",
+        .function = signal_cmd_ignore,
+        .minargs = 0,
+        .maxargs = -1,
+        .description = "Lists ignored signals, or adds to ignored signals"
+    },
+    {   .cmd = "default",
+        .args = "?signals ...?",
+        .function = signal_cmd_default,
+        .minargs = 0,
+        .maxargs = -1,
+        .description = "Lists defaulted signals, or adds to defaulted signals"
+    },
+    {   .cmd = "check",
+        .args = "?-clear? ?signals ...?",
+        .function = signal_cmd_check,
+        .minargs = 0,
+        .maxargs = -1,
+        .description = "Returns ignored signals which have occurred, and optionally clearing them"
+    },
+    {   .cmd = "throw",
+        .args = "?signal?",
+        .function = signal_cmd_throw,
+        .minargs = 0,
+        .maxargs = 1,
+        .description = "Raises the given signal (default SIGINT)"
+    },
+    { 0 }
+};
+
+static int Jim_AlarmCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int ret;
+
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "seconds");
+        return JIM_ERR;
+    }
+    else {
+#ifdef HAVE_UALARM
+        double t;
+
+        ret = Jim_GetDouble(interp, argv[1], &t);
+        if (ret == JIM_OK) {
+            if (t < 1) {
+                ualarm(t * 1e6, 0);
+            }
+            else {
+                alarm(t);
+            }
+        }
+#else
+        long t;
+
+        ret = Jim_GetLong(interp, argv[1], &t);
+        if (ret == JIM_OK) {
+            alarm(t);
+        }
+#endif
+    }
+
+    return ret;
+}
+
+static int Jim_SleepCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int ret;
+
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "seconds");
+        return JIM_ERR;
+    }
+    else {
+        double t;
+
+        ret = Jim_GetDouble(interp, argv[1], &t);
+        if (ret == JIM_OK) {
+#ifdef HAVE_USLEEP
+            if (t < 1) {
+                usleep(t * 1e6);
+            }
+            else
+#endif
+                sleep(t);
+        }
+    }
+
+    return ret;
+}
+
+static int Jim_KillCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int sig;
+    long pid;
+    Jim_Obj *pidObj;
+    const char *signame;
+
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "?SIG|-0? pid");
+        return JIM_ERR;
+    }
+
+    if (argc == 2) {
+        signame = "SIGTERM";
+        pidObj = argv[1];
+    }
+    else {
+        signame = Jim_String(argv[1]);
+        pidObj = argv[2];
+    }
+
+    /* Special 'kill -0 pid' to determine if a pid exists */
+    if (strcmp(signame, "-0") == 0 || strcmp(signame, "0") == 0) {
+        sig = 0;
+    }
+    else {
+        sig = find_signal_by_name(interp, signame);
+        if (sig < 0) {
+            return JIM_ERR;
+        }
+    }
+
+    if (Jim_GetLong(interp, pidObj, &pid) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    if (kill(pid, sig) == 0) {
+        return JIM_OK;
+    }
+
+    Jim_SetResultString(interp, "kill: Failed to deliver signal", -1);
+    return JIM_ERR;
+}
+
+int Jim_signalInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "signal", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    /* Teach the jim core how to set a result from a sigmask */
+    interp->signal_set_result = signal_set_sigmask_result;
+
+    /* Make sure we know where to store the signals which occur */
+    sigloc = &interp->sigmask;
+
+    Jim_CreateCommand(interp, "signal", Jim_SubCmdProc, (void *)signal_command_table, NULL);
+    Jim_CreateCommand(interp, "alarm", Jim_AlarmCmd, 0, 0);
+    Jim_CreateCommand(interp, "kill", Jim_KillCmd, 0, 0);
+
+    /* Sleep is slightly dubious here */
+    Jim_CreateCommand(interp, "sleep", Jim_SleepCmd, 0, 0);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-signal.h b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-signal.h
new file mode 100755
index 0000000..92e080d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-signal.h
@@ -0,0 +1,24 @@
+#ifndef JIM_SIGNAL_H
+#define JIM_SIGNAL_H
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SignalId --
+ *
+ *      Return a textual identifier for a signal number.
+ *
+ * Results:
+ *      This procedure returns a machine-readable textual identifier
+ *      that corresponds to sig.  The identifier is the same as the
+ *      #define name in signal.h.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------
+ */
+const char *Jim_SignalId(int sig);
+const char *Jim_SignalName(int sig);
+
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-subcmd.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-subcmd.c
new file mode 100755
index 0000000..2de560a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-subcmd.c
@@ -0,0 +1,293 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "jim-subcmd.h"
+#include "jimautoconf.h"
+
+/**
+ * Implements the common 'commands' subcommand
+ */
+static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    /* Nothing to do, since the result has already been created */
+    return JIM_OK;
+}
+
+/**
+ * Do-nothing command to support -commands and -usage
+ */
+static const jim_subcmd_type dummy_subcmd = {
+    .cmd = "dummy",
+    .function = subcmd_null,
+    .flags = JIM_MODFLAG_HIDDEN,
+};
+
+static void add_commands(Jim_Interp *interp, const jim_subcmd_type * ct, const char *sep)
+{
+    const char *s = "";
+
+    for (; ct->cmd; ct++) {
+        if (!(ct->flags & JIM_MODFLAG_HIDDEN)) {
+            Jim_AppendStrings(interp, Jim_GetResult(interp), s, ct->cmd, NULL);
+            s = sep;
+        }
+    }
+}
+
+static void bad_subcmd(Jim_Interp *interp, const jim_subcmd_type * command_table, const char *type,
+    Jim_Obj *cmd, Jim_Obj *subcmd)
+{
+    Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+    Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), ", ", type,
+        " command \"", Jim_String(subcmd), "\": should be ", NULL);
+    add_commands(interp, command_table, ", ");
+}
+
+static void show_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc,
+    Jim_Obj *const *argv)
+{
+    Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+    Jim_AppendStrings(interp, Jim_GetResult(interp), "Usage: \"", Jim_String(argv[0]),
+        " command ... \", where command is one of: ", NULL);
+    add_commands(interp, command_table, ", ");
+}
+
+static void add_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *cmd)
+{
+    if (cmd) {
+        Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), " ", NULL);
+    }
+    Jim_AppendStrings(interp, Jim_GetResult(interp), ct->cmd, NULL);
+    if (ct->args && *ct->args) {
+        Jim_AppendStrings(interp, Jim_GetResult(interp), " ", ct->args, NULL);
+    }
+}
+
+static void show_full_usage(Jim_Interp *interp, const jim_subcmd_type * ct, int argc,
+    Jim_Obj *const *argv)
+{
+    Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+    for (; ct->cmd; ct++) {
+        if (!(ct->flags & JIM_MODFLAG_HIDDEN)) {
+            /* subcmd */
+            add_cmd_usage(interp, ct, argv[0]);
+            if (ct->description) {
+                Jim_AppendStrings(interp, Jim_GetResult(interp), "\n\n    ", ct->description, NULL);
+            }
+            Jim_AppendStrings(interp, Jim_GetResult(interp), "\n\n", NULL);
+        }
+    }
+}
+
+static void set_wrong_args(Jim_Interp *interp, const jim_subcmd_type * command_table, Jim_Obj *subcmd)
+{
+    Jim_SetResultString(interp, "wrong # args: must be \"", -1);
+    add_cmd_usage(interp, command_table, subcmd);
+    Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
+}
+
+const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type * command_table,
+    int argc, Jim_Obj *const *argv)
+{
+    const jim_subcmd_type *ct;
+    const jim_subcmd_type *partial = 0;
+    int cmdlen;
+    Jim_Obj *cmd;
+    const char *cmdstr;
+    const char *cmdname;
+    int help = 0;
+
+    cmdname = Jim_String(argv[0]);
+
+    if (argc < 2) {
+        Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+        Jim_AppendStrings(interp, Jim_GetResult(interp), "wrong # args: should be \"", cmdname,
+            " command ...\"\n", NULL);
+        Jim_AppendStrings(interp, Jim_GetResult(interp), "Use \"", cmdname, " -help\" or \"",
+            cmdname, " -help command\" for help", NULL);
+        return 0;
+    }
+
+    cmd = argv[1];
+
+    if (argc == 2 && Jim_CompareStringImmediate(interp, cmd, "-usage")) {
+        /* Show full usage */
+        show_full_usage(interp, command_table, argc, argv);
+        return &dummy_subcmd;
+    }
+
+    /* Check for the help command */
+    if (Jim_CompareStringImmediate(interp, cmd, "-help")) {
+        if (argc == 2) {
+            /* Usage for the command, not the subcommand */
+            show_cmd_usage(interp, command_table, argc, argv);
+            return &dummy_subcmd;
+        }
+        help = 1;
+
+        /* Skip the 'help' command */
+        cmd = argv[2];
+    }
+
+    /* Check for special builtin '-commands' command first */
+    if (Jim_CompareStringImmediate(interp, cmd, "-commands")) {
+        /* Build the result here */
+        Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+        add_commands(interp, command_table, " ");
+        return &dummy_subcmd;
+    }
+
+    cmdstr = Jim_GetString(cmd, &cmdlen);
+
+    for (ct = command_table; ct->cmd; ct++) {
+        if (Jim_CompareStringImmediate(interp, cmd, ct->cmd)) {
+            /* Found an exact match */
+            break;
+        }
+        if (strncmp(cmdstr, ct->cmd, cmdlen) == 0) {
+            if (partial) {
+                /* Ambiguous */
+                if (help) {
+                    /* Just show the top level help here */
+                    show_cmd_usage(interp, command_table, argc, argv);
+                    return &dummy_subcmd;
+                }
+                bad_subcmd(interp, command_table, "ambiguous", argv[0], argv[1 + help]);
+                return 0;
+            }
+            partial = ct;
+        }
+        continue;
+    }
+
+    /* If we had an unambiguous partial match */
+    if (partial && !ct->cmd) {
+        ct = partial;
+    }
+
+    if (!ct->cmd) {
+        /* No matching command */
+        if (help) {
+            /* Just show the top level help here */
+            show_cmd_usage(interp, command_table, argc, argv);
+            return &dummy_subcmd;
+        }
+        bad_subcmd(interp, command_table, "unknown", argv[0], argv[1 + help]);
+        return 0;
+    }
+
+    if (help) {
+        Jim_SetResultString(interp, "Usage: ", -1);
+        /* subcmd */
+        add_cmd_usage(interp, ct, argv[0]);
+        if (ct->description) {
+            Jim_AppendStrings(interp, Jim_GetResult(interp), "\n\n", ct->description, NULL);
+        }
+        return &dummy_subcmd;
+    }
+
+    /* Check the number of args */
+    if (argc - 2 < ct->minargs || (ct->maxargs >= 0 && argc - 2 > ct->maxargs)) {
+        Jim_SetResultString(interp, "wrong # args: must be \"", -1);
+        /* subcmd */
+        add_cmd_usage(interp, ct, argv[0]);
+        Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
+
+        return 0;
+    }
+
+    /* Good command */
+    return ct;
+}
+
+int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type * ct, int argc, Jim_Obj *const *argv)
+{
+    int ret = JIM_ERR;
+
+    if (ct) {
+        if (ct->flags & JIM_MODFLAG_FULLARGV) {
+            ret = ct->function(interp, argc, argv);
+        }
+        else {
+            ret = ct->function(interp, argc - 2, argv + 2);
+        }
+        if (ret < 0) {
+            set_wrong_args(interp, ct, argv[0]);
+            ret = JIM_ERR;
+        }
+    }
+    return ret;
+}
+
+int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const jim_subcmd_type *ct =
+        Jim_ParseSubCmd(interp, (const jim_subcmd_type *)Jim_CmdPrivData(interp), argc, argv);
+
+    return Jim_CallSubCmd(interp, ct, argc, argv);
+}
+
+/* The following two functions are for normal commands */
+int
+Jim_CheckCmdUsage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc,
+    Jim_Obj *const *argv)
+{
+    /* -usage or -help */
+    if (argc == 2) {
+        if (Jim_CompareStringImmediate(interp, argv[1], "-usage")
+            || Jim_CompareStringImmediate(interp, argv[1], "-help")) {
+            Jim_SetResultString(interp, "Usage: ", -1);
+            add_cmd_usage(interp, command_table, NULL);
+            if (command_table->description) {
+                Jim_AppendStrings(interp, Jim_GetResult(interp), "\n\n", command_table->description,
+                    NULL);
+            }
+            return JIM_OK;
+        }
+    }
+    if (argc >= 2 && command_table->function) {
+        /* This is actually a sub command table */
+
+        Jim_Obj *nargv[4];
+        int nargc = 0;
+        const char *subcmd = NULL;
+
+        if (Jim_CompareStringImmediate(interp, argv[1], "-subcommands")) {
+            Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+            add_commands(interp, (jim_subcmd_type *) command_table->function, " ");
+            return JIM_OK;
+        }
+
+        if (Jim_CompareStringImmediate(interp, argv[1], "-subhelp")
+            || Jim_CompareStringImmediate(interp, argv[1], "-help")) {
+            subcmd = "-help";
+        }
+        else if (Jim_CompareStringImmediate(interp, argv[1], "-subusage")) {
+            subcmd = "-usage";
+        }
+
+        if (subcmd) {
+            nargv[nargc++] = Jim_NewStringObj(interp, "$handle", -1);
+            nargv[nargc++] = Jim_NewStringObj(interp, subcmd, -1);
+            if (argc >= 3) {
+                nargv[nargc++] = argv[2];
+            }
+            Jim_ParseSubCmd(interp, (jim_subcmd_type *) command_table->function, nargc, nargv);
+            Jim_FreeNewObj(interp, nargv[0]);
+            Jim_FreeNewObj(interp, nargv[1]);
+            return 0;
+        }
+    }
+
+    /* Check the number of args */
+    if (argc - 1 < command_table->minargs || (command_table->maxargs >= 0
+            && argc - 1 > command_table->maxargs)) {
+        set_wrong_args(interp, command_table, NULL);
+        Jim_AppendStrings(interp, Jim_GetResult(interp), "\nUse \"", Jim_String(argv[0]),
+            " -help\" for help", NULL);
+        return JIM_ERR;
+    }
+
+    /* Not usage, but passed arg checking */
+    return -1;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-subcmd.h b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-subcmd.h
new file mode 100755
index 0000000..3a672eb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-subcmd.h
@@ -0,0 +1,92 @@
+/* Provides a common approach to implementing Tcl commands
+ * which implement subcommands
+ */
+#ifndef JIM_SUBCMD_H
+#define JIM_SUBCMD_H
+
+#include <jim.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define JIM_MODFLAG_HIDDEN   0x0001		/* Don't show the subcommand in usage or commands */
+#define JIM_MODFLAG_FULLARGV 0x0002		/* Subcmd proc gets called with full argv */
+
+/* Custom flags start at 0x0100 */
+
+/**
+ * Returns JIM_OK if OK, JIM_ERR (etc.) on error, break, continue, etc.
+ * Returns -1 if invalid args.
+ */
+typedef int tclmod_cmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
+typedef struct {
+	const char *cmd;				/* Name of the (sub)command */
+	const char *args;				/* Textual description of allowed args */
+	tclmod_cmd_function *function;	/* Function implementing the subcommand */
+	short minargs;					/* Minimum required arguments */
+	short maxargs;					/* Maximum allowed arguments or -1 if no limit */
+	unsigned flags;					/* JIM_MODFLAG_... plus custom flags */
+	const char *description;		/* Description of the subcommand */
+} jim_subcmd_type;
+
+/**
+ * Looks up the appropriate subcommand in the given command table and return
+ * the command function which implements the subcommand.
+ * NULL will be returned and an appropriate error will be set if the subcommand or
+ * arguments are invalid.
+ *
+ * Typical usage is:
+ *  {
+ *    const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, command_table, argc, argv);
+ *
+ *    return Jim_CallSubCmd(interp, ct, argc, argv);
+ *  }
+ *
+ */
+const jim_subcmd_type *
+Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv);
+
+/**
+ * Parses the args against the given command table and executes the subcommand if found
+ * or sets an appropriate error if the subcommand or arguments is invalid.
+ *
+ * Can be used directly with Jim_CreateCommand() where the ClientData is the command table.
+ *
+ * e.g. Jim_CreateCommand(interp, "mycmd", Jim_SubCmdProc, command_table, NULL);
+ */
+int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
+/**
+ * Invokes the given subcmd with the given args as returned
+ * by Jim_ParseSubCmd()
+ *
+ * If ct is NULL, returns JIM_ERR, leaving any message.
+ * Otherwise invokes ct->function
+ *
+ * If ct->function returns -1, sets an error message and returns JIM_ERR.
+ * Otherwise returns the result of ct->function.
+ */
+int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type *ct, int argc, Jim_Obj *const *argv);
+
+/**
+ * Standard processing for a command.
+ *
+ * This does the '-help' and '-usage' check and the number of args checks.
+ * for a top level command against a single 'jim_subcmd_type' structure.
+ *
+ * Additionally, if command_table->function is set, it should point to a sub command table
+ * and '-subhelp ?subcmd?', '-subusage' and '-subcommands' are then also recognised.
+ *
+ * Returns 0 if user requested usage, -1 on arg error, 1 if OK to process.
+ */
+int
+Jim_CheckCmdUsage(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-syslog.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-syslog.c
new file mode 100755
index 0000000..4e14910
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-syslog.c
@@ -0,0 +1,190 @@
+
+/* Syslog interface for tcl
+ * Copyright Victor Wagner <vitus@ice.ru> at
+ * http://www.ice.ru/~vitus/works/tcl.html#syslog
+ *
+ * Slightly modified by Steve Bennett <steveb@snapgear.com>
+ * Ported to Jim by Steve Bennett <steveb@workware.net.au>
+ */
+#include <syslog.h>
+#include <string.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+
+typedef struct
+{
+    int logOpened;
+    int facility;
+    int options;
+    char ident[32];
+} SyslogInfo;
+
+#ifndef LOG_AUTHPRIV
+# define LOG_AUTHPRIV LOG_AUTH
+#endif
+
+static const char * const facilities[] = {
+    [LOG_AUTHPRIV] = "authpriv",
+    [LOG_CRON] = "cron",
+    [LOG_DAEMON] = "daemon",
+    [LOG_KERN] = "kernel",
+    [LOG_LPR] = "lpr",
+    [LOG_MAIL] = "mail",
+    [LOG_NEWS] = "news",
+    [LOG_SYSLOG] = "syslog",
+    [LOG_USER] = "user",
+    [LOG_UUCP] = "uucp",
+    [LOG_LOCAL0] = "local0",
+    [LOG_LOCAL1] = "local1",
+    [LOG_LOCAL2] = "local2",
+    [LOG_LOCAL3] = "local3",
+    [LOG_LOCAL4] = "local4",
+    [LOG_LOCAL5] = "local5",
+    [LOG_LOCAL6] = "local6",
+    [LOG_LOCAL7] = "local7",
+};
+
+static const char * const priorities[] = {
+    [LOG_EMERG] = "emerg",
+    [LOG_ALERT] = "alert",
+    [LOG_CRIT] = "crit",
+    [LOG_ERR] = "error",
+    [LOG_WARNING] = "warning",
+    [LOG_NOTICE] = "notice",
+    [LOG_INFO] = "info",
+    [LOG_DEBUG] = "debug",
+};
+
+/**
+ * Deletes the syslog command.
+ */
+static void Jim_SyslogCmdDelete(Jim_Interp *interp, void *privData)
+{
+    SyslogInfo *info = (SyslogInfo *) privData;
+
+    if (info->logOpened) {
+        closelog();
+    }
+    Jim_Free(info);
+}
+
+/* Syslog_Log -
+ * implements syslog tcl command. General format: syslog ?options? level text
+ * options -facility -ident -options
+ *
+ * syslog ?-facility cron|daemon|...? ?-ident string? ?-options int? ?debug|info|...? text
+ */
+int Jim_SyslogCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int priority = LOG_INFO;
+    int i = 1;
+    SyslogInfo *info = Jim_CmdPrivData(interp);
+
+    if (argc <= 1) {
+      wrongargs:
+        Jim_WrongNumArgs(interp, 1, argv,
+            "?-facility cron|daemon|...? ?-ident string? ?-options int? ?debug|info|...? message");
+        return JIM_ERR;
+    }
+    while (i < argc - 1) {
+        if (Jim_CompareStringImmediate(interp, argv[i], "-facility")) {
+            int entry =
+                Jim_FindByName(Jim_String(argv[i + 1]), facilities,
+                sizeof(facilities) / sizeof(*facilities));
+            if (entry < 0) {
+                Jim_SetResultString(interp, "Unknown facility", -1);
+                return JIM_ERR;
+            }
+            if (info->facility != entry) {
+                info->facility = entry;
+                if (info->logOpened) {
+                    closelog();
+                    info->logOpened = 0;
+                }
+            }
+        }
+        else if (Jim_CompareStringImmediate(interp, argv[i], "-options")) {
+            long tmp;
+
+            if (Jim_GetLong(interp, argv[i + 1], &tmp) == JIM_ERR) {
+                return JIM_ERR;
+            }
+            info->options = tmp;
+            if (info->logOpened) {
+                closelog();
+                info->logOpened = 0;
+            }
+        }
+        else if (Jim_CompareStringImmediate(interp, argv[i], "-ident")) {
+            strncpy(info->ident, Jim_String(argv[i + 1]), sizeof(info->ident));
+            info->ident[sizeof(info->ident) - 1] = 0;
+            if (info->logOpened) {
+                closelog();
+                info->logOpened = 0;
+            }
+        }
+        else {
+            break;
+        }
+        i += 2;
+    }
+
+    /* There should be either 0, 1 or 2 args left */
+    if (i == argc) {
+        /* No args, but they have set some options, so OK */
+        return JIM_OK;
+    }
+
+    if (i < argc - 1) {
+        priority =
+            Jim_FindByName(Jim_String(argv[i]), priorities,
+            sizeof(priorities) / sizeof(*priorities));
+        if (priority < 0) {
+            Jim_SetResultString(interp, "Unknown priority", -1);
+            return JIM_ERR;
+        }
+        i++;
+    }
+
+    if (i != argc - 1) {
+        goto wrongargs;
+    }
+    if (!info->logOpened) {
+        if (!info->ident[0]) {
+            Jim_Obj *argv0 = Jim_GetGlobalVariableStr(interp, "argv0", JIM_NONE);
+
+            if (argv0) {
+                strncpy(info->ident, Jim_String(argv0), sizeof(info->ident));
+            }
+            else {
+                strcpy(info->ident, "Tcl script");
+            }
+            info->ident[sizeof(info->ident) - 1] = 0;
+        }
+        openlog(info->ident, info->options, info->facility);
+        info->logOpened = 1;
+    }
+    syslog(priority, "%s", Jim_String(argv[i]));
+
+    return JIM_OK;
+}
+
+int Jim_syslogInit(Jim_Interp *interp)
+{
+    SyslogInfo *info;
+
+    if (Jim_PackageProvide(interp, "syslog", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    info = Jim_Alloc(sizeof(*info));
+
+    info->logOpened = 0;
+    info->options = 0;
+    info->facility = LOG_USER;
+    info->ident[0] = 0;
+
+    Jim_CreateCommand(interp, "syslog", Jim_SyslogCmd, info, Jim_SyslogCmdDelete);
+
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim-win32compat.h b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-win32compat.h
new file mode 100755
index 0000000..89e01f5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim-win32compat.h
@@ -0,0 +1,69 @@
+#ifndef JIM_WIN32COMPAT_H
+#define JIM_WIN32COMPAT_H
+
+/* Compatibility for Windows (mingw and msvc, not cygwin */
+
+/* Note that at this point we don't yet have access to jimautoconf.h */
+#if defined(_WIN32) || defined(WIN32)
+#ifndef STRICT
+	#define STRICT
+#endif
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#define HAVE_DLOPEN
+void *dlopen(const char *path, int mode);
+int dlclose(void *handle);
+void *dlsym(void *handle, const char *symbol);
+char *dlerror(void);
+
+#ifdef _MSC_VER
+/* These are msvc vs gcc */
+
+#if _MSC_VER >= 1000
+	#pragma warning(disable:4146)
+#endif
+
+#define strcasecmp _stricmp
+
+#define jim_wide _int64
+#ifndef LLONG_MAX
+	#define LLONG_MAX    9223372036854775807I64
+#endif
+#ifndef LLONG_MIN
+	#define LLONG_MIN    (-LLONG_MAX - 1I64)
+#endif
+#define JIM_WIDE_MIN LLONG_MIN
+#define JIM_WIDE_MAX LLONG_MAX
+#define JIM_WIDE_MODIFIER "I64d"
+
+#include <io.h>
+
+#define HAVE_GETTIMEOFDAY
+struct timeval {
+	long tv_sec;
+	long tv_usec;
+};
+
+int gettimeofday(struct timeval *tv, void *unused);
+
+#define HAVE_OPENDIR
+struct dirent {
+	char *d_name;
+};
+
+typedef struct DIR {
+	long                handle; /* -1 for failed rewind */
+	struct _finddata_t  info;
+	struct dirent       result; /* d_name null iff first time */
+	char                *name;  /* null-terminated char string */
+} DIR;
+
+DIR *opendir(const char *name);
+int closedir(DIR *dir);
+struct dirent *readdir(DIR *dir);
+#endif /* _MSC_VER */
+
+#endif /* WIN32 */
+
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jim.c
new file mode 100755
index 0000000..8543de4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim.c
@@ -0,0 +1,14478 @@
+
+/* Jim - A small embeddable Tcl interpreter
+ *
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
+ * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
+ * Copyright 2008,2009 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
+ * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
+ * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
+ * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
+ * Copyright 2008 Steve Bennett <steveb@workware.net.au>
+ * Copyright 2009 Nico Coesel <ncoesel@dealogic.nl>
+ * Copyright 2009 Zachary T Welch zw@superlucidity.net
+ * Copyright 2009 David Brownell
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ **/
+#define JIM_OPTIMIZATION        /* comment to avoid optimizations and reduce size */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <limits.h>
+#include <assert.h>
+#include <errno.h>
+#include <time.h>
+#include <setjmp.h>
+
+#include <unistd.h>
+#include <sys/time.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "utf8.h"
+
+#ifdef HAVE_BACKTRACE
+#include <execinfo.h>
+#endif
+#ifdef HAVE_CRT_EXTERNS_H
+#include <crt_externs.h>
+#endif
+
+/* For INFINITY, even if math functions are not enabled */
+#include <math.h>
+
+/* We may decide to switch to using $[...] after all, so leave it as an option */
+/*#define EXPRSUGAR_BRACKET*/
+
+/* For the no-autoconf case */
+#ifndef TCL_LIBRARY
+#define TCL_LIBRARY "."
+#endif
+#ifndef TCL_PLATFORM_OS
+#define TCL_PLATFORM_OS "unknown"
+#endif
+#ifndef TCL_PLATFORM_PLATFORM
+#define TCL_PLATFORM_PLATFORM "unknown"
+#endif
+#ifndef TCL_PLATFORM_PATH_SEPARATOR
+#define TCL_PLATFORM_PATH_SEPARATOR ":"
+#endif
+
+/*#define DEBUG_SHOW_SCRIPT*/
+/*#define DEBUG_SHOW_SCRIPT_TOKENS*/
+/*#define DEBUG_SHOW_SUBST*/
+/*#define DEBUG_SHOW_EXPR*/
+/*#define DEBUG_SHOW_EXPR_TOKENS*/
+/*#define JIM_DEBUG_GC*/
+#ifdef JIM_MAINTAINER
+#define JIM_DEBUG_COMMAND
+#define JIM_DEBUG_PANIC
+#endif
+
+const char *jim_tt_name(int type);
+
+#ifdef JIM_DEBUG_PANIC
+static void JimPanicDump(int panic_condition, const char *fmt, ...);
+#define JimPanic(X) JimPanicDump X
+#else
+#define JimPanic(X)
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Global variables
+ * ---------------------------------------------------------------------------*/
+
+/* A shared empty string for the objects string representation.
+ * Jim_InvalidateStringRep knows about it and doesn't try to free it. */
+static char JimEmptyStringRep[] = "";
+
+/* -----------------------------------------------------------------------------
+ * Required prototypes of not exported functions
+ * ---------------------------------------------------------------------------*/
+static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf);
+static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags);
+static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr,
+    int flags);
+static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr);
+static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
+static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
+    const char *prefix, const char *const *tablePtr, const char *name);
+static void JimDeleteLocalProcs(Jim_Interp *interp);
+static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, Jim_Obj *fileNameObj, int linenr,
+    int argc, Jim_Obj *const *argv);
+static int JimEvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv,
+    Jim_Obj *fileNameObj, int linenr);
+static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr);
+static int JimSign(jim_wide w);
+static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr);
+static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen);
+static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len);
+
+
+static const Jim_HashTableType JimVariablesHashTableType;
+
+/* Fast access to the int (wide) value of an object which is known to be of int type */
+#define JimWideValue(objPtr) (objPtr)->internalRep.wideValue
+
+#define JimObjTypeName(O) ((O)->typePtr ? (O)->typePtr->name : "none")
+
+static int utf8_tounicode_case(const char *s, int *uc, int upper)
+{
+    int l = utf8_tounicode(s, uc);
+    if (upper) {
+        *uc = utf8_upper(*uc);
+    }
+    return l;
+}
+
+/* These can be used in addition to JIM_CASESENS/JIM_NOCASE */
+#define JIM_CHARSET_SCAN 2
+#define JIM_CHARSET_GLOB 0
+
+/**
+ * pattern points to a string like "[^a-z\ub5]"
+ *
+ * The pattern may contain trailing chars, which are ignored.
+ *
+ * The pattern is matched against unicode char 'c'.
+ *
+ * If (flags & JIM_NOCASE), case is ignored when matching.
+ * If (flags & JIM_CHARSET_SCAN), the considers ^ and ] special at the start
+ * of the charset, per scan, rather than glob/string match.
+ *
+ * If the unicode char 'c' matches that set, returns a pointer to the ']' character,
+ * or the null character if the ']' is missing.
+ *
+ * Returns NULL on no match.
+ */
+static const char *JimCharsetMatch(const char *pattern, int c, int flags)
+{
+    int not = 0;
+    int pchar;
+    int match = 0;
+    int nocase = 0;
+
+    if (flags & JIM_NOCASE) {
+        nocase++;
+        c = utf8_upper(c);
+    }
+
+    if (flags & JIM_CHARSET_SCAN) {
+        if (*pattern == '^') {
+            not++;
+            pattern++;
+        }
+
+        /* Special case. If the first char is ']', it is part of the set */
+        if (*pattern == ']') {
+            goto first;
+        }
+    }
+
+    while (*pattern && *pattern != ']') {
+        /* Exact match */
+        if (pattern[0] == '\\') {
+first:
+            pattern += utf8_tounicode_case(pattern, &pchar, nocase);
+        }
+        else {
+            /* Is this a range? a-z */
+            int start;
+            int end;
+
+            pattern += utf8_tounicode_case(pattern, &start, nocase);
+            if (pattern[0] == '-' && pattern[1]) {
+                /* skip '-' */
+                pattern += utf8_tounicode(pattern, &pchar);
+                pattern += utf8_tounicode_case(pattern, &end, nocase);
+
+                /* Handle reversed range too */
+                if ((c >= start && c <= end) || (c >= end && c <= start)) {
+                    match = 1;
+                }
+                continue;
+            }
+            pchar = start;
+        }
+
+        if (pchar == c) {
+            match = 1;
+        }
+    }
+    if (not) {
+        match = !match;
+    }
+
+    return match ? pattern : NULL;
+}
+
+/* Glob-style pattern matching. */
+
+/* Note: string *must* be valid UTF-8 sequences
+ *       slen is a char length, not byte counts.
+ */
+static int GlobMatch(const char *pattern, const char *string, int nocase)
+{
+    int c;
+    int pchar;
+    while (*pattern) {
+        switch (pattern[0]) {
+            case '*':
+                while (pattern[1] == '*') {
+                    pattern++;
+                }
+                pattern++;
+                if (!pattern[0]) {
+                    return 1;   /* match */
+                }
+                while (*string) {
+                    /* Recursive call - Does the remaining pattern match anywhere? */
+                    if (GlobMatch(pattern, string, nocase))
+                        return 1;       /* match */
+                    string += utf8_tounicode(string, &c);
+                }
+                return 0;       /* no match */
+
+            case '?':
+                string += utf8_tounicode(string, &c);
+                break;
+
+            case '[': {
+                    string += utf8_tounicode(string, &c);
+                    pattern = JimCharsetMatch(pattern + 1, c, nocase ? JIM_NOCASE : 0);
+                    if (!pattern) {
+                        return 0;
+                    }
+                    if (!*pattern) {
+                        /* Ran out of pattern (no ']') */
+                        continue;
+                    }
+                    break;
+                }
+            case '\\':
+                if (pattern[1]) {
+                    pattern++;
+                }
+                /* fall through */
+            default:
+                string += utf8_tounicode_case(string, &c, nocase);
+                utf8_tounicode_case(pattern, &pchar, nocase);
+                if (pchar != c) {
+                    return 0;
+                }
+                break;
+        }
+        pattern += utf8_tounicode_case(pattern, &pchar, nocase);
+        if (!*string) {
+            while (*pattern == '*') {
+                pattern++;
+            }
+            break;
+        }
+    }
+    if (!*pattern && !*string) {
+        return 1;
+    }
+    return 0;
+}
+
+static int JimStringMatch(Jim_Interp *interp, Jim_Obj *patternObj, const char *string, int nocase)
+{
+    return GlobMatch(Jim_String(patternObj), string, nocase);
+}
+
+/**
+ * string comparison works on binary data.
+ *
+ * Note that the lengths are byte lengths, not char lengths.
+ */
+static int JimStringCompare(const char *s1, int l1, const char *s2, int l2)
+{
+    if (l1 < l2) {
+        return memcmp(s1, s2, l1) <= 0 ? -1 : 1;
+    }
+    else if (l2 < l1) {
+        return memcmp(s1, s2, l2) >= 0 ? 1 : -1;
+    }
+    else {
+        return JimSign(memcmp(s1, s2, l1));
+    }
+}
+
+/**
+ * No-case version.
+ *
+ * If maxchars is -1, compares to end of string.
+ * Otherwise compares at most 'maxchars' characters.
+ */
+static int JimStringCompareNoCase(const char *s1, const char *s2, int maxchars)
+{
+    while (*s1 && *s2 && maxchars) {
+        int c1, c2;
+        s1 += utf8_tounicode_case(s1, &c1, 1);
+        s2 += utf8_tounicode_case(s2, &c2, 1);
+        if (c1 != c2) {
+            return JimSign(c1 - c2);
+        }
+        maxchars--;
+    }
+    if (!maxchars) {
+        return 0;
+    }
+    /* One string or both terminated */
+    if (*s1) {
+        return 1;
+    }
+    if (*s2) {
+        return -1;
+    }
+    return 0;
+}
+
+/* Search 's1' inside 's2', starting to search from char 'index' of 's2'.
+ * The index of the first occurrence of s1 in s2 is returned.
+ * If s1 is not found inside s2, -1 is returned. */
+static int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int idx)
+{
+    int i;
+    int l1bytelen;
+
+    if (!l1 || !l2 || l1 > l2) {
+        return -1;
+    }
+    if (idx < 0)
+        idx = 0;
+    s2 += utf8_index(s2, idx);
+
+    l1bytelen = utf8_index(s1, l1);
+
+    for (i = idx; i <= l2 - l1; i++) {
+        int c;
+        if (memcmp(s2, s1, l1bytelen) == 0) {
+            return i;
+        }
+        s2 += utf8_tounicode(s2, &c);
+    }
+    return -1;
+}
+
+/**
+ * Note: Lengths and return value are in bytes, not chars.
+ */
+static int JimStringLast(const char *s1, int l1, const char *s2, int l2)
+{
+    const char *p;
+
+    if (!l1 || !l2 || l1 > l2)
+        return -1;
+
+    /* Now search for the needle */
+    for (p = s2 + l2 - 1; p != s2 - 1; p--) {
+        if (*p == *s1 && memcmp(s1, p, l1) == 0) {
+            return p - s2;
+        }
+    }
+    return -1;
+}
+
+#ifdef JIM_UTF8
+/**
+ * Note: Lengths and return value are in chars.
+ */
+static int JimStringLastUtf8(const char *s1, int l1, const char *s2, int l2)
+{
+    int n = JimStringLast(s1, utf8_index(s1, l1), s2, utf8_index(s2, l2));
+    if (n > 0) {
+        n = utf8_strlen(s2, n);
+    }
+    return n;
+}
+#endif
+
+int Jim_WideToString(char *buf, jim_wide wideValue)
+{
+    const char *fmt = "%" JIM_WIDE_MODIFIER;
+
+    return sprintf(buf, fmt, wideValue);
+}
+
+/**
+ * After an strtol()/strtod()-like conversion,
+ * check whether something was converted and that
+ * the only thing left is white space.
+ *
+ * Returns JIM_OK or JIM_ERR.
+ */
+static int JimCheckConversion(const char *str, const char *endptr)
+{
+    if (str[0] == '\0' || str == endptr) {
+        return JIM_ERR;
+    }
+
+    if (endptr[0] != '\0') {
+        while (*endptr) {
+            if (!isspace(UCHAR(*endptr))) {
+                return JIM_ERR;
+            }
+            endptr++;
+        }
+    }
+    return JIM_OK;
+}
+
+int Jim_StringToWide(const char *str, jim_wide * widePtr, int base)
+{
+    char *endptr;
+
+    *widePtr = strtoull(str, &endptr, base);
+
+    return JimCheckConversion(str, endptr);
+}
+
+int Jim_DoubleToString(char *buf, double doubleValue)
+{
+    int len;
+    char *buf0 = buf;
+
+    len = sprintf(buf, "%.12g", doubleValue);
+
+    /* Add a final ".0" if it's a number. But not
+     * for NaN or InF */
+    while (*buf) {
+        if (*buf == '.' || isalpha(UCHAR(*buf))) {
+            /* inf -> Inf, nan -> Nan */
+            if (*buf == 'i' || *buf == 'n') {
+                *buf = toupper(UCHAR(*buf));
+            }
+            if (*buf == 'I') {
+                /* Infinity -> Inf */
+                buf[3] = '\0';
+                len = buf - buf0 + 3;
+            }
+            return len;
+        }
+        buf++;
+    }
+
+    *buf++ = '.';
+    *buf++ = '0';
+    *buf = '\0';
+
+    return len + 2;
+}
+
+int Jim_StringToDouble(const char *str, double *doublePtr)
+{
+    char *endptr;
+
+    /* Callers can check for underflow via ERANGE */
+    errno = 0;
+
+    *doublePtr = strtod(str, &endptr);
+
+    return JimCheckConversion(str, endptr);
+}
+
+static jim_wide JimPowWide(jim_wide b, jim_wide e)
+{
+    jim_wide i, res = 1;
+
+    if ((b == 0 && e != 0) || (e < 0))
+        return 0;
+    for (i = 0; i < e; i++) {
+        res *= b;
+    }
+    return res;
+}
+
+/* -----------------------------------------------------------------------------
+ * Special functions
+ * ---------------------------------------------------------------------------*/
+#ifdef JIM_DEBUG_PANIC
+void JimPanicDump(int condition, const char *fmt, ...)
+{
+    va_list ap;
+
+    if (!condition) {
+        return;
+    }
+
+    va_start(ap, fmt);
+
+    fprintf(stderr, JIM_NL "JIM INTERPRETER PANIC: ");
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, JIM_NL JIM_NL);
+    va_end(ap);
+
+#ifdef HAVE_BACKTRACE
+    {
+        void *array[40];
+        int size, i;
+        char **strings;
+
+        size = backtrace(array, 40);
+        strings = backtrace_symbols(array, size);
+        for (i = 0; i < size; i++)
+            fprintf(stderr, "[backtrace] %s" JIM_NL, strings[i]);
+        fprintf(stderr, "[backtrace] Include the above lines and the output" JIM_NL);
+        fprintf(stderr, "[backtrace] of 'nm <executable>' in the bug report." JIM_NL);
+    }
+#endif
+
+    abort();
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Memory allocation
+ * ---------------------------------------------------------------------------*/
+
+void *Jim_Alloc(int size)
+{
+    return malloc(size);
+}
+
+void Jim_Free(void *ptr)
+{
+    free(ptr);
+}
+
+void *Jim_Realloc(void *ptr, int size)
+{
+    return realloc(ptr, size);
+}
+
+char *Jim_StrDup(const char *s)
+{
+    return strdup(s);
+}
+
+char *Jim_StrDupLen(const char *s, int l)
+{
+    char *copy = Jim_Alloc(l + 1);
+
+    memcpy(copy, s, l + 1);
+    copy[l] = 0;                /* Just to be sure, original could be substring */
+    return copy;
+}
+
+/* -----------------------------------------------------------------------------
+ * Time related functions
+ * ---------------------------------------------------------------------------*/
+
+/* Returns microseconds of CPU used since start. */
+static jim_wide JimClock(void)
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, NULL);
+    return (jim_wide) tv.tv_sec * 1000000 + tv.tv_usec;
+}
+
+/* -----------------------------------------------------------------------------
+ * Hash Tables
+ * ---------------------------------------------------------------------------*/
+
+/* -------------------------- private prototypes ---------------------------- */
+static int JimExpandHashTableIfNeeded(Jim_HashTable *ht);
+static unsigned int JimHashTableNextPower(unsigned int size);
+static int JimInsertHashEntry(Jim_HashTable *ht, const void *key);
+
+/* -------------------------- hash functions -------------------------------- */
+
+/* Thomas Wang's 32 bit Mix Function */
+unsigned int Jim_IntHashFunction(unsigned int key)
+{
+    key += ~(key << 15);
+    key ^= (key >> 10);
+    key += (key << 3);
+    key ^= (key >> 6);
+    key += ~(key << 11);
+    key ^= (key >> 16);
+    return key;
+}
+
+/* Generic hash function (we are using to multiply by 9 and add the byte
+ * as Tcl) */
+unsigned int Jim_GenHashFunction(const unsigned char *buf, int len)
+{
+    unsigned int h = 0;
+
+    while (len--)
+        h += (h << 3) + *buf++;
+    return h;
+}
+
+/* ----------------------------- API implementation ------------------------- */
+
+/* reset a hashtable already initialized with ht_init().
+ * NOTE: This function should only called by ht_destroy(). */
+static void JimResetHashTable(Jim_HashTable *ht)
+{
+    ht->table = NULL;
+    ht->size = 0;
+    ht->sizemask = 0;
+    ht->used = 0;
+    ht->collisions = 0;
+}
+
+/* Initialize the hash table */
+int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr)
+{
+    JimResetHashTable(ht);
+    ht->type = type;
+    ht->privdata = privDataPtr;
+    return JIM_OK;
+}
+
+/* Resize the table to the minimal size that contains all the elements,
+ * but with the invariant of a USER/BUCKETS ration near to <= 1 */
+int Jim_ResizeHashTable(Jim_HashTable *ht)
+{
+    int minimal = ht->used;
+
+    if (minimal < JIM_HT_INITIAL_SIZE)
+        minimal = JIM_HT_INITIAL_SIZE;
+    return Jim_ExpandHashTable(ht, minimal);
+}
+
+/* Expand or create the hashtable */
+int Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
+{
+    Jim_HashTable n;            /* the new hashtable */
+    unsigned int realsize = JimHashTableNextPower(size), i;
+
+    /* the size is invalid if it is smaller than the number of
+     * elements already inside the hashtable */
+    if (ht->used >= size)
+        return JIM_ERR;
+
+    Jim_InitHashTable(&n, ht->type, ht->privdata);
+    n.size = realsize;
+    n.sizemask = realsize - 1;
+    n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *));
+
+    /* Initialize all the pointers to NULL */
+    memset(n.table, 0, realsize * sizeof(Jim_HashEntry *));
+
+    /* Copy all the elements from the old to the new table:
+     * note that if the old hash table is empty ht->used is zero,
+     * so Jim_ExpandHashTable just creates an empty hash table. */
+    n.used = ht->used;
+    for (i = 0; ht->used > 0; i++) {
+        Jim_HashEntry *he, *nextHe;
+
+        if (ht->table[i] == NULL)
+            continue;
+
+        /* For each hash entry on this slot... */
+        he = ht->table[i];
+        while (he) {
+            unsigned int h;
+
+            nextHe = he->next;
+            /* Get the new element index */
+            h = Jim_HashKey(ht, he->key) & n.sizemask;
+            he->next = n.table[h];
+            n.table[h] = he;
+            ht->used--;
+            /* Pass to the next element */
+            he = nextHe;
+        }
+    }
+    assert(ht->used == 0);
+    Jim_Free(ht->table);
+
+    /* Remap the new hashtable in the old */
+    *ht = n;
+    return JIM_OK;
+}
+
+/* Add an element to the target hash table */
+int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val)
+{
+    int idx;
+    Jim_HashEntry *entry;
+
+    /* Get the index of the new element, or -1 if
+     * the element already exists. */
+    if ((idx = JimInsertHashEntry(ht, key)) == -1)
+        return JIM_ERR;
+
+    /* Allocates the memory and stores key */
+    entry = Jim_Alloc(sizeof(*entry));
+    entry->next = ht->table[idx];
+    ht->table[idx] = entry;
+
+    /* Set the hash entry fields. */
+    Jim_SetHashKey(ht, entry, key);
+    Jim_SetHashVal(ht, entry, val);
+    ht->used++;
+    return JIM_OK;
+}
+
+/* Add an element, discarding the old if the key already exists */
+int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val)
+{
+    Jim_HashEntry *entry;
+
+    /* Try to add the element. If the key
+     * does not exists Jim_AddHashEntry will suceed. */
+    if (Jim_AddHashEntry(ht, key, val) == JIM_OK)
+        return JIM_OK;
+    /* It already exists, get the entry */
+    entry = Jim_FindHashEntry(ht, key);
+    /* Free the old value and set the new one */
+    Jim_FreeEntryVal(ht, entry);
+    Jim_SetHashVal(ht, entry, val);
+    return JIM_OK;
+}
+
+/* Search and remove an element */
+int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key)
+{
+    unsigned int h;
+    Jim_HashEntry *he, *prevHe;
+
+    if (ht->used == 0)
+        return JIM_ERR;
+    h = Jim_HashKey(ht, key) & ht->sizemask;
+    he = ht->table[h];
+
+    prevHe = NULL;
+    while (he) {
+        if (Jim_CompareHashKeys(ht, key, he->key)) {
+            /* Unlink the element from the list */
+            if (prevHe)
+                prevHe->next = he->next;
+            else
+                ht->table[h] = he->next;
+            Jim_FreeEntryKey(ht, he);
+            Jim_FreeEntryVal(ht, he);
+            Jim_Free(he);
+            ht->used--;
+            return JIM_OK;
+        }
+        prevHe = he;
+        he = he->next;
+    }
+    return JIM_ERR;             /* not found */
+}
+
+/* Destroy an entire hash table */
+int Jim_FreeHashTable(Jim_HashTable *ht)
+{
+    unsigned int i;
+
+    /* Free all the elements */
+    for (i = 0; ht->used > 0; i++) {
+        Jim_HashEntry *he, *nextHe;
+
+        if ((he = ht->table[i]) == NULL)
+            continue;
+        while (he) {
+            nextHe = he->next;
+            Jim_FreeEntryKey(ht, he);
+            Jim_FreeEntryVal(ht, he);
+            Jim_Free(he);
+            ht->used--;
+            he = nextHe;
+        }
+    }
+    /* Free the table and the allocated cache structure */
+    Jim_Free(ht->table);
+    /* Re-initialize the table */
+    JimResetHashTable(ht);
+    return JIM_OK;              /* never fails */
+}
+
+Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key)
+{
+    Jim_HashEntry *he;
+    unsigned int h;
+
+    if (ht->used == 0)
+        return NULL;
+    h = Jim_HashKey(ht, key) & ht->sizemask;
+    he = ht->table[h];
+    while (he) {
+        if (Jim_CompareHashKeys(ht, key, he->key))
+            return he;
+        he = he->next;
+    }
+    return NULL;
+}
+
+Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht)
+{
+    Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter));
+
+    iter->ht = ht;
+    iter->index = -1;
+    iter->entry = NULL;
+    iter->nextEntry = NULL;
+    return iter;
+}
+
+Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter)
+{
+    while (1) {
+        if (iter->entry == NULL) {
+            iter->index++;
+            if (iter->index >= (signed)iter->ht->size)
+                break;
+            iter->entry = iter->ht->table[iter->index];
+        }
+        else {
+            iter->entry = iter->nextEntry;
+        }
+        if (iter->entry) {
+            /* We need to save the 'next' here, the iterator user
+             * may delete the entry we are returning. */
+            iter->nextEntry = iter->entry->next;
+            return iter->entry;
+        }
+    }
+    return NULL;
+}
+
+/* ------------------------- private functions ------------------------------ */
+
+/* Expand the hash table if needed */
+static int JimExpandHashTableIfNeeded(Jim_HashTable *ht)
+{
+    /* If the hash table is empty expand it to the intial size,
+     * if the table is "full" dobule its size. */
+    if (ht->size == 0)
+        return Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE);
+    if (ht->size == ht->used)
+        return Jim_ExpandHashTable(ht, ht->size * 2);
+    return JIM_OK;
+}
+
+/* Our hash table capability is a power of two */
+static unsigned int JimHashTableNextPower(unsigned int size)
+{
+    unsigned int i = JIM_HT_INITIAL_SIZE;
+
+    if (size >= 2147483648U)
+        return 2147483648U;
+    while (1) {
+        if (i >= size)
+            return i;
+        i *= 2;
+    }
+}
+
+/* Returns the index of a free slot that can be populated with
+ * an hash entry for the given 'key'.
+ * If the key already exists, -1 is returned. */
+static int JimInsertHashEntry(Jim_HashTable *ht, const void *key)
+{
+    unsigned int h;
+    Jim_HashEntry *he;
+
+    /* Expand the hashtable if needed */
+    if (JimExpandHashTableIfNeeded(ht) == JIM_ERR)
+        return -1;
+    /* Compute the key hash value */
+    h = Jim_HashKey(ht, key) & ht->sizemask;
+    /* Search if this slot does not already contain the given key */
+    he = ht->table[h];
+    while (he) {
+        if (Jim_CompareHashKeys(ht, key, he->key))
+            return -1;
+        he = he->next;
+    }
+    return h;
+}
+
+/* ----------------------- StringCopy Hash Table Type ------------------------*/
+
+static unsigned int JimStringCopyHTHashFunction(const void *key)
+{
+    return Jim_GenHashFunction(key, strlen(key));
+}
+
+static const void *JimStringCopyHTKeyDup(void *privdata, const void *key)
+{
+    int len = strlen(key);
+    char *copy = Jim_Alloc(len + 1);
+
+    JIM_NOTUSED(privdata);
+
+    memcpy(copy, key, len);
+    copy[len] = '\0';
+    return copy;
+}
+
+static void *JimStringKeyValCopyHTValDup(void *privdata, const void *val)
+{
+    int len = strlen(val);
+    char *copy = Jim_Alloc(len + 1);
+
+    JIM_NOTUSED(privdata);
+
+    memcpy(copy, val, len);
+    copy[len] = '\0';
+    return copy;
+}
+
+static int JimStringCopyHTKeyCompare(void *privdata, const void *key1, const void *key2)
+{
+    JIM_NOTUSED(privdata);
+
+    return strcmp(key1, key2) == 0;
+}
+
+static void JimStringCopyHTKeyDestructor(void *privdata, const void *key)
+{
+    JIM_NOTUSED(privdata);
+
+    Jim_Free((void *)key);      /* ATTENTION: const cast */
+}
+
+static void JimStringKeyValCopyHTValDestructor(void *privdata, void *val)
+{
+    JIM_NOTUSED(privdata);
+
+    Jim_Free((void *)val);      /* ATTENTION: const cast */
+}
+
+#if 0
+static Jim_HashTableType JimStringCopyHashTableType = {
+    JimStringCopyHTHashFunction,        /* hash function */
+    JimStringCopyHTKeyDup,      /* key dup */
+    NULL,                       /* val dup */
+    JimStringCopyHTKeyCompare,  /* key compare */
+    JimStringCopyHTKeyDestructor,       /* key destructor */
+    NULL                        /* val destructor */
+};
+#endif
+
+/* This is like StringCopy but does not auto-duplicate the key.
+ * It's used for intepreter's shared strings. */
+static const Jim_HashTableType JimSharedStringsHashTableType = {
+    JimStringCopyHTHashFunction,        /* hash function */
+    NULL,                       /* key dup */
+    NULL,                       /* val dup */
+    JimStringCopyHTKeyCompare,  /* key compare */
+    JimStringCopyHTKeyDestructor,       /* key destructor */
+    NULL                        /* val destructor */
+};
+
+/* This is like StringCopy but also automatically handle dynamic
+ * allocated C strings as values. */
+static const Jim_HashTableType JimStringKeyValCopyHashTableType = {
+    JimStringCopyHTHashFunction,        /* hash function */
+    JimStringCopyHTKeyDup,      /* key dup */
+    JimStringKeyValCopyHTValDup,        /* val dup */
+    JimStringCopyHTKeyCompare,  /* key compare */
+    JimStringCopyHTKeyDestructor,       /* key destructor */
+    JimStringKeyValCopyHTValDestructor, /* val destructor */
+};
+
+typedef struct AssocDataValue
+{
+    Jim_InterpDeleteProc *delProc;
+    void *data;
+} AssocDataValue;
+
+static void JimAssocDataHashTableValueDestructor(void *privdata, void *data)
+{
+    AssocDataValue *assocPtr = (AssocDataValue *) data;
+
+    if (assocPtr->delProc != NULL)
+        assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data);
+    Jim_Free(data);
+}
+
+static const Jim_HashTableType JimAssocDataHashTableType = {
+    JimStringCopyHTHashFunction,        /* hash function */
+    JimStringCopyHTKeyDup,      /* key dup */
+    NULL,                       /* val dup */
+    JimStringCopyHTKeyCompare,  /* key compare */
+    JimStringCopyHTKeyDestructor,       /* key destructor */
+    JimAssocDataHashTableValueDestructor        /* val destructor */
+};
+
+/* -----------------------------------------------------------------------------
+ * Stack - This is a simple generic stack implementation. It is used for
+ * example in the 'expr' expression compiler.
+ * ---------------------------------------------------------------------------*/
+void Jim_InitStack(Jim_Stack *stack)
+{
+    stack->len = 0;
+    stack->maxlen = 0;
+    stack->vector = NULL;
+}
+
+void Jim_FreeStack(Jim_Stack *stack)
+{
+    Jim_Free(stack->vector);
+}
+
+int Jim_StackLen(Jim_Stack *stack)
+{
+    return stack->len;
+}
+
+void Jim_StackPush(Jim_Stack *stack, void *element)
+{
+    int neededLen = stack->len + 1;
+
+    if (neededLen > stack->maxlen) {
+        stack->maxlen = neededLen < 20 ? 20 : neededLen * 2;
+        stack->vector = Jim_Realloc(stack->vector, sizeof(void *) * stack->maxlen);
+    }
+    stack->vector[stack->len] = element;
+    stack->len++;
+}
+
+void *Jim_StackPop(Jim_Stack *stack)
+{
+    if (stack->len == 0)
+        return NULL;
+    stack->len--;
+    return stack->vector[stack->len];
+}
+
+void *Jim_StackPeek(Jim_Stack *stack)
+{
+    if (stack->len == 0)
+        return NULL;
+    return stack->vector[stack->len - 1];
+}
+
+void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc) (void *ptr))
+{
+    int i;
+
+    for (i = 0; i < stack->len; i++)
+        freeFunc(stack->vector[i]);
+}
+
+/* -----------------------------------------------------------------------------
+ * Parser
+ * ---------------------------------------------------------------------------*/
+
+/* Token types */
+#define JIM_TT_NONE    0           /* No token returned */
+#define JIM_TT_STR     1          /* simple string */
+#define JIM_TT_ESC     2          /* string that needs escape chars conversion */
+#define JIM_TT_VAR     3          /* var substitution */
+#define JIM_TT_DICTSUGAR   4      /* Syntax sugar for [dict get], $foo(bar) */
+#define JIM_TT_CMD     5          /* command substitution */
+/* Note: Keep these three together for TOKEN_IS_SEP() */
+#define JIM_TT_SEP     6          /* word separator. arg is # of tokens. -ve if {*} */
+#define JIM_TT_EOL     7          /* line separator */
+#define JIM_TT_EOF     8          /* end of script */
+
+#define JIM_TT_LINE    9          /* special 'start-of-line' token. arg is # of arguments to the command. -ve if {*} */
+#define JIM_TT_WORD   10          /* special 'start-of-word' token. arg is # of tokens to combine. -ve if {*} */
+
+/* Additional token types needed for expressions */
+#define JIM_TT_SUBEXPR_START  11
+#define JIM_TT_SUBEXPR_END    12
+#define JIM_TT_SUBEXPR_COMMA  13
+#define JIM_TT_EXPR_INT       14
+#define JIM_TT_EXPR_DOUBLE    15
+
+#define JIM_TT_EXPRSUGAR      16  /* $(expression) */
+
+/* Operator token types start here */
+#define JIM_TT_EXPR_OP        20
+
+#define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
+
+/* Parser states */
+#define JIM_PS_DEF 0            /* Default state */
+#define JIM_PS_QUOTE 1          /* Inside "" */
+#define JIM_PS_DICTSUGAR 2      /* Tokenising abc(def) into 4 separate tokens */
+
+/* Parser context structure. The same context is used both to parse
+ * Tcl scripts and lists. */
+struct JimParserCtx
+{
+    const char *p;              /* Pointer to the point of the program we are parsing */
+    int len;                    /* Remaining length */
+    int linenr;                 /* Current line number */
+    const char *tstart;
+    const char *tend;           /* Returned token is at tstart-tend in 'prg'. */
+    int tline;                  /* Line number of the returned token */
+    int tt;                     /* Token type */
+    int eof;                    /* Non zero if EOF condition is true. */
+    int state;                  /* Parser state */
+    int comment;                /* Non zero if the next chars may be a comment. */
+    char missing;               /* At end of parse, ' ' if complete, '{' if braces incomplete, '"' if quotes incomplete */
+    int missingline;            /* Line number starting the missing token */
+};
+
+/**
+ * Results of missing quotes, braces, etc. from parsing.
+ */
+struct JimParseResult {
+    char missing;               /* From JimParserCtx.missing */
+    int line;                   /* From JimParserCtx.missingline */
+};
+
+static int JimParseScript(struct JimParserCtx *pc);
+static int JimParseSep(struct JimParserCtx *pc);
+static int JimParseEol(struct JimParserCtx *pc);
+static int JimParseCmd(struct JimParserCtx *pc);
+static int JimParseQuote(struct JimParserCtx *pc);
+static int JimParseVar(struct JimParserCtx *pc);
+static int JimParseBrace(struct JimParserCtx *pc);
+static int JimParseStr(struct JimParserCtx *pc);
+static int JimParseComment(struct JimParserCtx *pc);
+static void JimParseSubCmd(struct JimParserCtx *pc);
+static int JimParseSubQuote(struct JimParserCtx *pc);
+static void JimParseSubCmd(struct JimParserCtx *pc);
+static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc);
+
+/* Initialize a parser context.
+ * 'prg' is a pointer to the program text, linenr is the line
+ * number of the first line contained in the program. */
+static void JimParserInit(struct JimParserCtx *pc, const char *prg, int len, int linenr)
+{
+    pc->p = prg;
+    pc->len = len;
+    pc->tstart = NULL;
+    pc->tend = NULL;
+    pc->tline = 0;
+    pc->tt = JIM_TT_NONE;
+    pc->eof = 0;
+    pc->state = JIM_PS_DEF;
+    pc->linenr = linenr;
+    pc->comment = 1;
+    pc->missing = ' ';
+    pc->missingline = linenr;
+}
+
+static int JimParseScript(struct JimParserCtx *pc)
+{
+    while (1) {                 /* the while is used to reiterate with continue if needed */
+        if (!pc->len) {
+            pc->tstart = pc->p;
+            pc->tend = pc->p - 1;
+            pc->tline = pc->linenr;
+            pc->tt = JIM_TT_EOL;
+            pc->eof = 1;
+            return JIM_OK;
+        }
+        switch (*(pc->p)) {
+            case '\\':
+                if (*(pc->p + 1) == '\n' && pc->state == JIM_PS_DEF) {
+                    return JimParseSep(pc);
+                }
+                else {
+                    pc->comment = 0;
+                    return JimParseStr(pc);
+                }
+                break;
+            case ' ':
+            case '\t':
+            case '\r':
+                if (pc->state == JIM_PS_DEF)
+                    return JimParseSep(pc);
+                else {
+                    pc->comment = 0;
+                    return JimParseStr(pc);
+                }
+                break;
+            case '\n':
+            case ';':
+                pc->comment = 1;
+                if (pc->state == JIM_PS_DEF)
+                    return JimParseEol(pc);
+                else
+                    return JimParseStr(pc);
+                break;
+            case '[':
+                pc->comment = 0;
+                return JimParseCmd(pc);
+                break;
+            case '$':
+                pc->comment = 0;
+                if (JimParseVar(pc) == JIM_ERR) {
+                    pc->tstart = pc->tend = pc->p++;
+                    pc->len--;
+                    pc->tline = pc->linenr;
+                    pc->tt = JIM_TT_STR;
+                    return JIM_OK;
+                }
+                else
+                    return JIM_OK;
+                break;
+            case '#':
+                if (pc->comment) {
+                    JimParseComment(pc);
+                    continue;
+                }
+                else {
+                    return JimParseStr(pc);
+                }
+            default:
+                pc->comment = 0;
+                return JimParseStr(pc);
+                break;
+        }
+        return JIM_OK;
+    }
+}
+
+static int JimParseSep(struct JimParserCtx *pc)
+{
+    pc->tstart = pc->p;
+    pc->tline = pc->linenr;
+    while (*pc->p == ' ' || *pc->p == '\t' || *pc->p == '\r' ||
+        (*pc->p == '\\' && *(pc->p + 1) == '\n')) {
+        if (*pc->p == '\\') {
+            pc->p++;
+            pc->len--;
+            pc->linenr++;
+        }
+        pc->p++;
+        pc->len--;
+    }
+    pc->tend = pc->p - 1;
+    pc->tt = JIM_TT_SEP;
+    return JIM_OK;
+}
+
+static int JimParseEol(struct JimParserCtx *pc)
+{
+    pc->tstart = pc->p;
+    pc->tline = pc->linenr;
+    while (*pc->p == ' ' || *pc->p == '\n' || *pc->p == '\t' || *pc->p == '\r' || *pc->p == ';') {
+        if (*pc->p == '\n')
+            pc->linenr++;
+        pc->p++;
+        pc->len--;
+    }
+    pc->tend = pc->p - 1;
+    pc->tt = JIM_TT_EOL;
+    return JIM_OK;
+}
+
+/*
+** Here are the rules for parsing:
+** {braced expression}
+** - Count open and closing braces
+** - Backslash escapes meaning of braces
+**
+** "quoted expression"
+** - First double quote at start of word terminates the expression
+** - Backslash escapes quote and bracket
+** - [commands brackets] are counted/nested
+** - command rules apply within [brackets], not quoting rules (i.e. quotes have their own rules)
+**
+** [command expression]
+** - Count open and closing brackets
+** - Backslash escapes quote, bracket and brace
+** - [commands brackets] are counted/nested
+** - "quoted expressions" are parsed according to quoting rules
+** - {braced expressions} are parsed according to brace rules
+**
+** For everything, backslash escapes the next char, newline increments current line
+*/
+
+/**
+ * Parses a braced expression starting at pc->p.
+ *
+ * Positions the parser at the end of the braced expression,
+ * sets pc->tend and possibly pc->missing.
+ */
+static void JimParseSubBrace(struct JimParserCtx *pc)
+{
+    int level = 1;
+
+    /* Skip the brace */
+    pc->p++;
+    pc->len--;
+    while (pc->len) {
+        switch (*pc->p) {
+            case '\\':
+                if (pc->len > 1) {
+                    if (*++pc->p == '\n') {
+                        pc->linenr++;
+                    }
+                    pc->len--;
+                }
+                break;
+
+            case '{':
+                level++;
+                break;
+
+            case '}':
+                if (--level == 0) {
+                    pc->tend = pc->p - 1;
+                    pc->p++;
+                    pc->len--;
+                    return;
+                }
+                break;
+
+            case '\n':
+                pc->linenr++;
+                break;
+        }
+        pc->p++;
+        pc->len--;
+    }
+    pc->missing = '{';
+    pc->missingline = pc->tline;
+    pc->tend = pc->p - 1;
+}
+
+/**
+ * Parses a quoted expression starting at pc->p.
+ *
+ * Positions the parser at the end of the quoted expression,
+ * sets pc->tend and possibly pc->missing.
+ *
+ * Returns the type of the token of the string,
+ * either JIM_TT_ESC (if it contains values which need to be [subst]ed)
+ * or JIM_TT_STR.
+ */
+static int JimParseSubQuote(struct JimParserCtx *pc)
+{
+    int tt = JIM_TT_STR;
+    int line = pc->tline;
+
+    /* Skip the quote */
+    pc->p++;
+    pc->len--;
+    while (pc->len) {
+        switch (*pc->p) {
+            case '\\':
+                if (pc->len > 1) {
+                    if (*++pc->p == '\n') {
+                        pc->linenr++;
+                    }
+                    pc->len--;
+                    tt = JIM_TT_ESC;
+                }
+                break;
+
+            case '"':
+                pc->tend = pc->p - 1;
+                pc->p++;
+                pc->len--;
+                return tt;
+
+            case '[':
+                JimParseSubCmd(pc);
+                tt = JIM_TT_ESC;
+                continue;
+
+            case '\n':
+                pc->linenr++;
+                break;
+
+            case '$':
+                tt = JIM_TT_ESC;
+                break;
+        }
+        pc->p++;
+        pc->len--;
+    }
+    pc->missing = '"';
+    pc->missingline = line;
+    pc->tend = pc->p - 1;
+    return tt;
+}
+
+/**
+ * Parses a [command] expression starting at pc->p.
+ *
+ * Positions the parser at the end of the command expression,
+ * sets pc->tend and possibly pc->missing.
+ */
+static void JimParseSubCmd(struct JimParserCtx *pc)
+{
+    int level = 1;
+    int startofword = 1;
+    int line = pc->tline;
+
+    /* Skip the bracket */
+    pc->p++;
+    pc->len--;
+    while (pc->len) {
+        switch (*pc->p) {
+            case '\\':
+                if (pc->len > 1) {
+                    if (*++pc->p == '\n') {
+                        pc->linenr++;
+                    }
+                    pc->len--;
+                }
+                break;
+
+            case '[':
+                level++;
+                break;
+
+            case ']':
+                if (--level == 0) {
+                    pc->tend = pc->p - 1;
+                    pc->p++;
+                    pc->len--;
+                    return;
+                }
+                break;
+
+            case '"':
+                if (startofword) {
+                    JimParseSubQuote(pc);
+                    continue;
+                }
+                break;
+
+            case '{':
+                JimParseSubBrace(pc);
+                startofword = 0;
+                continue;
+
+            case '\n':
+                pc->linenr++;
+                break;
+        }
+        startofword = isspace(UCHAR(*pc->p));
+        pc->p++;
+        pc->len--;
+    }
+    pc->missing = '[';
+    pc->missingline = line;
+    pc->tend = pc->p - 1;
+}
+
+static int JimParseBrace(struct JimParserCtx *pc)
+{
+    pc->tstart = pc->p + 1;
+    pc->tline = pc->linenr;
+    pc->tt = JIM_TT_STR;
+    JimParseSubBrace(pc);
+    return JIM_OK;
+}
+
+static int JimParseCmd(struct JimParserCtx *pc)
+{
+    pc->tstart = pc->p + 1;
+    pc->tline = pc->linenr;
+    pc->tt = JIM_TT_CMD;
+    JimParseSubCmd(pc);
+    return JIM_OK;
+}
+
+static int JimParseQuote(struct JimParserCtx *pc)
+{
+    pc->tstart = pc->p + 1;
+    pc->tline = pc->linenr;
+    pc->tt = JimParseSubQuote(pc);
+    return JIM_OK;
+}
+
+static int JimParseVar(struct JimParserCtx *pc)
+{
+    /* skip the $ */
+    pc->p++;
+    pc->len--;
+
+#ifdef EXPRSUGAR_BRACKET
+    if (*pc->p == '[') {
+        /* Parse $[...] expr shorthand syntax */
+        JimParseCmd(pc);
+        pc->tt = JIM_TT_EXPRSUGAR;
+        return JIM_OK;
+    }
+#endif
+
+    pc->tstart = pc->p;
+    pc->tt = JIM_TT_VAR;
+    pc->tline = pc->linenr;
+
+    if (*pc->p == '{') {
+        pc->tstart = ++pc->p;
+        pc->len--;
+
+        while (pc->len && *pc->p != '}') {
+            if (*pc->p == '\n') {
+                pc->linenr++;
+            }
+            pc->p++;
+            pc->len--;
+        }
+        pc->tend = pc->p - 1;
+        if (pc->len) {
+            pc->p++;
+            pc->len--;
+        }
+    }
+    else {
+        while (1) {
+            /* Skip double colon, but not single colon! */
+            if (pc->p[0] == ':' && pc->p[1] == ':') {
+                pc->p += 2;
+                pc->len -= 2;
+                continue;
+            }
+            if (isalnum(UCHAR(*pc->p)) || *pc->p == '_') {
+                pc->p++;
+                pc->len--;
+                continue;
+            }
+            break;
+        }
+        /* Parse [dict get] syntax sugar. */
+        if (*pc->p == '(') {
+            int count = 1;
+            const char *paren = NULL;
+
+            pc->tt = JIM_TT_DICTSUGAR;
+
+            while (count && pc->len) {
+                pc->p++;
+                pc->len--;
+                if (*pc->p == '\\' && pc->len >= 1) {
+                    pc->p++;
+                    pc->len--;
+                }
+                else if (*pc->p == '(') {
+                    count++;
+                }
+                else if (*pc->p == ')') {
+                    paren = pc->p;
+                    count--;
+                }
+            }
+            if (count == 0) {
+                pc->p++;
+                pc->len--;
+            }
+            else if (paren) {
+                /* Did not find a matching paren. Back up */
+                paren++;
+                pc->len += (pc->p - paren);
+                pc->p = paren;
+            }
+#ifndef EXPRSUGAR_BRACKET
+            if (*pc->tstart == '(') {
+                pc->tt = JIM_TT_EXPRSUGAR;
+            }
+#endif
+        }
+        pc->tend = pc->p - 1;
+    }
+    /* Check if we parsed just the '$' character.
+     * That's not a variable so an error is returned
+     * to tell the state machine to consider this '$' just
+     * a string. */
+    if (pc->tstart == pc->p) {
+        pc->p--;
+        pc->len++;
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+static int JimParseStr(struct JimParserCtx *pc)
+{
+    int newword = (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
+        pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR);
+    if (newword && *pc->p == '{') {
+        return JimParseBrace(pc);
+    }
+    else if (newword && *pc->p == '"') {
+        pc->state = JIM_PS_QUOTE;
+        pc->p++;
+        pc->len--;
+        /* In case the end quote is missing */
+        pc->missingline = pc->tline;
+    }
+    pc->tstart = pc->p;
+    pc->tline = pc->linenr;
+    while (1) {
+        if (pc->len == 0) {
+            if (pc->state == JIM_PS_QUOTE) {
+                pc->missing = '"';
+            }
+            pc->tend = pc->p - 1;
+            pc->tt = JIM_TT_ESC;
+            return JIM_OK;
+        }
+        switch (*pc->p) {
+            case '\\':
+                if (pc->state == JIM_PS_DEF && *(pc->p + 1) == '\n') {
+                    pc->tend = pc->p - 1;
+                    pc->tt = JIM_TT_ESC;
+                    return JIM_OK;
+                }
+                if (pc->len >= 2) {
+                    if (*(pc->p + 1) == '\n') {
+                        pc->linenr++;
+                    }
+                    pc->p++;
+                    pc->len--;
+                }
+                break;
+            case '(':
+                /* If the following token is not '$' just keep going */
+                if (pc->len > 1 && pc->p[1] != '$') {
+                    break;
+                }
+            case ')':
+                /* Only need a separate ')' token if the previous was a var */
+                if (*pc->p == '(' || pc->tt == JIM_TT_VAR) {
+                    if (pc->p == pc->tstart) {
+                        /* At the start of the token, so just return this char */
+                        pc->p++;
+                        pc->len--;
+                    }
+                    pc->tend = pc->p - 1;
+                    pc->tt = JIM_TT_ESC;
+                    return JIM_OK;
+                }
+                break;
+
+            case '$':
+            case '[':
+                pc->tend = pc->p - 1;
+                pc->tt = JIM_TT_ESC;
+                return JIM_OK;
+            case ' ':
+            case '\t':
+            case '\n':
+            case '\r':
+            case ';':
+                if (pc->state == JIM_PS_DEF) {
+                    pc->tend = pc->p - 1;
+                    pc->tt = JIM_TT_ESC;
+                    return JIM_OK;
+                }
+                else if (*pc->p == '\n') {
+                    pc->linenr++;
+                }
+                break;
+            case '"':
+                if (pc->state == JIM_PS_QUOTE) {
+                    pc->tend = pc->p - 1;
+                    pc->tt = JIM_TT_ESC;
+                    pc->p++;
+                    pc->len--;
+                    pc->state = JIM_PS_DEF;
+                    return JIM_OK;
+                }
+                break;
+        }
+        pc->p++;
+        pc->len--;
+    }
+    return JIM_OK;              /* unreached */
+}
+
+static int JimParseComment(struct JimParserCtx *pc)
+{
+    while (*pc->p) {
+        if (*pc->p == '\n') {
+            pc->linenr++;
+            if (*(pc->p - 1) != '\\') {
+                pc->p++;
+                pc->len--;
+                return JIM_OK;
+            }
+        }
+        pc->p++;
+        pc->len--;
+    }
+    return JIM_OK;
+}
+
+/* xdigitval and odigitval are helper functions for JimEscape() */
+static int xdigitval(int c)
+{
+    if (c >= '0' && c <= '9')
+        return c - '0';
+    if (c >= 'a' && c <= 'f')
+        return c - 'a' + 10;
+    if (c >= 'A' && c <= 'F')
+        return c - 'A' + 10;
+    return -1;
+}
+
+static int odigitval(int c)
+{
+    if (c >= '0' && c <= '7')
+        return c - '0';
+    return -1;
+}
+
+/* Perform Tcl escape substitution of 's', storing the result
+ * string into 'dest'. The escaped string is guaranteed to
+ * be the same length or shorted than the source string.
+ * Slen is the length of the string at 's', if it's -1 the string
+ * length will be calculated by the function.
+ *
+ * The function returns the length of the resulting string. */
+static int JimEscape(char *dest, const char *s, int slen)
+{
+    char *p = dest;
+    int i, len;
+
+    if (slen == -1)
+        slen = strlen(s);
+
+    for (i = 0; i < slen; i++) {
+        switch (s[i]) {
+            case '\\':
+                switch (s[i + 1]) {
+                    case 'a':
+                        *p++ = 0x7;
+                        i++;
+                        break;
+                    case 'b':
+                        *p++ = 0x8;
+                        i++;
+                        break;
+                    case 'f':
+                        *p++ = 0xc;
+                        i++;
+                        break;
+                    case 'n':
+                        *p++ = 0xa;
+                        i++;
+                        break;
+                    case 'r':
+                        *p++ = 0xd;
+                        i++;
+                        break;
+                    case 't':
+                        *p++ = 0x9;
+                        i++;
+                        break;
+                    case 'u':
+                    case 'x':
+                        /* A unicode or hex sequence.
+                         * \u Expect 1-4 hex chars and convert to utf-8.
+                         * \x Expect 1-2 hex chars and convert to hex.
+                         * An invalid sequence means simply the escaped char.
+                         */
+                        {
+                            int val = 0;
+                            int k;
+
+                            i++;
+
+                            for (k = 0; k < (s[i] == 'u' ? 4 : 2); k++) {
+                                int c = xdigitval(s[i + k + 1]);
+                                if (c == -1) {
+                                    break;
+                                }
+                                val = (val << 4) | c;
+                            }
+                            if (k) {
+                                /* Got a valid sequence, so convert */
+                                if (s[i] == 'u') {
+                                    p += utf8_fromunicode(p, val);
+                                }
+                                else {
+                                    *p++ = val;
+                                }
+                                i += k;
+                                break;
+                            }
+                            /* Not a valid codepoint, just an escaped char */
+                            *p++ = s[i];
+                        }
+                        break;
+                    case 'v':
+                        *p++ = 0xb;
+                        i++;
+                        break;
+                    case '\0':
+                        *p++ = '\\';
+                        i++;
+                        break;
+                    case '\n':
+                        /* Replace all spaces and tabs after backslash newline with a single space*/
+                        *p++ = ' ';
+                        do {
+                            i++;
+                        } while (s[i + 1] == ' ' || s[i + 1] == '\t');
+                        break;
+                    case '0':
+                    case '1':
+                    case '2':
+                    case '3':
+                    case '4':
+                    case '5':
+                    case '6':
+                    case '7':
+                        /* octal escape */
+                        {
+                            int val = 0;
+                            int c = odigitval(s[i + 1]);
+
+                            val = c;
+                            c = odigitval(s[i + 2]);
+                            if (c == -1) {
+                                *p++ = val;
+                                i++;
+                                break;
+                            }
+                            val = (val * 8) + c;
+                            c = odigitval(s[i + 3]);
+                            if (c == -1) {
+                                *p++ = val;
+                                i += 2;
+                                break;
+                            }
+                            val = (val * 8) + c;
+                            *p++ = val;
+                            i += 3;
+                        }
+                        break;
+                    default:
+                        *p++ = s[i + 1];
+                        i++;
+                        break;
+                }
+                break;
+            default:
+                *p++ = s[i];
+                break;
+        }
+    }
+    len = p - dest;
+    *p = '\0';
+    return len;
+}
+
+/* Returns a dynamically allocated copy of the current token in the
+ * parser context. The function performs conversion of escapes if
+ * the token is of type JIM_TT_ESC.
+ *
+ * Note that after the conversion, tokens that are grouped with
+ * braces in the source code, are always recognizable from the
+ * identical string obtained in a different way from the type.
+ *
+ * For example the string:
+ *
+ * {*}$a
+ *
+ * will return as first token "*", of type JIM_TT_STR
+ *
+ * While the string:
+ *
+ * *$a
+ *
+ * will return as first token "*", of type JIM_TT_ESC
+ */
+static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc)
+{
+    const char *start, *end;
+    char *token;
+    int len;
+
+    start = pc->tstart;
+    end = pc->tend;
+    if (start > end) {
+        len = 0;
+        token = Jim_Alloc(1);
+        token[0] = '\0';
+    }
+    else {
+        len = (end - start) + 1;
+        token = Jim_Alloc(len + 1);
+        if (pc->tt != JIM_TT_ESC) {
+            /* No escape conversion needed? Just copy it. */
+            memcpy(token, start, len);
+            token[len] = '\0';
+        }
+        else {
+            /* Else convert the escape chars. */
+            len = JimEscape(token, start, len);
+        }
+    }
+
+    return Jim_NewStringObjNoAlloc(interp, token, len);
+}
+
+/* Parses the given string to determine if it represents a complete script.
+ *
+ * This is useful for interactive shells implementation, for [info complete].
+ *
+ * If 'stateCharPtr' != NULL, the function stores ' ' on complete script,
+ * '{' on scripts incomplete missing one or more '}' to be balanced.
+ * '[' on scripts incomplete missing one or more ']' to be balanced.
+ * '"' on scripts incomplete missing a '"' char.
+ *
+ * If the script is complete, 1 is returned, otherwise 0.
+ */
+int Jim_ScriptIsComplete(const char *s, int len, char *stateCharPtr)
+{
+    struct JimParserCtx parser;
+
+    JimParserInit(&parser, s, len, 1);
+    while (!parser.eof) {
+        JimParseScript(&parser);
+    }
+    if (stateCharPtr) {
+        *stateCharPtr = parser.missing;
+    }
+    return parser.missing == ' ';
+}
+
+/* -----------------------------------------------------------------------------
+ * Tcl Lists parsing
+ * ---------------------------------------------------------------------------*/
+static int JimParseListSep(struct JimParserCtx *pc);
+static int JimParseListStr(struct JimParserCtx *pc);
+static int JimParseListQuote(struct JimParserCtx *pc);
+
+static int JimParseList(struct JimParserCtx *pc)
+{
+    switch (*pc->p) {
+        case ' ':
+        case '\n':
+        case '\t':
+        case '\r':
+            return JimParseListSep(pc);
+
+        case '"':
+            return JimParseListQuote(pc);
+
+        case '{':
+            return JimParseBrace(pc);
+
+        default:
+            if (pc->len) {
+                return JimParseListStr(pc);
+            }
+            break;
+    }
+
+    pc->tstart = pc->tend = pc->p;
+    pc->tline = pc->linenr;
+    pc->tt = JIM_TT_EOL;
+    pc->eof = 1;
+    return JIM_OK;
+}
+
+static int JimParseListSep(struct JimParserCtx *pc)
+{
+    pc->tstart = pc->p;
+    pc->tline = pc->linenr;
+    while (*pc->p == ' ' || *pc->p == '\t' || *pc->p == '\r' || *pc->p == '\n') {
+        if (*pc->p == '\n') {
+            pc->linenr++;
+        }
+        pc->p++;
+        pc->len--;
+    }
+    pc->tend = pc->p - 1;
+    pc->tt = JIM_TT_SEP;
+    return JIM_OK;
+}
+
+static int JimParseListQuote(struct JimParserCtx *pc)
+{
+    pc->p++;
+    pc->len--;
+
+    pc->tstart = pc->p;
+    pc->tline = pc->linenr;
+    pc->tt = JIM_TT_STR;
+
+    while (pc->len) {
+        switch (*pc->p) {
+            case '\\':
+                pc->tt = JIM_TT_ESC;
+                if (--pc->len == 0) {
+                    /* Trailing backslash */
+                    pc->tend = pc->p;
+                    return JIM_OK;
+                }
+                pc->p++;
+                break;
+            case '\n':
+                pc->linenr++;
+                break;
+            case '"':
+                pc->tend = pc->p - 1;
+                pc->p++;
+                pc->len--;
+                return JIM_OK;
+        }
+        pc->p++;
+        pc->len--;
+    }
+
+    pc->tend = pc->p - 1;
+    return JIM_OK;
+}
+
+static int JimParseListStr(struct JimParserCtx *pc)
+{
+    pc->tstart = pc->p;
+    pc->tline = pc->linenr;
+    pc->tt = JIM_TT_STR;
+
+    while (pc->len) {
+        switch (*pc->p) {
+            case '\\':
+                if (--pc->len == 0) {
+                    /* Trailing backslash */
+                    pc->tend = pc->p;
+                    return JIM_OK;
+                }
+                pc->tt = JIM_TT_ESC;
+                pc->p++;
+                break;
+            case ' ':
+            case '\t':
+            case '\n':
+            case '\r':
+                pc->tend = pc->p - 1;
+                return JIM_OK;
+        }
+        pc->p++;
+        pc->len--;
+    }
+    pc->tend = pc->p - 1;
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * Jim_Obj related functions
+ * ---------------------------------------------------------------------------*/
+
+/* Return a new initialized object. */
+Jim_Obj *Jim_NewObj(Jim_Interp *interp)
+{
+    Jim_Obj *objPtr;
+
+    /* -- Check if there are objects in the free list -- */
+    if (interp->freeList != NULL) {
+        /* -- Unlink the object from the free list -- */
+        objPtr = interp->freeList;
+        interp->freeList = objPtr->nextObjPtr;
+    }
+    else {
+        /* -- No ready to use objects: allocate a new one -- */
+        objPtr = Jim_Alloc(sizeof(*objPtr));
+    }
+
+    /* Object is returned with refCount of 0. Every
+     * kind of GC implemented should take care to don't try
+     * to scan objects with refCount == 0. */
+    objPtr->refCount = 0;
+    /* All the other fields are left not initialized to save time.
+     * The caller will probably want to set them to the right
+     * value anyway. */
+
+    /* -- Put the object into the live list -- */
+    objPtr->prevObjPtr = NULL;
+    objPtr->nextObjPtr = interp->liveList;
+    if (interp->liveList)
+        interp->liveList->prevObjPtr = objPtr;
+    interp->liveList = objPtr;
+
+    return objPtr;
+}
+
+/* Free an object. Actually objects are never freed, but
+ * just moved to the free objects list, where they will be
+ * reused by Jim_NewObj(). */
+void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    /* Check if the object was already freed, panic. */
+    JimPanic((objPtr->refCount != 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr,
+        objPtr->refCount, objPtr->typePtr ? objPtr->typePtr->name : "<none>"));
+
+    /* Free the internal representation */
+    Jim_FreeIntRep(interp, objPtr);
+    /* Free the string representation */
+    if (objPtr->bytes != NULL) {
+        if (objPtr->bytes != JimEmptyStringRep)
+            Jim_Free(objPtr->bytes);
+    }
+    /* Unlink the object from the live objects list */
+    if (objPtr->prevObjPtr)
+        objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr;
+    if (objPtr->nextObjPtr)
+        objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr;
+    if (interp->liveList == objPtr)
+        interp->liveList = objPtr->nextObjPtr;
+    /* Link the object into the free objects list */
+    objPtr->prevObjPtr = NULL;
+    objPtr->nextObjPtr = interp->freeList;
+    if (interp->freeList)
+        interp->freeList->prevObjPtr = objPtr;
+    interp->freeList = objPtr;
+    objPtr->refCount = -1;
+}
+
+/* Invalidate the string representation of an object. */
+void Jim_InvalidateStringRep(Jim_Obj *objPtr)
+{
+    if (objPtr->bytes != NULL) {
+        if (objPtr->bytes != JimEmptyStringRep)
+            Jim_Free(objPtr->bytes);
+    }
+    objPtr->bytes = NULL;
+}
+
+#define Jim_SetStringRep(o, b, l) \
+    do { (o)->bytes = b; (o)->length = l; } while (0)
+
+/* Set the initial string representation for an object.
+ * Does not try to free an old one. */
+void Jim_InitStringRep(Jim_Obj *objPtr, const char *bytes, int length)
+{
+    if (length == 0) {
+        objPtr->bytes = JimEmptyStringRep;
+        objPtr->length = 0;
+    }
+    else {
+        objPtr->bytes = Jim_Alloc(length + 1);
+        objPtr->length = length;
+        memcpy(objPtr->bytes, bytes, length);
+        objPtr->bytes[length] = '\0';
+    }
+}
+
+/* Duplicate an object. The returned object has refcount = 0. */
+Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    Jim_Obj *dupPtr;
+
+    dupPtr = Jim_NewObj(interp);
+    if (objPtr->bytes == NULL) {
+        /* Object does not have a valid string representation. */
+        dupPtr->bytes = NULL;
+    }
+    else {
+        Jim_InitStringRep(dupPtr, objPtr->bytes, objPtr->length);
+    }
+
+    /* By default, the new object has the same type as the old object */
+    dupPtr->typePtr = objPtr->typePtr;
+    if (objPtr->typePtr != NULL) {
+        if (objPtr->typePtr->dupIntRepProc == NULL) {
+            dupPtr->internalRep = objPtr->internalRep;
+        }
+        else {
+            /* The dup proc may set a different type, e.g. NULL */
+            objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr);
+        }
+    }
+    return dupPtr;
+}
+
+/* Return the string representation for objPtr. If the object
+ * string representation is invalid, calls the method to create
+ * a new one starting from the internal representation of the object. */
+const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr)
+{
+    if (objPtr->bytes == NULL) {
+        /* Invalid string repr. Generate it. */
+        JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
+        objPtr->typePtr->updateStringProc(objPtr);
+    }
+    if (lenPtr)
+        *lenPtr = objPtr->length;
+    return objPtr->bytes;
+}
+
+/* Just returns the length of the object's string rep */
+int Jim_Length(Jim_Obj *objPtr)
+{
+    int len;
+
+    Jim_GetString(objPtr, &len);
+    return len;
+}
+
+static void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+
+static const Jim_ObjType dictSubstObjType = {
+    "dict-substitution",
+    FreeDictSubstInternalRep,
+    DupDictSubstInternalRep,
+    NULL,
+    JIM_TYPE_NONE,
+};
+
+static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    Jim_DecrRefCount(interp, (Jim_Obj *)objPtr->internalRep.twoPtrValue.ptr2);
+}
+
+static const Jim_ObjType interpolatedObjType = {
+    "interpolated",
+    FreeInterpolatedInternalRep,
+    NULL,
+    NULL,
+    JIM_TYPE_NONE,
+};
+
+/* -----------------------------------------------------------------------------
+ * String Object
+ * ---------------------------------------------------------------------------*/
+static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType stringObjType = {
+    "string",
+    NULL,
+    DupStringInternalRep,
+    NULL,
+    JIM_TYPE_REFERENCES,
+};
+
+static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+    JIM_NOTUSED(interp);
+
+    /* This is a bit subtle: the only caller of this function
+     * should be Jim_DuplicateObj(), that will copy the
+     * string representaion. After the copy, the duplicated
+     * object will not have more room in teh buffer than
+     * srcPtr->length bytes. So we just set it to length. */
+    dupPtr->internalRep.strValue.maxLength = srcPtr->length;
+
+    dupPtr->internalRep.strValue.charLength = srcPtr->internalRep.strValue.charLength;
+}
+
+static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    /* Get a fresh string representation. */
+    (void)Jim_String(objPtr);
+    /* Free any other internal representation. */
+    Jim_FreeIntRep(interp, objPtr);
+    /* Set it as string, i.e. just set the maxLength field. */
+    objPtr->typePtr = &stringObjType;
+    objPtr->internalRep.strValue.maxLength = objPtr->length;
+    /* Don't know the utf-8 length yet */
+    objPtr->internalRep.strValue.charLength = -1;
+    return JIM_OK;
+}
+
+/**
+ * Returns the length of the object string in chars, not bytes.
+ *
+ * These may be different for a utf-8 string.
+ */
+int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+#ifdef JIM_UTF8
+    if (objPtr->typePtr != &stringObjType)
+        SetStringFromAny(interp, objPtr);
+
+    if (objPtr->internalRep.strValue.charLength < 0) {
+        objPtr->internalRep.strValue.charLength = utf8_strlen(objPtr->bytes, objPtr->length);
+    }
+    return objPtr->internalRep.strValue.charLength;
+#else
+    return Jim_Length(objPtr);
+#endif
+}
+
+/* len is in bytes -- see also Jim_NewStringObjUtf8() */
+Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len)
+{
+    Jim_Obj *objPtr = Jim_NewObj(interp);
+
+    /* Need to find out how many bytes the string requires */
+    if (len == -1)
+        len = strlen(s);
+    /* Alloc/Set the string rep. */
+    if (len == 0) {
+        objPtr->bytes = JimEmptyStringRep;
+        objPtr->length = 0;
+    }
+    else {
+        objPtr->bytes = Jim_Alloc(len + 1);
+        objPtr->length = len;
+        memcpy(objPtr->bytes, s, len);
+        objPtr->bytes[len] = '\0';
+    }
+
+    /* No typePtr field for the vanilla string object. */
+    objPtr->typePtr = NULL;
+    return objPtr;
+}
+
+/* charlen is in characters -- see also Jim_NewStringObj() */
+Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, const char *s, int charlen)
+{
+#ifdef JIM_UTF8
+    /* Need to find out how many bytes the string requires */
+    int bytelen = utf8_index(s, charlen);
+
+    Jim_Obj *objPtr = Jim_NewStringObj(interp, s, bytelen);
+
+    /* Remember the utf8 length, so set the type */
+    objPtr->typePtr = &stringObjType;
+    objPtr->internalRep.strValue.maxLength = bytelen;
+    objPtr->internalRep.strValue.charLength = charlen;
+
+    return objPtr;
+#else
+    return Jim_NewStringObj(interp, s, charlen);
+#endif
+}
+
+/* This version does not try to duplicate the 's' pointer, but
+ * use it directly. */
+Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len)
+{
+    Jim_Obj *objPtr = Jim_NewObj(interp);
+
+    if (len == -1)
+        len = strlen(s);
+    Jim_SetStringRep(objPtr, s, len);
+    objPtr->typePtr = NULL;
+    return objPtr;
+}
+
+/* Low-level string append. Use it only against objects
+ * of type "string". */
+static void StringAppendString(Jim_Obj *objPtr, const char *str, int len)
+{
+    int needlen;
+
+    if (len == -1)
+        len = strlen(str);
+    needlen = objPtr->length + len;
+    if (objPtr->internalRep.strValue.maxLength < needlen ||
+        objPtr->internalRep.strValue.maxLength == 0) {
+        needlen *= 2;
+        /* Inefficient to malloc() for less than 8 bytes */
+        if (needlen < 7) {
+            needlen = 7;
+        }
+        if (objPtr->bytes == JimEmptyStringRep) {
+            objPtr->bytes = Jim_Alloc(needlen + 1);
+        }
+        else {
+            objPtr->bytes = Jim_Realloc(objPtr->bytes, needlen + 1);
+        }
+        objPtr->internalRep.strValue.maxLength = needlen;
+    }
+    memcpy(objPtr->bytes + objPtr->length, str, len);
+    objPtr->bytes[objPtr->length + len] = '\0';
+    if (objPtr->internalRep.strValue.charLength >= 0) {
+        /* Update the utf-8 char length */
+        objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len);
+    }
+    objPtr->length += len;
+}
+
+/* Higher level API to append strings to objects. */
+void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str, int len)
+{
+    JimPanic((Jim_IsShared(objPtr), "Jim_AppendString called with shared object"));
+    if (objPtr->typePtr != &stringObjType)
+        SetStringFromAny(interp, objPtr);
+    StringAppendString(objPtr, str, len);
+}
+
+void Jim_AppendObj(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *appendObjPtr)
+{
+    int len;
+    const char *str;
+
+    str = Jim_GetString(appendObjPtr, &len);
+    Jim_AppendString(interp, objPtr, str, len);
+}
+
+void Jim_AppendStrings(Jim_Interp *interp, Jim_Obj *objPtr, ...)
+{
+    va_list ap;
+
+    if (objPtr->typePtr != &stringObjType)
+        SetStringFromAny(interp, objPtr);
+    va_start(ap, objPtr);
+    while (1) {
+        char *s = va_arg(ap, char *);
+
+        if (s == NULL)
+            break;
+        Jim_AppendString(interp, objPtr, s, -1);
+    }
+    va_end(ap);
+}
+
+int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr)
+{
+    const char *aStr, *bStr;
+    int aLen, bLen;
+
+    if (aObjPtr == bObjPtr)
+        return 1;
+    aStr = Jim_GetString(aObjPtr, &aLen);
+    bStr = Jim_GetString(bObjPtr, &bLen);
+    if (aLen != bLen)
+        return 0;
+    return JimStringCompare(aStr, aLen, bStr, bLen) == 0;
+}
+
+int Jim_StringMatchObj(Jim_Interp *interp, Jim_Obj *patternObjPtr, Jim_Obj *objPtr, int nocase)
+{
+    return JimStringMatch(interp, patternObjPtr, Jim_String(objPtr), nocase);
+}
+
+int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase)
+{
+    const char *s1, *s2;
+    int l1, l2;
+
+    s1 = Jim_GetString(firstObjPtr, &l1);
+    s2 = Jim_GetString(secondObjPtr, &l2);
+
+    if (nocase) {
+        return JimStringCompareNoCase(s1, s2, -1);
+    }
+    return JimStringCompare(s1, l1, s2, l2);
+}
+
+/* Convert a range, as returned by Jim_GetRange(), into
+ * an absolute index into an object of the specified length.
+ * This function may return negative values, or values
+ * bigger or equal to the length of the list if the index
+ * is out of range. */
+static int JimRelToAbsIndex(int len, int idx)
+{
+    if (idx < 0)
+        return len + idx;
+    return idx;
+}
+
+/* Convert a pair of index as normalize by JimRelToAbsIndex(),
+ * into a range stored in *firstPtr, *lastPtr, *rangeLenPtr, suitable
+ * for implementation of commands like [string range] and [lrange].
+ *
+ * The resulting range is guaranteed to address valid elements of
+ * the structure. */
+static void JimRelToAbsRange(int len, int first, int last,
+    int *firstPtr, int *lastPtr, int *rangeLenPtr)
+{
+    int rangeLen;
+
+    if (first > last) {
+        rangeLen = 0;
+    }
+    else {
+        rangeLen = last - first + 1;
+        if (rangeLen) {
+            if (first < 0) {
+                rangeLen += first;
+                first = 0;
+            }
+            if (last >= len) {
+                rangeLen -= (last - (len - 1));
+                last = len - 1;
+            }
+        }
+    }
+    if (rangeLen < 0)
+        rangeLen = 0;
+
+    *firstPtr = first;
+    *lastPtr = last;
+    *rangeLenPtr = rangeLen;
+}
+
+Jim_Obj *Jim_StringByteRangeObj(Jim_Interp *interp,
+    Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
+{
+    int first, last;
+    const char *str;
+    int rangeLen;
+    int bytelen;
+
+    if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
+        Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
+        return NULL;
+    str = Jim_GetString(strObjPtr, &bytelen);
+    first = JimRelToAbsIndex(bytelen, first);
+    last = JimRelToAbsIndex(bytelen, last);
+    JimRelToAbsRange(bytelen, first, last, &first, &last, &rangeLen);
+    if (first == 0 && rangeLen == bytelen) {
+        return strObjPtr;
+    }
+    return Jim_NewStringObj(interp, str + first, rangeLen);
+}
+
+Jim_Obj *Jim_StringRangeObj(Jim_Interp *interp,
+    Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
+{
+#ifdef JIM_UTF8
+    int first, last;
+    const char *str;
+    int len, rangeLen;
+    int bytelen;
+
+    if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
+        Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
+        return NULL;
+    str = Jim_GetString(strObjPtr, &bytelen);
+    len = Jim_Utf8Length(interp, strObjPtr);
+    first = JimRelToAbsIndex(len, first);
+    last = JimRelToAbsIndex(len, last);
+    JimRelToAbsRange(len, first, last, &first, &last, &rangeLen);
+    if (first == 0 && rangeLen == len) {
+        return strObjPtr;
+    }
+    if (len == bytelen) {
+        /* ASCII optimisation */
+        return Jim_NewStringObj(interp, str + first, rangeLen);
+    }
+    return Jim_NewStringObjUtf8(interp, str + utf8_index(str, first), rangeLen);
+#else
+    return Jim_StringByteRangeObj(interp, strObjPtr, firstObjPtr, lastObjPtr);
+#endif
+}
+
+static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr)
+{
+    char *buf, *p;
+    int len;
+    const char *str;
+
+    if (strObjPtr->typePtr != &stringObjType) {
+        SetStringFromAny(interp, strObjPtr);
+    }
+
+    str = Jim_GetString(strObjPtr, &len);
+
+    buf = p = Jim_Alloc(len + 1);
+    while (*str) {
+        int c;
+        str += utf8_tounicode(str, &c);
+        p += utf8_fromunicode(p, utf8_lower(c));
+    }
+    *p = 0;
+    return Jim_NewStringObjNoAlloc(interp, buf, len);
+}
+
+static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr)
+{
+    char *buf, *p;
+    int len;
+    const char *str;
+
+    if (strObjPtr->typePtr != &stringObjType) {
+        SetStringFromAny(interp, strObjPtr);
+    }
+
+    str = Jim_GetString(strObjPtr, &len);
+
+    buf = p = Jim_Alloc(len + 1);
+    while (*str) {
+        int c;
+        str += utf8_tounicode(str, &c);
+        p += utf8_fromunicode(p, utf8_upper(c));
+    }
+    *p = 0;
+    return Jim_NewStringObjNoAlloc(interp, buf, len);
+}
+
+/* Similar to memchr() except searches a UTF-8 string 'str' of byte length 'len'
+ * for unicode character 'c'.
+ * Returns the position if found or NULL if not
+ */
+static const char *utf8_memchr(const char *str, int len, int c)
+{
+#ifdef JIM_UTF8
+    while (len) {
+        int sc;
+        int n = utf8_tounicode(str, &sc);
+        if (sc == c) {
+            return str;
+        }
+        str += n;
+        len -= n;
+    }
+    return NULL;
+#else
+    return memchr(str, c, len);
+#endif
+}
+
+/**
+ * Searches for the first non-trim char in string (str, len)
+ *
+ * If none is found, returns just past the last char.
+ *
+ * Lengths are in bytes.
+ */
+static const char *JimFindTrimLeft(const char *str, int len, const char *trimchars, int trimlen)
+{
+    while (len) {
+        int c;
+        int n = utf8_tounicode(str, &c);
+
+        if (utf8_memchr(trimchars, trimlen, c) == NULL) {
+            /* Not a trim char, so stop */
+            break;
+        }
+        str += n;
+        len -= n;
+    }
+    return str;
+}
+
+/**
+ * Searches backwards for a non-trim char in string (str, len).
+ *
+ * Returns a pointer to just after the non-trim char, or NULL if not found.
+ *
+ * Lengths are in bytes.
+ */
+static const char *JimFindTrimRight(const char *str, int len, const char *trimchars, int trimlen)
+{
+    str += len;
+
+    while (len) {
+        int c;
+        int n = utf8_prev_len(str, len);
+
+        len -= n;
+        str -= n;
+
+        n = utf8_tounicode(str, &c);
+
+        if (utf8_memchr(trimchars, trimlen, c) == NULL) {
+            return str + n;
+        }
+    }
+
+    return NULL;
+}
+
+static const char default_trim_chars[] = " \t\n\r";
+/* sizeof() here includes the null byte */
+static int default_trim_chars_len = sizeof(default_trim_chars);
+
+static Jim_Obj *JimStringTrimLeft(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
+{
+    int len;
+    const char *str = Jim_GetString(strObjPtr, &len);
+    const char *trimchars = default_trim_chars;
+    int trimcharslen = default_trim_chars_len;
+    const char *newstr;
+
+    if (trimcharsObjPtr) {
+        trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen);
+    }
+
+    newstr = JimFindTrimLeft(str, len, trimchars, trimcharslen);
+    if (newstr == str) {
+        return strObjPtr;
+    }
+
+    return Jim_NewStringObj(interp, newstr, len - (newstr - str));
+}
+
+static Jim_Obj *JimStringTrimRight(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
+{
+    int len;
+    const char *trimchars = default_trim_chars;
+    int trimcharslen = default_trim_chars_len;
+    const char *nontrim;
+
+    if (trimcharsObjPtr) {
+        trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen);
+    }
+
+    if (strObjPtr->typePtr != &stringObjType) {
+        SetStringFromAny(interp, strObjPtr);
+    }
+    len = Jim_Length(strObjPtr);
+    nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen);
+
+    if (nontrim == NULL) {
+        /* All trim, so return a zero-length string */
+        return Jim_NewEmptyStringObj(interp);
+    }
+    if (nontrim == strObjPtr->bytes + len) {
+        return strObjPtr;
+    }
+
+    if (Jim_IsShared(strObjPtr)) {
+        strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes));
+    }
+    else {
+        /* Can modify this string in place */
+        strObjPtr->bytes[nontrim - strObjPtr->bytes] = 0;
+        strObjPtr->length = (nontrim - strObjPtr->bytes);
+    }
+
+    return strObjPtr;
+}
+
+static Jim_Obj *JimStringTrim(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
+{
+    /* First trim left. */
+    Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr);
+
+    /* Now trim right */
+    strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr);
+
+    if (objPtr != strObjPtr) {
+        /* Note that we don't want this object to be leaked */
+        Jim_IncrRefCount(objPtr);
+        Jim_DecrRefCount(interp, objPtr);
+    }
+
+    return strObjPtr;
+}
+
+
+static int JimStringIs(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *strClass, int strict)
+{
+    static const char * const strclassnames[] = {
+        "integer", "alpha", "alnum", "ascii", "digit",
+        "double", "lower", "upper", "space", "xdigit",
+        "control", "print", "graph", "punct",
+        NULL
+    };
+    enum {
+        STR_IS_INTEGER, STR_IS_ALPHA, STR_IS_ALNUM, STR_IS_ASCII, STR_IS_DIGIT,
+        STR_IS_DOUBLE, STR_IS_LOWER, STR_IS_UPPER, STR_IS_SPACE, STR_IS_XDIGIT,
+        STR_IS_CONTROL, STR_IS_PRINT, STR_IS_GRAPH, STR_IS_PUNCT
+    };
+    int strclass;
+    int len;
+    int i;
+    const char *str;
+    int (*isclassfunc)(int c) = NULL;
+
+    if (Jim_GetEnum(interp, strClass, strclassnames, &strclass, "class", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    str = Jim_GetString(strObjPtr, &len);
+    if (len == 0) {
+        Jim_SetResultInt(interp, !strict);
+        return JIM_OK;
+    }
+
+    switch (strclass) {
+        case STR_IS_INTEGER:
+            {
+                jim_wide w;
+                Jim_SetResultInt(interp, JimGetWideNoErr(interp, strObjPtr, &w) == JIM_OK);
+                return JIM_OK;
+            }
+
+        case STR_IS_DOUBLE:
+            {
+                double d;
+                Jim_SetResultInt(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE);
+                return JIM_OK;
+            }
+
+        case STR_IS_ALPHA: isclassfunc = isalpha; break;
+        case STR_IS_ALNUM: isclassfunc = isalnum; break;
+        case STR_IS_ASCII: isclassfunc = isascii; break;
+        case STR_IS_DIGIT: isclassfunc = isdigit; break;
+        case STR_IS_LOWER: isclassfunc = islower; break;
+        case STR_IS_UPPER: isclassfunc = isupper; break;
+        case STR_IS_SPACE: isclassfunc = isspace; break;
+        case STR_IS_XDIGIT: isclassfunc = isxdigit; break;
+        case STR_IS_CONTROL: isclassfunc = iscntrl; break;
+        case STR_IS_PRINT: isclassfunc = isprint; break;
+        case STR_IS_GRAPH: isclassfunc = isgraph; break;
+        case STR_IS_PUNCT: isclassfunc = ispunct; break;
+        default:
+            return JIM_ERR;
+    }
+
+    for (i = 0; i < len; i++) {
+        if (!isclassfunc(str[i])) {
+            Jim_SetResultInt(interp, 0);
+            return JIM_OK;
+        }
+    }
+    Jim_SetResultInt(interp, 1);
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * Compared String Object
+ * ---------------------------------------------------------------------------*/
+
+/* This is strange object that allows to compare a C literal string
+ * with a Jim object in very short time if the same comparison is done
+ * multiple times. For example every time the [if] command is executed,
+ * Jim has to check if a given argument is "else". This comparions if
+ * the code has no errors are true most of the times, so we can cache
+ * inside the object the pointer of the string of the last matching
+ * comparison. Because most C compilers perform literal sharing,
+ * so that: char *x = "foo", char *y = "foo", will lead to x == y,
+ * this works pretty well even if comparisons are at different places
+ * inside the C code. */
+
+static const Jim_ObjType comparedStringObjType = {
+    "compared-string",
+    NULL,
+    NULL,
+    NULL,
+    JIM_TYPE_REFERENCES,
+};
+
+/* The only way this object is exposed to the API is via the following
+ * function. Returns true if the string and the object string repr.
+ * are the same, otherwise zero is returned.
+ *
+ * Note: this isn't binary safe, but it hardly needs to be.*/
+int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str)
+{
+    if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str)
+        return 1;
+    else {
+        const char *objStr = Jim_String(objPtr);
+
+        if (strcmp(str, objStr) != 0)
+            return 0;
+        if (objPtr->typePtr != &comparedStringObjType) {
+            Jim_FreeIntRep(interp, objPtr);
+            objPtr->typePtr = &comparedStringObjType;
+        }
+        objPtr->internalRep.ptr = (char *)str;  /*ATTENTION: const cast */
+        return 1;
+    }
+}
+
+static int qsortCompareStringPointers(const void *a, const void *b)
+{
+    char *const *sa = (char *const *)a;
+    char *const *sb = (char *const *)b;
+
+    return strcmp(*sa, *sb);
+}
+
+
+/* -----------------------------------------------------------------------------
+ * Source Object
+ *
+ * This object is just a string from the language point of view, but
+ * in the internal representation it contains the filename and line number
+ * where this given token was read. This information is used by
+ * Jim_EvalObj() if the object passed happens to be of type "source".
+ *
+ * This allows to propagate the information about line numbers and file
+ * names and give error messages with absolute line numbers.
+ *
+ * Note that this object uses shared strings for filenames, and the
+ * pointer to the filename together with the line number is taken into
+ * the space for the "inline" internal representation of the Jim_Object,
+ * so there is almost memory zero-overhead.
+ *
+ * Also the object will be converted to something else if the given
+ * token it represents in the source file is not something to be
+ * evaluated (not a script), and will be specialized in some other way,
+ * so the time overhead is also null.
+ * ---------------------------------------------------------------------------*/
+
+static void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+
+static const Jim_ObjType sourceObjType = {
+    "source",
+    FreeSourceInternalRep,
+    DupSourceInternalRep,
+    NULL,
+    JIM_TYPE_REFERENCES,
+};
+
+void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    Jim_DecrRefCount(interp, objPtr->internalRep.sourceValue.fileNameObj);
+}
+
+void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+    dupPtr->internalRep = srcPtr->internalRep;
+    Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj);
+}
+
+static void JimSetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
+    Jim_Obj *fileNameObj, int lineNumber)
+{
+    JimPanic((Jim_IsShared(objPtr), "JimSetSourceInfo called with shared object"));
+    JimPanic((objPtr->typePtr != NULL, "JimSetSourceInfo called with typePtr != NULL"));
+    Jim_IncrRefCount(fileNameObj);
+    objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
+    objPtr->internalRep.sourceValue.lineNumber = lineNumber;
+    objPtr->typePtr = &sourceObjType;
+}
+
+/* -----------------------------------------------------------------------------
+ * Script Object
+ * ---------------------------------------------------------------------------*/
+
+static const Jim_ObjType scriptLineObjType = {
+    "scriptline",
+    NULL,
+    NULL,
+    NULL,
+    0,
+};
+
+static Jim_Obj *JimNewScriptLineObj(Jim_Interp *interp, int argc, int line)
+{
+    Jim_Obj *objPtr;
+
+#ifdef DEBUG_SHOW_SCRIPT
+    char buf[100];
+    snprintf(buf, sizeof(buf), "line=%d, argc=%d", line, argc);
+    objPtr = Jim_NewStringObj(interp, buf, -1);
+#else
+    objPtr = Jim_NewEmptyStringObj(interp);
+#endif
+    objPtr->typePtr = &scriptLineObjType;
+    objPtr->internalRep.scriptLineValue.argc = argc;
+    objPtr->internalRep.scriptLineValue.line = line;
+
+    return objPtr;
+}
+
+#define JIM_CMDSTRUCT_EXPAND -1
+
+static void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, struct JimParseResult *result);
+
+static const Jim_ObjType scriptObjType = {
+    "script",
+    FreeScriptInternalRep,
+    DupScriptInternalRep,
+    NULL,
+    JIM_TYPE_REFERENCES,
+};
+
+/* The ScriptToken structure represents every token into a scriptObj.
+ * Every token contains an associated Jim_Obj that can be specialized
+ * by commands operating on it. */
+typedef struct ScriptToken
+{
+    int type;
+    Jim_Obj *objPtr;
+} ScriptToken;
+
+/* This is the script object internal representation. An array of
+ * ScriptToken structures, including a pre-computed representation of the
+ * command length and arguments.
+ *
+ * For example the script:
+ *
+ * puts hello
+ * set $i $x$y [foo]BAR
+ *
+ * will produce a ScriptObj with the following Tokens:
+ *
+ * LIN 2
+ * ESC puts
+ * ESC hello
+ * LIN 4
+ * ESC set
+ * VAR i
+ * WRD 2
+ * VAR x
+ * VAR y
+ * WRD 2
+ * CMD foo
+ * ESC BAR
+ *
+ * "puts hello" has two args (LIN 2), composed of single tokens.
+ * (Note that the WRD token is omitted for the common case of a single token.)
+ *
+ * "set $i $x$y [foo]BAR" has four (LIN 4) args, the first word
+ * has 1 token (ESC SET), and the last has two tokens (WRD 2 CMD foo ESC BAR)
+ *
+ * The precomputation of the command structure makes Jim_Eval() faster,
+ * and simpler because there aren't dynamic lengths / allocations.
+ *
+ * -- {expand}/{*} handling --
+ *
+ * Expand is handled in a special way.
+ *
+ *   If a "word" begins with {*}, the word token count is -ve.
+ *
+ * For example the command:
+ *
+ * list {*}{a b}
+ *
+ * Will produce the following cmdstruct array:
+ *
+ * LIN 2
+ * ESC list
+ * WRD -1
+ * STR a b
+ *
+ * Note that the 'LIN' token also contains the source information for the
+ * first word of the line for error reporting purposes
+ *
+ * -- the substFlags field of the structure --
+ *
+ * The scriptObj structure is used to represent both "script" objects
+ * and "subst" objects. In the second case, the there are no LIN and WRD
+ * tokens. Instead SEP and EOL tokens are added as-is.
+ * In addition, the field 'substFlags' is used to represent the flags used to turn
+ * the string into the internal representation used to perform the
+ * substitution. If this flags are not what the application requires
+ * the scriptObj is created again. For example the script:
+ *
+ * subst -nocommands $string
+ * subst -novariables $string
+ *
+ * Will recreate the internal representation of the $string object
+ * two times.
+ */
+typedef struct ScriptObj
+{
+    int len;                    /* Length as number of tokens. */
+    ScriptToken *token;         /* Tokens array. */
+    int substFlags;             /* flags used for the compilation of "subst" objects */
+    int inUse;                  /* Used to share a ScriptObj. Currently
+                                   only used by Jim_EvalObj() as protection against
+                                   shimmering of the currently evaluated object. */
+    Jim_Obj *fileNameObj;
+    int line;                   /* Line number of the first line */
+} ScriptObj;
+
+void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    int i;
+    struct ScriptObj *script = (void *)objPtr->internalRep.ptr;
+
+    script->inUse--;
+    if (script->inUse != 0)
+        return;
+    for (i = 0; i < script->len; i++) {
+        Jim_DecrRefCount(interp, script->token[i].objPtr);
+    }
+    Jim_Free(script->token);
+    Jim_DecrRefCount(interp, script->fileNameObj);
+    Jim_Free(script);
+}
+
+void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+    JIM_NOTUSED(interp);
+    JIM_NOTUSED(srcPtr);
+
+    /* Just returns an simple string. */
+    dupPtr->typePtr = NULL;
+}
+
+/* A simple parser token.
+ * All the simple tokens for the script point into the same script string rep.
+ */
+typedef struct
+{
+    const char *token;          /* Pointer to the start of the token */
+    int len;                    /* Length of this token */
+    int type;                   /* Token type */
+    int line;                   /* Line number */
+} ParseToken;
+
+/* A list of parsed tokens representing a script.
+ * Tokens are added to this list as the script is parsed.
+ * It grows as needed.
+ */
+typedef struct
+{
+    /* Start with a statically allocated list of tokens which will be expanded with realloc if needed */
+    ParseToken *list;           /* Array of tokens */
+    int size;                   /* Current size of the list */
+    int count;                  /* Number of entries used */
+    ParseToken static_list[20]; /* Small initial token space to avoid allocation */
+} ParseTokenList;
+
+static void ScriptTokenListInit(ParseTokenList *tokenlist)
+{
+    tokenlist->list = tokenlist->static_list;
+    tokenlist->size = sizeof(tokenlist->static_list) / sizeof(ParseToken);
+    tokenlist->count = 0;
+}
+
+static void ScriptTokenListFree(ParseTokenList *tokenlist)
+{
+    if (tokenlist->list != tokenlist->static_list) {
+        Jim_Free(tokenlist->list);
+    }
+}
+
+/**
+ * Adds the new token to the tokenlist.
+ * The token has the given length, type and line number.
+ * The token list is resized as necessary.
+ */
+static void ScriptAddToken(ParseTokenList *tokenlist, const char *token, int len, int type,
+    int line)
+{
+    ParseToken *t;
+
+    if (tokenlist->count == tokenlist->size) {
+        /* Resize the list */
+        tokenlist->size *= 2;
+        if (tokenlist->list != tokenlist->static_list) {
+            tokenlist->list =
+                Jim_Realloc(tokenlist->list, tokenlist->size * sizeof(*tokenlist->list));
+        }
+        else {
+            /* The list needs to become allocated */
+            tokenlist->list = Jim_Alloc(tokenlist->size * sizeof(*tokenlist->list));
+            memcpy(tokenlist->list, tokenlist->static_list,
+                tokenlist->count * sizeof(*tokenlist->list));
+        }
+    }
+    t = &tokenlist->list[tokenlist->count++];
+    t->token = token;
+    t->len = len;
+    t->type = type;
+    t->line = line;
+}
+
+/* Counts the number of adjoining non-separator.
+ *
+ * Returns -ve if the first token is the expansion
+ * operator (in which case the count doesn't include
+ * that token).
+ */
+static int JimCountWordTokens(ParseToken *t)
+{
+    int expand = 1;
+    int count = 0;
+
+    /* Is the first word {*} or {expand}? */
+    if (t->type == JIM_TT_STR && !TOKEN_IS_SEP(t[1].type)) {
+        if ((t->len == 1 && *t->token == '*') || (t->len == 6 && strncmp(t->token, "expand", 6) == 0)) {
+            /* Create an expand token */
+            expand = -1;
+            t++;
+        }
+    }
+
+    /* Now count non-separator words */
+    while (!TOKEN_IS_SEP(t->type)) {
+        t++;
+        count++;
+    }
+
+    return count * expand;
+}
+
+/**
+ * Create a script/subst object from the given token.
+ */
+static Jim_Obj *JimMakeScriptObj(Jim_Interp *interp, const ParseToken *t)
+{
+    Jim_Obj *objPtr;
+
+    if (t->type == JIM_TT_ESC && memchr(t->token, '\\', t->len) != NULL) {
+        /* Convert the backlash escapes . */
+        int len = t->len;
+        char *str = Jim_Alloc(len + 1);
+        len = JimEscape(str, t->token, len);
+        objPtr = Jim_NewStringObjNoAlloc(interp, str, len);
+    }
+    else {
+        /* REVIST: Strictly, JIM_TT_STR should replace <backslash><newline><whitespace>
+         *         with a single space. This is currently not done.
+         */
+        objPtr = Jim_NewStringObj(interp, t->token, t->len);
+    }
+    return objPtr;
+}
+
+/**
+ * Takes a tokenlist and creates the allocated list of script tokens
+ * in script->token, of length script->len.
+ *
+ * Unnecessary tokens are discarded, and LINE and WORD tokens are inserted
+ * as required.
+ *
+ * Also sets script->line to the line number of the first token
+ */
+static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
+    ParseTokenList *tokenlist)
+{
+    int i;
+    struct ScriptToken *token;
+    /* Number of tokens so far for the current command */
+    int lineargs = 0;
+    /* This is the first token for the current command */
+    ScriptToken *linefirst;
+    int count;
+    int linenr;
+
+#ifdef DEBUG_SHOW_SCRIPT_TOKENS
+    printf("==== Tokens ====\n");
+    for (i = 0; i < tokenlist->count; i++) {
+        printf("[%2d]@%d %s '%.*s'\n", i, tokenlist->list[i].line, jim_tt_name(tokenlist->list[i].type),
+            tokenlist->list[i].len, tokenlist->list[i].token);
+    }
+#endif
+
+    /* May need up to one extra script token for each EOL in the worst case */
+    count = tokenlist->count;
+    for (i = 0; i < tokenlist->count; i++) {
+        if (tokenlist->list[i].type == JIM_TT_EOL) {
+            count++;
+        }
+    }
+    linenr = script->line = tokenlist->list[0].line;
+
+    token = script->token = Jim_Alloc(sizeof(ScriptToken) * count);
+
+    /* This is the first token for the current command */
+    linefirst = token++;
+
+    for (i = 0; i < tokenlist->count; ) {
+        /* Look ahead to find out how many tokens make up the next word */
+        int wordtokens;
+
+        /* Skip any leading separators */
+        while (tokenlist->list[i].type == JIM_TT_SEP) {
+            i++;
+        }
+
+        wordtokens = JimCountWordTokens(tokenlist->list + i);
+
+        if (wordtokens == 0) {
+            /* None, so at end of line */
+            if (lineargs) {
+                linefirst->type = JIM_TT_LINE;
+                linefirst->objPtr = JimNewScriptLineObj(interp, lineargs, linenr);
+                Jim_IncrRefCount(linefirst->objPtr);
+
+                /* Reset for new line */
+                lineargs = 0;
+                linefirst = token++;
+            }
+            i++;
+            continue;
+        }
+        else if (wordtokens != 1) {
+            /* More than 1, or {expand}, so insert a WORD token */
+            token->type = JIM_TT_WORD;
+            token->objPtr = Jim_NewIntObj(interp, wordtokens);
+            Jim_IncrRefCount(token->objPtr);
+            token++;
+            if (wordtokens < 0) {
+                /* Skip the expand token */
+                i++;
+                wordtokens = -wordtokens - 1;
+                lineargs--;
+            }
+        }
+
+        if (lineargs == 0) {
+            /* First real token on the line, so record the line number */
+            linenr = tokenlist->list[i].line;
+        }
+        lineargs++;
+
+        /* Add each non-separator word token to the line */
+        while (wordtokens--) {
+            const ParseToken *t = &tokenlist->list[i++];
+
+            token->type = t->type;
+            token->objPtr = JimMakeScriptObj(interp, t);
+            Jim_IncrRefCount(token->objPtr);
+
+            /* Every object is initially a string, but the
+             * internal type may be specialized during execution of the
+             * script. */
+            JimSetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line);
+            token++;
+        }
+    }
+
+    if (lineargs == 0) {
+        token--;
+    }
+
+    script->len = token - script->token;
+
+    assert(script->len < count);
+
+#ifdef DEBUG_SHOW_SCRIPT
+    printf("==== Script (%s) ====\n", Jim_String(script->fileNameObj));
+    for (i = 0; i < script->len; i++) {
+        const ScriptToken *t = &script->token[i];
+        printf("[%2d] %s %s\n", i, jim_tt_name(t->type), Jim_String(t->objPtr));
+    }
+#endif
+
+}
+
+/**
+ * Similar to ScriptObjAddTokens(), but for subst objects.
+ */
+static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
+    ParseTokenList *tokenlist)
+{
+    int i;
+    struct ScriptToken *token;
+
+    token = script->token = Jim_Alloc(sizeof(ScriptToken) * tokenlist->count);
+
+    for (i = 0; i < tokenlist->count; i++) {
+        const ParseToken *t = &tokenlist->list[i];
+
+        /* Create a token for 't' */
+        token->type = t->type;
+        token->objPtr = JimMakeScriptObj(interp, t);
+        Jim_IncrRefCount(token->objPtr);
+        token++;
+    }
+
+    script->len = i;
+}
+
+/* This method takes the string representation of an object
+ * as a Tcl script, and generates the pre-parsed internal representation
+ * of the script. */
+static int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, struct JimParseResult *result)
+{
+    int scriptTextLen;
+    const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
+    struct JimParserCtx parser;
+    struct ScriptObj *script;
+    ParseTokenList tokenlist;
+    int line = 1;
+
+    /* Try to get information about filename / line number */
+    if (objPtr->typePtr == &sourceObjType) {
+        line = objPtr->internalRep.sourceValue.lineNumber;
+    }
+
+    /* Initially parse the script into tokens (in tokenlist) */
+    ScriptTokenListInit(&tokenlist);
+
+    JimParserInit(&parser, scriptText, scriptTextLen, line);
+    while (!parser.eof) {
+        JimParseScript(&parser);
+        ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
+            parser.tline);
+    }
+    if (result && parser.missing != ' ') {
+        ScriptTokenListFree(&tokenlist);
+        result->missing = parser.missing;
+        result->line = parser.missingline;
+        return JIM_ERR;
+    }
+
+    /* Add a final EOF token */
+    ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0);
+
+    /* Create the "real" script tokens from the initial token list */
+    script = Jim_Alloc(sizeof(*script));
+    memset(script, 0, sizeof(*script));
+    script->inUse = 1;
+    script->line = line;
+    if (objPtr->typePtr == &sourceObjType) {
+        script->fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
+    }
+    else {
+        script->fileNameObj = interp->emptyObj;
+    }
+    Jim_IncrRefCount(script->fileNameObj);
+
+    ScriptObjAddTokens(interp, script, &tokenlist);
+
+    /* No longer need the token list */
+    ScriptTokenListFree(&tokenlist);
+
+    /* Free the old internal rep and set the new one. */
+    Jim_FreeIntRep(interp, objPtr);
+    Jim_SetIntRepPtr(objPtr, script);
+    objPtr->typePtr = &scriptObjType;
+
+    return JIM_OK;
+}
+
+ScriptObj *Jim_GetScript(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    struct ScriptObj *script = Jim_GetIntRepPtr(objPtr);
+
+    if (objPtr->typePtr != &scriptObjType || script->substFlags) {
+        SetScriptFromAny(interp, objPtr, NULL);
+    }
+    return (ScriptObj *) Jim_GetIntRepPtr(objPtr);
+}
+
+/* -----------------------------------------------------------------------------
+ * Commands
+ * ---------------------------------------------------------------------------*/
+static void JimIncrCmdRefCount(Jim_Cmd *cmdPtr)
+{
+    cmdPtr->inUse++;
+}
+
+static void JimDecrCmdRefCount(Jim_Interp *interp, Jim_Cmd *cmdPtr)
+{
+    if (--cmdPtr->inUse == 0) {
+        if (cmdPtr->isproc) {
+            Jim_DecrRefCount(interp, cmdPtr->u.proc.argListObjPtr);
+            Jim_DecrRefCount(interp, cmdPtr->u.proc.bodyObjPtr);
+            if (cmdPtr->u.proc.staticVars) {
+                Jim_FreeHashTable(cmdPtr->u.proc.staticVars);
+                Jim_Free(cmdPtr->u.proc.staticVars);
+            }
+            if (cmdPtr->u.proc.prevCmd) {
+                /* Delete any pushed command too */
+                JimDecrCmdRefCount(interp, cmdPtr->u.proc.prevCmd);
+            }
+        }
+        else {
+            /* native (C) */
+            if (cmdPtr->u.native.delProc) {
+                cmdPtr->u.native.delProc(interp, cmdPtr->u.native.privData);
+            }
+        }
+        Jim_Free(cmdPtr);
+    }
+}
+
+/* Commands HashTable Type.
+ *
+ * Keys are dynamic allocated strings, Values are Jim_Cmd structures. */
+static void JimCommandsHT_ValDestructor(void *interp, void *val)
+{
+    JimDecrCmdRefCount(interp, val);
+}
+
+static const Jim_HashTableType JimCommandsHashTableType = {
+    JimStringCopyHTHashFunction,        /* hash function */
+    JimStringCopyHTKeyDup,      /* key dup */
+    NULL,                       /* val dup */
+    JimStringCopyHTKeyCompare,  /* key compare */
+    JimStringCopyHTKeyDestructor,       /* key destructor */
+    JimCommandsHT_ValDestructor        /* val destructor */
+};
+
+/* ------------------------- Commands related functions --------------------- */
+
+int Jim_CreateCommand(Jim_Interp *interp, const char *cmdName,
+    Jim_CmdProc cmdProc, void *privData, Jim_DelCmdProc delProc)
+{
+    Jim_Cmd *cmdPtr;
+
+    if (Jim_DeleteHashEntry(&interp->commands, cmdName) != JIM_ERR) {
+        /* Command existed so incr proc epoch */
+        Jim_InterpIncrProcEpoch(interp);
+    }
+
+    cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
+
+    /* Store the new details for this proc */
+    memset(cmdPtr, 0, sizeof(*cmdPtr));
+    cmdPtr->inUse = 1;
+    cmdPtr->u.native.delProc = delProc;
+    cmdPtr->u.native.cmdProc = cmdProc;
+    cmdPtr->u.native.privData = privData;
+
+    Jim_AddHashEntry(&interp->commands, cmdName, cmdPtr);
+
+    /* There is no need to increment the 'proc epoch' because
+     * creation of a new procedure can never affect existing
+     * cached commands. We don't do negative caching. */
+    return JIM_OK;
+}
+
+static int JimCreateProcedure(Jim_Interp *interp, Jim_Obj *cmdName,
+    Jim_Obj *argListObjPtr, Jim_Obj *staticsListObjPtr, Jim_Obj *bodyObjPtr)
+{
+    Jim_Cmd *cmdPtr;
+    Jim_HashEntry *he;
+    int argListLen;
+    int i;
+
+    if (JimValidName(interp, "procedure", cmdName) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    argListLen = Jim_ListLength(interp, argListObjPtr);
+
+    /* Allocate space for both the command pointer and the arg list */
+    cmdPtr = Jim_Alloc(sizeof(*cmdPtr) + sizeof(struct Jim_ProcArg) * argListLen);
+    memset(cmdPtr, 0, sizeof(*cmdPtr));
+    cmdPtr->inUse = 1;
+    cmdPtr->isproc = 1;
+    cmdPtr->u.proc.argListObjPtr = argListObjPtr;
+    cmdPtr->u.proc.argListLen = argListLen;
+    cmdPtr->u.proc.bodyObjPtr = bodyObjPtr;
+    cmdPtr->u.proc.argsPos = -1;
+    cmdPtr->u.proc.arglist = (struct Jim_ProcArg *)(cmdPtr + 1);
+    Jim_IncrRefCount(argListObjPtr);
+    Jim_IncrRefCount(bodyObjPtr);
+
+    /* Create the statics hash table. */
+    if (staticsListObjPtr) {
+        int len, i;
+
+        len = Jim_ListLength(interp, staticsListObjPtr);
+        if (len != 0) {
+            cmdPtr->u.proc.staticVars = Jim_Alloc(sizeof(Jim_HashTable));
+            Jim_InitHashTable(cmdPtr->u.proc.staticVars, &JimVariablesHashTableType, interp);
+            for (i = 0; i < len; i++) {
+                Jim_Obj *objPtr = 0, *initObjPtr = 0, *nameObjPtr = 0;
+                Jim_Var *varPtr;
+                int subLen;
+
+                Jim_ListIndex(interp, staticsListObjPtr, i, &objPtr, JIM_NONE);
+                /* Check if it's composed of two elements. */
+                subLen = Jim_ListLength(interp, objPtr);
+                if (subLen == 1 || subLen == 2) {
+                    /* Try to get the variable value from the current
+                     * environment. */
+                    Jim_ListIndex(interp, objPtr, 0, &nameObjPtr, JIM_NONE);
+                    if (subLen == 1) {
+                        initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE);
+                        if (initObjPtr == NULL) {
+                            Jim_SetResultFormatted(interp,
+                                "variable for initialization of static \"%#s\" not found in the local context",
+                                nameObjPtr);
+                            goto err;
+                        }
+                    }
+                    else {
+                        Jim_ListIndex(interp, objPtr, 1, &initObjPtr, JIM_NONE);
+                    }
+                    if (JimValidName(interp, "static variable", nameObjPtr) != JIM_OK) {
+                        goto err;
+                    }
+
+                    varPtr = Jim_Alloc(sizeof(*varPtr));
+                    varPtr->objPtr = initObjPtr;
+                    Jim_IncrRefCount(initObjPtr);
+                    varPtr->linkFramePtr = NULL;
+                    if (Jim_AddHashEntry(cmdPtr->u.proc.staticVars,
+                        Jim_String(nameObjPtr), varPtr) != JIM_OK) {
+                        Jim_SetResultFormatted(interp,
+                            "static variable name \"%#s\" duplicated in statics list", nameObjPtr);
+                        Jim_DecrRefCount(interp, initObjPtr);
+                        Jim_Free(varPtr);
+                        goto err;
+                    }
+                }
+                else {
+                    Jim_SetResultFormatted(interp, "too many fields in static specifier \"%#s\"",
+                        objPtr);
+                    goto err;
+                }
+            }
+        }
+    }
+
+    /* Parse the args out into arglist, validating as we go */
+    /* Examine the argument list for default parameters and 'args' */
+    for (i = 0; i < argListLen; i++) {
+        Jim_Obj *argPtr;
+        Jim_Obj *nameObjPtr;
+        Jim_Obj *defaultObjPtr;
+        int len;
+        int n = 1;
+
+        /* Examine a parameter */
+        Jim_ListIndex(interp, argListObjPtr, i, &argPtr, JIM_NONE);
+        len = Jim_ListLength(interp, argPtr);
+        if (len == 0) {
+            Jim_SetResultString(interp, "procedure has argument with no name", -1);
+            goto err;
+        }
+        if (len > 2) {
+            Jim_SetResultString(interp, "procedure has argument with too many fields", -1);
+            goto err;
+        }
+
+        if (len == 2) {
+            /* Optional parameter */
+            Jim_ListIndex(interp, argPtr, 0, &nameObjPtr, JIM_NONE);
+            Jim_ListIndex(interp, argPtr, 1, &defaultObjPtr, JIM_NONE);
+        }
+        else {
+            /* Required parameter */
+            nameObjPtr = argPtr;
+            defaultObjPtr = NULL;
+        }
+
+
+        if (Jim_CompareStringImmediate(interp, nameObjPtr, "args")) {
+            if (cmdPtr->u.proc.argsPos >= 0) {
+                Jim_SetResultString(interp, "procedure has 'args' specified more than once", -1);
+                goto err;
+            }
+            cmdPtr->u.proc.argsPos = i;
+        }
+        else {
+            if (len == 2) {
+                cmdPtr->u.proc.optArity += n;
+            }
+            else {
+                cmdPtr->u.proc.reqArity += n;
+            }
+        }
+
+        cmdPtr->u.proc.arglist[i].nameObjPtr = nameObjPtr;
+        cmdPtr->u.proc.arglist[i].defaultObjPtr = defaultObjPtr;
+    }
+
+    /* Add the new command */
+
+    /* It may already exist, so we try to delete the old one.
+     * Note that reference count means that it won't be deleted yet if
+     * it exists in the call stack.
+     *
+     * BUT, if 'local' is in force, instead of deleting the existing
+     * proc, we stash a reference to the old proc here.
+     */
+    he = Jim_FindHashEntry(&interp->commands, Jim_String(cmdName));
+    if (he) {
+        /* There was an old procedure with the same name, this requires
+         * a 'proc epoch' update. */
+
+        /* If a procedure with the same name didn't existed there is no need
+         * to increment the 'proc epoch' because creation of a new procedure
+         * can never affect existing cached commands. We don't do
+         * negative caching. */
+        Jim_InterpIncrProcEpoch(interp);
+    }
+
+    if (he && interp->local) {
+        /* Just push this proc over the top of the previous one */
+        cmdPtr->u.proc.prevCmd = he->u.val;
+        he->u.val = cmdPtr;
+    }
+    else {
+        if (he) {
+            /* Replace the existing proc */
+            Jim_DeleteHashEntry(&interp->commands, Jim_String(cmdName));
+        }
+
+        Jim_AddHashEntry(&interp->commands, Jim_String(cmdName), cmdPtr);
+    }
+
+    /* Unlike Tcl, set the name of the proc as the result */
+    Jim_SetResult(interp, cmdName);
+    return JIM_OK;
+
+  err:
+    if (cmdPtr->u.proc.staticVars) {
+        Jim_FreeHashTable(cmdPtr->u.proc.staticVars);
+    }
+    Jim_Free(cmdPtr->u.proc.staticVars);
+    Jim_DecrRefCount(interp, argListObjPtr);
+    Jim_DecrRefCount(interp, bodyObjPtr);
+    Jim_Free(cmdPtr);
+    return JIM_ERR;
+}
+
+int Jim_DeleteCommand(Jim_Interp *interp, const char *cmdName)
+{
+    if (Jim_DeleteHashEntry(&interp->commands, cmdName) == JIM_ERR)
+        return JIM_ERR;
+    Jim_InterpIncrProcEpoch(interp);
+    return JIM_OK;
+}
+
+int Jim_RenameCommand(Jim_Interp *interp, const char *oldName, const char *newName)
+{
+    Jim_HashEntry *he;
+
+    /* Does it exist? */
+    he = Jim_FindHashEntry(&interp->commands, oldName);
+    if (he == NULL) {
+        Jim_SetResultFormatted(interp, "can't %s \"%s\": command doesn't exist",
+            newName[0] ? "rename" : "delete", oldName);
+        return JIM_ERR;
+    }
+
+    if (newName[0] == '\0')     /* Delete! */
+        return Jim_DeleteCommand(interp, oldName);
+
+    /* rename */
+    if (Jim_FindHashEntry(&interp->commands, newName)) {
+        Jim_SetResultFormatted(interp, "can't rename to \"%s\": command already exists", newName);
+        return JIM_ERR;
+    }
+
+    /* Add the new name first */
+    JimIncrCmdRefCount(he->u.val);
+    Jim_AddHashEntry(&interp->commands, newName, he->u.val);
+
+    /* Now remove the old name */
+    Jim_DeleteHashEntry(&interp->commands, oldName);
+
+    /* Increment the epoch */
+    Jim_InterpIncrProcEpoch(interp);
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * Command object
+ * ---------------------------------------------------------------------------*/
+
+static int SetCommandFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType commandObjType = {
+    "command",
+    NULL,
+    NULL,
+    NULL,
+    JIM_TYPE_REFERENCES,
+};
+
+int SetCommandFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    Jim_HashEntry *he;
+    const char *cmdName;
+
+    /* Get the string representation */
+    cmdName = Jim_String(objPtr);
+    /* Lookup this name into the commands hash table */
+    he = Jim_FindHashEntry(&interp->commands, cmdName);
+    if (he == NULL)
+        return JIM_ERR;
+
+    /* Free the old internal repr and set the new one. */
+    Jim_FreeIntRep(interp, objPtr);
+    objPtr->typePtr = &commandObjType;
+    objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch;
+    objPtr->internalRep.cmdValue.cmdPtr = (void *)he->u.val;
+    return JIM_OK;
+}
+
+/* This function returns the command structure for the command name
+ * stored in objPtr. It tries to specialize the objPtr to contain
+ * a cached info instead to perform the lookup into the hash table
+ * every time. The information cached may not be uptodate, in such
+ * a case the lookup is performed and the cache updated.
+ *
+ * Respects the 'upcall' setting
+ */
+Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+    Jim_Cmd *cmd;
+
+    if ((objPtr->typePtr != &commandObjType ||
+            objPtr->internalRep.cmdValue.procEpoch != interp->procEpoch) &&
+        SetCommandFromAny(interp, objPtr) == JIM_ERR) {
+        if (flags & JIM_ERRMSG) {
+            Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr);
+        }
+        return NULL;
+    }
+    cmd = objPtr->internalRep.cmdValue.cmdPtr;
+    while (cmd->isproc && cmd->u.proc.upcall) {
+        cmd = cmd->u.proc.prevCmd;
+    }
+    return cmd;
+}
+
+/* -----------------------------------------------------------------------------
+ * Variables
+ * ---------------------------------------------------------------------------*/
+
+/* Variables HashTable Type.
+ *
+ * Keys are dynamic allocated strings, Values are Jim_Var structures. */
+static void JimVariablesHTValDestructor(void *interp, void *val)
+{
+    Jim_Var *varPtr = (void *)val;
+
+    Jim_DecrRefCount(interp, varPtr->objPtr);
+    Jim_Free(val);
+}
+
+static const Jim_HashTableType JimVariablesHashTableType = {
+    JimStringCopyHTHashFunction,        /* hash function */
+    JimStringCopyHTKeyDup,      /* key dup */
+    NULL,                       /* val dup */
+    JimStringCopyHTKeyCompare,  /* key compare */
+    JimStringCopyHTKeyDestructor,       /* key destructor */
+    JimVariablesHTValDestructor /* val destructor */
+};
+
+/* -----------------------------------------------------------------------------
+ * Variable object
+ * ---------------------------------------------------------------------------*/
+
+#define JIM_DICT_SUGAR 100      /* Only returned by SetVariableFromAny() */
+
+static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType variableObjType = {
+    "variable",
+    NULL,
+    NULL,
+    NULL,
+    JIM_TYPE_REFERENCES,
+};
+
+/* Return true if the string "str" looks like syntax sugar for [dict]. I.e.
+ * is in the form "varname(key)". */
+static int JimNameIsDictSugar(const char *str, int len)
+{
+    if (len && str[len - 1] == ')' && strchr(str, '(') != NULL)
+        return 1;
+    return 0;
+}
+
+/**
+ * Check that the name does not contain embedded nulls.
+ *
+ * Variable and procedure names are maniplated as null terminated strings, so
+ * don't allow names with embedded nulls.
+ */
+static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr)
+{
+    /* Variable names and proc names can't contain embedded nulls */
+    if (nameObjPtr->typePtr != &variableObjType) {
+        int len;
+        const char *str = Jim_GetString(nameObjPtr, &len);
+        if (memchr(str, '\0', len)) {
+            Jim_SetResultFormatted(interp, "%s name contains embedded null", type);
+            return JIM_ERR;
+        }
+    }
+    return JIM_OK;
+}
+
+/* This method should be called only by the variable API.
+ * It returns JIM_OK on success (variable already exists),
+ * JIM_ERR if it does not exists, JIM_DICT_SUGAR if it's not
+ * a variable name, but syntax glue for [dict] i.e. the last
+ * character is ')' */
+static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+    Jim_HashEntry *he;
+    const char *varName;
+    int len;
+    Jim_CallFrame *framePtr = interp->framePtr;
+
+    /* Check if the object is already an uptodate variable */
+    if (objPtr->typePtr == &variableObjType &&
+        objPtr->internalRep.varValue.callFrameId == framePtr->id) {
+        return JIM_OK;          /* nothing to do */
+    }
+
+    if (objPtr->typePtr == &dictSubstObjType) {
+        return JIM_DICT_SUGAR;
+    }
+
+    if (JimValidName(interp, "variable", objPtr) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    /* Get the string representation */
+    varName = Jim_GetString(objPtr, &len);
+
+    /* Make sure it's not syntax glue to get/set dict. */
+    if (JimNameIsDictSugar(varName, len)) {
+        return JIM_DICT_SUGAR;
+    }
+
+    if (varName[0] == ':' && varName[1] == ':') {
+        framePtr = interp->topFramePtr;
+        he = Jim_FindHashEntry(&framePtr->vars, varName + 2);
+        if (he == NULL) {
+            return JIM_ERR;
+        }
+    }
+    else {
+        /* Lookup this name into the variables hash table */
+        he = Jim_FindHashEntry(&framePtr->vars, varName);
+        if (he == NULL) {
+            /* Try with static vars. */
+            if (framePtr->staticVars == NULL)
+                return JIM_ERR;
+            if (!(he = Jim_FindHashEntry(framePtr->staticVars, varName)))
+                return JIM_ERR;
+        }
+    }
+    /* Free the old internal repr and set the new one. */
+    Jim_FreeIntRep(interp, objPtr);
+    objPtr->typePtr = &variableObjType;
+    objPtr->internalRep.varValue.callFrameId = framePtr->id;
+    objPtr->internalRep.varValue.varPtr = (void *)he->u.val;
+    return JIM_OK;
+}
+
+/* -------------------- Variables related functions ------------------------- */
+static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr, Jim_Obj *valObjPtr);
+static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr, int flags);
+
+/* For now that's dummy. Variables lookup should be optimized
+ * in many ways, with caching of lookups, and possibly with
+ * a table of pre-allocated vars in every CallFrame for local vars.
+ * All the caching should also have an 'epoch' mechanism similar
+ * to the one used by Tcl for procedures lookup caching. */
+
+int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
+{
+    const char *name;
+    Jim_Var *var;
+    int err;
+
+    if ((err = SetVariableFromAny(interp, nameObjPtr)) != JIM_OK) {
+        Jim_CallFrame *framePtr = interp->framePtr;
+
+        /* Check for [dict] syntax sugar. */
+        if (err == JIM_DICT_SUGAR)
+            return JimDictSugarSet(interp, nameObjPtr, valObjPtr);
+
+        if (JimValidName(interp, "variable", nameObjPtr) != JIM_OK) {
+            return JIM_ERR;
+        }
+
+        /* New variable to create */
+        name = Jim_String(nameObjPtr);
+
+        var = Jim_Alloc(sizeof(*var));
+        var->objPtr = valObjPtr;
+        Jim_IncrRefCount(valObjPtr);
+        var->linkFramePtr = NULL;
+        /* Insert the new variable */
+        if (name[0] == ':' && name[1] == ':') {
+            /* Into the top level frame */
+            framePtr = interp->topFramePtr;
+            Jim_AddHashEntry(&framePtr->vars, name + 2, var);
+        }
+        else {
+            Jim_AddHashEntry(&framePtr->vars, name, var);
+        }
+        /* Make the object int rep a variable */
+        Jim_FreeIntRep(interp, nameObjPtr);
+        nameObjPtr->typePtr = &variableObjType;
+        nameObjPtr->internalRep.varValue.callFrameId = framePtr->id;
+        nameObjPtr->internalRep.varValue.varPtr = var;
+    }
+    else {
+        var = nameObjPtr->internalRep.varValue.varPtr;
+        if (var->linkFramePtr == NULL) {
+            Jim_IncrRefCount(valObjPtr);
+            Jim_DecrRefCount(interp, var->objPtr);
+            var->objPtr = valObjPtr;
+        }
+        else {                  /* Else handle the link */
+            Jim_CallFrame *savedCallFrame;
+
+            savedCallFrame = interp->framePtr;
+            interp->framePtr = var->linkFramePtr;
+            err = Jim_SetVariable(interp, var->objPtr, valObjPtr);
+            interp->framePtr = savedCallFrame;
+            if (err != JIM_OK)
+                return err;
+        }
+    }
+    return JIM_OK;
+}
+
+int Jim_SetVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
+{
+    Jim_Obj *nameObjPtr;
+    int result;
+
+    nameObjPtr = Jim_NewStringObj(interp, name, -1);
+    Jim_IncrRefCount(nameObjPtr);
+    result = Jim_SetVariable(interp, nameObjPtr, objPtr);
+    Jim_DecrRefCount(interp, nameObjPtr);
+    return result;
+}
+
+int Jim_SetGlobalVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
+{
+    Jim_CallFrame *savedFramePtr;
+    int result;
+
+    savedFramePtr = interp->framePtr;
+    interp->framePtr = interp->topFramePtr;
+    result = Jim_SetVariableStr(interp, name, objPtr);
+    interp->framePtr = savedFramePtr;
+    return result;
+}
+
+int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val)
+{
+    Jim_Obj *nameObjPtr, *valObjPtr;
+    int result;
+
+    nameObjPtr = Jim_NewStringObj(interp, name, -1);
+    valObjPtr = Jim_NewStringObj(interp, val, -1);
+    Jim_IncrRefCount(nameObjPtr);
+    Jim_IncrRefCount(valObjPtr);
+    result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
+    Jim_DecrRefCount(interp, nameObjPtr);
+    Jim_DecrRefCount(interp, valObjPtr);
+    return result;
+}
+
+int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
+    Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame)
+{
+    const char *varName;
+    int len;
+
+    varName = Jim_GetString(nameObjPtr, &len);
+
+    if (varName[0] == ':' && varName[1] == ':') {
+        /* Linking a global var does nothing */
+        return JIM_OK;
+    }
+
+    if (JimNameIsDictSugar(varName, len)) {
+        Jim_SetResultString(interp, "Dict key syntax invalid as link source", -1);
+        return JIM_ERR;
+    }
+
+    /* Check for an existing variable or link */
+    if (SetVariableFromAny(interp, nameObjPtr) == JIM_OK) {
+        Jim_Var *varPtr = nameObjPtr->internalRep.varValue.varPtr;
+
+        if (varPtr->linkFramePtr == NULL) {
+            Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr);
+            return JIM_ERR;
+        }
+
+        /* It exists, but is a link, so delete the link */
+        varPtr->linkFramePtr = NULL;
+    }
+
+    /* Check for cycles. */
+    if (interp->framePtr == targetCallFrame) {
+        Jim_Obj *objPtr = targetNameObjPtr;
+        Jim_Var *varPtr;
+
+        /* Cycles are only possible with 'uplevel 0' */
+        while (1) {
+            if (Jim_StringEqObj(objPtr, nameObjPtr)) {
+                Jim_SetResultString(interp, "can't upvar from variable to itself", -1);
+                return JIM_ERR;
+            }
+            if (SetVariableFromAny(interp, objPtr) != JIM_OK)
+                break;
+            varPtr = objPtr->internalRep.varValue.varPtr;
+            if (varPtr->linkFramePtr != targetCallFrame)
+                break;
+            objPtr = varPtr->objPtr;
+        }
+    }
+
+    /* Perform the binding */
+    Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr);
+    /* We are now sure 'nameObjPtr' type is variableObjType */
+    nameObjPtr->internalRep.varValue.varPtr->linkFramePtr = targetCallFrame;
+    return JIM_OK;
+}
+
+/* Return the Jim_Obj pointer associated with a variable name,
+ * or NULL if the variable was not found in the current context.
+ * The same optimization discussed in the comment to the
+ * 'SetVariable' function should apply here.
+ *
+ * If JIM_UNSHARED is set and the variable is an array element (dict sugar)
+ * in a dictionary which is shared, the array variable value is duplicated first.
+ * This allows the array element to be updated (e.g. append, lappend) without
+ * affecting other references to the dictionary.
+ */
+Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
+{
+    switch (SetVariableFromAny(interp, nameObjPtr)) {
+        case JIM_OK:{
+                Jim_Var *varPtr = nameObjPtr->internalRep.varValue.varPtr;
+
+                if (varPtr->linkFramePtr == NULL) {
+                    return varPtr->objPtr;
+                }
+                else {
+                    Jim_Obj *objPtr;
+
+                    /* The variable is a link? Resolve it. */
+                    Jim_CallFrame *savedCallFrame = interp->framePtr;
+
+                    interp->framePtr = varPtr->linkFramePtr;
+                    objPtr = Jim_GetVariable(interp, varPtr->objPtr, flags);
+                    interp->framePtr = savedCallFrame;
+                    if (objPtr) {
+                        return objPtr;
+                    }
+                    /* Error, so fall through to the error message */
+                }
+            }
+            break;
+
+        case JIM_DICT_SUGAR:
+            /* [dict] syntax sugar. */
+            return JimDictSugarGet(interp, nameObjPtr, flags);
+    }
+    if (flags & JIM_ERRMSG) {
+        Jim_SetResultFormatted(interp, "can't read \"%#s\": no such variable", nameObjPtr);
+    }
+    return NULL;
+}
+
+Jim_Obj *Jim_GetGlobalVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
+{
+    Jim_CallFrame *savedFramePtr;
+    Jim_Obj *objPtr;
+
+    savedFramePtr = interp->framePtr;
+    interp->framePtr = interp->topFramePtr;
+    objPtr = Jim_GetVariable(interp, nameObjPtr, flags);
+    interp->framePtr = savedFramePtr;
+
+    return objPtr;
+}
+
+Jim_Obj *Jim_GetVariableStr(Jim_Interp *interp, const char *name, int flags)
+{
+    Jim_Obj *nameObjPtr, *varObjPtr;
+
+    nameObjPtr = Jim_NewStringObj(interp, name, -1);
+    Jim_IncrRefCount(nameObjPtr);
+    varObjPtr = Jim_GetVariable(interp, nameObjPtr, flags);
+    Jim_DecrRefCount(interp, nameObjPtr);
+    return varObjPtr;
+}
+
+Jim_Obj *Jim_GetGlobalVariableStr(Jim_Interp *interp, const char *name, int flags)
+{
+    Jim_CallFrame *savedFramePtr;
+    Jim_Obj *objPtr;
+
+    savedFramePtr = interp->framePtr;
+    interp->framePtr = interp->topFramePtr;
+    objPtr = Jim_GetVariableStr(interp, name, flags);
+    interp->framePtr = savedFramePtr;
+
+    return objPtr;
+}
+
+/* Unset a variable.
+ * Note: On success unset invalidates all the variable objects created
+ * in the current call frame incrementing. */
+int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
+{
+    const char *name;
+    Jim_Var *varPtr;
+    int retval;
+
+    retval = SetVariableFromAny(interp, nameObjPtr);
+    if (retval == JIM_DICT_SUGAR) {
+        /* [dict] syntax sugar. */
+        return JimDictSugarSet(interp, nameObjPtr, NULL);
+    }
+    else if (retval == JIM_OK) {
+        varPtr = nameObjPtr->internalRep.varValue.varPtr;
+
+        /* If it's a link call UnsetVariable recursively */
+        if (varPtr->linkFramePtr) {
+            Jim_CallFrame *savedCallFrame;
+
+            savedCallFrame = interp->framePtr;
+            interp->framePtr = varPtr->linkFramePtr;
+            retval = Jim_UnsetVariable(interp, varPtr->objPtr, JIM_NONE);
+            interp->framePtr = savedCallFrame;
+        }
+        else {
+            Jim_CallFrame *framePtr = interp->framePtr;
+
+            name = Jim_String(nameObjPtr);
+            if (name[0] == ':' && name[1] == ':') {
+                framePtr = interp->topFramePtr;
+                name += 2;
+            }
+            retval = Jim_DeleteHashEntry(&framePtr->vars, name);
+            if (retval == JIM_OK) {
+                /* Change the callframe id, invalidating var lookup caching */
+                JimChangeCallFrameId(interp, framePtr);
+            }
+        }
+    }
+    if (retval != JIM_OK && (flags & JIM_ERRMSG)) {
+        Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such variable", nameObjPtr);
+    }
+    return retval;
+}
+
+/* ----------  Dict syntax sugar (similar to array Tcl syntax) -------------- */
+
+/* Given a variable name for [dict] operation syntax sugar,
+ * this function returns two objects, the first with the name
+ * of the variable to set, and the second with the rispective key.
+ * For example "foo(bar)" will return objects with string repr. of
+ * "foo" and "bar".
+ *
+ * The returned objects have refcount = 1. The function can't fail. */
+static void JimDictSugarParseVarKey(Jim_Interp *interp, Jim_Obj *objPtr,
+    Jim_Obj **varPtrPtr, Jim_Obj **keyPtrPtr)
+{
+    const char *str, *p;
+    int len, keyLen;
+    Jim_Obj *varObjPtr, *keyObjPtr;
+
+    str = Jim_GetString(objPtr, &len);
+
+    p = strchr(str, '(');
+    JimPanic((p == NULL, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str));
+
+    varObjPtr = Jim_NewStringObj(interp, str, p - str);
+
+    p++;
+    keyLen = (str + len) - p;
+    if (str[len - 1] == ')') {
+        keyLen--;
+    }
+
+    /* Create the objects with the variable name and key. */
+    keyObjPtr = Jim_NewStringObj(interp, p, keyLen);
+
+    Jim_IncrRefCount(varObjPtr);
+    Jim_IncrRefCount(keyObjPtr);
+    *varPtrPtr = varObjPtr;
+    *keyPtrPtr = keyObjPtr;
+}
+
+/* Helper of Jim_SetVariable() to deal with dict-syntax variable names.
+ * Also used by Jim_UnsetVariable() with valObjPtr = NULL. */
+static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *valObjPtr)
+{
+    int err;
+
+    SetDictSubstFromAny(interp, objPtr);
+
+    err = Jim_SetDictKeysVector(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
+        &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_ERRMSG);
+
+    if (err == JIM_OK) {
+        /* Don't keep an extra ref to the result */
+        Jim_SetEmptyResult(interp);
+    }
+    else {
+        if (!valObjPtr) {
+            /* Better error message for unset a(2) where a exists but a(2) doesn't */
+            if (Jim_GetVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_NONE)) {
+                Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such element in array",
+                    objPtr);
+                return err;
+            }
+        }
+        /* Make the error more informative and Tcl-compatible */
+        Jim_SetResultFormatted(interp, "can't %s \"%#s\": variable isn't array",
+            (valObjPtr ? "set" : "unset"), objPtr);
+    }
+    return err;
+}
+
+/**
+ * Expands the array variable (dict sugar) and returns the result, or NULL on error.
+ *
+ * If JIM_UNSHARED is set and the dictionary is shared, it will be duplicated
+ * and stored back to the variable before expansion.
+ */
+static Jim_Obj *JimDictExpandArrayVariable(Jim_Interp *interp, Jim_Obj *varObjPtr,
+    Jim_Obj *keyObjPtr, int flags)
+{
+    Jim_Obj *dictObjPtr;
+    Jim_Obj *resObjPtr = NULL;
+    int ret;
+
+    dictObjPtr = Jim_GetVariable(interp, varObjPtr, JIM_ERRMSG);
+    if (!dictObjPtr) {
+        return NULL;
+    }
+
+    ret = Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE);
+    if (ret != JIM_OK) {
+        resObjPtr = NULL;
+        if (ret < 0) {
+            Jim_SetResultFormatted(interp,
+                "can't read \"%#s(%#s)\": variable isn't array", varObjPtr, keyObjPtr);
+        }
+        else {
+            Jim_SetResultFormatted(interp,
+                "can't read \"%#s(%#s)\": no such element in array", varObjPtr, keyObjPtr);
+        }
+    }
+    else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) {
+        dictObjPtr = Jim_DuplicateObj(interp, dictObjPtr);
+        if (Jim_SetVariable(interp, varObjPtr, dictObjPtr) != JIM_OK) {
+            /* This can probably never happen */
+            JimPanic((1, "SetVariable failed for JIM_UNSHARED"));
+        }
+        /* We know that the key exists. Get the result in the now-unshared dictionary */
+        Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE);
+    }
+
+    return resObjPtr;
+}
+
+/* Helper of Jim_GetVariable() to deal with dict-syntax variable names */
+static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+    SetDictSubstFromAny(interp, objPtr);
+
+    return JimDictExpandArrayVariable(interp,
+        objPtr->internalRep.dictSubstValue.varNameObjPtr,
+        objPtr->internalRep.dictSubstValue.indexObjPtr, flags);
+}
+
+/* --------- $var(INDEX) substitution, using a specialized object ----------- */
+
+void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr);
+    Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
+}
+
+void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+    JIM_NOTUSED(interp);
+
+    dupPtr->internalRep.dictSubstValue.varNameObjPtr =
+        srcPtr->internalRep.dictSubstValue.varNameObjPtr;
+    dupPtr->internalRep.dictSubstValue.indexObjPtr = srcPtr->internalRep.dictSubstValue.indexObjPtr;
+    dupPtr->typePtr = &dictSubstObjType;
+}
+
+/* Note: The object *must* be in dict-sugar format */
+static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    if (objPtr->typePtr != &dictSubstObjType) {
+        Jim_Obj *varObjPtr, *keyObjPtr;
+
+        if (objPtr->typePtr == &interpolatedObjType) {
+            /* An interpolated object in dict-sugar form */
+
+            const ScriptToken *token = objPtr->internalRep.twoPtrValue.ptr1;
+
+            varObjPtr = token[0].objPtr;
+            keyObjPtr = objPtr->internalRep.twoPtrValue.ptr2;
+
+            Jim_IncrRefCount(varObjPtr);
+            Jim_IncrRefCount(keyObjPtr);
+        }
+        else {
+            JimDictSugarParseVarKey(interp, objPtr, &varObjPtr, &keyObjPtr);
+        }
+
+        Jim_FreeIntRep(interp, objPtr);
+        objPtr->typePtr = &dictSubstObjType;
+        objPtr->internalRep.dictSubstValue.varNameObjPtr = varObjPtr;
+        objPtr->internalRep.dictSubstValue.indexObjPtr = keyObjPtr;
+    }
+}
+
+/* This function is used to expand [dict get] sugar in the form
+ * of $var(INDEX). The function is mainly used by Jim_EvalObj()
+ * to deal with tokens of type JIM_TT_DICTSUGAR. objPtr points to an
+ * object that is *guaranteed* to be in the form VARNAME(INDEX).
+ * The 'index' part is [subst]ituted, and is used to lookup a key inside
+ * the [dict]ionary contained in variable VARNAME. */
+static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    Jim_Obj *resObjPtr = NULL;
+    Jim_Obj *substKeyObjPtr = NULL;
+
+    SetDictSubstFromAny(interp, objPtr);
+
+    if (Jim_SubstObj(interp, objPtr->internalRep.dictSubstValue.indexObjPtr,
+            &substKeyObjPtr, JIM_NONE)
+        != JIM_OK) {
+        return NULL;
+    }
+    Jim_IncrRefCount(substKeyObjPtr);
+    resObjPtr =
+        JimDictExpandArrayVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
+        substKeyObjPtr, 0);
+    Jim_DecrRefCount(interp, substKeyObjPtr);
+
+    return resObjPtr;
+}
+
+static Jim_Obj *JimExpandExprSugar(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    Jim_Obj *resultObjPtr;
+
+    if (Jim_EvalExpression(interp, objPtr, &resultObjPtr) == JIM_OK) {
+        /* Note that the result has a ref count of 1, but we need a ref count of 0 */
+        resultObjPtr->refCount--;
+        return resultObjPtr;
+    }
+    return NULL;
+}
+
+/* -----------------------------------------------------------------------------
+ * CallFrame
+ * ---------------------------------------------------------------------------*/
+
+static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent)
+{
+    Jim_CallFrame *cf;
+
+    if (interp->freeFramesList) {
+        cf = interp->freeFramesList;
+        interp->freeFramesList = cf->nextFramePtr;
+    }
+    else {
+        cf = Jim_Alloc(sizeof(*cf));
+        cf->vars.table = NULL;
+    }
+
+    cf->id = interp->callFrameEpoch++;
+    cf->parentCallFrame = parent;
+    cf->level = parent ? parent->level + 1 : 0;
+    cf->argv = NULL;
+    cf->argc = 0;
+    cf->procArgsObjPtr = NULL;
+    cf->procBodyObjPtr = NULL;
+    cf->nextFramePtr = NULL;
+    cf->staticVars = NULL;
+    if (cf->vars.table == NULL)
+        Jim_InitHashTable(&cf->vars, &JimVariablesHashTableType, interp);
+    return cf;
+}
+
+/* Used to invalidate every caching related to callframe stability. */
+static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf)
+{
+    cf->id = interp->callFrameEpoch++;
+}
+
+#define JIM_FCF_NONE 0          /* no flags */
+#define JIM_FCF_NOHT 1          /* don't free the hash table */
+static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags)
+{
+    if (cf->procArgsObjPtr)
+        Jim_DecrRefCount(interp, cf->procArgsObjPtr);
+    if (cf->procBodyObjPtr)
+        Jim_DecrRefCount(interp, cf->procBodyObjPtr);
+    if (!(flags & JIM_FCF_NOHT))
+        Jim_FreeHashTable(&cf->vars);
+    else {
+        int i;
+        Jim_HashEntry **table = cf->vars.table, *he;
+
+        for (i = 0; i < JIM_HT_INITIAL_SIZE; i++) {
+            he = table[i];
+            while (he != NULL) {
+                Jim_HashEntry *nextEntry = he->next;
+                Jim_Var *varPtr = (void *)he->u.val;
+
+                Jim_DecrRefCount(interp, varPtr->objPtr);
+                Jim_Free(he->u.val);
+                Jim_Free((void *)he->key);      /* ATTENTION: const cast */
+                Jim_Free(he);
+                table[i] = NULL;
+                he = nextEntry;
+            }
+        }
+        cf->vars.used = 0;
+    }
+    cf->nextFramePtr = interp->freeFramesList;
+    interp->freeFramesList = cf;
+}
+
+/* -----------------------------------------------------------------------------
+ * References
+ * ---------------------------------------------------------------------------*/
+#ifdef JIM_REFERENCES
+
+/* References HashTable Type.
+ *
+ * Keys are jim_wide integers, dynamically allocated for now but in the
+ * future it's worth to cache this 8 bytes objects. Values are poitners
+ * to Jim_References. */
+static void JimReferencesHTValDestructor(void *interp, void *val)
+{
+    Jim_Reference *refPtr = (void *)val;
+
+    Jim_DecrRefCount(interp, refPtr->objPtr);
+    if (refPtr->finalizerCmdNamePtr != NULL) {
+        Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr);
+    }
+    Jim_Free(val);
+}
+
+static unsigned int JimReferencesHTHashFunction(const void *key)
+{
+    /* Only the least significant bits are used. */
+    const jim_wide *widePtr = key;
+    unsigned int intValue = (unsigned int)*widePtr;
+
+    return Jim_IntHashFunction(intValue);
+}
+
+static const void *JimReferencesHTKeyDup(void *privdata, const void *key)
+{
+    void *copy = Jim_Alloc(sizeof(jim_wide));
+
+    JIM_NOTUSED(privdata);
+
+    memcpy(copy, key, sizeof(jim_wide));
+    return copy;
+}
+
+static int JimReferencesHTKeyCompare(void *privdata, const void *key1, const void *key2)
+{
+    JIM_NOTUSED(privdata);
+
+    return memcmp(key1, key2, sizeof(jim_wide)) == 0;
+}
+
+static void JimReferencesHTKeyDestructor(void *privdata, const void *key)
+{
+    JIM_NOTUSED(privdata);
+
+    Jim_Free((void *)key);
+}
+
+static const Jim_HashTableType JimReferencesHashTableType = {
+    JimReferencesHTHashFunction,        /* hash function */
+    JimReferencesHTKeyDup,      /* key dup */
+    NULL,                       /* val dup */
+    JimReferencesHTKeyCompare,  /* key compare */
+    JimReferencesHTKeyDestructor,       /* key destructor */
+    JimReferencesHTValDestructor        /* val destructor */
+};
+
+/* -----------------------------------------------------------------------------
+ * Reference object type and References API
+ * ---------------------------------------------------------------------------*/
+
+/* The string representation of references has two features in order
+ * to make the GC faster. The first is that every reference starts
+ * with a non common character '<', in order to make the string matching
+ * faster. The second is that the reference string rep is 42 characters
+ * in length, this allows to avoid to check every object with a string
+ * repr < 42, and usually there aren't many of these objects. */
+
+#define JIM_REFERENCE_SPACE (35+JIM_REFERENCE_TAGLEN)
+
+static int JimFormatReference(char *buf, Jim_Reference *refPtr, jim_wide id)
+{
+    const char *fmt = "<reference.<%s>.%020" JIM_WIDE_MODIFIER ">";
+
+    sprintf(buf, fmt, refPtr->tag, id);
+    return JIM_REFERENCE_SPACE;
+}
+
+static void UpdateStringOfReference(struct Jim_Obj *objPtr);
+
+static const Jim_ObjType referenceObjType = {
+    "reference",
+    NULL,
+    NULL,
+    UpdateStringOfReference,
+    JIM_TYPE_REFERENCES,
+};
+
+void UpdateStringOfReference(struct Jim_Obj *objPtr)
+{
+    int len;
+    char buf[JIM_REFERENCE_SPACE + 1];
+    Jim_Reference *refPtr;
+
+    refPtr = objPtr->internalRep.refValue.refPtr;
+    len = JimFormatReference(buf, refPtr, objPtr->internalRep.refValue.id);
+    objPtr->bytes = Jim_Alloc(len + 1);
+    memcpy(objPtr->bytes, buf, len + 1);
+    objPtr->length = len;
+}
+
+/* returns true if 'c' is a valid reference tag character.
+ * i.e. inside the range [_a-zA-Z0-9] */
+static int isrefchar(int c)
+{
+    return (c == '_' || isalnum(c));
+}
+
+static int SetReferenceFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    jim_wide wideValue;
+    int i, len;
+    const char *str, *start, *end;
+    char refId[21];
+    Jim_Reference *refPtr;
+    Jim_HashEntry *he;
+
+    /* Get the string representation */
+    str = Jim_GetString(objPtr, &len);
+    /* Check if it looks like a reference */
+    if (len < JIM_REFERENCE_SPACE)
+        goto badformat;
+    /* Trim spaces */
+    start = str;
+    end = str + len - 1;
+    while (*start == ' ')
+        start++;
+    while (*end == ' ' && end > start)
+        end--;
+    if (end - start + 1 != JIM_REFERENCE_SPACE)
+        goto badformat;
+    /* <reference.<1234567>.%020> */
+    if (memcmp(start, "<reference.<", 12) != 0)
+        goto badformat;
+    if (start[12 + JIM_REFERENCE_TAGLEN] != '>' || end[0] != '>')
+        goto badformat;
+    /* The tag can't contain chars other than a-zA-Z0-9 + '_'. */
+    for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) {
+        if (!isrefchar(start[12 + i]))
+            goto badformat;
+    }
+    /* Extract info from the reference. */
+    memcpy(refId, start + 14 + JIM_REFERENCE_TAGLEN, 20);
+    refId[20] = '\0';
+    /* Try to convert the ID into a jim_wide */
+    if (Jim_StringToWide(refId, &wideValue, 10) != JIM_OK)
+        goto badformat;
+    /* Check if the reference really exists! */
+    he = Jim_FindHashEntry(&interp->references, &wideValue);
+    if (he == NULL) {
+        Jim_SetResultFormatted(interp, "invalid reference id \"%#s\"", objPtr);
+        return JIM_ERR;
+    }
+    refPtr = he->u.val;
+    /* Free the old internal repr and set the new one. */
+    Jim_FreeIntRep(interp, objPtr);
+    objPtr->typePtr = &referenceObjType;
+    objPtr->internalRep.refValue.id = wideValue;
+    objPtr->internalRep.refValue.refPtr = refPtr;
+    return JIM_OK;
+
+  badformat:
+    Jim_SetResultFormatted(interp, "expected reference but got \"%#s\"", objPtr);
+    return JIM_ERR;
+}
+
+/* Returns a new reference pointing to objPtr, having cmdNamePtr
+ * as finalizer command (or NULL if there is no finalizer).
+ * The returned reference object has refcount = 0. */
+Jim_Obj *Jim_NewReference(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr)
+{
+    struct Jim_Reference *refPtr;
+    jim_wide wideValue = interp->referenceNextId;
+    Jim_Obj *refObjPtr;
+    const char *tag;
+    int tagLen, i;
+
+    /* Perform the Garbage Collection if needed. */
+    Jim_CollectIfNeeded(interp);
+
+    refPtr = Jim_Alloc(sizeof(*refPtr));
+    refPtr->objPtr = objPtr;
+    Jim_IncrRefCount(objPtr);
+    refPtr->finalizerCmdNamePtr = cmdNamePtr;
+    if (cmdNamePtr)
+        Jim_IncrRefCount(cmdNamePtr);
+    Jim_AddHashEntry(&interp->references, &wideValue, refPtr);
+    refObjPtr = Jim_NewObj(interp);
+    refObjPtr->typePtr = &referenceObjType;
+    refObjPtr->bytes = NULL;
+    refObjPtr->internalRep.refValue.id = interp->referenceNextId;
+    refObjPtr->internalRep.refValue.refPtr = refPtr;
+    interp->referenceNextId++;
+    /* Set the tag. Trimmed at JIM_REFERENCE_TAGLEN. Everything
+     * that does not pass the 'isrefchar' test is replaced with '_' */
+    tag = Jim_GetString(tagPtr, &tagLen);
+    if (tagLen > JIM_REFERENCE_TAGLEN)
+        tagLen = JIM_REFERENCE_TAGLEN;
+    for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) {
+        if (i < tagLen && isrefchar(tag[i]))
+            refPtr->tag[i] = tag[i];
+        else
+            refPtr->tag[i] = '_';
+    }
+    refPtr->tag[JIM_REFERENCE_TAGLEN] = '\0';
+    return refObjPtr;
+}
+
+Jim_Reference *Jim_GetReference(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    if (objPtr->typePtr != &referenceObjType && SetReferenceFromAny(interp, objPtr) == JIM_ERR)
+        return NULL;
+    return objPtr->internalRep.refValue.refPtr;
+}
+
+int Jim_SetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr)
+{
+    Jim_Reference *refPtr;
+
+    if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL)
+        return JIM_ERR;
+    Jim_IncrRefCount(cmdNamePtr);
+    if (refPtr->finalizerCmdNamePtr)
+        Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr);
+    refPtr->finalizerCmdNamePtr = cmdNamePtr;
+    return JIM_OK;
+}
+
+int Jim_GetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr)
+{
+    Jim_Reference *refPtr;
+
+    if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL)
+        return JIM_ERR;
+    *cmdNamePtrPtr = refPtr->finalizerCmdNamePtr;
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * References Garbage Collection
+ * ---------------------------------------------------------------------------*/
+
+/* This the hash table type for the "MARK" phase of the GC */
+static const Jim_HashTableType JimRefMarkHashTableType = {
+    JimReferencesHTHashFunction,        /* hash function */
+    JimReferencesHTKeyDup,      /* key dup */
+    NULL,                       /* val dup */
+    JimReferencesHTKeyCompare,  /* key compare */
+    JimReferencesHTKeyDestructor,       /* key destructor */
+    NULL                        /* val destructor */
+};
+
+/* Performs the garbage collection. */
+int Jim_Collect(Jim_Interp *interp)
+{
+    int collected = 0;
+#ifndef JIM_BOOTSTRAP
+    Jim_HashTable marks;
+    Jim_HashTableIterator *htiter;
+    Jim_HashEntry *he;
+    Jim_Obj *objPtr;
+
+    /* Avoid recursive calls */
+    if (interp->lastCollectId == -1) {
+        /* Jim_Collect() already running. Return just now. */
+        return 0;
+    }
+    interp->lastCollectId = -1;
+
+    /* Mark all the references found into the 'mark' hash table.
+     * The references are searched in every live object that
+     * is of a type that can contain references. */
+    Jim_InitHashTable(&marks, &JimRefMarkHashTableType, NULL);
+    objPtr = interp->liveList;
+    while (objPtr) {
+        if (objPtr->typePtr == NULL || objPtr->typePtr->flags & JIM_TYPE_REFERENCES) {
+            const char *str, *p;
+            int len;
+
+            /* If the object is of type reference, to get the
+             * Id is simple... */
+            if (objPtr->typePtr == &referenceObjType) {
+                Jim_AddHashEntry(&marks, &objPtr->internalRep.refValue.id, NULL);
+#ifdef JIM_DEBUG_GC
+                printf("MARK (reference): %d refcount: %d" JIM_NL,
+                    (int)objPtr->internalRep.refValue.id, objPtr->refCount);
+#endif
+                objPtr = objPtr->nextObjPtr;
+                continue;
+            }
+            /* Get the string repr of the object we want
+             * to scan for references. */
+            p = str = Jim_GetString(objPtr, &len);
+            /* Skip objects too little to contain references. */
+            if (len < JIM_REFERENCE_SPACE) {
+                objPtr = objPtr->nextObjPtr;
+                continue;
+            }
+            /* Extract references from the object string repr. */
+            while (1) {
+                int i;
+                jim_wide id;
+                char buf[21];
+
+                if ((p = strstr(p, "<reference.<")) == NULL)
+                    break;
+                /* Check if it's a valid reference. */
+                if (len - (p - str) < JIM_REFERENCE_SPACE)
+                    break;
+                if (p[41] != '>' || p[19] != '>' || p[20] != '.')
+                    break;
+                for (i = 21; i <= 40; i++)
+                    if (!isdigit(UCHAR(p[i])))
+                        break;
+                /* Get the ID */
+                memcpy(buf, p + 21, 20);
+                buf[20] = '\0';
+                Jim_StringToWide(buf, &id, 10);
+
+                /* Ok, a reference for the given ID
+                 * was found. Mark it. */
+                Jim_AddHashEntry(&marks, &id, NULL);
+#ifdef JIM_DEBUG_GC
+                printf("MARK: %d" JIM_NL, (int)id);
+#endif
+                p += JIM_REFERENCE_SPACE;
+            }
+        }
+        objPtr = objPtr->nextObjPtr;
+    }
+
+    /* Run the references hash table to destroy every reference that
+     * is not referenced outside (not present in the mark HT). */
+    htiter = Jim_GetHashTableIterator(&interp->references);
+    while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+        const jim_wide *refId;
+        Jim_Reference *refPtr;
+
+        refId = he->key;
+        /* Check if in the mark phase we encountered
+         * this reference. */
+        if (Jim_FindHashEntry(&marks, refId) == NULL) {
+#ifdef JIM_DEBUG_GC
+            printf("COLLECTING %d" JIM_NL, (int)*refId);
+#endif
+            collected++;
+            /* Drop the reference, but call the
+             * finalizer first if registered. */
+            refPtr = he->u.val;
+            if (refPtr->finalizerCmdNamePtr) {
+                char *refstr = Jim_Alloc(JIM_REFERENCE_SPACE + 1);
+                Jim_Obj *objv[3], *oldResult;
+
+                JimFormatReference(refstr, refPtr, *refId);
+
+                objv[0] = refPtr->finalizerCmdNamePtr;
+                objv[1] = Jim_NewStringObjNoAlloc(interp, refstr, 32);
+                objv[2] = refPtr->objPtr;
+                Jim_IncrRefCount(objv[0]);
+                Jim_IncrRefCount(objv[1]);
+                Jim_IncrRefCount(objv[2]);
+
+                /* Drop the reference itself */
+                Jim_DeleteHashEntry(&interp->references, refId);
+
+                /* Call the finalizer. Errors ignored. */
+                oldResult = interp->result;
+                Jim_IncrRefCount(oldResult);
+                Jim_EvalObjVector(interp, 3, objv);
+                Jim_SetResult(interp, oldResult);
+                Jim_DecrRefCount(interp, oldResult);
+
+                Jim_DecrRefCount(interp, objv[0]);
+                Jim_DecrRefCount(interp, objv[1]);
+                Jim_DecrRefCount(interp, objv[2]);
+            }
+            else {
+                Jim_DeleteHashEntry(&interp->references, refId);
+            }
+        }
+    }
+    Jim_FreeHashTableIterator(htiter);
+    Jim_FreeHashTable(&marks);
+    interp->lastCollectId = interp->referenceNextId;
+    interp->lastCollectTime = time(NULL);
+#endif /* JIM_BOOTSTRAP */
+    return collected;
+}
+
+#define JIM_COLLECT_ID_PERIOD 5000
+#define JIM_COLLECT_TIME_PERIOD 300
+
+void Jim_CollectIfNeeded(Jim_Interp *interp)
+{
+    jim_wide elapsedId;
+    int elapsedTime;
+
+    elapsedId = interp->referenceNextId - interp->lastCollectId;
+    elapsedTime = time(NULL) - interp->lastCollectTime;
+
+
+    if (elapsedId > JIM_COLLECT_ID_PERIOD || elapsedTime > JIM_COLLECT_TIME_PERIOD) {
+        Jim_Collect(interp);
+    }
+}
+#endif
+
+static int JimIsBigEndian(void)
+{
+    union {
+        unsigned short s;
+        unsigned char c[2];
+    } uval = {0x0102};
+
+    return uval.c[0] == 1;
+}
+
+/* -----------------------------------------------------------------------------
+ * Interpreter related functions
+ * ---------------------------------------------------------------------------*/
+
+Jim_Interp *Jim_CreateInterp(void)
+{
+    Jim_Interp *i = Jim_Alloc(sizeof(*i));
+
+    memset(i, 0, sizeof(*i));
+
+    i->maxNestingDepth = JIM_MAX_NESTING_DEPTH;
+    i->lastCollectTime = time(NULL);
+
+    /* Note that we can create objects only after the
+     * interpreter liveList and freeList pointers are
+     * initialized to NULL. */
+    Jim_InitHashTable(&i->commands, &JimCommandsHashTableType, i);
+#ifdef JIM_REFERENCES
+    Jim_InitHashTable(&i->references, &JimReferencesHashTableType, i);
+#endif
+    Jim_InitHashTable(&i->assocData, &JimAssocDataHashTableType, i);
+    Jim_InitHashTable(&i->packages, &JimStringKeyValCopyHashTableType, NULL);
+    i->framePtr = i->topFramePtr = JimCreateCallFrame(i, NULL);
+    i->emptyObj = Jim_NewEmptyStringObj(i);
+    i->trueObj = Jim_NewIntObj(i, 1);
+    i->falseObj = Jim_NewIntObj(i, 0);
+    i->errorFileNameObj = i->emptyObj;
+    i->result = i->emptyObj;
+    i->stackTrace = Jim_NewListObj(i, NULL, 0);
+    i->unknown = Jim_NewStringObj(i, "unknown", -1);
+    i->errorProc = i->emptyObj;
+    i->currentScriptObj = Jim_NewEmptyStringObj(i);
+    Jim_IncrRefCount(i->emptyObj);
+    Jim_IncrRefCount(i->errorFileNameObj);
+    Jim_IncrRefCount(i->result);
+    Jim_IncrRefCount(i->stackTrace);
+    Jim_IncrRefCount(i->unknown);
+    Jim_IncrRefCount(i->currentScriptObj);
+    Jim_IncrRefCount(i->errorProc);
+    Jim_IncrRefCount(i->trueObj);
+    Jim_IncrRefCount(i->falseObj);
+
+    /* Initialize key variables every interpreter should contain */
+    Jim_SetVariableStrWithStr(i, JIM_LIBPATH, TCL_LIBRARY);
+    Jim_SetVariableStrWithStr(i, JIM_INTERACTIVE, "0");
+
+    Jim_SetVariableStrWithStr(i, "tcl_platform(os)", TCL_PLATFORM_OS);
+    Jim_SetVariableStrWithStr(i, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM);
+    Jim_SetVariableStrWithStr(i, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR);
+    Jim_SetVariableStrWithStr(i, "tcl_platform(byteOrder)", JimIsBigEndian() ? "bigEndian" : "littleEndian");
+    Jim_SetVariableStrWithStr(i, "tcl_platform(threaded)", "0");
+    Jim_SetVariableStr(i, "tcl_platform(pointerSize)", Jim_NewIntObj(i, sizeof(void *)));
+    Jim_SetVariableStr(i, "tcl_platform(wordSize)", Jim_NewIntObj(i, sizeof(jim_wide)));
+
+    return i;
+}
+
+void Jim_FreeInterp(Jim_Interp *i)
+{
+    Jim_CallFrame *cf = i->framePtr, *prevcf, *nextcf;
+    Jim_Obj *objPtr, *nextObjPtr;
+
+    Jim_DecrRefCount(i, i->emptyObj);
+    Jim_DecrRefCount(i, i->trueObj);
+    Jim_DecrRefCount(i, i->falseObj);
+    Jim_DecrRefCount(i, i->result);
+    Jim_DecrRefCount(i, i->stackTrace);
+    Jim_DecrRefCount(i, i->errorProc);
+    Jim_DecrRefCount(i, i->unknown);
+    Jim_DecrRefCount(i, i->errorFileNameObj);
+    Jim_DecrRefCount(i, i->currentScriptObj);
+    Jim_FreeHashTable(&i->commands);
+#ifdef JIM_REFERENCES
+    Jim_FreeHashTable(&i->references);
+#endif
+    Jim_FreeHashTable(&i->packages);
+    Jim_Free(i->prngState);
+    Jim_FreeHashTable(&i->assocData);
+    JimDeleteLocalProcs(i);
+
+    /* Free the call frames list */
+    while (cf) {
+        prevcf = cf->parentCallFrame;
+        JimFreeCallFrame(i, cf, JIM_FCF_NONE);
+        cf = prevcf;
+    }
+    /* Check that the live object list is empty, otherwise
+     * there is a memory leak. */
+    if (i->liveList != NULL) {
+        objPtr = i->liveList;
+
+        printf(JIM_NL "-------------------------------------" JIM_NL);
+        printf("Objects still in the free list:" JIM_NL);
+        while (objPtr) {
+            const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string";
+
+            printf("%p (%d) %-10s: '%.20s'" JIM_NL,
+                (void *)objPtr, objPtr->refCount, type, objPtr->bytes ? objPtr->bytes : "(null)");
+            if (objPtr->typePtr == &sourceObjType) {
+                printf("FILE %s LINE %d" JIM_NL,
+                    Jim_String(objPtr->internalRep.sourceValue.fileNameObj),
+                    objPtr->internalRep.sourceValue.lineNumber);
+            }
+            objPtr = objPtr->nextObjPtr;
+        }
+        printf("-------------------------------------" JIM_NL JIM_NL);
+        JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
+    }
+    /* Free all the freed objects. */
+    objPtr = i->freeList;
+    while (objPtr) {
+        nextObjPtr = objPtr->nextObjPtr;
+        Jim_Free(objPtr);
+        objPtr = nextObjPtr;
+    }
+    /* Free cached CallFrame structures */
+    cf = i->freeFramesList;
+    while (cf) {
+        nextcf = cf->nextFramePtr;
+        if (cf->vars.table != NULL)
+            Jim_Free(cf->vars.table);
+        Jim_Free(cf);
+        cf = nextcf;
+    }
+#ifdef jim_ext_load
+    Jim_FreeLoadHandles(i);
+#endif
+
+    /* Free the interpreter structure. */
+    Jim_Free(i);
+}
+
+/* Returns the call frame relative to the level represented by
+ * levelObjPtr. If levelObjPtr == NULL, the * level is assumed to be '1'.
+ *
+ * This function accepts the 'level' argument in the form
+ * of the commands [uplevel] and [upvar].
+ *
+ * For a function accepting a relative integer as level suitable
+ * for implementation of [info level ?level?] check the
+ * JimGetCallFrameByInteger() function.
+ *
+ * Returns NULL on error.
+ */
+Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr)
+{
+    long level;
+    const char *str;
+    Jim_CallFrame *framePtr;
+
+    if (levelObjPtr) {
+        str = Jim_String(levelObjPtr);
+        if (str[0] == '#') {
+            char *endptr;
+
+            level = strtol(str + 1, &endptr, 0);
+            if (str[1] == '\0' || endptr[0] != '\0') {
+                level = -1;
+            }
+        }
+        else {
+            if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0) {
+                level = -1;
+            }
+            else {
+                /* Convert from a relative to an absolute level */
+                level = interp->framePtr->level - level;
+            }
+        }
+    }
+    else {
+        str = "1";              /* Needed to format the error message. */
+        level = interp->framePtr->level - 1;
+    }
+
+    if (level == 0) {
+        return interp->topFramePtr;
+    }
+    if (level > 0) {
+        /* Lookup */
+        for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parentCallFrame) {
+            if (framePtr->level == level) {
+                return framePtr;
+            }
+        }
+    }
+
+    Jim_SetResultFormatted(interp, "bad level \"%s\"", str);
+    return NULL;
+}
+
+/* Similar to Jim_GetCallFrameByLevel() but the level is specified
+ * as a relative integer like in the [info level ?level?] command.
+ **/
+static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, Jim_Obj *levelObjPtr)
+{
+    long level;
+    Jim_CallFrame *framePtr;
+
+    if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
+        if (level <= 0) {
+            /* Convert from a relative to an absolute level */
+            level = interp->framePtr->level + level;
+        }
+
+        if (level == 0) {
+            return interp->topFramePtr;
+        }
+
+        /* Lookup */
+        for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parentCallFrame) {
+            if (framePtr->level == level) {
+                return framePtr;
+            }
+        }
+    }
+
+    Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
+    return NULL;
+}
+
+static void JimResetStackTrace(Jim_Interp *interp)
+{
+    Jim_DecrRefCount(interp, interp->stackTrace);
+    interp->stackTrace = Jim_NewListObj(interp, NULL, 0);
+    Jim_IncrRefCount(interp->stackTrace);
+}
+
+static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj)
+{
+    int len;
+
+    /* Increment reference first in case these are the same object */
+    Jim_IncrRefCount(stackTraceObj);
+    Jim_DecrRefCount(interp, interp->stackTrace);
+    interp->stackTrace = stackTraceObj;
+    interp->errorFlag = 1;
+
+    /* This is a bit ugly.
+     * If the filename of the last entry of the stack trace is empty,
+     * the next stack level should be added.
+     */
+    len = Jim_ListLength(interp, interp->stackTrace);
+    if (len >= 3) {
+        Jim_Obj *filenameObj;
+
+        Jim_ListIndex(interp, interp->stackTrace, len - 2, &filenameObj, JIM_NONE);
+
+        Jim_GetString(filenameObj, &len);
+
+        if (!Jim_Length(filenameObj)) {
+            interp->addStackTrace = 1;
+        }
+    }
+}
+
+/* Returns 1 if the stack trace information was used or 0 if not */
+static void JimAppendStackTrace(Jim_Interp *interp, const char *procname,
+    Jim_Obj *fileNameObj, int linenr)
+{
+    if (strcmp(procname, "unknown") == 0) {
+        procname = "";
+    }
+    if (!*procname && !Jim_Length(fileNameObj)) {
+        /* No useful info here */
+        return;
+    }
+
+    if (Jim_IsShared(interp->stackTrace)) {
+        Jim_DecrRefCount(interp, interp->stackTrace);
+        interp->stackTrace = Jim_DuplicateObj(interp, interp->stackTrace);
+        Jim_IncrRefCount(interp->stackTrace);
+    }
+
+    /* If we have no procname but the previous element did, merge with that frame */
+    if (!*procname && Jim_Length(fileNameObj)) {
+        /* Just a filename. Check the previous entry */
+        int len = Jim_ListLength(interp, interp->stackTrace);
+
+        if (len >= 3) {
+            Jim_Obj *objPtr;
+            if (Jim_ListIndex(interp, interp->stackTrace, len - 3, &objPtr, JIM_NONE) == JIM_OK && Jim_Length(objPtr)) {
+                /* Yes, the previous level had procname */
+                if (Jim_ListIndex(interp, interp->stackTrace, len - 2, &objPtr, JIM_NONE) == JIM_OK && !Jim_Length(objPtr)) {
+                    /* But no filename, so merge the new info with that frame */
+                    ListSetIndex(interp, interp->stackTrace, len - 2, fileNameObj, 0);
+                    ListSetIndex(interp, interp->stackTrace, len - 1, Jim_NewIntObj(interp, linenr), 0);
+                    return;
+                }
+            }
+        }
+    }
+
+    Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewStringObj(interp, procname, -1));
+    Jim_ListAppendElement(interp, interp->stackTrace, fileNameObj);
+    Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewIntObj(interp, linenr));
+}
+
+int Jim_SetAssocData(Jim_Interp *interp, const char *key, Jim_InterpDeleteProc * delProc,
+    void *data)
+{
+    AssocDataValue *assocEntryPtr = (AssocDataValue *) Jim_Alloc(sizeof(AssocDataValue));
+
+    assocEntryPtr->delProc = delProc;
+    assocEntryPtr->data = data;
+    return Jim_AddHashEntry(&interp->assocData, key, assocEntryPtr);
+}
+
+void *Jim_GetAssocData(Jim_Interp *interp, const char *key)
+{
+    Jim_HashEntry *entryPtr = Jim_FindHashEntry(&interp->assocData, key);
+
+    if (entryPtr != NULL) {
+        AssocDataValue *assocEntryPtr = (AssocDataValue *) entryPtr->u.val;
+
+        return assocEntryPtr->data;
+    }
+    return NULL;
+}
+
+int Jim_DeleteAssocData(Jim_Interp *interp, const char *key)
+{
+    return Jim_DeleteHashEntry(&interp->assocData, key);
+}
+
+int Jim_GetExitCode(Jim_Interp *interp)
+{
+    return interp->exitCode;
+}
+
+/* -----------------------------------------------------------------------------
+ * Integer object
+ * ---------------------------------------------------------------------------*/
+#define JIM_INTEGER_SPACE 24
+
+static void UpdateStringOfInt(struct Jim_Obj *objPtr);
+static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
+
+static const Jim_ObjType intObjType = {
+    "int",
+    NULL,
+    NULL,
+    UpdateStringOfInt,
+    JIM_TYPE_NONE,
+};
+
+/* A coerced double is closer to an int than a double.
+ * It is an int value temporarily masquerading as a double value.
+ * i.e. it has the same string value as an int and Jim_GetWide()
+ * succeeds, but also Jim_GetDouble() returns the value directly.
+ */
+static const Jim_ObjType coercedDoubleObjType = {
+    "coerced-double",
+    NULL,
+    NULL,
+    UpdateStringOfInt,
+    JIM_TYPE_NONE,
+};
+
+
+void UpdateStringOfInt(struct Jim_Obj *objPtr)
+{
+    int len;
+    char buf[JIM_INTEGER_SPACE + 1];
+
+    len = Jim_WideToString(buf, JimWideValue(objPtr));
+    objPtr->bytes = Jim_Alloc(len + 1);
+    memcpy(objPtr->bytes, buf, len + 1);
+    objPtr->length = len;
+}
+
+int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+    jim_wide wideValue;
+    const char *str;
+
+    if (objPtr->typePtr == &coercedDoubleObjType) {
+        /* Simple switcheroo */
+        objPtr->typePtr = &intObjType;
+        return JIM_OK;
+    }
+
+    /* Get the string representation */
+    str = Jim_String(objPtr);
+    /* Try to convert into a jim_wide */
+    if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) {
+        if (flags & JIM_ERRMSG) {
+            Jim_SetResultFormatted(interp, "expected integer but got \"%#s\"", objPtr);
+        }
+        return JIM_ERR;
+    }
+    if ((wideValue == JIM_WIDE_MIN || wideValue == JIM_WIDE_MAX) && errno == ERANGE) {
+        Jim_SetResultString(interp, "Integer value too big to be represented", -1);
+        return JIM_ERR;
+    }
+    /* Free the old internal repr and set the new one. */
+    Jim_FreeIntRep(interp, objPtr);
+    objPtr->typePtr = &intObjType;
+    objPtr->internalRep.wideValue = wideValue;
+    return JIM_OK;
+}
+
+#ifdef JIM_OPTIMIZATION
+static int JimIsWide(Jim_Obj *objPtr)
+{
+    return objPtr->typePtr == &intObjType;
+}
+#endif
+
+int Jim_GetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
+{
+    if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR)
+        return JIM_ERR;
+    *widePtr = JimWideValue(objPtr);
+    return JIM_OK;
+}
+
+/* Get a wide but does not set an error if the format is bad. */
+static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
+{
+    if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_NONE) == JIM_ERR)
+        return JIM_ERR;
+    *widePtr = JimWideValue(objPtr);
+    return JIM_OK;
+}
+
+int Jim_GetLong(Jim_Interp *interp, Jim_Obj *objPtr, long *longPtr)
+{
+    jim_wide wideValue;
+    int retval;
+
+    retval = Jim_GetWide(interp, objPtr, &wideValue);
+    if (retval == JIM_OK) {
+        *longPtr = (long)wideValue;
+        return JIM_OK;
+    }
+    return JIM_ERR;
+}
+
+Jim_Obj *Jim_NewIntObj(Jim_Interp *interp, jim_wide wideValue)
+{
+    Jim_Obj *objPtr;
+
+    objPtr = Jim_NewObj(interp);
+    objPtr->typePtr = &intObjType;
+    objPtr->bytes = NULL;
+    objPtr->internalRep.wideValue = wideValue;
+    return objPtr;
+}
+
+/* -----------------------------------------------------------------------------
+ * Double object
+ * ---------------------------------------------------------------------------*/
+#define JIM_DOUBLE_SPACE 30
+
+static void UpdateStringOfDouble(struct Jim_Obj *objPtr);
+static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
+
+static const Jim_ObjType doubleObjType = {
+    "double",
+    NULL,
+    NULL,
+    UpdateStringOfDouble,
+    JIM_TYPE_NONE,
+};
+
+void UpdateStringOfDouble(struct Jim_Obj *objPtr)
+{
+    int len;
+    char buf[JIM_DOUBLE_SPACE + 1];
+
+    len = Jim_DoubleToString(buf, objPtr->internalRep.doubleValue);
+    objPtr->bytes = Jim_Alloc(len + 1);
+    memcpy(objPtr->bytes, buf, len + 1);
+    objPtr->length = len;
+}
+
+int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    double doubleValue;
+    jim_wide wideValue;
+    const char *str;
+
+    /* Preserve the string representation.
+     * Needed so we can convert back to int without loss
+     */
+    str = Jim_String(objPtr);
+
+#ifdef HAVE_LONG_LONG
+    /* Assume a 53 bit mantissa */
+#define MIN_INT_IN_DOUBLE -(1LL << 53)
+#define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1)
+
+    if (objPtr->typePtr == &intObjType
+        && JimWideValue(objPtr) >= MIN_INT_IN_DOUBLE
+        && JimWideValue(objPtr) <= MAX_INT_IN_DOUBLE) {
+
+        /* Direct conversion to coerced double */
+        objPtr->typePtr = &coercedDoubleObjType;
+        return JIM_OK;
+    }
+    else
+#endif
+    if (Jim_StringToWide(str, &wideValue, 10) == JIM_OK) {
+        /* Managed to convert to an int, so we can use this as a cooerced double */
+        Jim_FreeIntRep(interp, objPtr);
+        objPtr->typePtr = &coercedDoubleObjType;
+        objPtr->internalRep.wideValue = wideValue;
+        return JIM_OK;
+    }
+    else {
+        /* Try to convert into a double */
+        if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) {
+            Jim_SetResultFormatted(interp, "expected number but got \"%#s\"", objPtr);
+            return JIM_ERR;
+        }
+        /* Free the old internal repr and set the new one. */
+        Jim_FreeIntRep(interp, objPtr);
+    }
+    objPtr->typePtr = &doubleObjType;
+    objPtr->internalRep.doubleValue = doubleValue;
+    return JIM_OK;
+}
+
+int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double *doublePtr)
+{
+    if (objPtr->typePtr == &coercedDoubleObjType) {
+        *doublePtr = JimWideValue(objPtr);
+        return JIM_OK;
+    }
+    if (objPtr->typePtr != &doubleObjType && SetDoubleFromAny(interp, objPtr) == JIM_ERR)
+        return JIM_ERR;
+
+    if (objPtr->typePtr == &coercedDoubleObjType) {
+        *doublePtr = JimWideValue(objPtr);
+    }
+    else {
+        *doublePtr = objPtr->internalRep.doubleValue;
+    }
+    return JIM_OK;
+}
+
+Jim_Obj *Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue)
+{
+    Jim_Obj *objPtr;
+
+    objPtr = Jim_NewObj(interp);
+    objPtr->typePtr = &doubleObjType;
+    objPtr->bytes = NULL;
+    objPtr->internalRep.doubleValue = doubleValue;
+    return objPtr;
+}
+
+/* -----------------------------------------------------------------------------
+ * List object
+ * ---------------------------------------------------------------------------*/
+static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr);
+static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static void UpdateStringOfList(struct Jim_Obj *objPtr);
+static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+/* Note that while the elements of the list may contain references,
+ * the list object itself can't. This basically means that the
+ * list object string representation as a whole can't contain references
+ * that are not presents in the single elements. */
+static const Jim_ObjType listObjType = {
+    "list",
+    FreeListInternalRep,
+    DupListInternalRep,
+    UpdateStringOfList,
+    JIM_TYPE_NONE,
+};
+
+void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    int i;
+
+    for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
+        Jim_DecrRefCount(interp, objPtr->internalRep.listValue.ele[i]);
+    }
+    Jim_Free(objPtr->internalRep.listValue.ele);
+}
+
+void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+    int i;
+
+    JIM_NOTUSED(interp);
+
+    dupPtr->internalRep.listValue.len = srcPtr->internalRep.listValue.len;
+    dupPtr->internalRep.listValue.maxLen = srcPtr->internalRep.listValue.maxLen;
+    dupPtr->internalRep.listValue.ele =
+        Jim_Alloc(sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.maxLen);
+    memcpy(dupPtr->internalRep.listValue.ele, srcPtr->internalRep.listValue.ele,
+        sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.len);
+    for (i = 0; i < dupPtr->internalRep.listValue.len; i++) {
+        Jim_IncrRefCount(dupPtr->internalRep.listValue.ele[i]);
+    }
+    dupPtr->typePtr = &listObjType;
+}
+
+/* The following function checks if a given string can be encoded
+ * into a list element without any kind of quoting, surrounded by braces,
+ * or using escapes to quote. */
+#define JIM_ELESTR_SIMPLE 0
+#define JIM_ELESTR_BRACE 1
+#define JIM_ELESTR_QUOTE 2
+static int ListElementQuotingType(const char *s, int len)
+{
+    int i, level, blevel, trySimple = 1;
+
+    /* Try with the SIMPLE case */
+    if (len == 0)
+        return JIM_ELESTR_BRACE;
+    if (s[0] == '#')
+        return JIM_ELESTR_BRACE;
+    if (s[0] == '"' || s[0] == '{') {
+        trySimple = 0;
+        goto testbrace;
+    }
+    for (i = 0; i < len; i++) {
+        switch (s[i]) {
+            case ' ':
+            case '$':
+            case '"':
+            case '[':
+            case ']':
+            case ';':
+            case '\\':
+            case '\r':
+            case '\n':
+            case '\t':
+            case '\f':
+            case '\v':
+                trySimple = 0;
+            case '{':
+            case '}':
+                goto testbrace;
+        }
+    }
+    return JIM_ELESTR_SIMPLE;
+
+  testbrace:
+    /* Test if it's possible to do with braces */
+    if (s[len - 1] == '\\')
+        return JIM_ELESTR_QUOTE;
+    level = 0;
+    blevel = 0;
+    for (i = 0; i < len; i++) {
+        switch (s[i]) {
+            case '{':
+                level++;
+                break;
+            case '}':
+                level--;
+                if (level < 0)
+                    return JIM_ELESTR_QUOTE;
+                break;
+            case '[':
+                blevel++;
+                break;
+            case ']':
+                blevel--;
+                break;
+            case '\\':
+                if (s[i + 1] == '\n')
+                    return JIM_ELESTR_QUOTE;
+                else if (s[i + 1] != '\0')
+                    i++;
+                break;
+        }
+    }
+    if (blevel < 0) {
+        return JIM_ELESTR_QUOTE;
+    }
+
+    if (level == 0) {
+        if (!trySimple)
+            return JIM_ELESTR_BRACE;
+        for (i = 0; i < len; i++) {
+            switch (s[i]) {
+                case ' ':
+                case '$':
+                case '"':
+                case '[':
+                case ']':
+                case ';':
+                case '\\':
+                case '\r':
+                case '\n':
+                case '\t':
+                case '\f':
+                case '\v':
+                    return JIM_ELESTR_BRACE;
+                    break;
+            }
+        }
+        return JIM_ELESTR_SIMPLE;
+    }
+    return JIM_ELESTR_QUOTE;
+}
+
+/* Returns the malloc-ed representation of a string
+ * using backslash to quote special chars. */
+static char *BackslashQuoteString(const char *s, int len, int *qlenPtr)
+{
+    char *q = Jim_Alloc(len * 2 + 1), *p;
+
+    p = q;
+    while (*s) {
+        switch (*s) {
+            case ' ':
+            case '$':
+            case '"':
+            case '[':
+            case ']':
+            case '{':
+            case '}':
+            case ';':
+            case '\\':
+                *p++ = '\\';
+                *p++ = *s++;
+                break;
+            case '\n':
+                *p++ = '\\';
+                *p++ = 'n';
+                s++;
+                break;
+            case '\r':
+                *p++ = '\\';
+                *p++ = 'r';
+                s++;
+                break;
+            case '\t':
+                *p++ = '\\';
+                *p++ = 't';
+                s++;
+                break;
+            case '\f':
+                *p++ = '\\';
+                *p++ = 'f';
+                s++;
+                break;
+            case '\v':
+                *p++ = '\\';
+                *p++ = 'v';
+                s++;
+                break;
+            default:
+                *p++ = *s++;
+                break;
+        }
+    }
+    *p = '\0';
+    *qlenPtr = p - q;
+    return q;
+}
+
+static void UpdateStringOfList(struct Jim_Obj *objPtr)
+{
+    int i, bufLen, realLength;
+    const char *strRep;
+    char *p;
+    int *quotingType;
+    Jim_Obj **ele = objPtr->internalRep.listValue.ele;
+
+    /* (Over) Estimate the space needed. */
+    quotingType = Jim_Alloc(sizeof(int) * objPtr->internalRep.listValue.len + 1);
+    bufLen = 0;
+    for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
+        int len;
+
+        strRep = Jim_GetString(ele[i], &len);
+        quotingType[i] = ListElementQuotingType(strRep, len);
+        switch (quotingType[i]) {
+            case JIM_ELESTR_SIMPLE:
+                bufLen += len;
+                break;
+            case JIM_ELESTR_BRACE:
+                bufLen += len + 2;
+                break;
+            case JIM_ELESTR_QUOTE:
+                bufLen += len * 2;
+                break;
+        }
+        bufLen++;               /* elements separator. */
+    }
+    bufLen++;
+
+    /* Generate the string rep. */
+    p = objPtr->bytes = Jim_Alloc(bufLen + 1);
+    realLength = 0;
+    for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
+        int len, qlen;
+        char *q;
+
+        strRep = Jim_GetString(ele[i], &len);
+
+        switch (quotingType[i]) {
+            case JIM_ELESTR_SIMPLE:
+                memcpy(p, strRep, len);
+                p += len;
+                realLength += len;
+                break;
+            case JIM_ELESTR_BRACE:
+                *p++ = '{';
+                memcpy(p, strRep, len);
+                p += len;
+                *p++ = '}';
+                realLength += len + 2;
+                break;
+            case JIM_ELESTR_QUOTE:
+                q = BackslashQuoteString(strRep, len, &qlen);
+                memcpy(p, q, qlen);
+                Jim_Free(q);
+                p += qlen;
+                realLength += qlen;
+                break;
+        }
+        /* Add a separating space */
+        if (i + 1 != objPtr->internalRep.listValue.len) {
+            *p++ = ' ';
+            realLength++;
+        }
+    }
+    *p = '\0';                  /* nul term. */
+    objPtr->length = realLength;
+    Jim_Free(quotingType);
+}
+
+int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+    struct JimParserCtx parser;
+    const char *str;
+    int strLen;
+    Jim_Obj *fileNameObj;
+    int linenr;
+
+    /* Try to preserve information about filename / line number */
+    if (objPtr->typePtr == &sourceObjType) {
+        fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
+        linenr = objPtr->internalRep.sourceValue.lineNumber;
+    }
+    else {
+        fileNameObj = interp->emptyObj;
+        linenr = 1;
+    }
+    Jim_IncrRefCount(fileNameObj);
+
+    /* Get the string representation */
+    str = Jim_GetString(objPtr, &strLen);
+
+    /* Free the old internal repr just now and initialize the
+     * new one just now. The string->list conversion can't fail. */
+    Jim_FreeIntRep(interp, objPtr);
+    objPtr->typePtr = &listObjType;
+    objPtr->internalRep.listValue.len = 0;
+    objPtr->internalRep.listValue.maxLen = 0;
+    objPtr->internalRep.listValue.ele = NULL;
+
+    /* Convert into a list */
+    JimParserInit(&parser, str, strLen, linenr);
+    while (!parser.eof) {
+        Jim_Obj *elementPtr;
+
+        JimParseList(&parser);
+        if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC)
+            continue;
+        elementPtr = JimParserGetTokenObj(interp, &parser);
+        JimSetSourceInfo(interp, elementPtr, fileNameObj, parser.tline);
+        ListAppendElement(objPtr, elementPtr);
+    }
+    Jim_DecrRefCount(interp, fileNameObj);
+    return JIM_OK;
+}
+
+Jim_Obj *Jim_NewListObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
+{
+    Jim_Obj *objPtr;
+    int i;
+
+    objPtr = Jim_NewObj(interp);
+    objPtr->typePtr = &listObjType;
+    objPtr->bytes = NULL;
+    objPtr->internalRep.listValue.ele = NULL;
+    objPtr->internalRep.listValue.len = 0;
+    objPtr->internalRep.listValue.maxLen = 0;
+    for (i = 0; i < len; i++) {
+        ListAppendElement(objPtr, elements[i]);
+    }
+    return objPtr;
+}
+
+/* Return a vector of Jim_Obj with the elements of a Jim list, and the
+ * length of the vector. Note that the user of this function should make
+ * sure that the list object can't shimmer while the vector returned
+ * is in use, this vector is the one stored inside the internal representation
+ * of the list object. This function is not exported, extensions should
+ * always access to the List object elements using Jim_ListIndex(). */
+static void JimListGetElements(Jim_Interp *interp, Jim_Obj *listObj, int *listLen,
+    Jim_Obj ***listVec)
+{
+    *listLen = Jim_ListLength(interp, listObj);
+    *listVec = listObj->internalRep.listValue.ele;
+}
+
+/* Sorting uses ints, but commands may return wide */
+static int JimSign(jim_wide w)
+{
+    if (w == 0) {
+        return 0;
+    }
+    else if (w < 0) {
+        return -1;
+    }
+    return 1;
+}
+
+/* ListSortElements type values */
+struct lsort_info {
+    jmp_buf jmpbuf;
+    Jim_Obj *command;
+    Jim_Interp *interp;
+    enum {
+        JIM_LSORT_ASCII,
+        JIM_LSORT_NOCASE,
+        JIM_LSORT_INTEGER,
+        JIM_LSORT_COMMAND
+    } type;
+    int order;
+    int index;
+    int indexed;
+    int (*subfn)(Jim_Obj **, Jim_Obj **);
+};
+
+static struct lsort_info *sort_info;
+
+static int ListSortIndexHelper(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+    Jim_Obj *lObj, *rObj;
+
+    if (Jim_ListIndex(sort_info->interp, *lhsObj, sort_info->index, &lObj, JIM_ERRMSG) != JIM_OK ||
+        Jim_ListIndex(sort_info->interp, *rhsObj, sort_info->index, &rObj, JIM_ERRMSG) != JIM_OK) {
+        longjmp(sort_info->jmpbuf, JIM_ERR);
+    }
+    return sort_info->subfn(&lObj, &rObj);
+}
+
+/* Sort the internal rep of a list. */
+static int ListSortString(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+    return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
+}
+
+static int ListSortStringNoCase(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+    return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 1) * sort_info->order;
+}
+
+static int ListSortInteger(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+    jim_wide lhs = 0, rhs = 0;
+
+    if (Jim_GetWide(sort_info->interp, *lhsObj, &lhs) != JIM_OK ||
+        Jim_GetWide(sort_info->interp, *rhsObj, &rhs) != JIM_OK) {
+        longjmp(sort_info->jmpbuf, JIM_ERR);
+    }
+
+    return JimSign(lhs - rhs) * sort_info->order;
+}
+
+static int ListSortCommand(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+    Jim_Obj *compare_script;
+    int rc;
+
+    jim_wide ret = 0;
+
+    /* This must be a valid list */
+    compare_script = Jim_DuplicateObj(sort_info->interp, sort_info->command);
+    Jim_ListAppendElement(sort_info->interp, compare_script, *lhsObj);
+    Jim_ListAppendElement(sort_info->interp, compare_script, *rhsObj);
+
+    rc = Jim_EvalObj(sort_info->interp, compare_script);
+
+    if (rc != JIM_OK || Jim_GetWide(sort_info->interp, Jim_GetResult(sort_info->interp), &ret) != JIM_OK) {
+        longjmp(sort_info->jmpbuf, rc);
+    }
+
+    return JimSign(ret) * sort_info->order;
+}
+
+/* Sort a list *in place*. MUST be called with non-shared objects. */
+static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info)
+{
+    struct lsort_info *prev_info;
+
+    typedef int (qsort_comparator) (const void *, const void *);
+    int (*fn) (Jim_Obj **, Jim_Obj **);
+    Jim_Obj **vector;
+    int len;
+    int rc;
+
+    JimPanic((Jim_IsShared(listObjPtr), "Jim_ListSortElements called with shared object"));
+    if (!Jim_IsList(listObjPtr))
+        SetListFromAny(interp, listObjPtr);
+
+    /* Allow lsort to be called reentrantly */
+    prev_info = sort_info;
+    sort_info = info;
+
+    vector = listObjPtr->internalRep.listValue.ele;
+    len = listObjPtr->internalRep.listValue.len;
+    switch (info->type) {
+        case JIM_LSORT_ASCII:
+            fn = ListSortString;
+            break;
+        case JIM_LSORT_NOCASE:
+            fn = ListSortStringNoCase;
+            break;
+        case JIM_LSORT_INTEGER:
+            fn = ListSortInteger;
+            break;
+        case JIM_LSORT_COMMAND:
+            fn = ListSortCommand;
+            break;
+        default:
+            fn = NULL;          /* avoid warning */
+            JimPanic((1, "ListSort called with invalid sort type"));
+    }
+
+    if (info->indexed) {
+        /* Need to interpose a "list index" function */
+        info->subfn = fn;
+        fn = ListSortIndexHelper;
+    }
+
+    if ((rc = setjmp(info->jmpbuf)) == 0) {
+        qsort(vector, len, sizeof(Jim_Obj *), (qsort_comparator *) fn);
+    }
+    Jim_InvalidateStringRep(listObjPtr);
+    sort_info = prev_info;
+
+    return rc;
+}
+
+/* This is the low-level function to insert elements into a list.
+ * The higher-level Jim_ListInsertElements() performs shared object
+ * check and invalidate the string repr. This version is used
+ * in the internals of the List Object and is not exported.
+ *
+ * NOTE: this function can be called only against objects
+ * with internal type of List. */
+static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec)
+{
+    int currentLen = listPtr->internalRep.listValue.len;
+    int requiredLen = currentLen + elemc;
+    int i;
+    Jim_Obj **point;
+
+    if (requiredLen > listPtr->internalRep.listValue.maxLen) {
+        int maxLen = requiredLen * 2;
+
+        listPtr->internalRep.listValue.ele =
+            Jim_Realloc(listPtr->internalRep.listValue.ele, sizeof(Jim_Obj *) * maxLen);
+        listPtr->internalRep.listValue.maxLen = maxLen;
+    }
+    point = listPtr->internalRep.listValue.ele + idx;
+    memmove(point + elemc, point, (currentLen - idx) * sizeof(Jim_Obj *));
+    for (i = 0; i < elemc; ++i) {
+        point[i] = elemVec[i];
+        Jim_IncrRefCount(point[i]);
+    }
+    listPtr->internalRep.listValue.len += elemc;
+}
+
+/* Convenience call to ListInsertElements() to append a single element.
+ */
+static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr)
+{
+    ListInsertElements(listPtr, listPtr->internalRep.listValue.len, 1, &objPtr);
+}
+
+
+/* Appends every element of appendListPtr into listPtr.
+ * Both have to be of the list type.
+ * Convenience call to ListInsertElements()
+ */
+static void ListAppendList(Jim_Obj *listPtr, Jim_Obj *appendListPtr)
+{
+    ListInsertElements(listPtr, listPtr->internalRep.listValue.len,
+        appendListPtr->internalRep.listValue.len, appendListPtr->internalRep.listValue.ele);
+}
+
+void Jim_ListAppendElement(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *objPtr)
+{
+    JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendElement called with shared object"));
+    if (!Jim_IsList(listPtr))
+        SetListFromAny(interp, listPtr);
+    Jim_InvalidateStringRep(listPtr);
+    ListAppendElement(listPtr, objPtr);
+}
+
+void Jim_ListAppendList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *appendListPtr)
+{
+    JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendList called with shared object"));
+    if (!Jim_IsList(listPtr))
+        SetListFromAny(interp, listPtr);
+    Jim_InvalidateStringRep(listPtr);
+    ListAppendList(listPtr, appendListPtr);
+}
+
+int Jim_ListLength(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    if (!Jim_IsList(objPtr))
+        SetListFromAny(interp, objPtr);
+    return objPtr->internalRep.listValue.len;
+}
+
+void Jim_ListInsertElements(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
+    int objc, Jim_Obj *const *objVec)
+{
+    JimPanic((Jim_IsShared(listPtr), "Jim_ListInsertElement called with shared object"));
+    if (!Jim_IsList(listPtr))
+        SetListFromAny(interp, listPtr);
+    if (idx >= 0 && idx > listPtr->internalRep.listValue.len)
+        idx = listPtr->internalRep.listValue.len;
+    else if (idx < 0)
+        idx = 0;
+    Jim_InvalidateStringRep(listPtr);
+    ListInsertElements(listPtr, idx, objc, objVec);
+}
+
+int Jim_ListIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx, Jim_Obj **objPtrPtr, int flags)
+{
+    if (!Jim_IsList(listPtr))
+        SetListFromAny(interp, listPtr);
+    if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) ||
+        (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) {
+        if (flags & JIM_ERRMSG) {
+            Jim_SetResultString(interp, "list index out of range", -1);
+        }
+        *objPtrPtr = NULL;
+        return JIM_ERR;
+    }
+    if (idx < 0)
+        idx = listPtr->internalRep.listValue.len + idx;
+    *objPtrPtr = listPtr->internalRep.listValue.ele[idx];
+    return JIM_OK;
+}
+
+static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
+    Jim_Obj *newObjPtr, int flags)
+{
+    if (!Jim_IsList(listPtr))
+        SetListFromAny(interp, listPtr);
+    if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) ||
+        (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) {
+        if (flags & JIM_ERRMSG) {
+            Jim_SetResultString(interp, "list index out of range", -1);
+        }
+        return JIM_ERR;
+    }
+    if (idx < 0)
+        idx = listPtr->internalRep.listValue.len + idx;
+    Jim_DecrRefCount(interp, listPtr->internalRep.listValue.ele[idx]);
+    listPtr->internalRep.listValue.ele[idx] = newObjPtr;
+    Jim_IncrRefCount(newObjPtr);
+    return JIM_OK;
+}
+
+/* Modify the list stored into the variable named 'varNamePtr'
+ * setting the element specified by the 'indexc' indexes objects in 'indexv',
+ * with the new element 'newObjptr'. */
+int Jim_SetListIndex(Jim_Interp *interp, Jim_Obj *varNamePtr,
+    Jim_Obj *const *indexv, int indexc, Jim_Obj *newObjPtr)
+{
+    Jim_Obj *varObjPtr, *objPtr, *listObjPtr;
+    int shared, i, idx;
+
+    varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG | JIM_UNSHARED);
+    if (objPtr == NULL)
+        return JIM_ERR;
+    if ((shared = Jim_IsShared(objPtr)))
+        varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
+    for (i = 0; i < indexc - 1; i++) {
+        listObjPtr = objPtr;
+        if (Jim_GetIndex(interp, indexv[i], &idx) != JIM_OK)
+            goto err;
+        if (Jim_ListIndex(interp, listObjPtr, idx, &objPtr, JIM_ERRMSG) != JIM_OK) {
+            goto err;
+        }
+        if (Jim_IsShared(objPtr)) {
+            objPtr = Jim_DuplicateObj(interp, objPtr);
+            ListSetIndex(interp, listObjPtr, idx, objPtr, JIM_NONE);
+        }
+        Jim_InvalidateStringRep(listObjPtr);
+    }
+    if (Jim_GetIndex(interp, indexv[indexc - 1], &idx) != JIM_OK)
+        goto err;
+    if (ListSetIndex(interp, objPtr, idx, newObjPtr, JIM_ERRMSG) == JIM_ERR)
+        goto err;
+    Jim_InvalidateStringRep(objPtr);
+    Jim_InvalidateStringRep(varObjPtr);
+    if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK)
+        goto err;
+    Jim_SetResult(interp, varObjPtr);
+    return JIM_OK;
+  err:
+    if (shared) {
+        Jim_FreeNewObj(interp, varObjPtr);
+    }
+    return JIM_ERR;
+}
+
+Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
+{
+    int i;
+
+    /* If all the objects in objv are lists,
+     * it's possible to return a list as result, that's the
+     * concatenation of all the lists. */
+    for (i = 0; i < objc; i++) {
+        if (!Jim_IsList(objv[i]))
+            break;
+    }
+    if (i == objc) {
+        Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
+
+        for (i = 0; i < objc; i++)
+            Jim_ListAppendList(interp, objPtr, objv[i]);
+        return objPtr;
+    }
+    else {
+        /* Else... we have to glue strings together */
+        int len = 0, objLen;
+        char *bytes, *p;
+
+        /* Compute the length */
+        for (i = 0; i < objc; i++) {
+            Jim_GetString(objv[i], &objLen);
+            len += objLen;
+        }
+        if (objc)
+            len += objc - 1;
+        /* Create the string rep, and a string object holding it. */
+        p = bytes = Jim_Alloc(len + 1);
+        for (i = 0; i < objc; i++) {
+            const char *s = Jim_GetString(objv[i], &objLen);
+
+            /* Remove leading space */
+            while (objLen && (*s == ' ' || *s == '\t' || *s == '\n')) {
+                s++;
+                objLen--;
+                len--;
+            }
+            /* And trailing space */
+            while (objLen && (s[objLen - 1] == ' ' ||
+                    s[objLen - 1] == '\n' || s[objLen - 1] == '\t')) {
+                /* Handle trailing backslash-space case */
+                if (objLen > 1 && s[objLen - 2] == '\\') {
+                    break;
+                }
+                objLen--;
+                len--;
+            }
+            memcpy(p, s, objLen);
+            p += objLen;
+            if (objLen && i + 1 != objc) {
+                *p++ = ' ';
+            }
+            else if (i + 1 != objc) {
+                /* Drop the space calcuated for this
+                 * element that is instead null. */
+                len--;
+            }
+        }
+        *p = '\0';
+        return Jim_NewStringObjNoAlloc(interp, bytes, len);
+    }
+}
+
+/* Returns a list composed of the elements in the specified range.
+ * first and start are directly accepted as Jim_Objects and
+ * processed for the end?-index? case. */
+Jim_Obj *Jim_ListRange(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *firstObjPtr,
+    Jim_Obj *lastObjPtr)
+{
+    int first, last;
+    int len, rangeLen;
+
+    if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
+        Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
+        return NULL;
+    len = Jim_ListLength(interp, listObjPtr);   /* will convert into list */
+    first = JimRelToAbsIndex(len, first);
+    last = JimRelToAbsIndex(len, last);
+    JimRelToAbsRange(len, first, last, &first, &last, &rangeLen);
+    if (first == 0 && last == len) {
+        return listObjPtr;
+    }
+    return Jim_NewListObj(interp, listObjPtr->internalRep.listValue.ele + first, rangeLen);
+}
+
+/* -----------------------------------------------------------------------------
+ * Dict object
+ * ---------------------------------------------------------------------------*/
+static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static void UpdateStringOfDict(struct Jim_Obj *objPtr);
+static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+/* Dict HashTable Type.
+ *
+ * Keys and Values are Jim objects. */
+
+static unsigned int JimObjectHTHashFunction(const void *key)
+{
+    const char *str;
+    Jim_Obj *objPtr = (Jim_Obj *)key;
+    int len;
+
+    str = Jim_GetString(objPtr, &len);
+    return Jim_GenHashFunction((unsigned char *)str, len);
+}
+
+static int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2)
+{
+    JIM_NOTUSED(privdata);
+
+    return Jim_StringEqObj((Jim_Obj *)key1, (Jim_Obj *)key2);
+}
+
+static void JimObjectHTKeyValDestructor(void *interp, void *val)
+{
+    Jim_Obj *objPtr = val;
+
+    Jim_DecrRefCount(interp, objPtr);
+}
+
+static const Jim_HashTableType JimDictHashTableType = {
+    JimObjectHTHashFunction,    /* hash function */
+    NULL,                       /* key dup */
+    NULL,                       /* val dup */
+    JimObjectHTKeyCompare,      /* key compare */
+    (void (*)(void *, const void *))    /* ATTENTION: const cast */
+        JimObjectHTKeyValDestructor,    /* key destructor */
+    JimObjectHTKeyValDestructor /* val destructor */
+};
+
+/* Note that while the elements of the dict may contain references,
+ * the list object itself can't. This basically means that the
+ * dict object string representation as a whole can't contain references
+ * that are not presents in the single elements. */
+static const Jim_ObjType dictObjType = {
+    "dict",
+    FreeDictInternalRep,
+    DupDictInternalRep,
+    UpdateStringOfDict,
+    JIM_TYPE_NONE,
+};
+
+void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    JIM_NOTUSED(interp);
+
+    Jim_FreeHashTable(objPtr->internalRep.ptr);
+    Jim_Free(objPtr->internalRep.ptr);
+}
+
+void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+    Jim_HashTable *ht, *dupHt;
+    Jim_HashTableIterator *htiter;
+    Jim_HashEntry *he;
+
+    /* Create a new hash table */
+    ht = srcPtr->internalRep.ptr;
+    dupHt = Jim_Alloc(sizeof(*dupHt));
+    Jim_InitHashTable(dupHt, &JimDictHashTableType, interp);
+    if (ht->size != 0)
+        Jim_ExpandHashTable(dupHt, ht->size);
+    /* Copy every element from the source to the dup hash table */
+    htiter = Jim_GetHashTableIterator(ht);
+    while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+        const Jim_Obj *keyObjPtr = he->key;
+        Jim_Obj *valObjPtr = he->u.val;
+
+        Jim_IncrRefCount((Jim_Obj *)keyObjPtr); /* ATTENTION: const cast */
+        Jim_IncrRefCount(valObjPtr);
+        Jim_AddHashEntry(dupHt, keyObjPtr, valObjPtr);
+    }
+    Jim_FreeHashTableIterator(htiter);
+
+    dupPtr->internalRep.ptr = dupHt;
+    dupPtr->typePtr = &dictObjType;
+}
+
+void UpdateStringOfDict(struct Jim_Obj *objPtr)
+{
+    int i, bufLen, realLength;
+    const char *strRep;
+    char *p;
+    int *quotingType, objc;
+    Jim_HashTable *ht;
+    Jim_HashTableIterator *htiter;
+    Jim_HashEntry *he;
+    Jim_Obj **objv;
+
+    /* Trun the hash table into a flat vector of Jim_Objects. */
+    ht = objPtr->internalRep.ptr;
+    objc = ht->used * 2;
+    objv = Jim_Alloc(objc * sizeof(Jim_Obj *));
+    htiter = Jim_GetHashTableIterator(ht);
+    i = 0;
+    while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+        objv[i++] = (Jim_Obj *)he->key; /* ATTENTION: const cast */
+        objv[i++] = he->u.val;
+    }
+    Jim_FreeHashTableIterator(htiter);
+    /* (Over) Estimate the space needed. */
+    quotingType = Jim_Alloc(sizeof(int) * objc);
+    bufLen = 0;
+    for (i = 0; i < objc; i++) {
+        int len;
+
+        strRep = Jim_GetString(objv[i], &len);
+        quotingType[i] = ListElementQuotingType(strRep, len);
+        switch (quotingType[i]) {
+            case JIM_ELESTR_SIMPLE:
+                bufLen += len;
+                break;
+            case JIM_ELESTR_BRACE:
+                bufLen += len + 2;
+                break;
+            case JIM_ELESTR_QUOTE:
+                bufLen += len * 2;
+                break;
+        }
+        bufLen++;               /* elements separator. */
+    }
+    bufLen++;
+
+    /* Generate the string rep. */
+    p = objPtr->bytes = Jim_Alloc(bufLen + 1);
+    realLength = 0;
+    for (i = 0; i < objc; i++) {
+        int len, qlen;
+        char *q;
+
+        strRep = Jim_GetString(objv[i], &len);
+
+        switch (quotingType[i]) {
+            case JIM_ELESTR_SIMPLE:
+                memcpy(p, strRep, len);
+                p += len;
+                realLength += len;
+                break;
+            case JIM_ELESTR_BRACE:
+                *p++ = '{';
+                memcpy(p, strRep, len);
+                p += len;
+                *p++ = '}';
+                realLength += len + 2;
+                break;
+            case JIM_ELESTR_QUOTE:
+                q = BackslashQuoteString(strRep, len, &qlen);
+                memcpy(p, q, qlen);
+                Jim_Free(q);
+                p += qlen;
+                realLength += qlen;
+                break;
+        }
+        /* Add a separating space */
+        if (i + 1 != objc) {
+            *p++ = ' ';
+            realLength++;
+        }
+    }
+    *p = '\0';                  /* nul term. */
+    objPtr->length = realLength;
+    Jim_Free(quotingType);
+    Jim_Free(objv);
+}
+
+static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+    int listlen;
+
+    /* Get the string representation. Do this first so we don't
+     * change order in case of fast conversion to dict.
+     */
+    Jim_String(objPtr);
+
+    /* For simplicity, convert a non-list object to a list and then to a dict */
+    listlen = Jim_ListLength(interp, objPtr);
+    if (listlen % 2) {
+        Jim_SetResultString(interp,
+            "invalid dictionary value: must be a list with an even number of elements", -1);
+        return JIM_ERR;
+    }
+    else {
+        /* Now it is easy to convert to a dict from a list, and it can't fail */
+        Jim_HashTable *ht;
+        int i;
+
+        ht = Jim_Alloc(sizeof(*ht));
+        Jim_InitHashTable(ht, &JimDictHashTableType, interp);
+
+        for (i = 0; i < listlen; i += 2) {
+            Jim_Obj *keyObjPtr;
+            Jim_Obj *valObjPtr;
+
+            Jim_ListIndex(interp, objPtr, i, &keyObjPtr, JIM_NONE);
+            Jim_ListIndex(interp, objPtr, i + 1, &valObjPtr, JIM_NONE);
+
+            Jim_IncrRefCount(keyObjPtr);
+            Jim_IncrRefCount(valObjPtr);
+
+            if (Jim_AddHashEntry(ht, keyObjPtr, valObjPtr) != JIM_OK) {
+                Jim_HashEntry *he;
+
+                he = Jim_FindHashEntry(ht, keyObjPtr);
+                Jim_DecrRefCount(interp, keyObjPtr);
+                /* ATTENTION: const cast */
+                Jim_DecrRefCount(interp, (Jim_Obj *)he->u.val);
+                he->u.val = valObjPtr;
+            }
+        }
+
+        Jim_FreeIntRep(interp, objPtr);
+        objPtr->typePtr = &dictObjType;
+        objPtr->internalRep.ptr = ht;
+
+        return JIM_OK;
+    }
+}
+
+/* Dict object API */
+
+/* Add an element to a dict. objPtr must be of the "dict" type.
+ * The higer-level exported function is Jim_DictAddElement().
+ * If an element with the specified key already exists, the value
+ * associated is replaced with the new one.
+ *
+ * if valueObjPtr == NULL, the key is instead removed if it exists. */
+static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
+    Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
+{
+    Jim_HashTable *ht = objPtr->internalRep.ptr;
+
+    if (valueObjPtr == NULL) {  /* unset */
+        return Jim_DeleteHashEntry(ht, keyObjPtr);
+    }
+    Jim_IncrRefCount(keyObjPtr);
+    Jim_IncrRefCount(valueObjPtr);
+    if (Jim_AddHashEntry(ht, keyObjPtr, valueObjPtr) != JIM_OK) {
+        Jim_HashEntry *he = Jim_FindHashEntry(ht, keyObjPtr);
+
+        Jim_DecrRefCount(interp, keyObjPtr);
+        /* ATTENTION: const cast */
+        Jim_DecrRefCount(interp, (Jim_Obj *)he->u.val);
+        he->u.val = valueObjPtr;
+    }
+    return JIM_OK;
+}
+
+/* Add an element, higher-level interface for DictAddElement().
+ * If valueObjPtr == NULL, the key is removed if it exists. */
+int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
+    Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
+{
+    int retcode;
+
+    JimPanic((Jim_IsShared(objPtr), "Jim_DictAddElement called with shared object"));
+    if (objPtr->typePtr != &dictObjType) {
+        if (SetDictFromAny(interp, objPtr) != JIM_OK)
+            return JIM_ERR;
+    }
+    retcode = DictAddElement(interp, objPtr, keyObjPtr, valueObjPtr);
+    Jim_InvalidateStringRep(objPtr);
+    return retcode;
+}
+
+Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
+{
+    Jim_Obj *objPtr;
+    int i;
+
+    JimPanic((len % 2, "Jim_NewDictObj() 'len' argument must be even"));
+
+    objPtr = Jim_NewObj(interp);
+    objPtr->typePtr = &dictObjType;
+    objPtr->bytes = NULL;
+    objPtr->internalRep.ptr = Jim_Alloc(sizeof(Jim_HashTable));
+    Jim_InitHashTable(objPtr->internalRep.ptr, &JimDictHashTableType, interp);
+    for (i = 0; i < len; i += 2)
+        DictAddElement(interp, objPtr, elements[i], elements[i + 1]);
+    return objPtr;
+}
+
+/* Return the value associated to the specified dict key
+ * Note: Returns JIM_OK if OK, JIM_ERR if entry not found or -1 if can't create dict value
+ */
+int Jim_DictKey(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *keyPtr,
+    Jim_Obj **objPtrPtr, int flags)
+{
+    Jim_HashEntry *he;
+    Jim_HashTable *ht;
+
+    if (dictPtr->typePtr != &dictObjType) {
+        if (SetDictFromAny(interp, dictPtr) != JIM_OK)
+            return -1;
+    }
+    ht = dictPtr->internalRep.ptr;
+    if ((he = Jim_FindHashEntry(ht, keyPtr)) == NULL) {
+        if (flags & JIM_ERRMSG) {
+            Jim_SetResultFormatted(interp, "key \"%#s\" not found in dictionary", keyPtr);
+        }
+        return JIM_ERR;
+    }
+    *objPtrPtr = he->u.val;
+    return JIM_OK;
+}
+
+/* Return an allocated array of key/value pairs for the dictionary. Stores the length in *len */
+int Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len)
+{
+    Jim_HashTable *ht;
+    Jim_HashTableIterator *htiter;
+    Jim_HashEntry *he;
+    Jim_Obj **objv;
+    int i;
+
+    if (dictPtr->typePtr != &dictObjType) {
+        if (SetDictFromAny(interp, dictPtr) != JIM_OK)
+            return JIM_ERR;
+    }
+    ht = dictPtr->internalRep.ptr;
+
+    /* Turn the hash table into a flat vector of Jim_Objects. */
+    objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *));
+    htiter = Jim_GetHashTableIterator(ht);
+    i = 0;
+    while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+        objv[i++] = (Jim_Obj *)he->key; /* ATTENTION: const cast */
+        objv[i++] = he->u.val;
+    }
+    *len = i;
+    Jim_FreeHashTableIterator(htiter);
+    *objPtrPtr = objv;
+    return JIM_OK;
+}
+
+
+/* Return the value associated to the specified dict keys */
+int Jim_DictKeysVector(Jim_Interp *interp, Jim_Obj *dictPtr,
+    Jim_Obj *const *keyv, int keyc, Jim_Obj **objPtrPtr, int flags)
+{
+    int i;
+
+    if (keyc == 0) {
+        *objPtrPtr = dictPtr;
+        return JIM_OK;
+    }
+
+    for (i = 0; i < keyc; i++) {
+        Jim_Obj *objPtr;
+
+        if (Jim_DictKey(interp, dictPtr, keyv[i], &objPtr, flags)
+            != JIM_OK)
+            return JIM_ERR;
+        dictPtr = objPtr;
+    }
+    *objPtrPtr = dictPtr;
+    return JIM_OK;
+}
+
+/* Modify the dict stored into the variable named 'varNamePtr'
+ * setting the element specified by the 'keyc' keys objects in 'keyv',
+ * with the new value of the element 'newObjPtr'.
+ *
+ * If newObjPtr == NULL the operation is to remove the given key
+ * from the dictionary.
+ *
+ * If flags & JIM_ERRMSG, then failure to remove the key is considered an error
+ * and JIM_ERR is returned. Otherwise it is ignored and JIM_OK is returned.
+ */
+int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr,
+    Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr, int flags)
+{
+    Jim_Obj *varObjPtr, *objPtr, *dictObjPtr;
+    int shared, i;
+
+    varObjPtr = objPtr =
+        Jim_GetVariable(interp, varNamePtr, newObjPtr == NULL ? JIM_ERRMSG : JIM_NONE);
+    if (objPtr == NULL) {
+        if (newObjPtr == NULL)  /* Cannot remove a key from non existing var */ {
+            return JIM_ERR;
+        }
+        varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0);
+        if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) {
+            Jim_FreeNewObj(interp, varObjPtr);
+            return JIM_ERR;
+        }
+    }
+    if ((shared = Jim_IsShared(objPtr)))
+        varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
+    for (i = 0; i < keyc - 1; i++) {
+        dictObjPtr = objPtr;
+
+        /* Check if it's a valid dictionary */
+        if (dictObjPtr->typePtr != &dictObjType) {
+            if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) {
+                goto err;
+            }
+        }
+        /* Check if the given key exists. */
+        Jim_InvalidateStringRep(dictObjPtr);
+        if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr,
+                newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK) {
+            /* This key exists at the current level.
+             * Make sure it's not shared!. */
+            if (Jim_IsShared(objPtr)) {
+                objPtr = Jim_DuplicateObj(interp, objPtr);
+                DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
+            }
+        }
+        else {
+            /* Key not found. If it's an [unset] operation
+             * this is an error. Only the last key may not
+             * exist. */
+            if (newObjPtr == NULL) {
+                goto err;
+            }
+            /* Otherwise set an empty dictionary
+             * as key's value. */
+            objPtr = Jim_NewDictObj(interp, NULL, 0);
+            DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
+        }
+    }
+    /* Note error on unset with missing last key is OK */
+    if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) {
+        if (newObjPtr || (flags & JIM_ERRMSG)) {
+            goto err;
+        }
+    }
+    Jim_InvalidateStringRep(objPtr);
+    Jim_InvalidateStringRep(varObjPtr);
+    if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) {
+        goto err;
+    }
+    Jim_SetResult(interp, varObjPtr);
+    return JIM_OK;
+  err:
+    if (shared) {
+        Jim_FreeNewObj(interp, varObjPtr);
+    }
+    return JIM_ERR;
+}
+
+/* -----------------------------------------------------------------------------
+ * Index object
+ * ---------------------------------------------------------------------------*/
+static void UpdateStringOfIndex(struct Jim_Obj *objPtr);
+static int SetIndexFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType indexObjType = {
+    "index",
+    NULL,
+    NULL,
+    UpdateStringOfIndex,
+    JIM_TYPE_NONE,
+};
+
+void UpdateStringOfIndex(struct Jim_Obj *objPtr)
+{
+    int len;
+    char buf[JIM_INTEGER_SPACE + 1];
+
+    if (objPtr->internalRep.indexValue >= 0)
+        len = sprintf(buf, "%d", objPtr->internalRep.indexValue);
+    else if (objPtr->internalRep.indexValue == -1)
+        len = sprintf(buf, "end");
+    else {
+        len = sprintf(buf, "end%d", objPtr->internalRep.indexValue + 1);
+    }
+    objPtr->bytes = Jim_Alloc(len + 1);
+    memcpy(objPtr->bytes, buf, len + 1);
+    objPtr->length = len;
+}
+
+int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    int idx, end = 0;
+    const char *str;
+    char *endptr;
+
+    /* Get the string representation */
+    str = Jim_String(objPtr);
+
+    /* Try to convert into an index */
+    if (strncmp(str, "end", 3) == 0) {
+        end = 1;
+        str += 3;
+        idx = 0;
+    }
+    else {
+        idx = strtol(str, &endptr, 10);
+
+        if (endptr == str) {
+            goto badindex;
+        }
+        str = endptr;
+    }
+
+    /* Now str may include or +<num> or -<num> */
+    if (*str == '+' || *str == '-') {
+        int sign = (*str == '+' ? 1 : -1);
+
+        idx += sign * strtol(++str, &endptr, 10);
+        if (str == endptr || *endptr) {
+            goto badindex;
+        }
+        str = endptr;
+    }
+    /* The only thing left should be spaces */
+    while (isspace(UCHAR(*str))) {
+        str++;
+    }
+    if (*str) {
+        goto badindex;
+    }
+    if (end) {
+        if (idx > 0) {
+            idx = INT_MAX;
+        }
+        else {
+            /* end-1 is repesented as -2 */
+            idx--;
+        }
+    }
+    else if (idx < 0) {
+        idx = -INT_MAX;
+    }
+
+    /* Free the old internal repr and set the new one. */
+    Jim_FreeIntRep(interp, objPtr);
+    objPtr->typePtr = &indexObjType;
+    objPtr->internalRep.indexValue = idx;
+    return JIM_OK;
+
+  badindex:
+    Jim_SetResultFormatted(interp,
+        "bad index \"%#s\": must be integer?[+-]integer? or end?[+-]integer?", objPtr);
+    return JIM_ERR;
+}
+
+int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
+{
+    /* Avoid shimmering if the object is an integer. */
+    if (objPtr->typePtr == &intObjType) {
+        jim_wide val = JimWideValue(objPtr);
+
+        if (!(val < LONG_MIN) && !(val > LONG_MAX)) {
+            *indexPtr = (val < 0) ? -INT_MAX : (long)val;;
+            return JIM_OK;
+        }
+    }
+    if (objPtr->typePtr != &indexObjType && SetIndexFromAny(interp, objPtr) == JIM_ERR)
+        return JIM_ERR;
+    *indexPtr = objPtr->internalRep.indexValue;
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * Return Code Object.
+ * ---------------------------------------------------------------------------*/
+
+/* NOTE: These must be kept in the same order as JIM_OK, JIM_ERR, ... */
+static const char * const jimReturnCodes[] = {
+    [JIM_OK] = "ok",
+    [JIM_ERR] = "error",
+    [JIM_RETURN] = "return",
+    [JIM_BREAK] = "break",
+    [JIM_CONTINUE] = "continue",
+    [JIM_SIGNAL] = "signal",
+    [JIM_EXIT] = "exit",
+    [JIM_EVAL] = "eval",
+    NULL
+};
+
+#define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes))
+
+static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
+
+static const Jim_ObjType returnCodeObjType = {
+    "return-code",
+    NULL,
+    NULL,
+    NULL,
+    JIM_TYPE_NONE,
+};
+
+/* Converts a (standard) return code to a string. Returns "?" for
+ * non-standard return codes.
+ */
+const char *Jim_ReturnCode(int code)
+{
+    if (code < 0 || code >= (int)jimReturnCodesSize) {
+        return "?";
+    }
+    else {
+        return jimReturnCodes[code];
+    }
+}
+
+int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    int returnCode;
+    jim_wide wideValue;
+
+    /* Try to convert into an integer */
+    if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR)
+        returnCode = (int)wideValue;
+    else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) {
+        Jim_SetResultFormatted(interp, "expected return code but got \"%#s\"", objPtr);
+        return JIM_ERR;
+    }
+    /* Free the old internal repr and set the new one. */
+    Jim_FreeIntRep(interp, objPtr);
+    objPtr->typePtr = &returnCodeObjType;
+    objPtr->internalRep.returnCode = returnCode;
+    return JIM_OK;
+}
+
+int Jim_GetReturnCode(Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr)
+{
+    if (objPtr->typePtr != &returnCodeObjType && SetReturnCodeFromAny(interp, objPtr) == JIM_ERR)
+        return JIM_ERR;
+    *intPtr = objPtr->internalRep.returnCode;
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * Expression Parsing
+ * ---------------------------------------------------------------------------*/
+static int JimParseExprOperator(struct JimParserCtx *pc);
+static int JimParseExprNumber(struct JimParserCtx *pc);
+static int JimParseExprIrrational(struct JimParserCtx *pc);
+
+/* Exrp's Stack machine operators opcodes. */
+
+/* Binary operators (numbers) */
+enum
+{
+    /* Continues on from the JIM_TT_ space */
+    /* Operations */
+    JIM_EXPROP_MUL = JIM_TT_EXPR_OP,    /* 15 */
+    JIM_EXPROP_DIV,
+    JIM_EXPROP_MOD,
+    JIM_EXPROP_SUB,
+    JIM_EXPROP_ADD,
+    JIM_EXPROP_LSHIFT,
+    JIM_EXPROP_RSHIFT,
+    JIM_EXPROP_ROTL,
+    JIM_EXPROP_ROTR,
+    JIM_EXPROP_LT,
+    JIM_EXPROP_GT,
+    JIM_EXPROP_LTE,
+    JIM_EXPROP_GTE,
+    JIM_EXPROP_NUMEQ,
+    JIM_EXPROP_NUMNE,
+    JIM_EXPROP_BITAND,          /* 30 */
+    JIM_EXPROP_BITXOR,
+    JIM_EXPROP_BITOR,
+
+    /* Note must keep these together */
+    JIM_EXPROP_LOGICAND,        /* 33 */
+    JIM_EXPROP_LOGICAND_LEFT,
+    JIM_EXPROP_LOGICAND_RIGHT,
+
+    /* and these */
+    JIM_EXPROP_LOGICOR,         /* 36 */
+    JIM_EXPROP_LOGICOR_LEFT,
+    JIM_EXPROP_LOGICOR_RIGHT,
+
+    /* and these */
+    /* Ternary operators */
+    JIM_EXPROP_TERNARY,         /* 39 */
+    JIM_EXPROP_TERNARY_LEFT,
+    JIM_EXPROP_TERNARY_RIGHT,
+
+    /* and these */
+    JIM_EXPROP_COLON,           /* 42 */
+    JIM_EXPROP_COLON_LEFT,
+    JIM_EXPROP_COLON_RIGHT,
+
+    JIM_EXPROP_POW,             /* 45 */
+
+/* Binary operators (strings) */
+    JIM_EXPROP_STREQ,
+    JIM_EXPROP_STRNE,
+    JIM_EXPROP_STRIN,
+    JIM_EXPROP_STRNI,
+
+/* Unary operators (numbers) */
+    JIM_EXPROP_NOT,
+    JIM_EXPROP_BITNOT,
+    JIM_EXPROP_UNARYMINUS,
+    JIM_EXPROP_UNARYPLUS,
+
+    /* Functions */
+    JIM_EXPROP_FUNC_FIRST,
+    JIM_EXPROP_FUNC_INT = JIM_EXPROP_FUNC_FIRST,
+    JIM_EXPROP_FUNC_ABS,
+    JIM_EXPROP_FUNC_DOUBLE,
+    JIM_EXPROP_FUNC_ROUND,
+    JIM_EXPROP_FUNC_RAND,
+    JIM_EXPROP_FUNC_SRAND,
+
+    /* math functions from libm */
+    JIM_EXPROP_FUNC_SIN,
+    JIM_EXPROP_FUNC_COS,
+    JIM_EXPROP_FUNC_TAN,
+    JIM_EXPROP_FUNC_ASIN,
+    JIM_EXPROP_FUNC_ACOS,
+    JIM_EXPROP_FUNC_ATAN,
+    JIM_EXPROP_FUNC_SINH,
+    JIM_EXPROP_FUNC_COSH,
+    JIM_EXPROP_FUNC_TANH,
+    JIM_EXPROP_FUNC_CEIL,
+    JIM_EXPROP_FUNC_FLOOR,
+    JIM_EXPROP_FUNC_EXP,
+    JIM_EXPROP_FUNC_LOG,
+    JIM_EXPROP_FUNC_LOG10,
+    JIM_EXPROP_FUNC_SQRT,
+    JIM_EXPROP_FUNC_POW,
+};
+
+struct JimExprState
+{
+    Jim_Obj **stack;
+    int stacklen;
+    int opcode;
+    int skip;
+};
+
+/* Operators table */
+typedef struct Jim_ExprOperator
+{
+    const char *name;
+    int precedence;
+    int arity;
+    int (*funcop) (Jim_Interp *interp, struct JimExprState * e);
+    int lazy;
+} Jim_ExprOperator;
+
+static void ExprPush(struct JimExprState *e, Jim_Obj *obj)
+{
+    Jim_IncrRefCount(obj);
+    e->stack[e->stacklen++] = obj;
+}
+
+static Jim_Obj *ExprPop(struct JimExprState *e)
+{
+    return e->stack[--e->stacklen];
+}
+
+static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprState *e)
+{
+    int intresult = 0;
+    int rc = JIM_OK;
+    Jim_Obj *A = ExprPop(e);
+    double dA, dC = 0;
+    jim_wide wA, wC = 0;
+
+    if ((A->typePtr != &doubleObjType || A->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK) {
+        intresult = 1;
+
+        switch (e->opcode) {
+            case JIM_EXPROP_FUNC_INT:
+                wC = wA;
+                break;
+            case JIM_EXPROP_FUNC_ROUND:
+                wC = wA;
+                break;
+            case JIM_EXPROP_FUNC_DOUBLE:
+                dC = wA;
+                intresult = 0;
+                break;
+            case JIM_EXPROP_FUNC_ABS:
+                wC = wA >= 0 ? wA : -wA;
+                break;
+            case JIM_EXPROP_UNARYMINUS:
+                wC = -wA;
+                break;
+            case JIM_EXPROP_UNARYPLUS:
+                wC = wA;
+                break;
+            case JIM_EXPROP_NOT:
+                wC = !wA;
+                break;
+            default:
+                abort();
+        }
+    }
+    else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) {
+        switch (e->opcode) {
+            case JIM_EXPROP_FUNC_INT:
+                wC = dA;
+                intresult = 1;
+                break;
+            case JIM_EXPROP_FUNC_ROUND:
+                wC = dA < 0 ? (dA - 0.5) : (dA + 0.5);
+                intresult = 1;
+                break;
+            case JIM_EXPROP_FUNC_DOUBLE:
+                dC = dA;
+                break;
+            case JIM_EXPROP_FUNC_ABS:
+                dC = dA >= 0 ? dA : -dA;
+                break;
+            case JIM_EXPROP_UNARYMINUS:
+                dC = -dA;
+                break;
+            case JIM_EXPROP_UNARYPLUS:
+                dC = dA;
+                break;
+            case JIM_EXPROP_NOT:
+                wC = !dA;
+                intresult = 1;
+                break;
+            default:
+                abort();
+        }
+    }
+
+    if (rc == JIM_OK) {
+        if (intresult) {
+            ExprPush(e, Jim_NewIntObj(interp, wC));
+        }
+        else {
+            ExprPush(e, Jim_NewDoubleObj(interp, dC));
+        }
+    }
+
+    Jim_DecrRefCount(interp, A);
+
+    return rc;
+}
+
+static double JimRandDouble(Jim_Interp *interp)
+{
+    unsigned long x;
+    JimRandomBytes(interp, &x, sizeof(x));
+
+    return (double)x / (unsigned long)~0;
+}
+
+static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprState *e)
+{
+    Jim_Obj *A = ExprPop(e);
+    jim_wide wA;
+
+    int rc = Jim_GetWide(interp, A, &wA);
+    if (rc == JIM_OK) {
+        switch (e->opcode) {
+            case JIM_EXPROP_BITNOT:
+                ExprPush(e, Jim_NewIntObj(interp, ~wA));
+                break;
+            case JIM_EXPROP_FUNC_SRAND:
+                JimPrngSeed(interp, (unsigned char *)&wA, sizeof(wA));
+                ExprPush(e, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
+                break;
+            default:
+                abort();
+        }
+    }
+
+    Jim_DecrRefCount(interp, A);
+
+    return rc;
+}
+
+static int JimExprOpNone(Jim_Interp *interp, struct JimExprState *e)
+{
+    JimPanic((e->opcode != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()"));
+
+    ExprPush(e, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
+
+    return JIM_OK;
+}
+
+#ifdef JIM_MATH_FUNCTIONS
+static int JimExprOpDoubleUnary(Jim_Interp *interp, struct JimExprState *e)
+{
+    int rc;
+    Jim_Obj *A = ExprPop(e);
+    double dA, dC;
+
+    rc = Jim_GetDouble(interp, A, &dA);
+    if (rc == JIM_OK) {
+        switch (e->opcode) {
+            case JIM_EXPROP_FUNC_SIN:
+                dC = sin(dA);
+                break;
+            case JIM_EXPROP_FUNC_COS:
+                dC = cos(dA);
+                break;
+            case JIM_EXPROP_FUNC_TAN:
+                dC = tan(dA);
+                break;
+            case JIM_EXPROP_FUNC_ASIN:
+                dC = asin(dA);
+                break;
+            case JIM_EXPROP_FUNC_ACOS:
+                dC = acos(dA);
+                break;
+            case JIM_EXPROP_FUNC_ATAN:
+                dC = atan(dA);
+                break;
+            case JIM_EXPROP_FUNC_SINH:
+                dC = sinh(dA);
+                break;
+            case JIM_EXPROP_FUNC_COSH:
+                dC = cosh(dA);
+                break;
+            case JIM_EXPROP_FUNC_TANH:
+                dC = tanh(dA);
+                break;
+            case JIM_EXPROP_FUNC_CEIL:
+                dC = ceil(dA);
+                break;
+            case JIM_EXPROP_FUNC_FLOOR:
+                dC = floor(dA);
+                break;
+            case JIM_EXPROP_FUNC_EXP:
+                dC = exp(dA);
+                break;
+            case JIM_EXPROP_FUNC_LOG:
+                dC = log(dA);
+                break;
+            case JIM_EXPROP_FUNC_LOG10:
+                dC = log10(dA);
+                break;
+            case JIM_EXPROP_FUNC_SQRT:
+                dC = sqrt(dA);
+                break;
+            default:
+                abort();
+        }
+        ExprPush(e, Jim_NewDoubleObj(interp, dC));
+    }
+
+    Jim_DecrRefCount(interp, A);
+
+    return rc;
+}
+#endif
+
+/* A binary operation on two ints */
+static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprState *e)
+{
+    Jim_Obj *B = ExprPop(e);
+    Jim_Obj *A = ExprPop(e);
+    jim_wide wA, wB;
+    int rc = JIM_ERR;
+
+    if (Jim_GetWide(interp, A, &wA) == JIM_OK && Jim_GetWide(interp, B, &wB) == JIM_OK) {
+        jim_wide wC;
+
+        rc = JIM_OK;
+
+        switch (e->opcode) {
+            case JIM_EXPROP_LSHIFT:
+                wC = wA << wB;
+                break;
+            case JIM_EXPROP_RSHIFT:
+                wC = wA >> wB;
+                break;
+            case JIM_EXPROP_BITAND:
+                wC = wA & wB;
+                break;
+            case JIM_EXPROP_BITXOR:
+                wC = wA ^ wB;
+                break;
+            case JIM_EXPROP_BITOR:
+                wC = wA | wB;
+                break;
+            case JIM_EXPROP_MOD:
+                if (wB == 0) {
+                    wC = 0;
+                    Jim_SetResultString(interp, "Division by zero", -1);
+                    rc = JIM_ERR;
+                }
+                else {
+                    /*
+                     * From Tcl 8.x
+                     *
+                     * This code is tricky: C doesn't guarantee much
+                     * about the quotient or remainder, but Tcl does.
+                     * The remainder always has the same sign as the
+                     * divisor and a smaller absolute value.
+                     */
+                    int negative = 0;
+
+                    if (wB < 0) {
+                        wB = -wB;
+                        wA = -wA;
+                        negative = 1;
+                    }
+                    wC = wA % wB;
+                    if (wC < 0) {
+                        wC += wB;
+                    }
+                    if (negative) {
+                        wC = -wC;
+                    }
+                }
+                break;
+            case JIM_EXPROP_ROTL:
+            case JIM_EXPROP_ROTR:{
+                    /* uint32_t would be better. But not everyone has inttypes.h? */
+                    unsigned long uA = (unsigned long)wA;
+                    unsigned long uB = (unsigned long)wB;
+                    const unsigned int S = sizeof(unsigned long) * 8;
+
+                    /* Shift left by the word size or more is undefined. */
+                    uB %= S;
+
+                    if (e->opcode == JIM_EXPROP_ROTR) {
+                        uB = S - uB;
+                    }
+                    wC = (unsigned long)(uA << uB) | (uA >> (S - uB));
+                    break;
+                }
+            default:
+                abort();
+        }
+        ExprPush(e, Jim_NewIntObj(interp, wC));
+
+    }
+
+    Jim_DecrRefCount(interp, A);
+    Jim_DecrRefCount(interp, B);
+
+    return rc;
+}
+
+
+/* A binary operation on two ints or two doubles (or two strings for some ops) */
+static int JimExprOpBin(Jim_Interp *interp, struct JimExprState *e)
+{
+    int intresult = 0;
+    int rc = JIM_OK;
+    double dA, dB, dC = 0;
+    jim_wide wA, wB, wC = 0;
+
+    Jim_Obj *B = ExprPop(e);
+    Jim_Obj *A = ExprPop(e);
+
+    if ((A->typePtr != &doubleObjType || A->bytes) &&
+        (B->typePtr != &doubleObjType || B->bytes) &&
+        JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) {
+
+        /* Both are ints */
+
+        intresult = 1;
+
+        switch (e->opcode) {
+            case JIM_EXPROP_POW:
+            case JIM_EXPROP_FUNC_POW:
+                wC = JimPowWide(wA, wB);
+                break;
+            case JIM_EXPROP_ADD:
+                wC = wA + wB;
+                break;
+            case JIM_EXPROP_SUB:
+                wC = wA - wB;
+                break;
+            case JIM_EXPROP_MUL:
+                wC = wA * wB;
+                break;
+            case JIM_EXPROP_DIV:
+                if (wB == 0) {
+                    Jim_SetResultString(interp, "Division by zero", -1);
+                    rc = JIM_ERR;
+                }
+                else {
+                    /*
+                     * From Tcl 8.x
+                     *
+                     * This code is tricky: C doesn't guarantee much
+                     * about the quotient or remainder, but Tcl does.
+                     * The remainder always has the same sign as the
+                     * divisor and a smaller absolute value.
+                     */
+                    if (wB < 0) {
+                        wB = -wB;
+                        wA = -wA;
+                    }
+                    wC = wA / wB;
+                    if (wA % wB < 0) {
+                        wC--;
+                    }
+                }
+                break;
+            case JIM_EXPROP_LT:
+                wC = wA < wB;
+                break;
+            case JIM_EXPROP_GT:
+                wC = wA > wB;
+                break;
+            case JIM_EXPROP_LTE:
+                wC = wA <= wB;
+                break;
+            case JIM_EXPROP_GTE:
+                wC = wA >= wB;
+                break;
+            case JIM_EXPROP_NUMEQ:
+                wC = wA == wB;
+                break;
+            case JIM_EXPROP_NUMNE:
+                wC = wA != wB;
+                break;
+            default:
+                abort();
+        }
+    }
+    else if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) {
+        switch (e->opcode) {
+            case JIM_EXPROP_POW:
+            case JIM_EXPROP_FUNC_POW:
+#ifdef JIM_MATH_FUNCTIONS
+                dC = pow(dA, dB);
+#else
+                Jim_SetResultString(interp, "unsupported", -1);
+                rc = JIM_ERR;
+#endif
+                break;
+            case JIM_EXPROP_ADD:
+                dC = dA + dB;
+                break;
+            case JIM_EXPROP_SUB:
+                dC = dA - dB;
+                break;
+            case JIM_EXPROP_MUL:
+                dC = dA * dB;
+                break;
+            case JIM_EXPROP_DIV:
+                if (dB == 0) {
+#ifdef INFINITY
+                    dC = dA < 0 ? -INFINITY : INFINITY;
+#else
+                    dC = (dA < 0 ? -1.0 : 1.0) * strtod("Inf", NULL);
+#endif
+                }
+                else {
+                    dC = dA / dB;
+                }
+                break;
+            case JIM_EXPROP_LT:
+                wC = dA < dB;
+                intresult = 1;
+                break;
+            case JIM_EXPROP_GT:
+                wC = dA > dB;
+                intresult = 1;
+                break;
+            case JIM_EXPROP_LTE:
+                wC = dA <= dB;
+                intresult = 1;
+                break;
+            case JIM_EXPROP_GTE:
+                wC = dA >= dB;
+                intresult = 1;
+                break;
+            case JIM_EXPROP_NUMEQ:
+                wC = dA == dB;
+                intresult = 1;
+                break;
+            case JIM_EXPROP_NUMNE:
+                wC = dA != dB;
+                intresult = 1;
+                break;
+            default:
+                abort();
+        }
+    }
+    else {
+        /* Handle the string case */
+
+        /* REVISIT: Could optimise the eq/ne case by checking lengths */
+        int i = Jim_StringCompareObj(interp, A, B, 0);
+
+        intresult = 1;
+
+        switch (e->opcode) {
+            case JIM_EXPROP_LT:
+                wC = i < 0;
+                break;
+            case JIM_EXPROP_GT:
+                wC = i > 0;
+                break;
+            case JIM_EXPROP_LTE:
+                wC = i <= 0;
+                break;
+            case JIM_EXPROP_GTE:
+                wC = i >= 0;
+                break;
+            case JIM_EXPROP_NUMEQ:
+                wC = i == 0;
+                break;
+            case JIM_EXPROP_NUMNE:
+                wC = i != 0;
+                break;
+            default:
+                rc = JIM_ERR;
+                break;
+        }
+    }
+
+    if (rc == JIM_OK) {
+        if (intresult) {
+            ExprPush(e, Jim_NewIntObj(interp, wC));
+        }
+        else {
+            ExprPush(e, Jim_NewDoubleObj(interp, dC));
+        }
+    }
+
+    Jim_DecrRefCount(interp, A);
+    Jim_DecrRefCount(interp, B);
+
+    return rc;
+}
+
+static int JimSearchList(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *valObj)
+{
+    int listlen;
+    int i;
+
+    listlen = Jim_ListLength(interp, listObjPtr);
+    for (i = 0; i < listlen; i++) {
+        Jim_Obj *objPtr;
+
+        Jim_ListIndex(interp, listObjPtr, i, &objPtr, JIM_NONE);
+
+        if (Jim_StringEqObj(objPtr, valObj)) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprState *e)
+{
+    Jim_Obj *B = ExprPop(e);
+    Jim_Obj *A = ExprPop(e);
+
+    jim_wide wC;
+
+    switch (e->opcode) {
+        case JIM_EXPROP_STREQ:
+        case JIM_EXPROP_STRNE: {
+            int Alen, Blen;
+            const char *sA = Jim_GetString(A, &Alen);
+            const char *sB = Jim_GetString(B, &Blen);
+
+            if (e->opcode == JIM_EXPROP_STREQ) {
+                wC = (Alen == Blen && memcmp(sA, sB, Alen) == 0);
+            }
+            else {
+                wC = (Alen != Blen || memcmp(sA, sB, Alen) != 0);
+            }
+            break;
+        }
+        case JIM_EXPROP_STRIN:
+            wC = JimSearchList(interp, B, A);
+            break;
+        case JIM_EXPROP_STRNI:
+            wC = !JimSearchList(interp, B, A);
+            break;
+        default:
+            abort();
+    }
+    ExprPush(e, Jim_NewIntObj(interp, wC));
+
+    Jim_DecrRefCount(interp, A);
+    Jim_DecrRefCount(interp, B);
+
+    return JIM_OK;
+}
+
+static int ExprBool(Jim_Interp *interp, Jim_Obj *obj)
+{
+    long l;
+    double d;
+
+    if (Jim_GetLong(interp, obj, &l) == JIM_OK) {
+        return l != 0;
+    }
+    if (Jim_GetDouble(interp, obj, &d) == JIM_OK) {
+        return d != 0;
+    }
+    return -1;
+}
+
+static int JimExprOpAndLeft(Jim_Interp *interp, struct JimExprState *e)
+{
+    Jim_Obj *skip = ExprPop(e);
+    Jim_Obj *A = ExprPop(e);
+    int rc = JIM_OK;
+
+    switch (ExprBool(interp, A)) {
+        case 0:
+            /* false, so skip RHS opcodes with a 0 result */
+            e->skip = JimWideValue(skip);
+            ExprPush(e, Jim_NewIntObj(interp, 0));
+            break;
+
+        case 1:
+            /* true so continue */
+            break;
+
+        case -1:
+            /* Invalid */
+            rc = JIM_ERR;
+    }
+    Jim_DecrRefCount(interp, A);
+    Jim_DecrRefCount(interp, skip);
+
+    return rc;
+}
+
+static int JimExprOpOrLeft(Jim_Interp *interp, struct JimExprState *e)
+{
+    Jim_Obj *skip = ExprPop(e);
+    Jim_Obj *A = ExprPop(e);
+    int rc = JIM_OK;
+
+    switch (ExprBool(interp, A)) {
+        case 0:
+            /* false, so do nothing */
+            break;
+
+        case 1:
+            /* true so skip RHS opcodes with a 1 result */
+            e->skip = JimWideValue(skip);
+            ExprPush(e, Jim_NewIntObj(interp, 1));
+            break;
+
+        case -1:
+            /* Invalid */
+            rc = JIM_ERR;
+            break;
+    }
+    Jim_DecrRefCount(interp, A);
+    Jim_DecrRefCount(interp, skip);
+
+    return rc;
+}
+
+static int JimExprOpAndOrRight(Jim_Interp *interp, struct JimExprState *e)
+{
+    Jim_Obj *A = ExprPop(e);
+    int rc = JIM_OK;
+
+    switch (ExprBool(interp, A)) {
+        case 0:
+            ExprPush(e, Jim_NewIntObj(interp, 0));
+            break;
+
+        case 1:
+            ExprPush(e, Jim_NewIntObj(interp, 1));
+            break;
+
+        case -1:
+            /* Invalid */
+            rc = JIM_ERR;
+            break;
+    }
+    Jim_DecrRefCount(interp, A);
+
+    return rc;
+}
+
+static int JimExprOpTernaryLeft(Jim_Interp *interp, struct JimExprState *e)
+{
+    Jim_Obj *skip = ExprPop(e);
+    Jim_Obj *A = ExprPop(e);
+    int rc = JIM_OK;
+
+    /* Repush A */
+    ExprPush(e, A);
+
+    switch (ExprBool(interp, A)) {
+        case 0:
+            /* false, skip RHS opcodes */
+            e->skip = JimWideValue(skip);
+            /* Push a dummy value */
+            ExprPush(e, Jim_NewIntObj(interp, 0));
+            break;
+
+        case 1:
+            /* true so do nothing */
+            break;
+
+        case -1:
+            /* Invalid */
+            rc = JIM_ERR;
+            break;
+    }
+    Jim_DecrRefCount(interp, A);
+    Jim_DecrRefCount(interp, skip);
+
+    return rc;
+}
+
+static int JimExprOpColonLeft(Jim_Interp *interp, struct JimExprState *e)
+{
+    Jim_Obj *skip = ExprPop(e);
+    Jim_Obj *B = ExprPop(e);
+    Jim_Obj *A = ExprPop(e);
+
+    /* No need to check for A as non-boolean */
+    if (ExprBool(interp, A)) {
+        /* true, so skip RHS opcodes */
+        e->skip = JimWideValue(skip);
+        /* Repush B as the answer */
+        ExprPush(e, B);
+    }
+
+    Jim_DecrRefCount(interp, skip);
+    Jim_DecrRefCount(interp, A);
+    Jim_DecrRefCount(interp, B);
+    return JIM_OK;
+}
+
+static int JimExprOpNull(Jim_Interp *interp, struct JimExprState *e)
+{
+    return JIM_OK;
+}
+
+enum
+{
+    LAZY_NONE,
+    LAZY_OP,
+    LAZY_LEFT,
+    LAZY_RIGHT
+};
+
+/* name - precedence - arity - opcode */
+static const struct Jim_ExprOperator Jim_ExprOperators[] = {
+    [JIM_EXPROP_FUNC_INT] = {"int", 400, 1, JimExprOpNumUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_DOUBLE] = {"double", 400, 1, JimExprOpNumUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_ABS] = {"abs", 400, 1, JimExprOpNumUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_ROUND] = {"round", 400, 1, JimExprOpNumUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_RAND] = {"rand", 400, 0, JimExprOpNone, LAZY_NONE},
+    [JIM_EXPROP_FUNC_SRAND] = {"srand", 400, 1, JimExprOpIntUnary, LAZY_NONE},
+
+#ifdef JIM_MATH_FUNCTIONS
+    [JIM_EXPROP_FUNC_SIN] = {"sin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_COS] = {"cos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_TAN] = {"tan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_ASIN] = {"asin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_ACOS] = {"acos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_ATAN] = {"atan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_SINH] = {"sinh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_COSH] = {"cosh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_TANH] = {"tanh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_CEIL] = {"ceil", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_FLOOR] = {"floor", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_EXP] = {"exp", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_LOG] = {"log", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_LOG10] = {"log10", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_SQRT] = {"sqrt", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_POW] = {"pow", 400, 2, JimExprOpBin, LAZY_NONE},
+#endif
+
+    [JIM_EXPROP_NOT] = {"!", 300, 1, JimExprOpNumUnary, LAZY_NONE},
+    [JIM_EXPROP_BITNOT] = {"~", 300, 1, JimExprOpIntUnary, LAZY_NONE},
+    [JIM_EXPROP_UNARYMINUS] = {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE},
+    [JIM_EXPROP_UNARYPLUS] = {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE},
+
+    [JIM_EXPROP_POW] = {"**", 250, 2, JimExprOpBin, LAZY_NONE},
+
+    [JIM_EXPROP_MUL] = {"*", 200, 2, JimExprOpBin, LAZY_NONE},
+    [JIM_EXPROP_DIV] = {"/", 200, 2, JimExprOpBin, LAZY_NONE},
+    [JIM_EXPROP_MOD] = {"%", 200, 2, JimExprOpIntBin, LAZY_NONE},
+
+    [JIM_EXPROP_SUB] = {"-", 100, 2, JimExprOpBin, LAZY_NONE},
+    [JIM_EXPROP_ADD] = {"+", 100, 2, JimExprOpBin, LAZY_NONE},
+
+    [JIM_EXPROP_ROTL] = {"<<<", 90, 2, JimExprOpIntBin, LAZY_NONE},
+    [JIM_EXPROP_ROTR] = {">>>", 90, 2, JimExprOpIntBin, LAZY_NONE},
+    [JIM_EXPROP_LSHIFT] = {"<<", 90, 2, JimExprOpIntBin, LAZY_NONE},
+    [JIM_EXPROP_RSHIFT] = {">>", 90, 2, JimExprOpIntBin, LAZY_NONE},
+
+    [JIM_EXPROP_LT] = {"<", 80, 2, JimExprOpBin, LAZY_NONE},
+    [JIM_EXPROP_GT] = {">", 80, 2, JimExprOpBin, LAZY_NONE},
+    [JIM_EXPROP_LTE] = {"<=", 80, 2, JimExprOpBin, LAZY_NONE},
+    [JIM_EXPROP_GTE] = {">=", 80, 2, JimExprOpBin, LAZY_NONE},
+
+    [JIM_EXPROP_NUMEQ] = {"==", 70, 2, JimExprOpBin, LAZY_NONE},
+    [JIM_EXPROP_NUMNE] = {"!=", 70, 2, JimExprOpBin, LAZY_NONE},
+
+    [JIM_EXPROP_STREQ] = {"eq", 60, 2, JimExprOpStrBin, LAZY_NONE},
+    [JIM_EXPROP_STRNE] = {"ne", 60, 2, JimExprOpStrBin, LAZY_NONE},
+
+    [JIM_EXPROP_STRIN] = {"in", 55, 2, JimExprOpStrBin, LAZY_NONE},
+    [JIM_EXPROP_STRNI] = {"ni", 55, 2, JimExprOpStrBin, LAZY_NONE},
+
+    [JIM_EXPROP_BITAND] = {"&", 50, 2, JimExprOpIntBin, LAZY_NONE},
+    [JIM_EXPROP_BITXOR] = {"^", 49, 2, JimExprOpIntBin, LAZY_NONE},
+    [JIM_EXPROP_BITOR] = {"|", 48, 2, JimExprOpIntBin, LAZY_NONE},
+
+    [JIM_EXPROP_LOGICAND] = {"&&", 10, 2, NULL, LAZY_OP},
+    [JIM_EXPROP_LOGICOR] = {"||", 9, 2, NULL, LAZY_OP},
+
+    [JIM_EXPROP_TERNARY] = {"?", 5, 2, JimExprOpNull, LAZY_OP},
+    [JIM_EXPROP_COLON] = {":", 5, 2, JimExprOpNull, LAZY_OP},
+
+    /* private operators */
+    [JIM_EXPROP_TERNARY_LEFT] = {NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT},
+    [JIM_EXPROP_TERNARY_RIGHT] = {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT},
+    [JIM_EXPROP_COLON_LEFT] = {NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT},
+    [JIM_EXPROP_COLON_RIGHT] = {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT},
+    [JIM_EXPROP_LOGICAND_LEFT] = {NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT},
+    [JIM_EXPROP_LOGICAND_RIGHT] = {NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT},
+    [JIM_EXPROP_LOGICOR_LEFT] = {NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT},
+    [JIM_EXPROP_LOGICOR_RIGHT] = {NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT},
+};
+
+#define JIM_EXPR_OPERATORS_NUM \
+    (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
+
+static int JimParseExpression(struct JimParserCtx *pc)
+{
+    /* Discard spaces and quoted newline */
+    while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
+        if (*pc->p == '\n') {
+            pc->linenr++;
+        }
+        pc->p++;
+        pc->len--;
+    }
+
+    if (pc->len == 0) {
+        pc->tstart = pc->tend = pc->p;
+        pc->tline = pc->linenr;
+        pc->tt = JIM_TT_EOL;
+        pc->eof = 1;
+        return JIM_OK;
+    }
+    switch (*(pc->p)) {
+        case '(':
+                pc->tt = JIM_TT_SUBEXPR_START;
+                goto singlechar;
+        case ')':
+                pc->tt = JIM_TT_SUBEXPR_END;
+                goto singlechar;
+        case ',':
+            pc->tt = JIM_TT_SUBEXPR_COMMA;
+singlechar:
+            pc->tstart = pc->tend = pc->p;
+            pc->tline = pc->linenr;
+            pc->p++;
+            pc->len--;
+            break;
+        case '[':
+            return JimParseCmd(pc);
+        case '$':
+            if (JimParseVar(pc) == JIM_ERR)
+                return JimParseExprOperator(pc);
+            else {
+                /* Don't allow expr sugar in expressions */
+                if (pc->tt == JIM_TT_EXPRSUGAR) {
+                    return JIM_ERR;
+                }
+                return JIM_OK;
+            }
+            break;
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+        case '.':
+            return JimParseExprNumber(pc);
+        case '"':
+            return JimParseQuote(pc);
+        case '{':
+            return JimParseBrace(pc);
+
+        case 'N':
+        case 'I':
+        case 'n':
+        case 'i':
+            if (JimParseExprIrrational(pc) == JIM_ERR)
+                return JimParseExprOperator(pc);
+            break;
+        default:
+            return JimParseExprOperator(pc);
+            break;
+    }
+    return JIM_OK;
+}
+
+static int JimParseExprNumber(struct JimParserCtx *pc)
+{
+    int allowdot = 1;
+    int allowhex = 0;
+
+    /* Assume an integer for now */
+    pc->tt = JIM_TT_EXPR_INT;
+    pc->tstart = pc->p;
+    pc->tline = pc->linenr;
+    while (isdigit(UCHAR(*pc->p))
+        || (allowhex && isxdigit(UCHAR(*pc->p)))
+        || (allowdot && *pc->p == '.')
+        || (pc->p - pc->tstart == 1 && *pc->tstart == '0' && (*pc->p == 'x' || *pc->p == 'X'))
+        ) {
+        if ((*pc->p == 'x') || (*pc->p == 'X')) {
+            allowhex = 1;
+            allowdot = 0;
+        }
+        if (*pc->p == '.') {
+            allowdot = 0;
+            pc->tt = JIM_TT_EXPR_DOUBLE;
+        }
+        pc->p++;
+        pc->len--;
+        if (!allowhex && (*pc->p == 'e' || *pc->p == 'E') && (pc->p[1] == '-' || pc->p[1] == '+'
+                || isdigit(UCHAR(pc->p[1])))) {
+            pc->p += 2;
+            pc->len -= 2;
+            pc->tt = JIM_TT_EXPR_DOUBLE;
+        }
+    }
+    pc->tend = pc->p - 1;
+    return JIM_OK;
+}
+
+static int JimParseExprIrrational(struct JimParserCtx *pc)
+{
+    const char *Tokens[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL };
+    const char **token;
+
+    for (token = Tokens; *token != NULL; token++) {
+        int len = strlen(*token);
+
+        if (strncmp(*token, pc->p, len) == 0) {
+            pc->tstart = pc->p;
+            pc->tend = pc->p + len - 1;
+            pc->p += len;
+            pc->len -= len;
+            pc->tline = pc->linenr;
+            pc->tt = JIM_TT_EXPR_DOUBLE;
+            return JIM_OK;
+        }
+    }
+    return JIM_ERR;
+}
+
+static int JimParseExprOperator(struct JimParserCtx *pc)
+{
+    int i;
+    int bestIdx = -1, bestLen = 0;
+
+    /* Try to get the longest match. */
+    for (i = JIM_TT_EXPR_OP; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
+        const char *opname;
+        int oplen;
+
+        opname = Jim_ExprOperators[i].name;
+        if (opname == NULL) {
+            continue;
+        }
+        oplen = strlen(opname);
+
+        if (strncmp(opname, pc->p, oplen) == 0 && oplen > bestLen) {
+            bestIdx = i;
+            bestLen = oplen;
+        }
+    }
+    if (bestIdx == -1) {
+        return JIM_ERR;
+    }
+
+    /* Validate paretheses around function arguments */
+    if (bestIdx >= JIM_EXPROP_FUNC_FIRST) {
+        const char *p = pc->p + bestLen;
+        int len = pc->len - bestLen;
+
+        while (len && isspace(UCHAR(*p))) {
+            len--;
+            p++;
+        }
+        if (*p != '(') {
+            return JIM_ERR;
+        }
+    }
+    pc->tstart = pc->p;
+    pc->tend = pc->p + bestLen - 1;
+    pc->p += bestLen;
+    pc->len -= bestLen;
+    pc->tline = pc->linenr;
+
+    pc->tt = bestIdx;
+    return JIM_OK;
+}
+
+static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode)
+{
+    return &Jim_ExprOperators[opcode];
+}
+
+const char *jim_tt_name(int type)
+{
+    static const char * const tt_names[JIM_TT_EXPR_OP] =
+        { "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT",
+            "DBL", "$()" };
+    if (type < JIM_TT_EXPR_OP) {
+        return tt_names[type];
+    }
+    else {
+        const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(type);
+        static char buf[20];
+
+        if (op && op->name) {
+            return op->name;
+        }
+        sprintf(buf, "(%d)", type);
+        return buf;
+    }
+}
+
+/* -----------------------------------------------------------------------------
+ * Expression Object
+ * ---------------------------------------------------------------------------*/
+static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType exprObjType = {
+    "expression",
+    FreeExprInternalRep,
+    DupExprInternalRep,
+    NULL,
+    JIM_TYPE_REFERENCES,
+};
+
+/* Expr bytecode structure */
+typedef struct ExprByteCode
+{
+    int len;                    /* Length as number of tokens. */
+    ScriptToken *token;         /* Tokens array. */
+    int inUse;                  /* Used for sharing. */
+} ExprByteCode;
+
+static void ExprFreeByteCode(Jim_Interp *interp, ExprByteCode * expr)
+{
+    int i;
+
+    for (i = 0; i < expr->len; i++) {
+        Jim_DecrRefCount(interp, expr->token[i].objPtr);
+    }
+    Jim_Free(expr->token);
+    Jim_Free(expr);
+}
+
+static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    ExprByteCode *expr = (void *)objPtr->internalRep.ptr;
+
+    if (expr) {
+        if (--expr->inUse != 0) {
+            return;
+        }
+
+        ExprFreeByteCode(interp, expr);
+    }
+}
+
+static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+    JIM_NOTUSED(interp);
+    JIM_NOTUSED(srcPtr);
+
+    /* Just returns an simple string. */
+    dupPtr->typePtr = NULL;
+}
+
+/* Check if an expr program looks correct. */
+static int ExprCheckCorrectness(ExprByteCode * expr)
+{
+    int i;
+    int stacklen = 0;
+    int ternary = 0;
+
+    /* Try to check if there are stack underflows,
+     * and make sure at the end of the program there is
+     * a single result on the stack. */
+    for (i = 0; i < expr->len; i++) {
+        ScriptToken *t = &expr->token[i];
+        const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type);
+
+        if (op) {
+            stacklen -= op->arity;
+            if (stacklen < 0) {
+                break;
+            }
+            if (t->type == JIM_EXPROP_TERNARY || t->type == JIM_EXPROP_TERNARY_LEFT) {
+                ternary++;
+            }
+            else if (t->type == JIM_EXPROP_COLON || t->type == JIM_EXPROP_COLON_LEFT) {
+                ternary--;
+            }
+        }
+
+        /* All operations and operands add one to the stack */
+        stacklen++;
+    }
+    if (stacklen != 1 || ternary != 0) {
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+/* This procedure converts every occurrence of || and && opereators
+ * in lazy unary versions.
+ *
+ * a b || is converted into:
+ *
+ * a <offset> |L b |R
+ *
+ * a b && is converted into:
+ *
+ * a <offset> &L b &R
+ *
+ * "|L" checks if 'a' is true:
+ *   1) if it is true pushes 1 and skips <offset> instructions to reach
+ *      the opcode just after |R.
+ *   2) if it is false does nothing.
+ * "|R" checks if 'b' is true:
+ *   1) if it is true pushes 1, otherwise pushes 0.
+ *
+ * "&L" checks if 'a' is true:
+ *   1) if it is true does nothing.
+ *   2) If it is false pushes 0 and skips <offset> instructions to reach
+ *      the opcode just after &R
+ * "&R" checks if 'a' is true:
+ *      if it is true pushes 1, otherwise pushes 0.
+ */
+static int ExprAddLazyOperator(Jim_Interp *interp, ExprByteCode * expr, ParseToken *t)
+{
+    int i;
+
+    int leftindex, arity, offset;
+
+    /* Search for the end of the first operator */
+    leftindex = expr->len - 1;
+
+    arity = 1;
+    while (arity) {
+        ScriptToken *tt = &expr->token[leftindex];
+
+        if (tt->type >= JIM_TT_EXPR_OP) {
+            arity += JimExprOperatorInfoByOpcode(tt->type)->arity;
+        }
+        arity--;
+        if (--leftindex < 0) {
+            return JIM_ERR;
+        }
+    }
+    leftindex++;
+
+    /* Move them up */
+    memmove(&expr->token[leftindex + 2], &expr->token[leftindex],
+        sizeof(*expr->token) * (expr->len - leftindex));
+    expr->len += 2;
+    offset = (expr->len - leftindex) - 1;
+
+    /* Now we rely on the fact the the left and right version have opcodes
+     * 1 and 2 after the main opcode respectively
+     */
+    expr->token[leftindex + 1].type = t->type + 1;
+    expr->token[leftindex + 1].objPtr = interp->emptyObj;
+
+    expr->token[leftindex].type = JIM_TT_EXPR_INT;
+    expr->token[leftindex].objPtr = Jim_NewIntObj(interp, offset);
+
+    /* Now add the 'R' operator */
+    expr->token[expr->len].objPtr = interp->emptyObj;
+    expr->token[expr->len].type = t->type + 2;
+    expr->len++;
+
+    /* Do we need to adjust the skip count for any &L, |L, ?L or :L in the left operand? */
+    for (i = leftindex - 1; i > 0; i--) {
+        if (JimExprOperatorInfoByOpcode(expr->token[i].type)->lazy == LAZY_LEFT) {
+            if (JimWideValue(expr->token[i - 1].objPtr) + i - 1 >= leftindex) {
+                JimWideValue(expr->token[i - 1].objPtr) += 2;
+            }
+        }
+    }
+    return JIM_OK;
+}
+
+static int ExprAddOperator(Jim_Interp *interp, ExprByteCode * expr, ParseToken *t)
+{
+    struct ScriptToken *token = &expr->token[expr->len];
+    const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type);
+
+    if (op->lazy == LAZY_OP) {
+        if (ExprAddLazyOperator(interp, expr, t) != JIM_OK) {
+            Jim_SetResultFormatted(interp, "Expression has bad operands to %s", op->name);
+            return JIM_ERR;
+        }
+    }
+    else {
+        token->objPtr = interp->emptyObj;
+        token->type = t->type;
+        expr->len++;
+    }
+    return JIM_OK;
+}
+
+/**
+ * Returns the index of the COLON_LEFT to the left of 'right_index'
+ * taking into account nesting.
+ *
+ * The expression *must* be well formed, thus a COLON_LEFT will always be found.
+ */
+static int ExprTernaryGetColonLeftIndex(ExprByteCode *expr, int right_index)
+{
+    int ternary_count = 1;
+
+    right_index--;
+
+    while (right_index > 1) {
+        if (expr->token[right_index].type == JIM_EXPROP_TERNARY_LEFT) {
+            ternary_count--;
+        }
+        else if (expr->token[right_index].type == JIM_EXPROP_COLON_RIGHT) {
+            ternary_count++;
+        }
+        else if (expr->token[right_index].type == JIM_EXPROP_COLON_LEFT && ternary_count == 1) {
+            return right_index;
+        }
+        right_index--;
+    }
+
+    /*notreached*/
+    return -1;
+}
+
+/**
+ * Find the left/right indices for the ternary expression to the left of 'right_index'.
+ *
+ * Returns 1 if found, and fills in *prev_right_index and *prev_left_index.
+ * Otherwise returns 0.
+ */
+static int ExprTernaryGetMoveIndices(ExprByteCode *expr, int right_index, int *prev_right_index, int *prev_left_index)
+{
+    int i = right_index - 1;
+    int ternary_count = 1;
+
+    while (i > 1) {
+        if (expr->token[i].type == JIM_EXPROP_TERNARY_LEFT) {
+            if (--ternary_count == 0 && expr->token[i - 2].type == JIM_EXPROP_COLON_RIGHT) {
+                *prev_right_index = i - 2;
+                *prev_left_index = ExprTernaryGetColonLeftIndex(expr, *prev_right_index);
+                return 1;
+            }
+        }
+        else if (expr->token[i].type == JIM_EXPROP_COLON_RIGHT) {
+            if (ternary_count == 0) {
+                return 0;
+            }
+            ternary_count++;
+        }
+        i--;
+    }
+    return 0;
+}
+
+/*
+* ExprTernaryReorderExpression description
+* ========================================
+*
+* ?: is right-to-left associative which doesn't work with the stack-based
+* expression engine. The fix is to reorder the bytecode.
+*
+* The expression:
+*
+*    expr 1?2:0?3:4
+*
+* Has initial bytecode:
+*
+*    '1' '2' (40=TERNARY_LEFT) '2' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '0' (44=COLON_RIGHT)
+*    '2' (40=TERNARY_LEFT) '3' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '4' (44=COLON_RIGHT)
+*
+* The fix involves simulating this expression instead:
+*
+*    expr 1?2:(0?3:4)
+*
+* With the following bytecode:
+*
+*    '1' '2' (40=TERNARY_LEFT) '2' (41=TERNARY_RIGHT) '10' (43=COLON_LEFT) '0' '2' (40=TERNARY_LEFT)
+*    '3' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '4' (44=COLON_RIGHT) (44=COLON_RIGHT)
+*
+* i.e. The token COLON_RIGHT at index 8 is moved towards the end of the stack, all tokens above 8
+*      are shifted down and the skip count of the token JIM_EXPROP_COLON_LEFT at index 5 is
+*      incremented by the amount tokens shifted down. The token JIM_EXPROP_COLON_RIGHT that is moved
+*      is identified as immediately preceeding a token JIM_EXPROP_TERNARY_LEFT
+*
+* ExprTernaryReorderExpression works thus as follows :
+* - start from the end of the stack
+* - while walking towards the beginning of the stack
+*     if token=JIM_EXPROP_COLON_RIGHT then
+*        find the associated token JIM_EXPROP_TERNARY_LEFT, which allows to
+*            find the associated token previous(JIM_EXPROP_COLON_RIGHT)
+*            find the associated token previous(JIM_EXPROP_LEFT_RIGHT)
+*        if all found then
+*            perform the rotation
+*            update the skip count of the token previous(JIM_EXPROP_LEFT_RIGHT)
+*        end if
+*    end if
+*
+* Note: care has to be taken for nested ternary constructs!!!
+*/
+static void ExprTernaryReorderExpression(Jim_Interp *interp, ExprByteCode *expr)
+{
+    int i;
+
+    for (i = expr->len - 1; i > 1; i--) {
+        int prev_right_index;
+        int prev_left_index;
+        int j;
+        ScriptToken tmp;
+
+        if (expr->token[i].type != JIM_EXPROP_COLON_RIGHT) {
+            continue;
+        }
+
+        /* COLON_RIGHT found: get the indexes needed to move the tokens in the stack (if any) */
+        if (ExprTernaryGetMoveIndices(expr, i, &prev_right_index, &prev_left_index) == 0) {
+            continue;
+        }
+
+        /*
+        ** rotate tokens down
+        **
+        ** +->  [i]                         : JIM_EXPROP_COLON_RIGHT
+        ** |     |                             |
+        ** |     V                             V
+        ** |   [...]                        : ...
+        ** |     |                             |
+        ** |     V                             V
+        ** |   [...]                        : ...
+        ** |     |                             |
+        ** |     V                             V
+        ** +-  [prev_right_index]           : JIM_EXPROP_COLON_RIGHT
+        */
+        tmp = expr->token[prev_right_index];
+        for (j = prev_right_index; j < i; j++) {
+            expr->token[j] = expr->token[j + 1];
+        }
+        expr->token[i] = tmp;
+
+        /* Increment the 'skip' count associated to the previous JIM_EXPROP_COLON_LEFT token
+         *
+         * This is 'colon left increment' = i - prev_right_index
+         *
+         * [prev_left_index]      : JIM_EXPROP_LEFT_RIGHT
+         * [prev_left_index-1]    : skip_count
+         *
+         */
+        JimWideValue(expr->token[prev_left_index-1].objPtr) += (i - prev_right_index);
+
+        /* Adjust for i-- in the loop */
+        i++;
+    }
+}
+
+static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *fileNameObj)
+{
+    Jim_Stack stack;
+    ExprByteCode *expr;
+    int ok = 1;
+    int i;
+    int prevtt = JIM_TT_NONE;
+    int have_ternary = 0;
+
+    /* -1 for EOL */
+    int count = tokenlist->count - 1;
+
+    expr = Jim_Alloc(sizeof(*expr));
+    expr->inUse = 1;
+    expr->len = 0;
+
+    Jim_InitStack(&stack);
+
+    /* Need extra bytecodes for lazy operators.
+     * Also check for the ternary operator
+     */
+    for (i = 0; i < tokenlist->count; i++) {
+        ParseToken *t = &tokenlist->list[i];
+
+        if (JimExprOperatorInfoByOpcode(t->type)->lazy == LAZY_OP) {
+            count += 2;
+            /* Ternary is a lazy op but also needs reordering */
+            if (t->type == JIM_EXPROP_TERNARY) {
+                have_ternary = 1;
+            }
+        }
+    }
+
+    expr->token = Jim_Alloc(sizeof(ScriptToken) * count);
+
+    for (i = 0; i < tokenlist->count && ok; i++) {
+        ParseToken *t = &tokenlist->list[i];
+
+        /* Next token will be stored here */
+        struct ScriptToken *token = &expr->token[expr->len];
+
+        if (t->type == JIM_TT_EOL) {
+            break;
+        }
+
+        switch (t->type) {
+            case JIM_TT_STR:
+            case JIM_TT_ESC:
+            case JIM_TT_VAR:
+            case JIM_TT_DICTSUGAR:
+            case JIM_TT_EXPRSUGAR:
+            case JIM_TT_CMD:
+                token->objPtr = Jim_NewStringObj(interp, t->token, t->len);
+                token->type = t->type;
+                if (t->type == JIM_TT_CMD) {
+                    /* Only commands need source info */
+                    JimSetSourceInfo(interp, token->objPtr, fileNameObj, t->line);
+                }
+                expr->len++;
+                break;
+
+            case JIM_TT_EXPR_INT:
+                token->objPtr = Jim_NewIntObj(interp, strtoull(t->token, NULL, 0));
+                token->type = t->type;
+                expr->len++;
+                break;
+
+            case JIM_TT_EXPR_DOUBLE:
+                token->objPtr = Jim_NewDoubleObj(interp, strtod(t->token, NULL));
+                token->type = t->type;
+                expr->len++;
+                break;
+
+            case JIM_TT_SUBEXPR_START:
+                Jim_StackPush(&stack, t);
+                prevtt = JIM_TT_NONE;
+                continue;
+
+            case JIM_TT_SUBEXPR_COMMA:
+                /* Simple approach. Comma is simply ignored */
+                continue;
+
+            case JIM_TT_SUBEXPR_END:
+                ok = 0;
+                while (Jim_StackLen(&stack)) {
+                    ParseToken *tt = Jim_StackPop(&stack);
+
+                    if (tt->type == JIM_TT_SUBEXPR_START) {
+                        ok = 1;
+                        break;
+                    }
+
+                    if (ExprAddOperator(interp, expr, tt) != JIM_OK) {
+                        goto err;
+                    }
+                }
+                if (!ok) {
+                    Jim_SetResultString(interp, "Unexpected close parenthesis", -1);
+                    goto err;
+                }
+                break;
+
+
+            default:{
+                    /* Must be an operator */
+                    const struct Jim_ExprOperator *op;
+                    ParseToken *tt;
+
+                    /* Convert -/+ to unary minus or unary plus if necessary */
+                    if (prevtt == JIM_TT_NONE || prevtt >= JIM_TT_EXPR_OP) {
+                        if (t->type == JIM_EXPROP_SUB) {
+                            t->type = JIM_EXPROP_UNARYMINUS;
+                        }
+                        else if (t->type == JIM_EXPROP_ADD) {
+                            t->type = JIM_EXPROP_UNARYPLUS;
+                        }
+                    }
+
+                    op = JimExprOperatorInfoByOpcode(t->type);
+
+                    /* Now handle precedence */
+                    while ((tt = Jim_StackPeek(&stack)) != NULL) {
+                        const struct Jim_ExprOperator *tt_op =
+                            JimExprOperatorInfoByOpcode(tt->type);
+
+                        /* Note that right-to-left associativity of ?: operator is handled later */
+
+                        if (op->arity != 1 && tt_op->precedence >= op->precedence) {
+                            if (ExprAddOperator(interp, expr, tt) != JIM_OK) {
+                                ok = 0;
+                                goto err;
+                            }
+                            Jim_StackPop(&stack);
+                        }
+                        else {
+                            break;
+                        }
+                    }
+                    Jim_StackPush(&stack, t);
+                    break;
+                }
+        }
+        prevtt = t->type;
+    }
+
+    /* Reduce any remaining subexpr */
+    while (Jim_StackLen(&stack)) {
+        ParseToken *tt = Jim_StackPop(&stack);
+
+        if (tt->type == JIM_TT_SUBEXPR_START) {
+            ok = 0;
+            Jim_SetResultString(interp, "Missing close parenthesis", -1);
+            goto err;
+        }
+        if (ExprAddOperator(interp, expr, tt) != JIM_OK) {
+            ok = 0;
+            goto err;
+        }
+    }
+
+    if (have_ternary) {
+        ExprTernaryReorderExpression(interp, expr);
+    }
+
+  err:
+    /* Free the stack used for the compilation. */
+    Jim_FreeStack(&stack);
+
+    for (i = 0; i < expr->len; i++) {
+        Jim_IncrRefCount(expr->token[i].objPtr);
+    }
+
+    if (!ok) {
+        ExprFreeByteCode(interp, expr);
+        return NULL;
+    }
+
+    return expr;
+}
+
+
+/* This method takes the string representation of an expression
+ * and generates a program for the Expr's stack-based VM. */
+static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+    int exprTextLen;
+    const char *exprText;
+    struct JimParserCtx parser;
+    struct ExprByteCode *expr;
+    ParseTokenList tokenlist;
+    int line;
+    Jim_Obj *fileNameObj;
+    int rc = JIM_ERR;
+
+    /* Try to get information about filename / line number */
+    if (objPtr->typePtr == &sourceObjType) {
+        fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
+        line = objPtr->internalRep.sourceValue.lineNumber;
+    }
+    else {
+        fileNameObj = interp->emptyObj;
+        line = 1;
+    }
+    Jim_IncrRefCount(fileNameObj);
+
+    exprText = Jim_GetString(objPtr, &exprTextLen);
+
+    /* Initially tokenise the expression into tokenlist */
+    ScriptTokenListInit(&tokenlist);
+
+    JimParserInit(&parser, exprText, exprTextLen, line);
+    while (!parser.eof) {
+        if (JimParseExpression(&parser) != JIM_OK) {
+            ScriptTokenListFree(&tokenlist);
+          invalidexpr:
+            Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr);
+            expr = NULL;
+            goto err;
+        }
+
+        ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
+            parser.tline);
+    }
+
+#ifdef DEBUG_SHOW_EXPR_TOKENS
+    {
+        int i;
+        printf("==== Expr Tokens ====\n");
+        for (i = 0; i < tokenlist.count; i++) {
+            printf("[%2d]@%d %s '%.*s'\n", i, tokenlist.list[i].line, jim_tt_name(tokenlist.list[i].type),
+                tokenlist.list[i].len, tokenlist.list[i].token);
+        }
+    }
+#endif
+
+    /* Now create the expression bytecode from the tokenlist */
+    expr = ExprCreateByteCode(interp, &tokenlist, fileNameObj);
+
+    /* No longer need the token list */
+    ScriptTokenListFree(&tokenlist);
+
+    if (!expr) {
+        goto err;
+    }
+
+#ifdef DEBUG_SHOW_EXPR
+    {
+        int i;
+
+        printf("==== Expr ====\n");
+        for (i = 0; i < expr->len; i++) {
+            ScriptToken *t = &expr->token[i];
+
+            printf("[%2d] %s '%s'\n", i, jim_tt_name(t->type), Jim_String(t->objPtr));
+        }
+    }
+#endif
+
+    /* Check program correctness. */
+    if (ExprCheckCorrectness(expr) != JIM_OK) {
+        ExprFreeByteCode(interp, expr);
+        goto invalidexpr;
+    }
+
+    rc = JIM_OK;
+
+  err:
+    /* Free the old internal rep and set the new one. */
+    Jim_DecrRefCount(interp, fileNameObj);
+    Jim_FreeIntRep(interp, objPtr);
+    Jim_SetIntRepPtr(objPtr, expr);
+    objPtr->typePtr = &exprObjType;
+    return rc;
+}
+
+static ExprByteCode *JimGetExpression(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    if (objPtr->typePtr != &exprObjType) {
+        if (SetExprFromAny(interp, objPtr) != JIM_OK) {
+            return NULL;
+        }
+    }
+    return (ExprByteCode *) Jim_GetIntRepPtr(objPtr);
+}
+
+/* -----------------------------------------------------------------------------
+ * Expressions evaluation.
+ * Jim uses a specialized stack-based virtual machine for expressions,
+ * that takes advantage of the fact that expr's operators
+ * can't be redefined.
+ *
+ * Jim_EvalExpression() uses the bytecode compiled by
+ * SetExprFromAny() method of the "expression" object.
+ *
+ * On success a Tcl Object containing the result of the evaluation
+ * is stored into expResultPtrPtr (having refcount of 1), and JIM_OK is
+ * returned.
+ * On error the function returns a retcode != to JIM_OK and set a suitable
+ * error on the interp.
+ * ---------------------------------------------------------------------------*/
+#define JIM_EE_STATICSTACK_LEN 10
+
+int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr)
+{
+    ExprByteCode *expr;
+    Jim_Obj *staticStack[JIM_EE_STATICSTACK_LEN];
+    int i;
+    int retcode = JIM_OK;
+    struct JimExprState e;
+
+    expr = JimGetExpression(interp, exprObjPtr);
+    if (!expr) {
+        return JIM_ERR;         /* error in expression. */
+    }
+
+#ifdef JIM_OPTIMIZATION
+    /* Check for one of the following common expressions used by while/for
+     *
+     *   CONST
+     *   $a
+     *   !$a
+     *   $a < CONST, $a < $b
+     *   $a <= CONST, $a <= $b
+     *   $a > CONST, $a > $b
+     *   $a >= CONST, $a >= $b
+     *   $a != CONST, $a != $b
+     *   $a == CONST, $a == $b
+     */
+    {
+        Jim_Obj *objPtr;
+
+        /* STEP 1 -- Check if there are the conditions to run the specialized
+         * version of while */
+
+        switch (expr->len) {
+            case 1:
+                if (expr->token[0].type == JIM_TT_EXPR_INT) {
+                    *exprResultPtrPtr = expr->token[0].objPtr;
+                    Jim_IncrRefCount(*exprResultPtrPtr);
+                    return JIM_OK;
+                }
+                if (expr->token[0].type == JIM_TT_VAR) {
+                    objPtr = Jim_GetVariable(interp, expr->token[0].objPtr, JIM_ERRMSG);
+                    if (objPtr) {
+                        *exprResultPtrPtr = objPtr;
+                        Jim_IncrRefCount(*exprResultPtrPtr);
+                        return JIM_OK;
+                    }
+                }
+                break;
+
+            case 2:
+                if (expr->token[1].type == JIM_EXPROP_NOT && expr->token[0].type == JIM_TT_VAR) {
+                    jim_wide wideValue;
+
+                    objPtr = Jim_GetVariable(interp, expr->token[0].objPtr, JIM_NONE);
+                    if (objPtr && JimIsWide(objPtr)
+                        && Jim_GetWide(interp, objPtr, &wideValue) == JIM_OK) {
+                        *exprResultPtrPtr = wideValue ? interp->falseObj : interp->trueObj;
+                        Jim_IncrRefCount(*exprResultPtrPtr);
+                        return JIM_OK;
+                    }
+                }
+                break;
+
+            case 3:
+                if (expr->token[0].type == JIM_TT_VAR && (expr->token[1].type == JIM_TT_EXPR_INT
+                        || expr->token[1].type == JIM_TT_VAR)) {
+                    switch (expr->token[2].type) {
+                        case JIM_EXPROP_LT:
+                        case JIM_EXPROP_LTE:
+                        case JIM_EXPROP_GT:
+                        case JIM_EXPROP_GTE:
+                        case JIM_EXPROP_NUMEQ:
+                        case JIM_EXPROP_NUMNE:{
+                                /* optimise ok */
+                                jim_wide wideValueA;
+                                jim_wide wideValueB;
+
+                                objPtr = Jim_GetVariable(interp, expr->token[0].objPtr, JIM_NONE);
+                                if (objPtr && JimIsWide(objPtr)
+                                    && Jim_GetWide(interp, objPtr, &wideValueA) == JIM_OK) {
+                                    if (expr->token[1].type == JIM_TT_VAR) {
+                                        objPtr =
+                                            Jim_GetVariable(interp, expr->token[1].objPtr,
+                                            JIM_NONE);
+                                    }
+                                    else {
+                                        objPtr = expr->token[1].objPtr;
+                                    }
+                                    if (objPtr && JimIsWide(objPtr)
+                                        && Jim_GetWide(interp, objPtr, &wideValueB) == JIM_OK) {
+                                        int cmpRes;
+
+                                        switch (expr->token[2].type) {
+                                            case JIM_EXPROP_LT:
+                                                cmpRes = wideValueA < wideValueB;
+                                                break;
+                                            case JIM_EXPROP_LTE:
+                                                cmpRes = wideValueA <= wideValueB;
+                                                break;
+                                            case JIM_EXPROP_GT:
+                                                cmpRes = wideValueA > wideValueB;
+                                                break;
+                                            case JIM_EXPROP_GTE:
+                                                cmpRes = wideValueA >= wideValueB;
+                                                break;
+                                            case JIM_EXPROP_NUMEQ:
+                                                cmpRes = wideValueA == wideValueB;
+                                                break;
+                                            case JIM_EXPROP_NUMNE:
+                                                cmpRes = wideValueA != wideValueB;
+                                                break;
+                                            default:   /*notreached */
+                                                cmpRes = 0;
+                                        }
+                                        *exprResultPtrPtr =
+                                            cmpRes ? interp->trueObj : interp->falseObj;
+                                        Jim_IncrRefCount(*exprResultPtrPtr);
+                                        return JIM_OK;
+                                    }
+                                }
+                            }
+                    }
+                }
+                break;
+        }
+    }
+#endif
+
+    /* In order to avoid that the internal repr gets freed due to
+     * shimmering of the exprObjPtr's object, we make the internal rep
+     * shared. */
+    expr->inUse++;
+
+    /* The stack-based expr VM itself */
+
+    /* Stack allocation. Expr programs have the feature that
+     * a program of length N can't require a stack longer than
+     * N. */
+    if (expr->len > JIM_EE_STATICSTACK_LEN)
+        e.stack = Jim_Alloc(sizeof(Jim_Obj *) * expr->len);
+    else
+        e.stack = staticStack;
+
+    e.stacklen = 0;
+
+    /* Execute every instruction */
+    for (i = 0; i < expr->len && retcode == JIM_OK; i++) {
+        Jim_Obj *objPtr;
+
+        switch (expr->token[i].type) {
+            case JIM_TT_EXPR_INT:
+            case JIM_TT_EXPR_DOUBLE:
+            case JIM_TT_STR:
+                ExprPush(&e, expr->token[i].objPtr);
+                break;
+
+            case JIM_TT_VAR:
+                objPtr = Jim_GetVariable(interp, expr->token[i].objPtr, JIM_ERRMSG);
+                if (objPtr) {
+                    ExprPush(&e, objPtr);
+                }
+                else {
+                    retcode = JIM_ERR;
+                }
+                break;
+
+            case JIM_TT_DICTSUGAR:
+                objPtr = JimExpandDictSugar(interp, expr->token[i].objPtr);
+                if (objPtr) {
+                    ExprPush(&e, objPtr);
+                }
+                else {
+                    retcode = JIM_ERR;
+                }
+                break;
+
+            case JIM_TT_ESC:
+                retcode = Jim_SubstObj(interp, expr->token[i].objPtr, &objPtr, JIM_NONE);
+                if (retcode == JIM_OK) {
+                    ExprPush(&e, objPtr);
+                }
+                break;
+
+            case JIM_TT_CMD:
+                retcode = Jim_EvalObj(interp, expr->token[i].objPtr);
+                if (retcode == JIM_OK) {
+                    ExprPush(&e, Jim_GetResult(interp));
+                }
+                break;
+
+            default:{
+                    /* Find and execute the operation */
+                    e.skip = 0;
+                    e.opcode = expr->token[i].type;
+
+                    retcode = JimExprOperatorInfoByOpcode(e.opcode)->funcop(interp, &e);
+                    /* Skip some opcodes if necessary */
+                    i += e.skip;
+                    continue;
+                }
+        }
+    }
+
+    expr->inUse--;
+
+    if (retcode == JIM_OK) {
+        *exprResultPtrPtr = ExprPop(&e);
+    }
+    else {
+        for (i = 0; i < e.stacklen; i++) {
+            Jim_DecrRefCount(interp, e.stack[i]);
+        }
+    }
+    if (e.stack != staticStack) {
+        Jim_Free(e.stack);
+    }
+    return retcode;
+}
+
+int Jim_GetBoolFromExpr(Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr)
+{
+    int retcode;
+    jim_wide wideValue;
+    double doubleValue;
+    Jim_Obj *exprResultPtr;
+
+    retcode = Jim_EvalExpression(interp, exprObjPtr, &exprResultPtr);
+    if (retcode != JIM_OK)
+        return retcode;
+
+    if (JimGetWideNoErr(interp, exprResultPtr, &wideValue) != JIM_OK) {
+        if (Jim_GetDouble(interp, exprResultPtr, &doubleValue) != JIM_OK) {
+            Jim_DecrRefCount(interp, exprResultPtr);
+            return JIM_ERR;
+        }
+        else {
+            Jim_DecrRefCount(interp, exprResultPtr);
+            *boolPtr = doubleValue != 0;
+            return JIM_OK;
+        }
+    }
+    *boolPtr = wideValue != 0;
+
+    Jim_DecrRefCount(interp, exprResultPtr);
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * ScanFormat String Object
+ * ---------------------------------------------------------------------------*/
+
+/* This Jim_Obj will held a parsed representation of a format string passed to
+ * the Jim_ScanString command. For error diagnostics, the scanformat string has
+ * to be parsed in its entirely first and then, if correct, can be used for
+ * scanning. To avoid endless re-parsing, the parsed representation will be
+ * stored in an internal representation and re-used for performance reason. */
+
+/* A ScanFmtPartDescr will held the information of /one/ part of the whole
+ * scanformat string. This part will later be used to extract information
+ * out from the string to be parsed by Jim_ScanString */
+
+typedef struct ScanFmtPartDescr
+{
+    char type;                  /* Type of conversion (e.g. c, d, f) */
+    char modifier;              /* Modify type (e.g. l - long, h - short */
+    size_t width;               /* Maximal width of input to be converted */
+    int pos;                    /* -1 - no assign, 0 - natural pos, >0 - XPG3 pos */
+    char *arg;                  /* Specification of a CHARSET conversion */
+    char *prefix;               /* Prefix to be scanned literally before conversion */
+} ScanFmtPartDescr;
+
+/* The ScanFmtStringObj will hold the internal representation of a scanformat
+ * string parsed and separated in part descriptions. Furthermore it contains
+ * the original string representation of the scanformat string to allow for
+ * fast update of the Jim_Obj's string representation part.
+ *
+ * As an add-on the internal object representation adds some scratch pad area
+ * for usage by Jim_ScanString to avoid endless allocating and freeing of
+ * memory for purpose of string scanning.
+ *
+ * The error member points to a static allocated string in case of a mal-
+ * formed scanformat string or it contains '0' (NULL) in case of a valid
+ * parse representation.
+ *
+ * The whole memory of the internal representation is allocated as a single
+ * area of memory that will be internally separated. So freeing and duplicating
+ * of such an object is cheap */
+
+typedef struct ScanFmtStringObj
+{
+    jim_wide size;              /* Size of internal repr in bytes */
+    char *stringRep;            /* Original string representation */
+    size_t count;               /* Number of ScanFmtPartDescr contained */
+    size_t convCount;           /* Number of conversions that will assign */
+    size_t maxPos;              /* Max position index if XPG3 is used */
+    const char *error;          /* Ptr to error text (NULL if no error */
+    char *scratch;              /* Some scratch pad used by Jim_ScanString */
+    ScanFmtPartDescr descr[1];  /* The vector of partial descriptions */
+} ScanFmtStringObj;
+
+
+static void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static void UpdateStringOfScanFmt(Jim_Obj *objPtr);
+
+static const Jim_ObjType scanFmtStringObjType = {
+    "scanformatstring",
+    FreeScanFmtInternalRep,
+    DupScanFmtInternalRep,
+    UpdateStringOfScanFmt,
+    JIM_TYPE_NONE,
+};
+
+void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    JIM_NOTUSED(interp);
+    Jim_Free((char *)objPtr->internalRep.ptr);
+    objPtr->internalRep.ptr = 0;
+}
+
+void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+    size_t size = (size_t) ((ScanFmtStringObj *) srcPtr->internalRep.ptr)->size;
+    ScanFmtStringObj *newVec = (ScanFmtStringObj *) Jim_Alloc(size);
+
+    JIM_NOTUSED(interp);
+    memcpy(newVec, srcPtr->internalRep.ptr, size);
+    dupPtr->internalRep.ptr = newVec;
+    dupPtr->typePtr = &scanFmtStringObjType;
+}
+
+void UpdateStringOfScanFmt(Jim_Obj *objPtr)
+{
+    char *bytes = ((ScanFmtStringObj *) objPtr->internalRep.ptr)->stringRep;
+
+    objPtr->bytes = Jim_StrDup(bytes);
+    objPtr->length = strlen(bytes);
+}
+
+/* SetScanFmtFromAny will parse a given string and create the internal
+ * representation of the format specification. In case of an error
+ * the error data member of the internal representation will be set
+ * to an descriptive error text and the function will be left with
+ * JIM_ERR to indicate unsucessful parsing (aka. malformed scanformat
+ * specification */
+
+static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    ScanFmtStringObj *fmtObj;
+    char *buffer;
+    int maxCount, i, approxSize, lastPos = -1;
+    const char *fmt = objPtr->bytes;
+    int maxFmtLen = objPtr->length;
+    const char *fmtEnd = fmt + maxFmtLen;
+    int curr;
+
+    Jim_FreeIntRep(interp, objPtr);
+    /* Count how many conversions could take place maximally */
+    for (i = 0, maxCount = 0; i < maxFmtLen; ++i)
+        if (fmt[i] == '%')
+            ++maxCount;
+    /* Calculate an approximation of the memory necessary */
+    approxSize = sizeof(ScanFmtStringObj)       /* Size of the container */
+        +(maxCount + 1) * sizeof(ScanFmtPartDescr)      /* Size of all partials */
+        +maxFmtLen * sizeof(char) + 3 + 1       /* Scratch + "%n" + '\0' */
+        + maxFmtLen * sizeof(char) + 1  /* Original stringrep */
+        + maxFmtLen * sizeof(char)      /* Arg for CHARSETs */
+        +(maxCount + 1) * sizeof(char)  /* '\0' for every partial */
+        +1;                     /* safety byte */
+    fmtObj = (ScanFmtStringObj *) Jim_Alloc(approxSize);
+    memset(fmtObj, 0, approxSize);
+    fmtObj->size = approxSize;
+    fmtObj->maxPos = 0;
+    fmtObj->scratch = (char *)&fmtObj->descr[maxCount + 1];
+    fmtObj->stringRep = fmtObj->scratch + maxFmtLen + 3 + 1;
+    memcpy(fmtObj->stringRep, fmt, maxFmtLen);
+    buffer = fmtObj->stringRep + maxFmtLen + 1;
+    objPtr->internalRep.ptr = fmtObj;
+    objPtr->typePtr = &scanFmtStringObjType;
+    for (i = 0, curr = 0; fmt < fmtEnd; ++fmt) {
+        int width = 0, skip;
+        ScanFmtPartDescr *descr = &fmtObj->descr[curr];
+
+        fmtObj->count++;
+        descr->width = 0;       /* Assume width unspecified */
+        /* Overread and store any "literal" prefix */
+        if (*fmt != '%' || fmt[1] == '%') {
+            descr->type = 0;
+            descr->prefix = &buffer[i];
+            for (; fmt < fmtEnd; ++fmt) {
+                if (*fmt == '%') {
+                    if (fmt[1] != '%')
+                        break;
+                    ++fmt;
+                }
+                buffer[i++] = *fmt;
+            }
+            buffer[i++] = 0;
+        }
+        /* Skip the conversion introducing '%' sign */
+        ++fmt;
+        /* End reached due to non-conversion literal only? */
+        if (fmt >= fmtEnd)
+            goto done;
+        descr->pos = 0;         /* Assume "natural" positioning */
+        if (*fmt == '*') {
+            descr->pos = -1;    /* Okay, conversion will not be assigned */
+            ++fmt;
+        }
+        else
+            fmtObj->convCount++;        /* Otherwise count as assign-conversion */
+        /* Check if next token is a number (could be width or pos */
+        if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
+            fmt += skip;
+            /* Was the number a XPG3 position specifier? */
+            if (descr->pos != -1 && *fmt == '$') {
+                int prev;
+
+                ++fmt;
+                descr->pos = width;
+                width = 0;
+                /* Look if "natural" postioning and XPG3 one was mixed */
+                if ((lastPos == 0 && descr->pos > 0)
+                    || (lastPos > 0 && descr->pos == 0)) {
+                    fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers";
+                    return JIM_ERR;
+                }
+                /* Look if this position was already used */
+                for (prev = 0; prev < curr; ++prev) {
+                    if (fmtObj->descr[prev].pos == -1)
+                        continue;
+                    if (fmtObj->descr[prev].pos == descr->pos) {
+                        fmtObj->error =
+                            "variable is assigned by multiple \"%n$\" conversion specifiers";
+                        return JIM_ERR;
+                    }
+                }
+                /* Try to find a width after the XPG3 specifier */
+                if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
+                    descr->width = width;
+                    fmt += skip;
+                }
+                if (descr->pos > 0 && (size_t) descr->pos > fmtObj->maxPos)
+                    fmtObj->maxPos = descr->pos;
+            }
+            else {
+                /* Number was not a XPG3, so it has to be a width */
+                descr->width = width;
+            }
+        }
+        /* If positioning mode was undetermined yet, fix this */
+        if (lastPos == -1)
+            lastPos = descr->pos;
+        /* Handle CHARSET conversion type ... */
+        if (*fmt == '[') {
+            int swapped = 1, beg = i, end, j;
+
+            descr->type = '[';
+            descr->arg = &buffer[i];
+            ++fmt;
+            if (*fmt == '^')
+                buffer[i++] = *fmt++;
+            if (*fmt == ']')
+                buffer[i++] = *fmt++;
+            while (*fmt && *fmt != ']')
+                buffer[i++] = *fmt++;
+            if (*fmt != ']') {
+                fmtObj->error = "unmatched [ in format string";
+                return JIM_ERR;
+            }
+            end = i;
+            buffer[i++] = 0;
+            /* In case a range fence was given "backwards", swap it */
+            while (swapped) {
+                swapped = 0;
+                for (j = beg + 1; j < end - 1; ++j) {
+                    if (buffer[j] == '-' && buffer[j - 1] > buffer[j + 1]) {
+                        char tmp = buffer[j - 1];
+
+                        buffer[j - 1] = buffer[j + 1];
+                        buffer[j + 1] = tmp;
+                        swapped = 1;
+                    }
+                }
+            }
+        }
+        else {
+            /* Remember any valid modifier if given */
+            if (strchr("hlL", *fmt) != 0)
+                descr->modifier = tolower((int)*fmt++);
+
+            descr->type = *fmt;
+            if (strchr("efgcsndoxui", *fmt) == 0) {
+                fmtObj->error = "bad scan conversion character";
+                return JIM_ERR;
+            }
+            else if (*fmt == 'c' && descr->width != 0) {
+                fmtObj->error = "field width may not be specified in %c " "conversion";
+                return JIM_ERR;
+            }
+            else if (*fmt == 'u' && descr->modifier == 'l') {
+                fmtObj->error = "unsigned wide not supported";
+                return JIM_ERR;
+            }
+        }
+        curr++;
+    }
+  done:
+    return JIM_OK;
+}
+
+/* Some accessor macros to allow lowlevel access to fields of internal repr */
+
+#define FormatGetCnvCount(_fo_) \
+    ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount
+#define FormatGetMaxPos(_fo_) \
+    ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos
+#define FormatGetError(_fo_) \
+    ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error
+
+/* JimScanAString is used to scan an unspecified string that ends with
+ * next WS, or a string that is specified via a charset.
+ *
+ */
+static Jim_Obj *JimScanAString(Jim_Interp *interp, const char *sdescr, const char *str)
+{
+    char *buffer = Jim_StrDup(str);
+    char *p = buffer;
+
+    while (*str) {
+        int c;
+        int n;
+
+        if (!sdescr && isspace(UCHAR(*str)))
+            break;              /* EOS via WS if unspecified */
+
+        n = utf8_tounicode(str, &c);
+        if (sdescr && !JimCharsetMatch(sdescr, c, JIM_CHARSET_SCAN))
+            break;
+        while (n--)
+            *p++ = *str++;
+    }
+    *p = 0;
+    return Jim_NewStringObjNoAlloc(interp, buffer, p - buffer);
+}
+
+/* ScanOneEntry will scan one entry out of the string passed as argument.
+ * It use the sscanf() function for this task. After extracting and
+ * converting of the value, the count of scanned characters will be
+ * returned of -1 in case of no conversion tool place and string was
+ * already scanned thru */
+
+static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int strLen,
+    ScanFmtStringObj * fmtObj, long idx, Jim_Obj **valObjPtr)
+{
+    const char *tok;
+    const ScanFmtPartDescr *descr = &fmtObj->descr[idx];
+    size_t scanned = 0;
+    size_t anchor = pos;
+    int i;
+    Jim_Obj *tmpObj = NULL;
+
+    /* First pessimistically assume, we will not scan anything :-) */
+    *valObjPtr = 0;
+    if (descr->prefix) {
+        /* There was a prefix given before the conversion, skip it and adjust
+         * the string-to-be-parsed accordingly */
+        /* XXX: Should be checking strLen, not str[pos] */
+        for (i = 0; pos < strLen && descr->prefix[i]; ++i) {
+            /* If prefix require, skip WS */
+            if (isspace(UCHAR(descr->prefix[i])))
+                while (pos < strLen && isspace(UCHAR(str[pos])))
+                    ++pos;
+            else if (descr->prefix[i] != str[pos])
+                break;          /* Prefix do not match here, leave the loop */
+            else
+                ++pos;          /* Prefix matched so far, next round */
+        }
+        if (pos >= strLen) {
+            return -1;          /* All of str consumed: EOF condition */
+        }
+        else if (descr->prefix[i] != 0)
+            return 0;           /* Not whole prefix consumed, no conversion possible */
+    }
+    /* For all but following conversion, skip leading WS */
+    if (descr->type != 'c' && descr->type != '[' && descr->type != 'n')
+        while (isspace(UCHAR(str[pos])))
+            ++pos;
+    /* Determine how much skipped/scanned so far */
+    scanned = pos - anchor;
+
+    /* %c is a special, simple case. no width */
+    if (descr->type == 'n') {
+        /* Return pseudo conversion means: how much scanned so far? */
+        *valObjPtr = Jim_NewIntObj(interp, anchor + scanned);
+    }
+    else if (pos >= strLen) {
+        /* Cannot scan anything, as str is totally consumed */
+        return -1;
+    }
+    else if (descr->type == 'c') {
+            int c;
+            scanned += utf8_tounicode(&str[pos], &c);
+            *valObjPtr = Jim_NewIntObj(interp, c);
+            return scanned;
+    }
+    else {
+        /* Processing of conversions follows ... */
+        if (descr->width > 0) {
+            /* Do not try to scan as fas as possible but only the given width.
+             * To ensure this, we copy the part that should be scanned. */
+            size_t sLen = utf8_strlen(&str[pos], strLen - pos);
+            size_t tLen = descr->width > sLen ? sLen : descr->width;
+
+            tmpObj = Jim_NewStringObjUtf8(interp, str + pos, tLen);
+            tok = tmpObj->bytes;
+        }
+        else {
+            /* As no width was given, simply refer to the original string */
+            tok = &str[pos];
+        }
+        switch (descr->type) {
+            case 'd':
+            case 'o':
+            case 'x':
+            case 'u':
+            case 'i':{
+                    char *endp; /* Position where the number finished */
+                    jim_wide w;
+
+                    int base = descr->type == 'o' ? 8
+                        : descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10;
+
+                    /* Try to scan a number with the given base */
+                    w = strtoull(tok, &endp, base);
+                    if (endp == tok && base == 0) {
+                        /* If scanning failed, and base was undetermined, simply
+                         * put it to 10 and try once more. This should catch the
+                         * case where %i begin to parse a number prefix (e.g.
+                         * '0x' but no further digits follows. This will be
+                         * handled as a ZERO followed by a char 'x' by Tcl */
+                        w = strtoull(tok, &endp, 10);
+                    }
+
+                    if (endp != tok) {
+                        /* There was some number sucessfully scanned! */
+                        *valObjPtr = Jim_NewIntObj(interp, w);
+
+                        /* Adjust the number-of-chars scanned so far */
+                        scanned += endp - tok;
+                    }
+                    else {
+                        /* Nothing was scanned. We have to determine if this
+                         * happened due to e.g. prefix mismatch or input str
+                         * exhausted */
+                        scanned = *tok ? 0 : -1;
+                    }
+                    break;
+                }
+            case 's':
+            case '[':{
+                    *valObjPtr = JimScanAString(interp, descr->arg, tok);
+                    scanned += Jim_Length(*valObjPtr);
+                    break;
+                }
+            case 'e':
+            case 'f':
+            case 'g':{
+                    char *endp;
+                    double value = strtod(tok, &endp);
+
+                    if (endp != tok) {
+                        /* There was some number sucessfully scanned! */
+                        *valObjPtr = Jim_NewDoubleObj(interp, value);
+                        /* Adjust the number-of-chars scanned so far */
+                        scanned += endp - tok;
+                    }
+                    else {
+                        /* Nothing was scanned. We have to determine if this
+                         * happened due to e.g. prefix mismatch or input str
+                         * exhausted */
+                        scanned = *tok ? 0 : -1;
+                    }
+                    break;
+                }
+        }
+        /* If a substring was allocated (due to pre-defined width) do not
+         * forget to free it */
+        if (tmpObj) {
+            Jim_FreeNewObj(interp, tmpObj);
+        }
+    }
+    return scanned;
+}
+
+/* Jim_ScanString is the workhorse of string scanning. It will scan a given
+ * string and returns all converted (and not ignored) values in a list back
+ * to the caller. If an error occured, a NULL pointer will be returned */
+
+Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjPtr, int flags)
+{
+    size_t i, pos;
+    int scanned = 1;
+    const char *str = Jim_String(strObjPtr);
+    int strLen = Jim_Utf8Length(interp, strObjPtr);
+    Jim_Obj *resultList = 0;
+    Jim_Obj **resultVec = 0;
+    int resultc;
+    Jim_Obj *emptyStr = 0;
+    ScanFmtStringObj *fmtObj;
+
+    /* This should never happen. The format object should already be of the correct type */
+    JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, "Jim_ScanString() for non-scan format"));
+
+    fmtObj = (ScanFmtStringObj *) fmtObjPtr->internalRep.ptr;
+    /* Check if format specification was valid */
+    if (fmtObj->error != 0) {
+        if (flags & JIM_ERRMSG)
+            Jim_SetResultString(interp, fmtObj->error, -1);
+        return 0;
+    }
+    /* Allocate a new "shared" empty string for all unassigned conversions */
+    emptyStr = Jim_NewEmptyStringObj(interp);
+    Jim_IncrRefCount(emptyStr);
+    /* Create a list and fill it with empty strings up to max specified XPG3 */
+    resultList = Jim_NewListObj(interp, 0, 0);
+    if (fmtObj->maxPos > 0) {
+        for (i = 0; i < fmtObj->maxPos; ++i)
+            Jim_ListAppendElement(interp, resultList, emptyStr);
+        JimListGetElements(interp, resultList, &resultc, &resultVec);
+    }
+    /* Now handle every partial format description */
+    for (i = 0, pos = 0; i < fmtObj->count; ++i) {
+        ScanFmtPartDescr *descr = &(fmtObj->descr[i]);
+        Jim_Obj *value = 0;
+
+        /* Only last type may be "literal" w/o conversion - skip it! */
+        if (descr->type == 0)
+            continue;
+        /* As long as any conversion could be done, we will proceed */
+        if (scanned > 0)
+            scanned = ScanOneEntry(interp, str, pos, strLen, fmtObj, i, &value);
+        /* In case our first try results in EOF, we will leave */
+        if (scanned == -1 && i == 0)
+            goto eof;
+        /* Advance next pos-to-be-scanned for the amount scanned already */
+        pos += scanned;
+
+        /* value == 0 means no conversion took place so take empty string */
+        if (value == 0)
+            value = Jim_NewEmptyStringObj(interp);
+        /* If value is a non-assignable one, skip it */
+        if (descr->pos == -1) {
+            Jim_FreeNewObj(interp, value);
+        }
+        else if (descr->pos == 0)
+            /* Otherwise append it to the result list if no XPG3 was given */
+            Jim_ListAppendElement(interp, resultList, value);
+        else if (resultVec[descr->pos - 1] == emptyStr) {
+            /* But due to given XPG3, put the value into the corr. slot */
+            Jim_DecrRefCount(interp, resultVec[descr->pos - 1]);
+            Jim_IncrRefCount(value);
+            resultVec[descr->pos - 1] = value;
+        }
+        else {
+            /* Otherwise, the slot was already used - free obj and ERROR */
+            Jim_FreeNewObj(interp, value);
+            goto err;
+        }
+    }
+    Jim_DecrRefCount(interp, emptyStr);
+    return resultList;
+  eof:
+    Jim_DecrRefCount(interp, emptyStr);
+    Jim_FreeNewObj(interp, resultList);
+    return (Jim_Obj *)EOF;
+  err:
+    Jim_DecrRefCount(interp, emptyStr);
+    Jim_FreeNewObj(interp, resultList);
+    return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Pseudo Random Number Generation
+ * ---------------------------------------------------------------------------*/
+/* Initialize the sbox with the numbers from 0 to 255 */
+static void JimPrngInit(Jim_Interp *interp)
+{
+#define PRNG_SEED_SIZE 256
+    int i;
+    unsigned int *seed;
+    time_t t = time(NULL);
+
+    interp->prngState = Jim_Alloc(sizeof(Jim_PrngState));
+
+    seed = Jim_Alloc(PRNG_SEED_SIZE * sizeof(*seed));
+    for (i = 0; i < PRNG_SEED_SIZE; i++) {
+        seed[i] = (rand() ^ t ^ clock());
+    }
+    JimPrngSeed(interp, (unsigned char *)seed, PRNG_SEED_SIZE * sizeof(*seed));
+    Jim_Free(seed);
+}
+
+/* Generates N bytes of random data */
+static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len)
+{
+    Jim_PrngState *prng;
+    unsigned char *destByte = (unsigned char *)dest;
+    unsigned int si, sj, x;
+
+    /* initialization, only needed the first time */
+    if (interp->prngState == NULL)
+        JimPrngInit(interp);
+    prng = interp->prngState;
+    /* generates 'len' bytes of pseudo-random numbers */
+    for (x = 0; x < len; x++) {
+        prng->i = (prng->i + 1) & 0xff;
+        si = prng->sbox[prng->i];
+        prng->j = (prng->j + si) & 0xff;
+        sj = prng->sbox[prng->j];
+        prng->sbox[prng->i] = sj;
+        prng->sbox[prng->j] = si;
+        *destByte++ = prng->sbox[(si + sj) & 0xff];
+    }
+}
+
+/* Re-seed the generator with user-provided bytes */
+static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen)
+{
+    int i;
+    Jim_PrngState *prng;
+
+    /* initialization, only needed the first time */
+    if (interp->prngState == NULL)
+        JimPrngInit(interp);
+    prng = interp->prngState;
+
+    /* Set the sbox[i] with i */
+    for (i = 0; i < 256; i++)
+        prng->sbox[i] = i;
+    /* Now use the seed to perform a random permutation of the sbox */
+    for (i = 0; i < seedLen; i++) {
+        unsigned char t;
+
+        t = prng->sbox[i & 0xFF];
+        prng->sbox[i & 0xFF] = prng->sbox[seed[i]];
+        prng->sbox[seed[i]] = t;
+    }
+    prng->i = prng->j = 0;
+
+    /* discard at least the first 256 bytes of stream.
+     * borrow the seed buffer for this
+     */
+    for (i = 0; i < 256; i += seedLen) {
+        JimRandomBytes(interp, seed, seedLen);
+    }
+}
+
+/* [incr] */
+static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    jim_wide wideValue, increment = 1;
+    Jim_Obj *intObjPtr;
+
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "varName ?increment?");
+        return JIM_ERR;
+    }
+    if (argc == 3) {
+        if (Jim_GetWide(interp, argv[2], &increment) != JIM_OK)
+            return JIM_ERR;
+    }
+    intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
+    if (!intObjPtr) {
+        /* Set missing variable to 0 */
+        wideValue = 0;
+    }
+    else if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK) {
+        return JIM_ERR;
+    }
+    if (!intObjPtr || Jim_IsShared(intObjPtr)) {
+        intObjPtr = Jim_NewIntObj(interp, wideValue + increment);
+        if (Jim_SetVariable(interp, argv[1], intObjPtr) != JIM_OK) {
+            Jim_FreeNewObj(interp, intObjPtr);
+            return JIM_ERR;
+        }
+    }
+    else {
+        /* Can do it the quick way */
+        Jim_InvalidateStringRep(intObjPtr);
+        JimWideValue(intObjPtr) = wideValue + increment;
+
+        /* The following step is required in order to invalidate the
+         * string repr of "FOO" if the var name is on the form of "FOO(IDX)" */
+        if (argv[1]->typePtr != &variableObjType) {
+            /* Note that this can't fail since GetVariable already succeeded */
+            Jim_SetVariable(interp, argv[1], intObjPtr);
+        }
+    }
+    Jim_SetResult(interp, intObjPtr);
+    return JIM_OK;
+}
+
+
+/* -----------------------------------------------------------------------------
+ * Eval
+ * ---------------------------------------------------------------------------*/
+#define JIM_EVAL_SARGV_LEN 8    /* static arguments vector length */
+#define JIM_EVAL_SINTV_LEN 8    /* static interpolation vector length */
+
+/* Handle calls to the [unknown] command */
+static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv, Jim_Obj *fileNameObj,
+    int linenr)
+{
+    Jim_Obj **v, *sv[JIM_EVAL_SARGV_LEN];
+    int retCode;
+
+    /* If JimUnknown() is recursively called too many times...
+     * done here
+     */
+    if (interp->unknown_called > 50) {
+        return JIM_ERR;
+    }
+
+    /* If the [unknown] command does not exists returns
+     * just now */
+    if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL)
+        return JIM_ERR;
+
+    /* The object interp->unknown just contains
+     * the "unknown" string, it is used in order to
+     * avoid to lookup the unknown command every time
+     * but instread to cache the result. */
+    if (argc + 1 <= JIM_EVAL_SARGV_LEN)
+        v = sv;
+    else
+        v = Jim_Alloc(sizeof(Jim_Obj *) * (argc + 1));
+    /* Make a copy of the arguments vector, but shifted on
+     * the right of one position. The command name of the
+     * command will be instead the first argument of the
+     * [unknown] call. */
+    memcpy(v + 1, argv, sizeof(Jim_Obj *) * argc);
+    v[0] = interp->unknown;
+    /* Call it */
+    interp->unknown_called++;
+    retCode = JimEvalObjVector(interp, argc + 1, v, fileNameObj, linenr);
+    interp->unknown_called--;
+
+    /* Clean up */
+    if (v != sv)
+        Jim_Free(v);
+    return retCode;
+}
+
+/* Eval the object vector 'objv' composed of 'objc' elements.
+ * Every element is used as single argument.
+ * Jim_EvalObj() will call this function every time its object
+ * argument is of "list" type, with no string representation.
+ *
+ * This is possible because the string representation of a
+ * list object generated by the UpdateStringOfList is made
+ * in a way that ensures that every list element is a different
+ * command argument. */
+static int JimEvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv,
+    Jim_Obj *fileNameObj, int linenr)
+{
+    int i, retcode;
+    Jim_Cmd *cmdPtr;
+
+    /* Incr refcount of arguments. */
+    for (i = 0; i < objc; i++)
+        Jim_IncrRefCount(objv[i]);
+    /* Command lookup */
+    cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
+    if (cmdPtr == NULL) {
+        retcode = JimUnknown(interp, objc, objv, fileNameObj, linenr);
+    }
+    else {
+        /* Call it -- Make sure result is an empty object. */
+        JimIncrCmdRefCount(cmdPtr);
+        Jim_SetEmptyResult(interp);
+        if (cmdPtr->isproc) {
+            retcode = JimCallProcedure(interp, cmdPtr, fileNameObj, linenr, objc, objv);
+        }
+        else {
+            interp->cmdPrivData = cmdPtr->u.native.privData;
+            retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
+        }
+        JimDecrCmdRefCount(interp, cmdPtr);
+    }
+    /* Decr refcount of arguments and return the retcode */
+    for (i = 0; i < objc; i++)
+        Jim_DecrRefCount(interp, objv[i]);
+
+    return retcode;
+}
+
+int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
+{
+    return JimEvalObjVector(interp, objc, objv, interp->emptyObj, 1);
+}
+
+/**
+ * Invokes 'prefix' as a command with the objv array as arguments.
+ */
+int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *const *objv)
+{
+    int i;
+    int ret;
+    Jim_Obj **nargv = Jim_Alloc((objc + 1) * sizeof(*nargv));
+
+    nargv[0] = prefix;
+    for (i = 0; i < objc; i++) {
+        nargv[i + 1] = objv[i];
+    }
+    ret = Jim_EvalObjVector(interp, objc + 1, nargv);
+    Jim_Free(nargv);
+    return ret;
+}
+
+static void JimAddErrorToStack(Jim_Interp *interp, int retcode, Jim_Obj *fileNameObj, int line)
+{
+    int rc = retcode;
+
+    if (rc == JIM_ERR && !interp->errorFlag) {
+        /* This is the first error, so save the file/line information and reset the stack */
+        interp->errorFlag = 1;
+        Jim_IncrRefCount(fileNameObj);
+        Jim_DecrRefCount(interp, interp->errorFileNameObj);
+        interp->errorFileNameObj = fileNameObj;
+        interp->errorLine = line;
+
+        JimResetStackTrace(interp);
+        /* Always add a level where the error first occurs */
+        interp->addStackTrace++;
+    }
+
+    /* Now if this is an "interesting" level, add it to the stack trace */
+    if (rc == JIM_ERR && interp->addStackTrace > 0) {
+        /* Add the stack info for the current level */
+
+        JimAppendStackTrace(interp, Jim_String(interp->errorProc), fileNameObj, line);
+
+        /* Note: if we didn't have a filename for this level,
+         * don't clear the addStackTrace flag
+         * so we can pick it up at the next level
+         */
+        if (Jim_Length(fileNameObj)) {
+            interp->addStackTrace = 0;
+        }
+
+        Jim_DecrRefCount(interp, interp->errorProc);
+        interp->errorProc = interp->emptyObj;
+        Jim_IncrRefCount(interp->errorProc);
+    }
+    else if (rc == JIM_RETURN && interp->returnCode == JIM_ERR) {
+        /* Propagate the addStackTrace value through 'return -code error' */
+    }
+    else {
+        interp->addStackTrace = 0;
+    }
+}
+
+/* And delete any local procs */
+static void JimDeleteLocalProcs(Jim_Interp *interp)
+{
+    if (interp->localProcs) {
+        char *procname;
+
+        while ((procname = Jim_StackPop(interp->localProcs)) != NULL) {
+            /* If there is a pushed command, find it */
+            Jim_Cmd *prevCmd = NULL;
+            Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, procname);
+            if (he) {
+                Jim_Cmd *cmd = (Jim_Cmd *)he->u.val;
+                if (cmd->isproc && cmd->u.proc.prevCmd) {
+                    prevCmd = cmd->u.proc.prevCmd;
+                    cmd->u.proc.prevCmd = NULL;
+                }
+            }
+
+            /* Delete the local proc */
+            Jim_DeleteCommand(interp, procname);
+
+            if (prevCmd) {
+                /* And restore the pushed command */
+                Jim_AddHashEntry(&interp->commands, procname, prevCmd);
+            }
+            Jim_Free(procname);
+        }
+        Jim_FreeStack(interp->localProcs);
+        Jim_Free(interp->localProcs);
+        interp->localProcs = NULL;
+    }
+}
+
+static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Obj **objPtrPtr)
+{
+    Jim_Obj *objPtr;
+
+    switch (token->type) {
+        case JIM_TT_STR:
+        case JIM_TT_ESC:
+            objPtr = token->objPtr;
+            break;
+        case JIM_TT_VAR:
+            objPtr = Jim_GetVariable(interp, token->objPtr, JIM_ERRMSG);
+            break;
+        case JIM_TT_DICTSUGAR:
+            objPtr = JimExpandDictSugar(interp, token->objPtr);
+            break;
+        case JIM_TT_EXPRSUGAR:
+            objPtr = JimExpandExprSugar(interp, token->objPtr);
+            break;
+        case JIM_TT_CMD:
+            switch (Jim_EvalObj(interp, token->objPtr)) {
+                case JIM_OK:
+                case JIM_RETURN:
+                    objPtr = interp->result;
+                    break;
+                case JIM_BREAK:
+                    /* Stop substituting */
+                    return JIM_BREAK;
+                case JIM_CONTINUE:
+                    /* just skip this one */
+                    return JIM_CONTINUE;
+                default:
+                    return JIM_ERR;
+            }
+            break;
+        default:
+            JimPanic((1,
+                "default token type (%d) reached " "in Jim_SubstObj().", token->type));
+            objPtr = NULL;
+            break;
+    }
+    if (objPtr) {
+        *objPtrPtr = objPtr;
+        return JIM_OK;
+    }
+    return JIM_ERR;
+}
+
+/* Interpolate the given tokens into a unique Jim_Obj returned by reference
+ * via *objPtrPtr. This function is only called by Jim_EvalObj() and Jim_SubstObj()
+ * The returned object has refcount = 0.
+ */
+static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * token, int tokens, int flags)
+{
+    int totlen = 0, i;
+    Jim_Obj **intv;
+    Jim_Obj *sintv[JIM_EVAL_SINTV_LEN];
+    Jim_Obj *objPtr;
+    char *s;
+
+    if (tokens <= JIM_EVAL_SINTV_LEN)
+        intv = sintv;
+    else
+        intv = Jim_Alloc(sizeof(Jim_Obj *) * tokens);
+
+    /* Compute every token forming the argument
+     * in the intv objects vector. */
+    for (i = 0; i < tokens; i++) {
+        switch (JimSubstOneToken(interp, &token[i], &intv[i])) {
+            case JIM_OK:
+            case JIM_RETURN:
+                break;
+            case JIM_BREAK:
+                if (flags & JIM_SUBST_FLAG) {
+                    /* Stop here */
+                    tokens = i;
+                    continue;
+                }
+                /* XXX: Should probably set an error about break outside loop */
+                /* fall through to error */
+            case JIM_CONTINUE:
+                if (flags & JIM_SUBST_FLAG) {
+                    intv[i] = NULL;
+                    continue;
+                }
+                /* XXX: Ditto continue outside loop */
+                /* fall through to error */
+            default:
+                while (i--) {
+                    Jim_DecrRefCount(interp, intv[i]);
+                }
+                if (intv != sintv) {
+                    Jim_Free(intv);
+                }
+                return NULL;
+        }
+        Jim_IncrRefCount(intv[i]);
+        Jim_String(intv[i]);
+        totlen += intv[i]->length;
+    }
+
+    /* Fast path return for a single token */
+    if (tokens == 1 && intv[0] && intv == sintv) {
+        Jim_DecrRefCount(interp, intv[0]);
+        return intv[0];
+    }
+
+    /* Concatenate every token in an unique
+     * object. */
+    objPtr = Jim_NewStringObjNoAlloc(interp, NULL, 0);
+
+    if (tokens == 4 && token[0].type == JIM_TT_ESC && token[1].type == JIM_TT_ESC
+        && token[2].type == JIM_TT_VAR) {
+        /* May be able to do fast interpolated object -> dictSubst */
+        objPtr->typePtr = &interpolatedObjType;
+        objPtr->internalRep.twoPtrValue.ptr1 = (void *)token;
+        objPtr->internalRep.twoPtrValue.ptr2 = intv[2];
+        Jim_IncrRefCount(intv[2]);
+    }
+
+    s = objPtr->bytes = Jim_Alloc(totlen + 1);
+    objPtr->length = totlen;
+    for (i = 0; i < tokens; i++) {
+        if (intv[i]) {
+            memcpy(s, intv[i]->bytes, intv[i]->length);
+            s += intv[i]->length;
+            Jim_DecrRefCount(interp, intv[i]);
+        }
+    }
+    objPtr->bytes[totlen] = '\0';
+    /* Free the intv vector if not static. */
+    if (intv != sintv) {
+        Jim_Free(intv);
+    }
+
+    return objPtr;
+}
+
+
+/* If listPtr is a list, call JimEvalObjVector() with the given source info.
+ * Otherwise eval with Jim_EvalObj()
+ */
+static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *fileNameObj, int linenr)
+{
+    if (!Jim_IsList(listPtr)) {
+        return Jim_EvalObj(interp, listPtr);
+    }
+    else {
+        int retcode = JIM_OK;
+
+        if (listPtr->internalRep.listValue.len) {
+            Jim_IncrRefCount(listPtr);
+            retcode = JimEvalObjVector(interp,
+                listPtr->internalRep.listValue.len,
+                listPtr->internalRep.listValue.ele, fileNameObj, linenr);
+            Jim_DecrRefCount(interp, listPtr);
+        }
+        return retcode;
+    }
+}
+
+int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
+{
+    int i;
+    ScriptObj *script;
+    ScriptToken *token;
+    int retcode = JIM_OK;
+    Jim_Obj *sargv[JIM_EVAL_SARGV_LEN], **argv = NULL;
+    int linenr = 0;
+
+    interp->errorFlag = 0;
+
+    /* If the object is of type "list", with no string rep we can call
+     * a specialized version of Jim_EvalObj() */
+    if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) {
+        return JimEvalObjList(interp, scriptObjPtr, interp->emptyObj, 1);
+    }
+
+    Jim_IncrRefCount(scriptObjPtr);     /* Make sure it's shared. */
+    script = Jim_GetScript(interp, scriptObjPtr);
+
+    /* Reset the interpreter result. This is useful to
+     * return the empty result in the case of empty program. */
+    Jim_SetEmptyResult(interp);
+
+#ifdef JIM_OPTIMIZATION
+    /* Check for one of the following common scripts used by for, while
+     *
+     *   {}
+     *   incr a
+     */
+    if (script->len == 0) {
+        Jim_DecrRefCount(interp, scriptObjPtr);
+        return JIM_OK;
+    }
+    if (script->len == 3
+        && script->token[1].objPtr->typePtr == &commandObjType
+        && script->token[1].objPtr->internalRep.cmdValue.cmdPtr->isproc == 0
+        && script->token[1].objPtr->internalRep.cmdValue.cmdPtr->u.native.cmdProc == Jim_IncrCoreCommand
+        && script->token[2].objPtr->typePtr == &variableObjType) {
+
+        Jim_Obj *objPtr = Jim_GetVariable(interp, script->token[2].objPtr, JIM_NONE);
+
+        if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
+            JimWideValue(objPtr)++;
+            Jim_InvalidateStringRep(objPtr);
+            Jim_DecrRefCount(interp, scriptObjPtr);
+            Jim_SetResult(interp, objPtr);
+            return JIM_OK;
+        }
+    }
+#endif
+
+    /* Now we have to make sure the internal repr will not be
+     * freed on shimmering.
+     *
+     * Think for example to this:
+     *
+     * set x {llength $x; ... some more code ...}; eval $x
+     *
+     * In order to preserve the internal rep, we increment the
+     * inUse field of the script internal rep structure. */
+    script->inUse++;
+
+    token = script->token;
+    argv = sargv;
+
+    /* Execute every command sequentially until the end of the script
+     * or an error occurs.
+     */
+    for (i = 0; i < script->len && retcode == JIM_OK; ) {
+        int argc;
+        int j;
+        Jim_Cmd *cmd;
+
+        /* First token of the line is always JIM_TT_LINE */
+        argc = token[i].objPtr->internalRep.scriptLineValue.argc;
+        linenr = token[i].objPtr->internalRep.scriptLineValue.line;
+
+        /* Allocate the arguments vector if required */
+        if (argc > JIM_EVAL_SARGV_LEN)
+            argv = Jim_Alloc(sizeof(Jim_Obj *) * argc);
+
+        /* Skip the JIM_TT_LINE token */
+        i++;
+
+        /* Populate the arguments objects.
+         * If an error occurs, retcode will be set and
+         * 'j' will be set to the number of args expanded
+         */
+        for (j = 0; j < argc; j++) {
+            long wordtokens = 1;
+            int expand = 0;
+            Jim_Obj *wordObjPtr = NULL;
+
+            if (token[i].type == JIM_TT_WORD) {
+                wordtokens = JimWideValue(token[i++].objPtr);
+                if (wordtokens < 0) {
+                    expand = 1;
+                    wordtokens = -wordtokens;
+                }
+            }
+
+            if (wordtokens == 1) {
+                /* Fast path if the token does not
+                 * need interpolation */
+
+                switch (token[i].type) {
+                    case JIM_TT_ESC:
+                    case JIM_TT_STR:
+                        wordObjPtr = token[i].objPtr;
+                        break;
+                    case JIM_TT_VAR:
+                        wordObjPtr = Jim_GetVariable(interp, token[i].objPtr, JIM_ERRMSG);
+                        break;
+                    case JIM_TT_EXPRSUGAR:
+                        wordObjPtr = JimExpandExprSugar(interp, token[i].objPtr);
+                        break;
+                    case JIM_TT_DICTSUGAR:
+                        wordObjPtr = JimExpandDictSugar(interp, token[i].objPtr);
+                        break;
+                    case JIM_TT_CMD:
+                        retcode = Jim_EvalObj(interp, token[i].objPtr);
+                        if (retcode == JIM_OK) {
+                            wordObjPtr = Jim_GetResult(interp);
+                        }
+                        break;
+                    default:
+                        JimPanic((1, "default token type reached " "in Jim_EvalObj()."));
+                }
+            }
+            else {
+                /* For interpolation we call a helper
+                 * function to do the work for us. */
+                wordObjPtr = JimInterpolateTokens(interp, token + i, wordtokens, JIM_NONE);
+            }
+
+            if (!wordObjPtr) {
+                if (retcode == JIM_OK) {
+                    retcode = JIM_ERR;
+                }
+                break;
+            }
+
+            Jim_IncrRefCount(wordObjPtr);
+            i += wordtokens;
+
+            if (!expand) {
+                argv[j] = wordObjPtr;
+            }
+            else {
+                /* Need to expand wordObjPtr into multiple args from argv[j] ... */
+                int len = Jim_ListLength(interp, wordObjPtr);
+                int newargc = argc + len - 1;
+                int k;
+
+                if (len > 1) {
+                    if (argv == sargv) {
+                        if (newargc > JIM_EVAL_SARGV_LEN) {
+                            argv = Jim_Alloc(sizeof(*argv) * newargc);
+                            memcpy(argv, sargv, sizeof(*argv) * j);
+                        }
+                    }
+                    else {
+                        /* Need to realloc to make room for (len - 1) more entries */
+                        argv = Jim_Realloc(argv, sizeof(*argv) * newargc);
+                    }
+                }
+
+                /* Now copy in the expanded version */
+                for (k = 0; k < len; k++) {
+                    argv[j++] = wordObjPtr->internalRep.listValue.ele[k];
+                    Jim_IncrRefCount(wordObjPtr->internalRep.listValue.ele[k]);
+                }
+
+                /* The original object reference is no longer needed,
+                 * after the expansion it is no longer present on
+                 * the argument vector, but the single elements are
+                 * in its place. */
+                Jim_DecrRefCount(interp, wordObjPtr);
+
+                /* And update the indexes */
+                j--;
+                argc += len - 1;
+            }
+        }
+
+        if (retcode == JIM_OK && argc) {
+            /* Lookup the command to call */
+            cmd = Jim_GetCommand(interp, argv[0], JIM_ERRMSG);
+            if (cmd != NULL) {
+                /* Call it -- Make sure result is an empty object. */
+                JimIncrCmdRefCount(cmd);
+                Jim_SetEmptyResult(interp);
+                if (cmd->isproc) {
+                    retcode =
+                        JimCallProcedure(interp, cmd, script->fileNameObj, linenr, argc, argv);
+                } else {
+                    interp->cmdPrivData = cmd->u.native.privData;
+                    retcode = cmd->u.native.cmdProc(interp, argc, argv);
+                }
+                JimDecrCmdRefCount(interp, cmd);
+            }
+            else {
+                /* Call [unknown] */
+                retcode = JimUnknown(interp, argc, argv, script->fileNameObj, linenr);
+            }
+            if (interp->signal_level && interp->sigmask) {
+                /* Check for a signal after each command */
+                retcode = JIM_SIGNAL;
+            }
+        }
+
+        /* Finished with the command, so decrement ref counts of each argument */
+        while (j-- > 0) {
+            Jim_DecrRefCount(interp, argv[j]);
+        }
+
+        if (argv != sargv) {
+            Jim_Free(argv);
+            argv = sargv;
+        }
+    }
+
+    /* Possibly add to the error stack trace */
+    JimAddErrorToStack(interp, retcode, script->fileNameObj, linenr);
+
+    /* Note that we don't have to decrement inUse, because the
+     * following code transfers our use of the reference again to
+     * the script object. */
+    Jim_FreeIntRep(interp, scriptObjPtr);
+    scriptObjPtr->typePtr = &scriptObjType;
+    Jim_SetIntRepPtr(scriptObjPtr, script);
+    Jim_DecrRefCount(interp, scriptObjPtr);
+
+    return retcode;
+}
+
+static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argValObj)
+{
+    int retcode;
+    /* If argObjPtr begins with '&', do an automatic upvar */
+    const char *varname = Jim_String(argNameObj);
+    if (*varname == '&') {
+        /* First check that the target variable exists */
+        Jim_Obj *objPtr;
+        Jim_CallFrame *savedCallFrame = interp->framePtr;
+
+        interp->framePtr = interp->framePtr->parentCallFrame;
+        objPtr = Jim_GetVariable(interp, argValObj, JIM_ERRMSG);
+        interp->framePtr = savedCallFrame;
+        if (!objPtr) {
+            return JIM_ERR;
+        }
+
+        /* It exists, so perform the binding. */
+        objPtr = Jim_NewStringObj(interp, varname + 1, -1);
+        Jim_IncrRefCount(objPtr);
+        retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parentCallFrame);
+        Jim_DecrRefCount(interp, objPtr);
+    }
+    else {
+        retcode = Jim_SetVariable(interp, argNameObj, argValObj);
+    }
+    return retcode;
+}
+
+/**
+ * Sets the interp result to be an error message indicating the required proc args.
+ */
+static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cmd *cmd)
+{
+    /* Create a nice error message, consistent with Tcl 8.5 */
+    Jim_Obj *argmsg = Jim_NewStringObj(interp, "", 0);
+    int i;
+
+    for (i = 0; i < cmd->u.proc.argListLen; i++) {
+        Jim_AppendString(interp, argmsg, " ", 1);
+
+        if (i == cmd->u.proc.argsPos) {
+            if (cmd->u.proc.arglist[i].defaultObjPtr) {
+                /* Renamed args */
+                Jim_AppendString(interp, argmsg, "?", 1);
+                Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].defaultObjPtr);
+                Jim_AppendString(interp, argmsg, " ...?", -1);
+            }
+            else {
+                /* We have plain args */
+                Jim_AppendString(interp, argmsg, "?argument ...?", -1);
+            }
+        }
+        else {
+            if (cmd->u.proc.arglist[i].defaultObjPtr) {
+                Jim_AppendString(interp, argmsg, "?", 1);
+                Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].nameObjPtr);
+                Jim_AppendString(interp, argmsg, "?", 1);
+            }
+            else {
+                Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].nameObjPtr);
+            }
+        }
+    }
+    Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s%#s\"", procNameObj, argmsg);
+    Jim_FreeNewObj(interp, argmsg);
+}
+
+/* Call a procedure implemented in Tcl.
+ * It's possible to speed-up a lot this function, currently
+ * the callframes are not cached, but allocated and
+ * destroied every time. What is expecially costly is
+ * to create/destroy the local vars hash table every time.
+ *
+ * This can be fixed just implementing callframes caching
+ * in JimCreateCallFrame() and JimFreeCallFrame(). */
+static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, Jim_Obj *fileNameObj, int linenr, int argc,
+    Jim_Obj *const *argv)
+{
+    Jim_CallFrame *callFramePtr;
+    Jim_Stack *prevLocalProcs;
+    int i, d, retcode, optargs;
+
+    /* Check arity */
+    if (argc - 1 < cmd->u.proc.reqArity ||
+        (cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) {
+        JimSetProcWrongArgs(interp, argv[0], cmd);
+        return JIM_ERR;
+    }
+
+    /* Check if there are too nested calls */
+    if (interp->framePtr->level == interp->maxNestingDepth) {
+        Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
+        return JIM_ERR;
+    }
+
+    /* Create a new callframe */
+    callFramePtr = JimCreateCallFrame(interp, interp->framePtr);
+    callFramePtr->argv = argv;
+    callFramePtr->argc = argc;
+    callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr;
+    callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr;
+    callFramePtr->staticVars = cmd->u.proc.staticVars;
+    callFramePtr->fileNameObj = fileNameObj;
+    callFramePtr->line = linenr;
+    Jim_IncrRefCount(cmd->u.proc.argListObjPtr);
+    Jim_IncrRefCount(cmd->u.proc.bodyObjPtr);
+    interp->framePtr = callFramePtr;
+
+    /* How many optional args are available */
+    optargs = (argc - 1 - cmd->u.proc.reqArity);
+
+    /* Step 'i' along the actual args, and step 'd' along the formal args */
+    i = 1;
+    for (d = 0; d < cmd->u.proc.argListLen; d++) {
+        Jim_Obj *nameObjPtr = cmd->u.proc.arglist[d].nameObjPtr;
+        if (d == cmd->u.proc.argsPos) {
+            /* assign $args */
+            Jim_Obj *listObjPtr;
+            int argsLen = 0;
+            if (cmd->u.proc.reqArity + cmd->u.proc.optArity < argc - 1) {
+                argsLen = argc - 1 - (cmd->u.proc.reqArity + cmd->u.proc.optArity);
+            }
+            listObjPtr = Jim_NewListObj(interp, &argv[i], argsLen);
+
+            /* It is possible to rename args. */
+            if (cmd->u.proc.arglist[d].defaultObjPtr) {
+                nameObjPtr =cmd->u.proc.arglist[d].defaultObjPtr;
+            }
+            retcode = Jim_SetVariable(interp, nameObjPtr, listObjPtr);
+            if (retcode != JIM_OK) {
+                goto badargset;
+            }
+
+            i += argsLen;
+            continue;
+        }
+
+        /* Optional or required? */
+        if (cmd->u.proc.arglist[d].defaultObjPtr == NULL || optargs-- > 0) {
+            retcode = JimSetProcArg(interp, nameObjPtr, argv[i++]);
+        }
+        else {
+            /* Ran out, so use the default */
+            retcode = Jim_SetVariable(interp, nameObjPtr, cmd->u.proc.arglist[d].defaultObjPtr);
+        }
+        if (retcode != JIM_OK) {
+            goto badargset;
+        }
+    }
+
+    /* Install a new stack for local procs */
+    prevLocalProcs = interp->localProcs;
+    interp->localProcs = NULL;
+
+    /* Eval the body */
+    retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr);
+
+    /* Delete any local procs */
+    JimDeleteLocalProcs(interp);
+    interp->localProcs = prevLocalProcs;
+
+badargset:
+    /* Destroy the callframe */
+    interp->framePtr = interp->framePtr->parentCallFrame;
+    if (callFramePtr->vars.size != JIM_HT_INITIAL_SIZE) {
+        JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NONE);
+    }
+    else {
+        JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NOHT);
+    }
+    /* Handle the JIM_EVAL return code */
+    while (retcode == JIM_EVAL) {
+        Jim_Obj *resultScriptObjPtr = Jim_GetResult(interp);
+
+        Jim_IncrRefCount(resultScriptObjPtr);
+        /* Should be a list! */
+        retcode = JimEvalObjList(interp, resultScriptObjPtr, fileNameObj, linenr);
+        Jim_DecrRefCount(interp, resultScriptObjPtr);
+    }
+    /* Handle the JIM_RETURN return code */
+    if (retcode == JIM_RETURN) {
+        if (--interp->returnLevel <= 0) {
+            retcode = interp->returnCode;
+            interp->returnCode = JIM_OK;
+            interp->returnLevel = 0;
+        }
+    }
+    else if (retcode == JIM_ERR) {
+        interp->addStackTrace++;
+        Jim_DecrRefCount(interp, interp->errorProc);
+        interp->errorProc = argv[0];
+        Jim_IncrRefCount(interp->errorProc);
+    }
+    return retcode;
+}
+
+int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script)
+{
+    int retval;
+    Jim_Obj *scriptObjPtr;
+
+    scriptObjPtr = Jim_NewStringObj(interp, script, -1);
+    Jim_IncrRefCount(scriptObjPtr);
+
+    if (filename) {
+        Jim_Obj *prevScriptObj;
+
+        JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
+
+        prevScriptObj = interp->currentScriptObj;
+        interp->currentScriptObj = scriptObjPtr;
+
+        retval = Jim_EvalObj(interp, scriptObjPtr);
+
+        interp->currentScriptObj = prevScriptObj;
+    }
+    else {
+        retval = Jim_EvalObj(interp, scriptObjPtr);
+    }
+    Jim_DecrRefCount(interp, scriptObjPtr);
+    return retval;
+}
+
+int Jim_Eval(Jim_Interp *interp, const char *script)
+{
+    return Jim_EvalObj(interp, Jim_NewStringObj(interp, script, -1));
+}
+
+/* Execute script in the scope of the global level */
+int Jim_EvalGlobal(Jim_Interp *interp, const char *script)
+{
+    int retval;
+    Jim_CallFrame *savedFramePtr = interp->framePtr;
+
+    interp->framePtr = interp->topFramePtr;
+    retval = Jim_Eval(interp, script);
+    interp->framePtr = savedFramePtr;
+
+    return retval;
+}
+
+int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename)
+{
+    int retval;
+    Jim_CallFrame *savedFramePtr = interp->framePtr;
+
+    interp->framePtr = interp->topFramePtr;
+    retval = Jim_EvalFile(interp, filename);
+    interp->framePtr = savedFramePtr;
+
+    return retval;
+}
+
+#include <sys/stat.h>
+
+int Jim_EvalFile(Jim_Interp *interp, const char *filename)
+{
+    FILE *fp;
+    char *buf;
+    Jim_Obj *scriptObjPtr;
+    Jim_Obj *prevScriptObj;
+    struct stat sb;
+    int retcode;
+    int readlen;
+    struct JimParseResult result;
+
+    if (stat(filename, &sb) != 0 || (fp = fopen(filename, "rt")) == NULL) {
+        Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", filename, strerror(errno));
+        return JIM_ERR;
+    }
+    if (sb.st_size == 0) {
+        fclose(fp);
+        return JIM_OK;
+    }
+
+    buf = Jim_Alloc(sb.st_size + 1);
+    readlen = fread(buf, 1, sb.st_size, fp);
+    if (ferror(fp)) {
+        fclose(fp);
+        Jim_Free(buf);
+        Jim_SetResultFormatted(interp, "failed to load file \"%s\": %s", filename, strerror(errno));
+        return JIM_ERR;
+    }
+    fclose(fp);
+    buf[readlen] = 0;
+
+    scriptObjPtr = Jim_NewStringObjNoAlloc(interp, buf, readlen);
+    JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), 1);
+    Jim_IncrRefCount(scriptObjPtr);
+
+    /* Now check the script for unmatched braces, etc. */
+    if (SetScriptFromAny(interp, scriptObjPtr, &result) == JIM_ERR) {
+        const char *msg;
+        char linebuf[20];
+
+        switch (result.missing) {
+            case '[':
+                msg = "unmatched \"[\"";
+                break;
+            case '{':
+                msg = "missing close-brace";
+                break;
+            case '"':
+            default:
+                msg = "missing quote";
+                break;
+        }
+
+        snprintf(linebuf, sizeof(linebuf), "%d", result.line);
+
+        Jim_SetResultFormatted(interp, "%s in \"%s\" at line %s",
+            msg, filename, linebuf);
+        Jim_DecrRefCount(interp, scriptObjPtr);
+        return JIM_ERR;
+    }
+
+    prevScriptObj = interp->currentScriptObj;
+    interp->currentScriptObj = scriptObjPtr;
+
+    retcode = Jim_EvalObj(interp, scriptObjPtr);
+
+    /* Handle the JIM_RETURN return code */
+    if (retcode == JIM_RETURN) {
+        if (--interp->returnLevel <= 0) {
+            retcode = interp->returnCode;
+            interp->returnCode = JIM_OK;
+            interp->returnLevel = 0;
+        }
+    }
+    if (retcode == JIM_ERR) {
+        /* EvalFile changes context, so add a stack frame here */
+        interp->addStackTrace++;
+    }
+
+    interp->currentScriptObj = prevScriptObj;
+
+    Jim_DecrRefCount(interp, scriptObjPtr);
+
+    return retcode;
+}
+
+/* -----------------------------------------------------------------------------
+ * Subst
+ * ---------------------------------------------------------------------------*/
+static int JimParseSubstStr(struct JimParserCtx *pc)
+{
+    pc->tstart = pc->p;
+    pc->tline = pc->linenr;
+    while (pc->len && *pc->p != '$' && *pc->p != '[') {
+        if (*pc->p == '\\' && pc->len > 1) {
+            pc->p++;
+            pc->len--;
+        }
+        pc->p++;
+        pc->len--;
+    }
+    pc->tend = pc->p - 1;
+    pc->tt = JIM_TT_ESC;
+    return JIM_OK;
+}
+
+static int JimParseSubst(struct JimParserCtx *pc, int flags)
+{
+    int retval;
+
+    if (pc->len == 0) {
+        pc->tstart = pc->tend = pc->p;
+        pc->tline = pc->linenr;
+        pc->tt = JIM_TT_EOL;
+        pc->eof = 1;
+        return JIM_OK;
+    }
+    switch (*pc->p) {
+        case '[':
+            retval = JimParseCmd(pc);
+            if (flags & JIM_SUBST_NOCMD) {
+                pc->tstart--;
+                pc->tend++;
+                pc->tt = (flags & JIM_SUBST_NOESC) ? JIM_TT_STR : JIM_TT_ESC;
+            }
+            return retval;
+            break;
+        case '$':
+            if (JimParseVar(pc) == JIM_ERR) {
+                pc->tstart = pc->tend = pc->p++;
+                pc->len--;
+                pc->tline = pc->linenr;
+                pc->tt = JIM_TT_STR;
+            }
+            else {
+                if (flags & JIM_SUBST_NOVAR) {
+                    pc->tstart--;
+                    if (flags & JIM_SUBST_NOESC)
+                        pc->tt = JIM_TT_STR;
+                    else
+                        pc->tt = JIM_TT_ESC;
+                    if (*pc->tstart == '{') {
+                        pc->tstart--;
+                        if (*(pc->tend + 1))
+                            pc->tend++;
+                    }
+                }
+            }
+            break;
+        default:
+            retval = JimParseSubstStr(pc);
+            if (flags & JIM_SUBST_NOESC)
+                pc->tt = JIM_TT_STR;
+            return retval;
+            break;
+    }
+    return JIM_OK;
+}
+
+/* The subst object type reuses most of the data structures and functions
+ * of the script object. Script's data structures are a bit more complex
+ * for what is needed for [subst]itution tasks, but the reuse helps to
+ * deal with a single data structure at the cost of some more memory
+ * usage for substitutions. */
+
+/* This method takes the string representation of an object
+ * as a Tcl string where to perform [subst]itution, and generates
+ * the pre-parsed internal representation. */
+static int SetSubstFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, int flags)
+{
+    int scriptTextLen;
+    const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
+    struct JimParserCtx parser;
+    struct ScriptObj *script = Jim_Alloc(sizeof(*script));
+    ParseTokenList tokenlist;
+
+    /* Initially parse the subst into tokens (in tokenlist) */
+    ScriptTokenListInit(&tokenlist);
+
+    JimParserInit(&parser, scriptText, scriptTextLen, 1);
+    while (1) {
+        JimParseSubst(&parser, flags);
+        if (parser.eof) {
+            /* Note that subst doesn't need the EOL token */
+            break;
+        }
+        ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
+            parser.tline);
+    }
+
+    /* Create the "real" subst/script tokens from the initial token list */
+    script->inUse = 1;
+    script->substFlags = flags;
+    script->fileNameObj = interp->emptyObj;
+    Jim_IncrRefCount(script->fileNameObj);
+    SubstObjAddTokens(interp, script, &tokenlist);
+
+    /* No longer need the token list */
+    ScriptTokenListFree(&tokenlist);
+
+#ifdef DEBUG_SHOW_SUBST
+    {
+        int i;
+
+        printf("==== Subst ====\n");
+        for (i = 0; i < script->len; i++) {
+            printf("[%2d] %s '%s'\n", i, jim_tt_name(script->token[i].type),
+                Jim_String(script->token[i].objPtr));
+        }
+    }
+#endif
+
+    /* Free the old internal rep and set the new one. */
+    Jim_FreeIntRep(interp, objPtr);
+    Jim_SetIntRepPtr(objPtr, script);
+    objPtr->typePtr = &scriptObjType;
+    return JIM_OK;
+}
+
+static ScriptObj *Jim_GetSubst(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+    if (objPtr->typePtr != &scriptObjType || ((ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags != flags)
+        SetSubstFromAny(interp, objPtr, flags);
+    return (ScriptObj *) Jim_GetIntRepPtr(objPtr);
+}
+
+/* Performs commands,variables,blackslashes substitution,
+ * storing the result object (with refcount 0) into
+ * resObjPtrPtr. */
+int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags)
+{
+    ScriptObj *script = Jim_GetSubst(interp, substObjPtr, flags);
+
+    Jim_IncrRefCount(substObjPtr);      /* Make sure it's shared. */
+    /* In order to preserve the internal rep, we increment the
+     * inUse field of the script internal rep structure. */
+    script->inUse++;
+
+    *resObjPtrPtr = JimInterpolateTokens(interp, script->token, script->len, flags);
+
+    script->inUse--;
+    Jim_DecrRefCount(interp, substObjPtr);
+    if (*resObjPtrPtr == NULL) {
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * Core commands utility functions
+ * ---------------------------------------------------------------------------*/
+void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg)
+{
+    int i;
+    Jim_Obj *objPtr = Jim_NewEmptyStringObj(interp);
+
+    Jim_AppendString(interp, objPtr, "wrong # args: should be \"", -1);
+    for (i = 0; i < argc; i++) {
+        Jim_AppendObj(interp, objPtr, argv[i]);
+        if (!(i + 1 == argc && msg[0] == '\0'))
+            Jim_AppendString(interp, objPtr, " ", 1);
+    }
+    Jim_AppendString(interp, objPtr, msg, -1);
+    Jim_AppendString(interp, objPtr, "\"", 1);
+    Jim_SetResult(interp, objPtr);
+}
+
+#define JimTrivialMatch(pattern)	(strpbrk((pattern), "*[?\\") == NULL)
+
+/* type is: 0=commands, 1=procs, 2=channels */
+static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int type)
+{
+    Jim_HashTableIterator *htiter;
+    Jim_HashEntry *he;
+    Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+    /* Check for the non-pattern case. We can do this much more efficiently. */
+    if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) {
+        Jim_Cmd *cmdPtr = Jim_GetCommand(interp, patternObjPtr, JIM_NONE);
+        if (cmdPtr) {
+            if (type == 1 && !cmdPtr->isproc) {
+                /* not a proc */
+            }
+            else if (type == 2 && !Jim_AioFilehandle(interp, patternObjPtr)) {
+                /* not a channel */
+            }
+            else {
+                Jim_ListAppendElement(interp, listObjPtr, patternObjPtr);
+            }
+        }
+        return listObjPtr;
+    }
+
+    htiter = Jim_GetHashTableIterator(&interp->commands);
+    while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+        Jim_Cmd *cmdPtr = he->u.val;
+        Jim_Obj *cmdNameObj;
+
+        if (type == 1 && !cmdPtr->isproc) {
+            /* not a proc */
+            continue;
+        }
+        if (patternObjPtr && !JimStringMatch(interp, patternObjPtr, he->key, 0))
+            continue;
+
+        cmdNameObj = Jim_NewStringObj(interp, he->key, -1);
+
+        /* Is it a channel? */
+        if (type == 2 && !Jim_AioFilehandle(interp, cmdNameObj)) {
+            Jim_FreeNewObj(interp, cmdNameObj);
+            continue;
+        }
+
+        Jim_ListAppendElement(interp, listObjPtr, cmdNameObj);
+    }
+    Jim_FreeHashTableIterator(htiter);
+    return listObjPtr;
+}
+
+/* Keep this in order */
+#define JIM_VARLIST_GLOBALS 0
+#define JIM_VARLIST_LOCALS 1
+#define JIM_VARLIST_VARS 2
+
+static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int mode)
+{
+    Jim_HashTableIterator *htiter;
+    Jim_HashEntry *he;
+    Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+    if (mode == JIM_VARLIST_GLOBALS) {
+        htiter = Jim_GetHashTableIterator(&interp->topFramePtr->vars);
+    }
+    else {
+        /* For [info locals], if we are at top level an emtpy list
+         * is returned. I don't agree, but we aim at compatibility (SS) */
+        if (mode == JIM_VARLIST_LOCALS && interp->framePtr == interp->topFramePtr)
+            return listObjPtr;
+        htiter = Jim_GetHashTableIterator(&interp->framePtr->vars);
+    }
+    while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+        Jim_Var *varPtr = (Jim_Var *)he->u.val;
+
+        if (mode == JIM_VARLIST_LOCALS) {
+            if (varPtr->linkFramePtr != NULL)
+                continue;
+        }
+        if (patternObjPtr && !JimStringMatch(interp, patternObjPtr, he->key, 0))
+            continue;
+        Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, he->key, -1));
+    }
+    Jim_FreeHashTableIterator(htiter);
+    return listObjPtr;
+}
+
+static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr,
+    Jim_Obj **objPtrPtr, int info_level_cmd)
+{
+    Jim_CallFrame *targetCallFrame;
+
+    targetCallFrame = JimGetCallFrameByInteger(interp, levelObjPtr);
+    if (targetCallFrame == NULL) {
+        return JIM_ERR;
+    }
+    /* No proc call at toplevel callframe */
+    if (targetCallFrame == interp->topFramePtr) {
+        Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
+        return JIM_ERR;
+    }
+    if (info_level_cmd) {
+        *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, targetCallFrame->argc);
+    }
+    else {
+        Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
+        Jim_ListAppendElement(interp, listObj, targetCallFrame->argv[0]);
+        Jim_ListAppendElement(interp, listObj, targetCallFrame->fileNameObj);
+        Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, targetCallFrame->line));
+        *objPtrPtr = listObj;
+    }
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * Core commands
+ * ---------------------------------------------------------------------------*/
+
+/* fake [puts] -- not the real puts, just for debugging. */
+static int Jim_PutsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "?-nonewline? string");
+        return JIM_ERR;
+    }
+    if (argc == 3) {
+        if (!Jim_CompareStringImmediate(interp, argv[1], "-nonewline")) {
+            Jim_SetResultString(interp, "The second argument must " "be -nonewline", -1);
+            return JIM_ERR;
+        }
+        else {
+            fputs(Jim_String(argv[2]), stdout);
+        }
+    }
+    else {
+        puts(Jim_String(argv[1]));
+    }
+    return JIM_OK;
+}
+
+/* Helper for [+] and [*] */
+static int JimAddMulHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
+{
+    jim_wide wideValue, res;
+    double doubleValue, doubleRes;
+    int i;
+
+    res = (op == JIM_EXPROP_ADD) ? 0 : 1;
+
+    for (i = 1; i < argc; i++) {
+        if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK)
+            goto trydouble;
+        if (op == JIM_EXPROP_ADD)
+            res += wideValue;
+        else
+            res *= wideValue;
+    }
+    Jim_SetResultInt(interp, res);
+    return JIM_OK;
+  trydouble:
+    doubleRes = (double)res;
+    for (; i < argc; i++) {
+        if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
+            return JIM_ERR;
+        if (op == JIM_EXPROP_ADD)
+            doubleRes += doubleValue;
+        else
+            doubleRes *= doubleValue;
+    }
+    Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+    return JIM_OK;
+}
+
+/* Helper for [-] and [/] */
+static int JimSubDivHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
+{
+    jim_wide wideValue, res = 0;
+    double doubleValue, doubleRes = 0;
+    int i = 2;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "number ?number ... number?");
+        return JIM_ERR;
+    }
+    else if (argc == 2) {
+        /* The arity = 2 case is different. For [- x] returns -x,
+         * while [/ x] returns 1/x. */
+        if (Jim_GetWide(interp, argv[1], &wideValue) != JIM_OK) {
+            if (Jim_GetDouble(interp, argv[1], &doubleValue) != JIM_OK) {
+                return JIM_ERR;
+            }
+            else {
+                if (op == JIM_EXPROP_SUB)
+                    doubleRes = -doubleValue;
+                else
+                    doubleRes = 1.0 / doubleValue;
+                Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+                return JIM_OK;
+            }
+        }
+        if (op == JIM_EXPROP_SUB) {
+            res = -wideValue;
+            Jim_SetResultInt(interp, res);
+        }
+        else {
+            doubleRes = 1.0 / wideValue;
+            Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+        }
+        return JIM_OK;
+    }
+    else {
+        if (Jim_GetWide(interp, argv[1], &res) != JIM_OK) {
+            if (Jim_GetDouble(interp, argv[1], &doubleRes)
+                != JIM_OK) {
+                return JIM_ERR;
+            }
+            else {
+                goto trydouble;
+            }
+        }
+    }
+    for (i = 2; i < argc; i++) {
+        if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK) {
+            doubleRes = (double)res;
+            goto trydouble;
+        }
+        if (op == JIM_EXPROP_SUB)
+            res -= wideValue;
+        else
+            res /= wideValue;
+    }
+    Jim_SetResultInt(interp, res);
+    return JIM_OK;
+  trydouble:
+    for (; i < argc; i++) {
+        if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
+            return JIM_ERR;
+        if (op == JIM_EXPROP_SUB)
+            doubleRes -= doubleValue;
+        else
+            doubleRes /= doubleValue;
+    }
+    Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+    return JIM_OK;
+}
+
+
+/* [+] */
+static int Jim_AddCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_ADD);
+}
+
+/* [*] */
+static int Jim_MulCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_MUL);
+}
+
+/* [-] */
+static int Jim_SubCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_SUB);
+}
+
+/* [/] */
+static int Jim_DivCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_DIV);
+}
+
+/* [set] */
+static int Jim_SetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "varName ?newValue?");
+        return JIM_ERR;
+    }
+    if (argc == 2) {
+        Jim_Obj *objPtr;
+
+        objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
+        if (!objPtr)
+            return JIM_ERR;
+        Jim_SetResult(interp, objPtr);
+        return JIM_OK;
+    }
+    /* argc == 3 case. */
+    if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
+        return JIM_ERR;
+    Jim_SetResult(interp, argv[2]);
+    return JIM_OK;
+}
+
+/* [unset]
+ *
+ * unset ?-nocomplain? ?--? ?varName ...?
+ */
+static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int i = 1;
+    int complain = 1;
+
+    while (i < argc) {
+        if (Jim_CompareStringImmediate(interp, argv[i], "--")) {
+            i++;
+            break;
+        }
+        if (Jim_CompareStringImmediate(interp, argv[i], "-nocomplain")) {
+            complain = 0;
+            i++;
+            continue;
+        }
+        break;
+    }
+
+    while (i < argc) {
+        if (Jim_UnsetVariable(interp, argv[i], complain ? JIM_ERRMSG : JIM_NONE) != JIM_OK
+            && complain) {
+            return JIM_ERR;
+        }
+        i++;
+    }
+    return JIM_OK;
+}
+
+/* [while] */
+static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "condition body");
+        return JIM_ERR;
+    }
+
+    /* The general purpose implementation of while starts here */
+    while (1) {
+        int boolean, retval;
+
+        if ((retval = Jim_GetBoolFromExpr(interp, argv[1], &boolean)) != JIM_OK)
+            return retval;
+        if (!boolean)
+            break;
+
+        if ((retval = Jim_EvalObj(interp, argv[2])) != JIM_OK) {
+            switch (retval) {
+                case JIM_BREAK:
+                    goto out;
+                    break;
+                case JIM_CONTINUE:
+                    continue;
+                    break;
+                default:
+                    return retval;
+            }
+        }
+    }
+  out:
+    Jim_SetEmptyResult(interp);
+    return JIM_OK;
+}
+
+/* [for] */
+static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int retval;
+    int boolean = 1;
+    Jim_Obj *varNamePtr = NULL;
+    Jim_Obj *stopVarNamePtr = NULL;
+
+    if (argc != 5) {
+        Jim_WrongNumArgs(interp, 1, argv, "start test next body");
+        return JIM_ERR;
+    }
+
+    /* Do the initialisation */
+    if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK) {
+        return retval;
+    }
+
+    /* And do the first test now. Better for optimisation
+     * if we can do next/test at the bottom of the loop
+     */
+    retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
+
+    /* Ready to do the body as follows:
+     * while (1) {
+     *     body // check retcode
+     *     next // check retcode
+     *     test // check retcode/test bool
+     * }
+     */
+
+#ifdef JIM_OPTIMIZATION
+    /* Check if the for is on the form:
+     *      for ... {$i < CONST} {incr i}
+     *      for ... {$i < $j} {incr i}
+     */
+    if (retval == JIM_OK && boolean) {
+        ScriptObj *incrScript;
+        ExprByteCode *expr;
+        jim_wide stop, currentVal;
+        unsigned jim_wide procEpoch;
+        Jim_Obj *objPtr;
+        int cmpOffset;
+
+        /* Do it only if there aren't shared arguments */
+        expr = JimGetExpression(interp, argv[2]);
+        incrScript = Jim_GetScript(interp, argv[3]);
+
+        /* Ensure proper lengths to start */
+        if (incrScript->len != 3 || !expr || expr->len != 3) {
+            goto evalstart;
+        }
+        /* Ensure proper token types. */
+        if (incrScript->token[1].type != JIM_TT_ESC ||
+            expr->token[0].type != JIM_TT_VAR ||
+            (expr->token[1].type != JIM_TT_EXPR_INT && expr->token[1].type != JIM_TT_VAR)) {
+            goto evalstart;
+        }
+
+        if (expr->token[2].type == JIM_EXPROP_LT) {
+            cmpOffset = 0;
+        }
+        else if (expr->token[2].type == JIM_EXPROP_LTE) {
+            cmpOffset = 1;
+        }
+        else {
+            goto evalstart;
+        }
+
+        /* Update command must be incr */
+        if (!Jim_CompareStringImmediate(interp, incrScript->token[1].objPtr, "incr")) {
+            goto evalstart;
+        }
+
+        /* incr, expression must be about the same variable */
+        if (!Jim_StringEqObj(incrScript->token[2].objPtr, expr->token[0].objPtr)) {
+            goto evalstart;
+        }
+
+        /* Get the stop condition (must be a variable or integer) */
+        if (expr->token[1].type == JIM_TT_EXPR_INT) {
+            if (Jim_GetWide(interp, expr->token[1].objPtr, &stop) == JIM_ERR) {
+                goto evalstart;
+            }
+        }
+        else {
+            stopVarNamePtr = expr->token[1].objPtr;
+            Jim_IncrRefCount(stopVarNamePtr);
+            /* Keep the compiler happy */
+            stop = 0;
+        }
+
+        /* Initialization */
+        procEpoch = interp->procEpoch;
+        varNamePtr = expr->token[0].objPtr;
+        Jim_IncrRefCount(varNamePtr);
+
+        objPtr = Jim_GetVariable(interp, varNamePtr, JIM_NONE);
+        if (objPtr == NULL || Jim_GetWide(interp, objPtr, &currentVal) != JIM_OK) {
+            goto testcond;
+        }
+
+        /* --- OPTIMIZED FOR --- */
+        while (retval == JIM_OK) {
+            /* === Check condition === */
+            /* Note that currentVal is already set here */
+
+            /* Immediate or Variable? get the 'stop' value if the latter. */
+            if (stopVarNamePtr) {
+                objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE);
+                if (objPtr == NULL || Jim_GetWide(interp, objPtr, &stop) != JIM_OK) {
+                    goto testcond;
+                }
+            }
+
+            if (currentVal >= stop + cmpOffset) {
+                break;
+            }
+
+            /* Eval body */
+            retval = Jim_EvalObj(interp, argv[4]);
+            if (retval == JIM_OK || retval == JIM_CONTINUE) {
+                retval = JIM_OK;
+                /* If there was a change in procedures/command continue
+                 * with the usual [for] command implementation */
+                if (procEpoch != interp->procEpoch) {
+                    goto evalnext;
+                }
+
+                objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
+
+                /* Increment */
+                if (objPtr == NULL) {
+                    retval = JIM_ERR;
+                    goto out;
+                }
+                if (!Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
+                    currentVal = ++JimWideValue(objPtr);
+                    Jim_InvalidateStringRep(objPtr);
+                }
+                else {
+                    if (Jim_GetWide(interp, objPtr, &currentVal) != JIM_OK ||
+                        Jim_SetVariable(interp, varNamePtr, Jim_NewIntObj(interp,
+                                ++currentVal)) != JIM_OK) {
+                        goto evalnext;
+                    }
+                }
+            }
+        }
+        goto out;
+    }
+  evalstart:
+#endif
+
+    while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) {
+        /* Body */
+        retval = Jim_EvalObj(interp, argv[4]);
+
+        if (retval == JIM_OK || retval == JIM_CONTINUE) {
+            /* increment */
+          evalnext:
+            retval = Jim_EvalObj(interp, argv[3]);
+            if (retval == JIM_OK || retval == JIM_CONTINUE) {
+                /* test */
+              testcond:
+                retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
+            }
+        }
+    }
+  out:
+    if (stopVarNamePtr) {
+        Jim_DecrRefCount(interp, stopVarNamePtr);
+    }
+    if (varNamePtr) {
+        Jim_DecrRefCount(interp, varNamePtr);
+    }
+
+    if (retval == JIM_CONTINUE || retval == JIM_BREAK || retval == JIM_OK) {
+        Jim_SetEmptyResult(interp);
+        return JIM_OK;
+    }
+
+    return retval;
+}
+
+/* [loop] */
+static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int retval;
+    jim_wide i;
+    jim_wide limit;
+    jim_wide incr = 1;
+    Jim_Obj *bodyObjPtr;
+
+    if (argc != 5 && argc != 6) {
+        Jim_WrongNumArgs(interp, 1, argv, "var first limit ?incr? body");
+        return JIM_ERR;
+    }
+
+    if (Jim_GetWide(interp, argv[2], &i) != JIM_OK ||
+        Jim_GetWide(interp, argv[3], &limit) != JIM_OK ||
+          (argc == 6 && Jim_GetWide(interp, argv[4], &incr) != JIM_OK)) {
+        return JIM_ERR;
+    }
+    bodyObjPtr = (argc == 5) ? argv[4] : argv[5];
+
+    retval = Jim_SetVariable(interp, argv[1], argv[2]);
+
+    while (((i < limit && incr > 0) || (i > limit && incr < 0)) && retval == JIM_OK) {
+        retval = Jim_EvalObj(interp, bodyObjPtr);
+        if (retval == JIM_OK || retval == JIM_CONTINUE) {
+            Jim_Obj *objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
+
+            retval = JIM_OK;
+
+            /* Increment */
+            i += incr;
+
+            if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
+                if (argv[1]->typePtr != &variableObjType) {
+                    if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
+                        return JIM_ERR;
+                    }
+                }
+                JimWideValue(objPtr) = i;
+                Jim_InvalidateStringRep(objPtr);
+
+                /* The following step is required in order to invalidate the
+                 * string repr of "FOO" if the var name is of the form of "FOO(IDX)" */
+                if (argv[1]->typePtr != &variableObjType) {
+                    if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
+                        retval = JIM_ERR;
+                        break;
+                    }
+                }
+            }
+            else {
+                objPtr = Jim_NewIntObj(interp, i);
+                retval = Jim_SetVariable(interp, argv[1], objPtr);
+                if (retval != JIM_OK) {
+                    Jim_FreeNewObj(interp, objPtr);
+                }
+            }
+        }
+    }
+
+    if (retval == JIM_OK || retval == JIM_CONTINUE || retval == JIM_BREAK) {
+        Jim_SetEmptyResult(interp);
+        return JIM_OK;
+    }
+    return retval;
+}
+
+/* foreach + lmap implementation. */
+static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap)
+{
+    int result = JIM_ERR, i, nbrOfLists, *listsIdx, *listsEnd;
+    int nbrOfLoops = 0;
+    Jim_Obj *emptyStr, *script, *mapRes = NULL;
+
+    if (argc < 4 || argc % 2 != 0) {
+        Jim_WrongNumArgs(interp, 1, argv, "varList list ?varList list ...? script");
+        return JIM_ERR;
+    }
+    if (doMap) {
+        mapRes = Jim_NewListObj(interp, NULL, 0);
+        Jim_IncrRefCount(mapRes);
+    }
+    emptyStr = Jim_NewEmptyStringObj(interp);
+    Jim_IncrRefCount(emptyStr);
+    script = argv[argc - 1];    /* Last argument is a script */
+    nbrOfLists = (argc - 1 - 1) / 2;    /* argc - 'foreach' - script */
+    listsIdx = (int *)Jim_Alloc(nbrOfLists * sizeof(int));
+    listsEnd = (int *)Jim_Alloc(nbrOfLists * 2 * sizeof(int));
+    /* Initialize iterators and remember max nbr elements each list */
+    memset(listsIdx, 0, nbrOfLists * sizeof(int));
+    /* Remember lengths of all lists and calculate how much rounds to loop */
+    for (i = 0; i < nbrOfLists * 2; i += 2) {
+        div_t cnt;
+        int count;
+
+        listsEnd[i] = Jim_ListLength(interp, argv[i + 1]);
+        listsEnd[i + 1] = Jim_ListLength(interp, argv[i + 2]);
+        if (listsEnd[i] == 0) {
+            Jim_SetResultString(interp, "foreach varlist is empty", -1);
+            goto err;
+        }
+        cnt = div(listsEnd[i + 1], listsEnd[i]);
+        count = cnt.quot + (cnt.rem ? 1 : 0);
+        if (count > nbrOfLoops)
+            nbrOfLoops = count;
+    }
+    for (; nbrOfLoops-- > 0;) {
+        for (i = 0; i < nbrOfLists; ++i) {
+            int varIdx = 0, var = i * 2;
+
+            while (varIdx < listsEnd[var]) {
+                Jim_Obj *varName, *ele;
+                int lst = i * 2 + 1;
+
+                /* List index operations below can't fail */
+                Jim_ListIndex(interp, argv[var + 1], varIdx, &varName, JIM_NONE);
+                if (listsIdx[i] < listsEnd[lst]) {
+                    Jim_ListIndex(interp, argv[lst + 1], listsIdx[i], &ele, JIM_NONE);
+                    /* Avoid shimmering */
+                    Jim_IncrRefCount(ele);
+                    result = Jim_SetVariable(interp, varName, ele);
+                    Jim_DecrRefCount(interp, ele);
+                    if (result == JIM_OK) {
+                        ++listsIdx[i];  /* Remember next iterator of current list */
+                        ++varIdx;       /* Next variable */
+                        continue;
+                    }
+                }
+                else if (Jim_SetVariable(interp, varName, emptyStr) == JIM_OK) {
+                    ++varIdx;   /* Next variable */
+                    continue;
+                }
+                goto err;
+            }
+        }
+        switch (result = Jim_EvalObj(interp, script)) {
+            case JIM_OK:
+                if (doMap)
+                    Jim_ListAppendElement(interp, mapRes, interp->result);
+                break;
+            case JIM_CONTINUE:
+                break;
+            case JIM_BREAK:
+                goto out;
+                break;
+            default:
+                goto err;
+        }
+    }
+  out:
+    result = JIM_OK;
+    if (doMap)
+        Jim_SetResult(interp, mapRes);
+    else
+        Jim_SetEmptyResult(interp);
+  err:
+    if (doMap)
+        Jim_DecrRefCount(interp, mapRes);
+    Jim_DecrRefCount(interp, emptyStr);
+    Jim_Free(listsIdx);
+    Jim_Free(listsEnd);
+    return result;
+}
+
+/* [foreach] */
+static int Jim_ForeachCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return JimForeachMapHelper(interp, argc, argv, 0);
+}
+
+/* [lmap] */
+static int Jim_LmapCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return JimForeachMapHelper(interp, argc, argv, 1);
+}
+
+/* [if] */
+static int Jim_IfCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int boolean, retval, current = 1, falsebody = 0;
+
+    if (argc >= 3) {
+        while (1) {
+            /* Far not enough arguments given! */
+            if (current >= argc)
+                goto err;
+            if ((retval = Jim_GetBoolFromExpr(interp, argv[current++], &boolean))
+                != JIM_OK)
+                return retval;
+            /* There lacks something, isn't it? */
+            if (current >= argc)
+                goto err;
+            if (Jim_CompareStringImmediate(interp, argv[current], "then"))
+                current++;
+            /* Tsk tsk, no then-clause? */
+            if (current >= argc)
+                goto err;
+            if (boolean)
+                return Jim_EvalObj(interp, argv[current]);
+            /* Ok: no else-clause follows */
+            if (++current >= argc) {
+                Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+                return JIM_OK;
+            }
+            falsebody = current++;
+            if (Jim_CompareStringImmediate(interp, argv[falsebody], "else")) {
+                /* IIICKS - else-clause isn't last cmd? */
+                if (current != argc - 1)
+                    goto err;
+                return Jim_EvalObj(interp, argv[current]);
+            }
+            else if (Jim_CompareStringImmediate(interp, argv[falsebody], "elseif"))
+                /* Ok: elseif follows meaning all the stuff
+                 * again (how boring...) */
+                continue;
+            /* OOPS - else-clause is not last cmd? */
+            else if (falsebody != argc - 1)
+                goto err;
+            return Jim_EvalObj(interp, argv[falsebody]);
+        }
+        return JIM_OK;
+    }
+  err:
+    Jim_WrongNumArgs(interp, 1, argv, "condition ?then? trueBody ?elseif ...? ?else? falseBody");
+    return JIM_ERR;
+}
+
+
+/* Returns 1 if match, 0 if no match or -<error> on error (e.g. -JIM_ERR, -JIM_BREAK)*/
+int Jim_CommandMatchObj(Jim_Interp *interp, Jim_Obj *commandObj, Jim_Obj *patternObj,
+    Jim_Obj *stringObj, int nocase)
+{
+    Jim_Obj *parms[4];
+    int argc = 0;
+    long eq;
+    int rc;
+
+    parms[argc++] = commandObj;
+    if (nocase) {
+        parms[argc++] = Jim_NewStringObj(interp, "-nocase", -1);
+    }
+    parms[argc++] = patternObj;
+    parms[argc++] = stringObj;
+
+    rc = Jim_EvalObjVector(interp, argc, parms);
+
+    if (rc != JIM_OK || Jim_GetLong(interp, Jim_GetResult(interp), &eq) != JIM_OK) {
+        eq = -rc;
+    }
+
+    return eq;
+}
+
+enum
+{ SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD };
+
+/* [switch] */
+static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int matchOpt = SWITCH_EXACT, opt = 1, patCount, i;
+    Jim_Obj *command = 0, *const *caseList = 0, *strObj;
+    Jim_Obj *script = 0;
+
+    if (argc < 3) {
+      wrongnumargs:
+        Jim_WrongNumArgs(interp, 1, argv, "?options? string "
+            "pattern body ... ?default body?   or   " "{pattern body ?pattern body ...?}");
+        return JIM_ERR;
+    }
+    for (opt = 1; opt < argc; ++opt) {
+        const char *option = Jim_String(argv[opt]);
+
+        if (*option != '-')
+            break;
+        else if (strncmp(option, "--", 2) == 0) {
+            ++opt;
+            break;
+        }
+        else if (strncmp(option, "-exact", 2) == 0)
+            matchOpt = SWITCH_EXACT;
+        else if (strncmp(option, "-glob", 2) == 0)
+            matchOpt = SWITCH_GLOB;
+        else if (strncmp(option, "-regexp", 2) == 0)
+            matchOpt = SWITCH_RE;
+        else if (strncmp(option, "-command", 2) == 0) {
+            matchOpt = SWITCH_CMD;
+            if ((argc - opt) < 2)
+                goto wrongnumargs;
+            command = argv[++opt];
+        }
+        else {
+            Jim_SetResultFormatted(interp,
+                "bad option \"%#s\": must be -exact, -glob, -regexp, -command procname or --",
+                argv[opt]);
+            return JIM_ERR;
+        }
+        if ((argc - opt) < 2)
+            goto wrongnumargs;
+    }
+    strObj = argv[opt++];
+    patCount = argc - opt;
+    if (patCount == 1) {
+        Jim_Obj **vector;
+
+        JimListGetElements(interp, argv[opt], &patCount, &vector);
+        caseList = vector;
+    }
+    else
+        caseList = &argv[opt];
+    if (patCount == 0 || patCount % 2 != 0)
+        goto wrongnumargs;
+    for (i = 0; script == 0 && i < patCount; i += 2) {
+        Jim_Obj *patObj = caseList[i];
+
+        if (!Jim_CompareStringImmediate(interp, patObj, "default")
+            || i < (patCount - 2)) {
+            switch (matchOpt) {
+                case SWITCH_EXACT:
+                    if (Jim_StringEqObj(strObj, patObj))
+                        script = caseList[i + 1];
+                    break;
+                case SWITCH_GLOB:
+                    if (Jim_StringMatchObj(interp, patObj, strObj, 0))
+                        script = caseList[i + 1];
+                    break;
+                case SWITCH_RE:
+                    command = Jim_NewStringObj(interp, "regexp", -1);
+                    /* Fall thru intentionally */
+                case SWITCH_CMD:{
+                        int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, 0);
+
+                        /* After the execution of a command we need to
+                         * make sure to reconvert the object into a list
+                         * again. Only for the single-list style [switch]. */
+                        if (argc - opt == 1) {
+                            Jim_Obj **vector;
+
+                            JimListGetElements(interp, argv[opt], &patCount, &vector);
+                            caseList = vector;
+                        }
+                        /* command is here already decref'd */
+                        if (rc < 0) {
+                            return -rc;
+                        }
+                        if (rc)
+                            script = caseList[i + 1];
+                        break;
+                    }
+            }
+        }
+        else {
+            script = caseList[i + 1];
+        }
+    }
+    for (; i < patCount && Jim_CompareStringImmediate(interp, script, "-"); i += 2)
+        script = caseList[i + 1];
+    if (script && Jim_CompareStringImmediate(interp, script, "-")) {
+        Jim_SetResultFormatted(interp, "no body specified for pattern \"%#s\"", caseList[i - 2]);
+        return JIM_ERR;
+    }
+    Jim_SetEmptyResult(interp);
+    if (script) {
+        return Jim_EvalObj(interp, script);
+    }
+    return JIM_OK;
+}
+
+/* [list] */
+static int Jim_ListCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *listObjPtr;
+
+    listObjPtr = Jim_NewListObj(interp, argv + 1, argc - 1);
+    Jim_SetResult(interp, listObjPtr);
+    return JIM_OK;
+}
+
+/* [lindex] */
+static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr, *listObjPtr;
+    int i;
+    int idx;
+
+    if (argc < 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "list index ?...?");
+        return JIM_ERR;
+    }
+    objPtr = argv[1];
+    Jim_IncrRefCount(objPtr);
+    for (i = 2; i < argc; i++) {
+        listObjPtr = objPtr;
+        if (Jim_GetIndex(interp, argv[i], &idx) != JIM_OK) {
+            Jim_DecrRefCount(interp, listObjPtr);
+            return JIM_ERR;
+        }
+        if (Jim_ListIndex(interp, listObjPtr, idx, &objPtr, JIM_NONE) != JIM_OK) {
+            /* Returns an empty object if the index
+             * is out of range. */
+            Jim_DecrRefCount(interp, listObjPtr);
+            Jim_SetEmptyResult(interp);
+            return JIM_OK;
+        }
+        Jim_IncrRefCount(objPtr);
+        Jim_DecrRefCount(interp, listObjPtr);
+    }
+    Jim_SetResult(interp, objPtr);
+    Jim_DecrRefCount(interp, objPtr);
+    return JIM_OK;
+}
+
+/* [llength] */
+static int Jim_LlengthCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "list");
+        return JIM_ERR;
+    }
+    Jim_SetResultInt(interp, Jim_ListLength(interp, argv[1]));
+    return JIM_OK;
+}
+
+/* [lsearch] */
+static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    static const char * const options[] = {
+        "-bool", "-not", "-nocase", "-exact", "-glob", "-regexp", "-all", "-inline", "-command",
+            NULL
+    };
+    enum
+    { OPT_BOOL, OPT_NOT, OPT_NOCASE, OPT_EXACT, OPT_GLOB, OPT_REGEXP, OPT_ALL, OPT_INLINE,
+            OPT_COMMAND };
+    int i;
+    int opt_bool = 0;
+    int opt_not = 0;
+    int opt_nocase = 0;
+    int opt_all = 0;
+    int opt_inline = 0;
+    int opt_match = OPT_EXACT;
+    int listlen;
+    int rc = JIM_OK;
+    Jim_Obj *listObjPtr = NULL;
+    Jim_Obj *commandObj = NULL;
+
+    if (argc < 3) {
+      wrongargs:
+        Jim_WrongNumArgs(interp, 1, argv,
+            "?-exact|-glob|-regexp|-command 'command'? ?-bool|-inline? ?-not? ?-nocase? ?-all? list value");
+        return JIM_ERR;
+    }
+
+    for (i = 1; i < argc - 2; i++) {
+        int option;
+
+        if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+            return JIM_ERR;
+        }
+        switch (option) {
+            case OPT_BOOL:
+                opt_bool = 1;
+                opt_inline = 0;
+                break;
+            case OPT_NOT:
+                opt_not = 1;
+                break;
+            case OPT_NOCASE:
+                opt_nocase = 1;
+                break;
+            case OPT_INLINE:
+                opt_inline = 1;
+                opt_bool = 0;
+                break;
+            case OPT_ALL:
+                opt_all = 1;
+                break;
+            case OPT_COMMAND:
+                if (i >= argc - 2) {
+                    goto wrongargs;
+                }
+                commandObj = argv[++i];
+                /* fallthru */
+            case OPT_EXACT:
+            case OPT_GLOB:
+            case OPT_REGEXP:
+                opt_match = option;
+                break;
+        }
+    }
+
+    argv += i;
+
+    if (opt_all) {
+        listObjPtr = Jim_NewListObj(interp, NULL, 0);
+    }
+    if (opt_match == OPT_REGEXP) {
+        commandObj = Jim_NewStringObj(interp, "regexp", -1);
+    }
+    if (commandObj) {
+        Jim_IncrRefCount(commandObj);
+    }
+
+    listlen = Jim_ListLength(interp, argv[0]);
+    for (i = 0; i < listlen; i++) {
+        Jim_Obj *objPtr;
+        int eq = 0;
+
+        Jim_ListIndex(interp, argv[0], i, &objPtr, JIM_NONE);
+        switch (opt_match) {
+            case OPT_EXACT:
+                eq = Jim_StringCompareObj(interp, objPtr, argv[1], opt_nocase) == 0;
+                break;
+
+            case OPT_GLOB:
+                eq = Jim_StringMatchObj(interp, argv[1], objPtr, opt_nocase);
+                break;
+
+            case OPT_REGEXP:
+            case OPT_COMMAND:
+                eq = Jim_CommandMatchObj(interp, commandObj, argv[1], objPtr, opt_nocase);
+                if (eq < 0) {
+                    if (listObjPtr) {
+                        Jim_FreeNewObj(interp, listObjPtr);
+                    }
+                    rc = JIM_ERR;
+                    goto done;
+                }
+                break;
+        }
+
+        /* If we have a non-match with opt_bool, opt_not, !opt_all, can't exit early */
+        if (!eq && opt_bool && opt_not && !opt_all) {
+            continue;
+        }
+
+        if ((!opt_bool && eq == !opt_not) || (opt_bool && (eq || opt_all))) {
+            /* Got a match (or non-match for opt_not), or (opt_bool && opt_all) */
+            Jim_Obj *resultObj;
+
+            if (opt_bool) {
+                resultObj = Jim_NewIntObj(interp, eq ^ opt_not);
+            }
+            else if (!opt_inline) {
+                resultObj = Jim_NewIntObj(interp, i);
+            }
+            else {
+                resultObj = objPtr;
+            }
+
+            if (opt_all) {
+                Jim_ListAppendElement(interp, listObjPtr, resultObj);
+            }
+            else {
+                Jim_SetResult(interp, resultObj);
+                goto done;
+            }
+        }
+    }
+
+    if (opt_all) {
+        Jim_SetResult(interp, listObjPtr);
+    }
+    else {
+        /* No match */
+        if (opt_bool) {
+            Jim_SetResultBool(interp, opt_not);
+        }
+        else if (!opt_inline) {
+            Jim_SetResultInt(interp, -1);
+        }
+    }
+
+  done:
+    if (commandObj) {
+        Jim_DecrRefCount(interp, commandObj);
+    }
+    return rc;
+}
+
+/* [lappend] */
+static int Jim_LappendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *listObjPtr;
+    int shared, i;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
+        return JIM_ERR;
+    }
+    listObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
+    if (!listObjPtr) {
+        /* Create the list if it does not exists */
+        listObjPtr = Jim_NewListObj(interp, NULL, 0);
+        if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) {
+            Jim_FreeNewObj(interp, listObjPtr);
+            return JIM_ERR;
+        }
+    }
+    shared = Jim_IsShared(listObjPtr);
+    if (shared)
+        listObjPtr = Jim_DuplicateObj(interp, listObjPtr);
+    for (i = 2; i < argc; i++)
+        Jim_ListAppendElement(interp, listObjPtr, argv[i]);
+    if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) {
+        if (shared)
+            Jim_FreeNewObj(interp, listObjPtr);
+        return JIM_ERR;
+    }
+    Jim_SetResult(interp, listObjPtr);
+    return JIM_OK;
+}
+
+/* [linsert] */
+static int Jim_LinsertCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int idx, len;
+    Jim_Obj *listPtr;
+
+    if (argc < 4) {
+        Jim_WrongNumArgs(interp, 1, argv, "list index element " "?element ...?");
+        return JIM_ERR;
+    }
+    listPtr = argv[1];
+    if (Jim_IsShared(listPtr))
+        listPtr = Jim_DuplicateObj(interp, listPtr);
+    if (Jim_GetIndex(interp, argv[2], &idx) != JIM_OK)
+        goto err;
+    len = Jim_ListLength(interp, listPtr);
+    if (idx >= len)
+        idx = len;
+    else if (idx < 0)
+        idx = len + idx + 1;
+    Jim_ListInsertElements(interp, listPtr, idx, argc - 3, &argv[3]);
+    Jim_SetResult(interp, listPtr);
+    return JIM_OK;
+  err:
+    if (listPtr != argv[1]) {
+        Jim_FreeNewObj(interp, listPtr);
+    }
+    return JIM_ERR;
+}
+
+/* [lreplace] */
+static int Jim_LreplaceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int first, last, len, rangeLen;
+    Jim_Obj *listObj;
+    Jim_Obj *newListObj;
+    int i;
+    int shared;
+
+    if (argc < 4) {
+        Jim_WrongNumArgs(interp, 1, argv, "list first last ?element element ...?");
+        return JIM_ERR;
+    }
+    if (Jim_GetIndex(interp, argv[2], &first) != JIM_OK ||
+        Jim_GetIndex(interp, argv[3], &last) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    listObj = argv[1];
+    len = Jim_ListLength(interp, listObj);
+
+    first = JimRelToAbsIndex(len, first);
+    last = JimRelToAbsIndex(len, last);
+    JimRelToAbsRange(len, first, last, &first, &last, &rangeLen);
+
+    /* Now construct a new list which consists of:
+     * <elements before first> <supplied elements> <elements after last>
+     */
+
+    /* Check to see if trying to replace past the end of the list */
+    if (first < len) {
+        /* OK. Not past the end */
+    }
+    else if (len == 0) {
+        /* Special for empty list, adjust first to 0 */
+        first = 0;
+    }
+    else {
+        Jim_SetResultString(interp, "list doesn't contain element ", -1);
+        Jim_AppendObj(interp, Jim_GetResult(interp), argv[2]);
+        return JIM_ERR;
+    }
+
+    newListObj = Jim_NewListObj(interp, NULL, 0);
+
+    shared = Jim_IsShared(listObj);
+    if (shared) {
+        listObj = Jim_DuplicateObj(interp, listObj);
+    }
+
+    /* Add the first set of elements */
+    for (i = 0; i < first; i++) {
+        Jim_ListAppendElement(interp, newListObj, listObj->internalRep.listValue.ele[i]);
+    }
+
+    /* Add supplied elements */
+    for (i = 4; i < argc; i++) {
+        Jim_ListAppendElement(interp, newListObj, argv[i]);
+    }
+
+    /* Add the remaining elements */
+    for (i = first + rangeLen; i < len; i++) {
+        Jim_ListAppendElement(interp, newListObj, listObj->internalRep.listValue.ele[i]);
+    }
+    Jim_SetResult(interp, newListObj);
+    if (shared) {
+        Jim_FreeNewObj(interp, listObj);
+    }
+    return JIM_OK;
+}
+
+/* [lset] */
+static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc < 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "listVar ?index...? newVal");
+        return JIM_ERR;
+    }
+    else if (argc == 3) {
+        if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
+            return JIM_ERR;
+        Jim_SetResult(interp, argv[2]);
+        return JIM_OK;
+    }
+    if (Jim_SetListIndex(interp, argv[1], argv + 2, argc - 3, argv[argc - 1])
+        == JIM_ERR)
+        return JIM_ERR;
+    return JIM_OK;
+}
+
+/* [lsort] */
+static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[])
+{
+    static const char * const options[] = {
+        "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-index", NULL
+    };
+    enum
+    { OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_INDEX };
+    Jim_Obj *resObj;
+    int i;
+    int retCode;
+
+    struct lsort_info info;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "?options? list");
+        return JIM_ERR;
+    }
+
+    info.type = JIM_LSORT_ASCII;
+    info.order = 1;
+    info.indexed = 0;
+    info.command = NULL;
+    info.interp = interp;
+
+    for (i = 1; i < (argc - 1); i++) {
+        int option;
+
+        if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG)
+            != JIM_OK)
+            return JIM_ERR;
+        switch (option) {
+            case OPT_ASCII:
+                info.type = JIM_LSORT_ASCII;
+                break;
+            case OPT_NOCASE:
+                info.type = JIM_LSORT_NOCASE;
+                break;
+            case OPT_INTEGER:
+                info.type = JIM_LSORT_INTEGER;
+                break;
+            case OPT_INCREASING:
+                info.order = 1;
+                break;
+            case OPT_DECREASING:
+                info.order = -1;
+                break;
+            case OPT_COMMAND:
+                if (i >= (argc - 2)) {
+                    Jim_SetResultString(interp, "\"-command\" option must be followed by comparison command", -1);
+                    return JIM_ERR;
+                }
+                info.type = JIM_LSORT_COMMAND;
+                info.command = argv[i + 1];
+                i++;
+                break;
+            case OPT_INDEX:
+                if (i >= (argc - 2)) {
+                    Jim_SetResultString(interp, "\"-index\" option must be followed by list index", -1);
+                    return JIM_ERR;
+                }
+                if (Jim_GetIndex(interp, argv[i + 1], &info.index) != JIM_OK) {
+                    return JIM_ERR;
+                }
+                info.indexed = 1;
+                i++;
+                break;
+        }
+    }
+    resObj = Jim_DuplicateObj(interp, argv[argc - 1]);
+    retCode = ListSortElements(interp, resObj, &info);
+    if (retCode == JIM_OK) {
+        Jim_SetResult(interp, resObj);
+    }
+    else {
+        Jim_FreeNewObj(interp, resObj);
+    }
+    return retCode;
+}
+
+/* [append] */
+static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *stringObjPtr;
+    int i;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
+        return JIM_ERR;
+    }
+    if (argc == 2) {
+        stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
+        if (!stringObjPtr)
+            return JIM_ERR;
+    }
+    else {
+        int freeobj = 0;
+        stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
+        if (!stringObjPtr) {
+            /* Create the string if it doesn't exist */
+            stringObjPtr = Jim_NewEmptyStringObj(interp);
+            freeobj = 1;
+        }
+        else if (Jim_IsShared(stringObjPtr)) {
+            freeobj = 1;
+            stringObjPtr = Jim_DuplicateObj(interp, stringObjPtr);
+        }
+        for (i = 2; i < argc; i++) {
+            Jim_AppendObj(interp, stringObjPtr, argv[i]);
+        }
+        if (Jim_SetVariable(interp, argv[1], stringObjPtr) != JIM_OK) {
+            if (freeobj) {
+                Jim_FreeNewObj(interp, stringObjPtr);
+            }
+            return JIM_ERR;
+        }
+    }
+    Jim_SetResult(interp, stringObjPtr);
+    return JIM_OK;
+}
+
+/* [debug] */
+static int Jim_DebugCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+#if defined(JIM_DEBUG_COMMAND) && !defined(JIM_BOOTSTRAP)
+    static const char * const options[] = {
+        "refcount", "objcount", "objects", "invstr", "scriptlen", "exprlen",
+        "exprbc", "show",
+        NULL
+    };
+    enum
+    {
+        OPT_REFCOUNT, OPT_OBJCOUNT, OPT_OBJECTS, OPT_INVSTR, OPT_SCRIPTLEN,
+        OPT_EXPRLEN, OPT_EXPRBC, OPT_SHOW,
+    };
+    int option;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "subcommand ?...?");
+        return JIM_ERR;
+    }
+    if (Jim_GetEnum(interp, argv[1], options, &option, "subcommand", JIM_ERRMSG) != JIM_OK)
+        return JIM_ERR;
+    if (option == OPT_REFCOUNT) {
+        if (argc != 3) {
+            Jim_WrongNumArgs(interp, 2, argv, "object");
+            return JIM_ERR;
+        }
+        Jim_SetResultInt(interp, argv[2]->refCount);
+        return JIM_OK;
+    }
+    else if (option == OPT_OBJCOUNT) {
+        int freeobj = 0, liveobj = 0;
+        char buf[256];
+        Jim_Obj *objPtr;
+
+        if (argc != 2) {
+            Jim_WrongNumArgs(interp, 2, argv, "");
+            return JIM_ERR;
+        }
+        /* Count the number of free objects. */
+        objPtr = interp->freeList;
+        while (objPtr) {
+            freeobj++;
+            objPtr = objPtr->nextObjPtr;
+        }
+        /* Count the number of live objects. */
+        objPtr = interp->liveList;
+        while (objPtr) {
+            liveobj++;
+            objPtr = objPtr->nextObjPtr;
+        }
+        /* Set the result string and return. */
+        sprintf(buf, "free %d used %d", freeobj, liveobj);
+        Jim_SetResultString(interp, buf, -1);
+        return JIM_OK;
+    }
+    else if (option == OPT_OBJECTS) {
+        Jim_Obj *objPtr, *listObjPtr, *subListObjPtr;
+
+        /* Count the number of live objects. */
+        objPtr = interp->liveList;
+        listObjPtr = Jim_NewListObj(interp, NULL, 0);
+        while (objPtr) {
+            char buf[128];
+            const char *type = objPtr->typePtr ? objPtr->typePtr->name : "";
+
+            subListObjPtr = Jim_NewListObj(interp, NULL, 0);
+            sprintf(buf, "%p", objPtr);
+            Jim_ListAppendElement(interp, subListObjPtr, Jim_NewStringObj(interp, buf, -1));
+            Jim_ListAppendElement(interp, subListObjPtr, Jim_NewStringObj(interp, type, -1));
+            Jim_ListAppendElement(interp, subListObjPtr, Jim_NewIntObj(interp, objPtr->refCount));
+            Jim_ListAppendElement(interp, subListObjPtr, objPtr);
+            Jim_ListAppendElement(interp, listObjPtr, subListObjPtr);
+            objPtr = objPtr->nextObjPtr;
+        }
+        Jim_SetResult(interp, listObjPtr);
+        return JIM_OK;
+    }
+    else if (option == OPT_INVSTR) {
+        Jim_Obj *objPtr;
+
+        if (argc != 3) {
+            Jim_WrongNumArgs(interp, 2, argv, "object");
+            return JIM_ERR;
+        }
+        objPtr = argv[2];
+        if (objPtr->typePtr != NULL)
+            Jim_InvalidateStringRep(objPtr);
+        Jim_SetEmptyResult(interp);
+        return JIM_OK;
+    }
+    else if (option == OPT_SHOW) {
+        const char *s;
+        int len, charlen;
+
+        if (argc != 3) {
+            Jim_WrongNumArgs(interp, 2, argv, "object");
+            return JIM_ERR;
+        }
+        s = Jim_GetString(argv[2], &len);
+#ifdef JIM_UTF8
+        charlen = utf8_strlen(s, len);
+#else
+        charlen = len;
+#endif
+        printf("refcount: %d, type: %s\n", argv[2]->refCount, JimObjTypeName(argv[2]));
+        printf("chars (%d): <<%s>>\n", charlen, s);
+        printf("bytes (%d):", len);
+        while (len--) {
+            printf(" %02x", (unsigned char)*s++);
+        }
+        printf("\n");
+        return JIM_OK;
+    }
+    else if (option == OPT_SCRIPTLEN) {
+        ScriptObj *script;
+
+        if (argc != 3) {
+            Jim_WrongNumArgs(interp, 2, argv, "script");
+            return JIM_ERR;
+        }
+        script = Jim_GetScript(interp, argv[2]);
+        Jim_SetResultInt(interp, script->len);
+        return JIM_OK;
+    }
+    else if (option == OPT_EXPRLEN) {
+        ExprByteCode *expr;
+
+        if (argc != 3) {
+            Jim_WrongNumArgs(interp, 2, argv, "expression");
+            return JIM_ERR;
+        }
+        expr = JimGetExpression(interp, argv[2]);
+        if (expr == NULL)
+            return JIM_ERR;
+        Jim_SetResultInt(interp, expr->len);
+        return JIM_OK;
+    }
+    else if (option == OPT_EXPRBC) {
+        Jim_Obj *objPtr;
+        ExprByteCode *expr;
+        int i;
+
+        if (argc != 3) {
+            Jim_WrongNumArgs(interp, 2, argv, "expression");
+            return JIM_ERR;
+        }
+        expr = JimGetExpression(interp, argv[2]);
+        if (expr == NULL)
+            return JIM_ERR;
+        objPtr = Jim_NewListObj(interp, NULL, 0);
+        for (i = 0; i < expr->len; i++) {
+            const char *type;
+            const Jim_ExprOperator *op;
+            Jim_Obj *obj = expr->token[i].objPtr;
+
+            switch (expr->token[i].type) {
+                case JIM_TT_EXPR_INT:
+                    type = "int";
+                    break;
+                case JIM_TT_EXPR_DOUBLE:
+                    type = "double";
+                    break;
+                case JIM_TT_CMD:
+                    type = "command";
+                    break;
+                case JIM_TT_VAR:
+                    type = "variable";
+                    break;
+                case JIM_TT_DICTSUGAR:
+                    type = "dictsugar";
+                    break;
+                case JIM_TT_EXPRSUGAR:
+                    type = "exprsugar";
+                    break;
+                case JIM_TT_ESC:
+                    type = "subst";
+                    break;
+                case JIM_TT_STR:
+                    type = "string";
+                    break;
+                default:
+                    op = JimExprOperatorInfoByOpcode(expr->token[i].type);
+                    if (op == NULL) {
+                        type = "private";
+                    }
+                    else {
+                        type = "operator";
+                    }
+                    obj = Jim_NewStringObj(interp, op ? op->name : "", -1);
+                    break;
+            }
+            Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, type, -1));
+            Jim_ListAppendElement(interp, objPtr, obj);
+        }
+        Jim_SetResult(interp, objPtr);
+        return JIM_OK;
+    }
+    else {
+        Jim_SetResultString(interp,
+            "bad option. Valid options are refcount, " "objcount, objects, invstr", -1);
+        return JIM_ERR;
+    }
+    /* unreached */
+#endif /* JIM_BOOTSTRAP */
+#if !defined(JIM_DEBUG_COMMAND)
+    Jim_SetResultString(interp, "unsupported", -1);
+    return JIM_ERR;
+#endif
+}
+
+/* [eval] */
+static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int rc;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "script ?...?");
+        return JIM_ERR;
+    }
+
+    if (argc == 2) {
+        rc = Jim_EvalObj(interp, argv[1]);
+    }
+    else {
+        rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
+    }
+
+    if (rc == JIM_ERR) {
+        /* eval is "interesting", so add a stack frame here */
+        interp->addStackTrace++;
+    }
+    return rc;
+}
+
+/* [uplevel] */
+static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc >= 2) {
+        int retcode;
+        Jim_CallFrame *savedCallFrame, *targetCallFrame;
+        Jim_Obj *objPtr;
+        const char *str;
+
+        /* Save the old callframe pointer */
+        savedCallFrame = interp->framePtr;
+
+        /* Lookup the target frame pointer */
+        str = Jim_String(argv[1]);
+        if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') {
+            targetCallFrame =Jim_GetCallFrameByLevel(interp, argv[1]);
+            argc--;
+            argv++;
+        }
+        else {
+            targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL);
+        }
+        if (targetCallFrame == NULL) {
+            return JIM_ERR;
+        }
+        if (argc < 2) {
+            argv--;
+            Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?");
+            return JIM_ERR;
+        }
+        /* Eval the code in the target callframe. */
+        interp->framePtr = targetCallFrame;
+        if (argc == 2) {
+            retcode = Jim_EvalObj(interp, argv[1]);
+        }
+        else {
+            objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1);
+            Jim_IncrRefCount(objPtr);
+            retcode = Jim_EvalObj(interp, objPtr);
+            Jim_DecrRefCount(interp, objPtr);
+        }
+        interp->framePtr = savedCallFrame;
+        return retcode;
+    }
+    else {
+        Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?");
+        return JIM_ERR;
+    }
+}
+
+/* [expr] */
+static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *exprResultPtr;
+    int retcode;
+
+    if (argc == 2) {
+        retcode = Jim_EvalExpression(interp, argv[1], &exprResultPtr);
+    }
+    else if (argc > 2) {
+        Jim_Obj *objPtr;
+
+        objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1);
+        Jim_IncrRefCount(objPtr);
+        retcode = Jim_EvalExpression(interp, objPtr, &exprResultPtr);
+        Jim_DecrRefCount(interp, objPtr);
+    }
+    else {
+        Jim_WrongNumArgs(interp, 1, argv, "expression ?...?");
+        return JIM_ERR;
+    }
+    if (retcode != JIM_OK)
+        return retcode;
+    Jim_SetResult(interp, exprResultPtr);
+    Jim_DecrRefCount(interp, exprResultPtr);
+    return JIM_OK;
+}
+
+/* [break] */
+static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 1) {
+        Jim_WrongNumArgs(interp, 1, argv, "");
+        return JIM_ERR;
+    }
+    return JIM_BREAK;
+}
+
+/* [continue] */
+static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 1) {
+        Jim_WrongNumArgs(interp, 1, argv, "");
+        return JIM_ERR;
+    }
+    return JIM_CONTINUE;
+}
+
+/* [return] */
+static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int i;
+    Jim_Obj *stackTraceObj = NULL;
+    Jim_Obj *errorCodeObj = NULL;
+    int returnCode = JIM_OK;
+    long level = 1;
+
+    for (i = 1; i < argc - 1; i += 2) {
+        if (Jim_CompareStringImmediate(interp, argv[i], "-code")) {
+            if (Jim_GetReturnCode(interp, argv[i + 1], &returnCode) == JIM_ERR) {
+                return JIM_ERR;
+            }
+        }
+        else if (Jim_CompareStringImmediate(interp, argv[i], "-errorinfo")) {
+            stackTraceObj = argv[i + 1];
+        }
+        else if (Jim_CompareStringImmediate(interp, argv[i], "-errorcode")) {
+            errorCodeObj = argv[i + 1];
+        }
+        else if (Jim_CompareStringImmediate(interp, argv[i], "-level")) {
+            if (Jim_GetLong(interp, argv[i + 1], &level) != JIM_OK || level < 0) {
+                Jim_SetResultFormatted(interp, "bad level \"%#s\"", argv[i + 1]);
+                return JIM_ERR;
+            }
+        }
+        else {
+            break;
+        }
+    }
+
+    if (i != argc - 1 && i != argc) {
+        Jim_WrongNumArgs(interp, 1, argv,
+            "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?");
+    }
+
+    /* If a stack trace is supplied and code is error, set the stack trace */
+    if (stackTraceObj && returnCode == JIM_ERR) {
+        JimSetStackTrace(interp, stackTraceObj);
+    }
+    /* If an error code list is supplied, set the global $errorCode */
+    if (errorCodeObj && returnCode == JIM_ERR) {
+        Jim_SetGlobalVariableStr(interp, "errorCode", errorCodeObj);
+    }
+    interp->returnCode = returnCode;
+    interp->returnLevel = level;
+
+    if (i == argc - 1) {
+        Jim_SetResult(interp, argv[i]);
+    }
+    return JIM_RETURN;
+}
+
+/* [tailcall] */
+static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr;
+
+    objPtr = Jim_NewListObj(interp, argv + 1, argc - 1);
+    Jim_SetResult(interp, objPtr);
+    return JIM_EVAL;
+}
+
+/* [proc] */
+static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 4 && argc != 5) {
+        Jim_WrongNumArgs(interp, 1, argv, "name arglist ?statics? body");
+        return JIM_ERR;
+    }
+
+    if (argc == 4) {
+        return JimCreateProcedure(interp, argv[1], argv[2], NULL, argv[3]);
+    }
+    else {
+        return JimCreateProcedure(interp, argv[1], argv[2], argv[3], argv[4]);
+    }
+}
+
+/* [local] */
+static int Jim_LocalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int retcode;
+
+    /* Evaluate the arguments with 'local' in force */
+    interp->local++;
+    retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
+    interp->local--;
+
+
+    /* If OK, and the result is a proc, add it to the list of local procs */
+    if (retcode == 0) {
+        const char *procname = Jim_String(Jim_GetResult(interp));
+
+        if (Jim_FindHashEntry(&interp->commands, procname) == NULL) {
+            Jim_SetResultFormatted(interp, "not a proc: \"%s\"", procname);
+            return JIM_ERR;
+        }
+        if (interp->localProcs == NULL) {
+            interp->localProcs = Jim_Alloc(sizeof(*interp->localProcs));
+            Jim_InitStack(interp->localProcs);
+        }
+        Jim_StackPush(interp->localProcs, Jim_StrDup(procname));
+    }
+
+    return retcode;
+}
+
+/* [upcall] */
+static int Jim_UpcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?");
+        return JIM_ERR;
+    }
+    else {
+        int retcode;
+
+        Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
+        if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->u.proc.prevCmd) {
+            Jim_SetResultFormatted(interp, "no previous proc: \"%#s\"", argv[1]);
+            return JIM_ERR;
+        }
+        /* OK. Mark this command as being in an upcall */
+        cmdPtr->u.proc.upcall++;
+        JimIncrCmdRefCount(cmdPtr);
+
+        /* Invoke the command as normal */
+        retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
+
+        /* No longer in an upcall */
+        cmdPtr->u.proc.upcall--;
+        JimDecrCmdRefCount(interp, cmdPtr);
+
+        return retcode;
+    }
+}
+
+/* [concat] */
+static int Jim_ConcatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_SetResult(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
+    return JIM_OK;
+}
+
+/* [upvar] */
+static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int i;
+    Jim_CallFrame *targetCallFrame;
+
+    /* Lookup the target frame pointer */
+    if (argc > 3 && (argc % 2 == 0)) {
+        targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
+        argc--;
+        argv++;
+    }
+    else {
+        targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL);
+    }
+    if (targetCallFrame == NULL) {
+        return JIM_ERR;
+    }
+
+    /* Check for arity */
+    if (argc < 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?");
+        return JIM_ERR;
+    }
+
+    /* Now... for every other/local couple: */
+    for (i = 1; i < argc; i += 2) {
+        if (Jim_SetVariableLink(interp, argv[i + 1], argv[i], targetCallFrame) != JIM_OK)
+            return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+/* [global] */
+static int Jim_GlobalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int i;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?");
+        return JIM_ERR;
+    }
+    /* Link every var to the toplevel having the same name */
+    if (interp->framePtr->level == 0)
+        return JIM_OK;          /* global at toplevel... */
+    for (i = 1; i < argc; i++) {
+        if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK)
+            return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+/* does the [string map] operation. On error NULL is returned,
+ * otherwise a new string object with the result, having refcount = 0,
+ * is returned. */
+static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr,
+    Jim_Obj *objPtr, int nocase)
+{
+    int numMaps;
+    const char *str, *noMatchStart = NULL;
+    int strLen, i;
+    Jim_Obj *resultObjPtr;
+
+    numMaps = Jim_ListLength(interp, mapListObjPtr);
+    if (numMaps % 2) {
+        Jim_SetResultString(interp, "list must contain an even number of elements", -1);
+        return NULL;
+    }
+
+    str = Jim_String(objPtr);
+    strLen = Jim_Utf8Length(interp, objPtr);
+
+    /* Map it */
+    resultObjPtr = Jim_NewStringObj(interp, "", 0);
+    while (strLen) {
+        for (i = 0; i < numMaps; i += 2) {
+            Jim_Obj *objPtr;
+            const char *k;
+            int kl;
+
+            Jim_ListIndex(interp, mapListObjPtr, i, &objPtr, JIM_NONE);
+            k = Jim_String(objPtr);
+            kl = Jim_Utf8Length(interp, objPtr);
+
+            if (strLen >= kl && kl) {
+                int rc;
+                if (nocase) {
+                    rc = JimStringCompareNoCase(str, k, kl);
+                }
+                else {
+                    rc = JimStringCompare(str, kl, k, kl);
+                }
+                if (rc == 0) {
+                    if (noMatchStart) {
+                        Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
+                        noMatchStart = NULL;
+                    }
+                    Jim_ListIndex(interp, mapListObjPtr, i + 1, &objPtr, JIM_NONE);
+                    Jim_AppendObj(interp, resultObjPtr, objPtr);
+                    str += utf8_index(str, kl);
+                    strLen -= kl;
+                    break;
+                }
+            }
+        }
+        if (i == numMaps) {     /* no match */
+            int c;
+            if (noMatchStart == NULL)
+                noMatchStart = str;
+            str += utf8_tounicode(str, &c);
+            strLen--;
+        }
+    }
+    if (noMatchStart) {
+        Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
+    }
+    return resultObjPtr;
+}
+
+/* [string] */
+static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int len;
+    int opt_case = 1;
+    int option;
+    static const char * const options[] = {
+        "bytelength", "length", "compare", "match", "equal", "is", "byterange", "range", "map",
+        "repeat", "reverse", "index", "first", "last",
+        "trim", "trimleft", "trimright", "tolower", "toupper", NULL
+    };
+    enum
+    {
+        OPT_BYTELENGTH, OPT_LENGTH, OPT_COMPARE, OPT_MATCH, OPT_EQUAL, OPT_IS, OPT_BYTERANGE, OPT_RANGE, OPT_MAP,
+        OPT_REPEAT, OPT_REVERSE, OPT_INDEX, OPT_FIRST, OPT_LAST,
+        OPT_TRIM, OPT_TRIMLEFT, OPT_TRIMRIGHT, OPT_TOLOWER, OPT_TOUPPER
+    };
+    static const char * const nocase_options[] = {
+        "-nocase", NULL
+    };
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?");
+        return JIM_ERR;
+    }
+    if (Jim_GetEnum(interp, argv[1], options, &option, NULL,
+            JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK)
+        return JIM_ERR;
+
+    switch (option) {
+        case OPT_LENGTH:
+        case OPT_BYTELENGTH:
+            if (argc != 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "string");
+                return JIM_ERR;
+            }
+            if (option == OPT_LENGTH) {
+                len = Jim_Utf8Length(interp, argv[2]);
+            }
+            else {
+                len = Jim_Length(argv[2]);
+            }
+            Jim_SetResultInt(interp, len);
+            return JIM_OK;
+
+        case OPT_COMPARE:
+        case OPT_EQUAL:
+            if (argc != 4 &&
+                (argc != 5 ||
+                    Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
+                        JIM_ENUM_ABBREV) != JIM_OK)) {
+                Jim_WrongNumArgs(interp, 2, argv, "?-nocase? string1 string2");
+                return JIM_ERR;
+            }
+            if (opt_case == 0) {
+                argv++;
+            }
+            if (option == OPT_COMPARE || !opt_case) {
+                Jim_SetResultInt(interp, Jim_StringCompareObj(interp, argv[2], argv[3], !opt_case));
+            }
+            else {
+                Jim_SetResultBool(interp, Jim_StringEqObj(argv[2], argv[3]));
+            }
+            return JIM_OK;
+
+        case OPT_MATCH:
+            if (argc != 4 &&
+                (argc != 5 ||
+                    Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
+                        JIM_ENUM_ABBREV) != JIM_OK)) {
+                Jim_WrongNumArgs(interp, 2, argv, "?-nocase? pattern string");
+                return JIM_ERR;
+            }
+            if (opt_case == 0) {
+                argv++;
+            }
+            Jim_SetResultBool(interp, Jim_StringMatchObj(interp, argv[2], argv[3], !opt_case));
+            return JIM_OK;
+
+        case OPT_MAP:{
+                Jim_Obj *objPtr;
+
+                if (argc != 4 &&
+                    (argc != 5 ||
+                        Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
+                            JIM_ENUM_ABBREV) != JIM_OK)) {
+                    Jim_WrongNumArgs(interp, 2, argv, "?-nocase? mapList string");
+                    return JIM_ERR;
+                }
+
+                if (opt_case == 0) {
+                    argv++;
+                }
+                objPtr = JimStringMap(interp, argv[2], argv[3], !opt_case);
+                if (objPtr == NULL) {
+                    return JIM_ERR;
+                }
+                Jim_SetResult(interp, objPtr);
+                return JIM_OK;
+            }
+
+        case OPT_RANGE:
+        case OPT_BYTERANGE:{
+                Jim_Obj *objPtr;
+
+                if (argc != 5) {
+                    Jim_WrongNumArgs(interp, 2, argv, "string first last");
+                    return JIM_ERR;
+                }
+                if (option == OPT_RANGE) {
+                    objPtr = Jim_StringRangeObj(interp, argv[2], argv[3], argv[4]);
+                }
+                else
+                {
+                    objPtr = Jim_StringByteRangeObj(interp, argv[2], argv[3], argv[4]);
+                }
+
+                if (objPtr == NULL) {
+                    return JIM_ERR;
+                }
+                Jim_SetResult(interp, objPtr);
+                return JIM_OK;
+            }
+
+        case OPT_REPEAT:{
+                Jim_Obj *objPtr;
+                jim_wide count;
+
+                if (argc != 4) {
+                    Jim_WrongNumArgs(interp, 2, argv, "string count");
+                    return JIM_ERR;
+                }
+                if (Jim_GetWide(interp, argv[3], &count) != JIM_OK) {
+                    return JIM_ERR;
+                }
+                objPtr = Jim_NewStringObj(interp, "", 0);
+                if (count > 0) {
+                    while (count--) {
+                        Jim_AppendObj(interp, objPtr, argv[2]);
+                    }
+                }
+                Jim_SetResult(interp, objPtr);
+                return JIM_OK;
+            }
+
+        case OPT_REVERSE:{
+                char *buf, *p;
+                const char *str;
+                int len;
+                int i;
+
+                if (argc != 3) {
+                    Jim_WrongNumArgs(interp, 2, argv, "string");
+                    return JIM_ERR;
+                }
+
+                str = Jim_GetString(argv[2], &len);
+                buf = Jim_Alloc(len + 1);
+                p = buf + len;
+                *p = 0;
+                for (i = 0; i < len; ) {
+                    int c;
+                    int l = utf8_tounicode(str, &c);
+                    memcpy(p - l, str, l);
+                    p -= l;
+                    i += l;
+                    str += l;
+                }
+                Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
+                return JIM_OK;
+            }
+
+        case OPT_INDEX:{
+                int idx;
+                const char *str;
+
+                if (argc != 4) {
+                    Jim_WrongNumArgs(interp, 2, argv, "string index");
+                    return JIM_ERR;
+                }
+                if (Jim_GetIndex(interp, argv[3], &idx) != JIM_OK) {
+                    return JIM_ERR;
+                }
+                str = Jim_String(argv[2]);
+                len = Jim_Utf8Length(interp, argv[2]);
+                if (idx != INT_MIN && idx != INT_MAX) {
+                    idx = JimRelToAbsIndex(len, idx);
+                }
+                if (idx < 0 || idx >= len || str == NULL) {
+                    Jim_SetResultString(interp, "", 0);
+                }
+                else if (len == Jim_Length(argv[2])) {
+                    /* ASCII optimisation */
+                    Jim_SetResultString(interp, str + idx, 1);
+                }
+                else {
+                    int c;
+                    int i = utf8_index(str, idx);
+                    Jim_SetResultString(interp, str + i, utf8_tounicode(str + i, &c));
+                }
+                return JIM_OK;
+            }
+
+        case OPT_FIRST:
+        case OPT_LAST:{
+                int idx = 0, l1, l2;
+                const char *s1, *s2;
+
+                if (argc != 4 && argc != 5) {
+                    Jim_WrongNumArgs(interp, 2, argv, "subString string ?index?");
+                    return JIM_ERR;
+                }
+                s1 = Jim_String(argv[2]);
+                s2 = Jim_String(argv[3]);
+                l1 = Jim_Utf8Length(interp, argv[2]);
+                l2 = Jim_Utf8Length(interp, argv[3]);
+                if (argc == 5) {
+                    if (Jim_GetIndex(interp, argv[4], &idx) != JIM_OK) {
+                        return JIM_ERR;
+                    }
+                    idx = JimRelToAbsIndex(l2, idx);
+                }
+                else if (option == OPT_LAST) {
+                    idx = l2;
+                }
+                if (option == OPT_FIRST) {
+                    Jim_SetResultInt(interp, JimStringFirst(s1, l1, s2, l2, idx));
+                }
+                else {
+#ifdef JIM_UTF8
+                    Jim_SetResultInt(interp, JimStringLastUtf8(s1, l1, s2, idx));
+#else
+                    Jim_SetResultInt(interp, JimStringLast(s1, l1, s2, idx));
+#endif
+                }
+                return JIM_OK;
+            }
+
+        case OPT_TRIM:
+        case OPT_TRIMLEFT:
+        case OPT_TRIMRIGHT:{
+                Jim_Obj *trimchars;
+
+                if (argc != 3 && argc != 4) {
+                    Jim_WrongNumArgs(interp, 2, argv, "string ?trimchars?");
+                    return JIM_ERR;
+                }
+                trimchars = (argc == 4 ? argv[3] : NULL);
+                if (option == OPT_TRIM) {
+                    Jim_SetResult(interp, JimStringTrim(interp, argv[2], trimchars));
+                }
+                else if (option == OPT_TRIMLEFT) {
+                    Jim_SetResult(interp, JimStringTrimLeft(interp, argv[2], trimchars));
+                }
+                else if (option == OPT_TRIMRIGHT) {
+                    Jim_SetResult(interp, JimStringTrimRight(interp, argv[2], trimchars));
+                }
+                return JIM_OK;
+            }
+
+        case OPT_TOLOWER:
+        case OPT_TOUPPER:
+            if (argc != 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "string");
+                return JIM_ERR;
+            }
+            if (option == OPT_TOLOWER) {
+                Jim_SetResult(interp, JimStringToLower(interp, argv[2]));
+            }
+            else {
+                Jim_SetResult(interp, JimStringToUpper(interp, argv[2]));
+            }
+            return JIM_OK;
+
+        case OPT_IS:
+            if (argc == 4 || (argc == 5 && Jim_CompareStringImmediate(interp, argv[3], "-strict"))) {
+                return JimStringIs(interp, argv[argc - 1], argv[2], argc == 5);
+            }
+            Jim_WrongNumArgs(interp, 2, argv, "class ?-strict? str");
+            return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+/* [time] */
+static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    long i, count = 1;
+    jim_wide start, elapsed;
+    char buf[60];
+    const char *fmt = "%" JIM_WIDE_MODIFIER " microseconds per iteration";
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "script ?count?");
+        return JIM_ERR;
+    }
+    if (argc == 3) {
+        if (Jim_GetLong(interp, argv[2], &count) != JIM_OK)
+            return JIM_ERR;
+    }
+    if (count < 0)
+        return JIM_OK;
+    i = count;
+    start = JimClock();
+    while (i-- > 0) {
+        int retval;
+
+        retval = Jim_EvalObj(interp, argv[1]);
+        if (retval != JIM_OK) {
+            return retval;
+        }
+    }
+    elapsed = JimClock() - start;
+    sprintf(buf, fmt, count == 0 ? 0 : elapsed / count);
+    Jim_SetResultString(interp, buf, -1);
+    return JIM_OK;
+}
+
+/* [exit] */
+static int Jim_ExitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    long exitCode = 0;
+
+    if (argc > 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "?exitCode?");
+        return JIM_ERR;
+    }
+    if (argc == 2) {
+        if (Jim_GetLong(interp, argv[1], &exitCode) != JIM_OK)
+            return JIM_ERR;
+    }
+    interp->exitCode = exitCode;
+    return JIM_EXIT;
+}
+
+/* [catch] */
+static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int exitCode = 0;
+    int i;
+    int sig = 0;
+
+    /* Which return codes are ignored (passed through)? By default, only exit, eval and signal */
+    jim_wide ignore_mask = (1 << JIM_EXIT) | (1 << JIM_EVAL) | (1 << JIM_SIGNAL);
+    static const int max_ignore_code = sizeof(ignore_mask) * 8;
+
+    /* Reset the error code before catch.
+     * Note that this is not strictly correct.
+     */
+    Jim_SetGlobalVariableStr(interp, "errorCode", Jim_NewStringObj(interp, "NONE", -1));
+
+    for (i = 1; i < argc - 1; i++) {
+        const char *arg = Jim_String(argv[i]);
+        jim_wide option;
+        int ignore;
+
+        /* It's a pity we can't use Jim_GetEnum here :-( */
+        if (strcmp(arg, "--") == 0) {
+            i++;
+            break;
+        }
+        if (*arg != '-') {
+            break;
+        }
+
+        if (strncmp(arg, "-no", 3) == 0) {
+            arg += 3;
+            ignore = 1;
+        }
+        else {
+            arg++;
+            ignore = 0;
+        }
+
+        if (Jim_StringToWide(arg, &option, 10) != JIM_OK) {
+            option = -1;
+        }
+        if (option < 0) {
+            option = Jim_FindByName(arg, jimReturnCodes, jimReturnCodesSize);
+        }
+        if (option < 0) {
+            goto wrongargs;
+        }
+
+        if (ignore) {
+            ignore_mask |= (1 << option);
+        }
+        else {
+            ignore_mask &= ~(1 << option);
+        }
+    }
+
+    argc -= i;
+    if (argc < 1 || argc > 3) {
+      wrongargs:
+        Jim_WrongNumArgs(interp, 1, argv,
+            "?-?no?code ... --? script ?resultVarName? ?optionVarName?");
+        return JIM_ERR;
+    }
+    argv += i;
+
+    if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) {
+        sig++;
+    }
+
+    interp->signal_level += sig;
+    if (interp->signal_level && interp->sigmask) {
+        /* If a signal is set, don't even try to execute the body */
+        exitCode = JIM_SIGNAL;
+    }
+    else {
+        exitCode = Jim_EvalObj(interp, argv[0]);
+    }
+    interp->signal_level -= sig;
+
+    /* Catch or pass through? Only the first 32/64 codes can be passed through */
+    if (exitCode >= 0 && exitCode < max_ignore_code && ((1 << exitCode) & ignore_mask)) {
+        /* Not caught, pass it up */
+        return exitCode;
+    }
+
+    if (sig && exitCode == JIM_SIGNAL) {
+        /* Catch the signal at this level */
+        if (interp->signal_set_result) {
+            interp->signal_set_result(interp, interp->sigmask);
+        }
+        else {
+            Jim_SetResultInt(interp, interp->sigmask);
+        }
+        interp->sigmask = 0;
+    }
+
+    if (argc >= 2) {
+        if (Jim_SetVariable(interp, argv[1], Jim_GetResult(interp)) != JIM_OK) {
+            return JIM_ERR;
+        }
+        if (argc == 3) {
+            Jim_Obj *optListObj = Jim_NewListObj(interp, NULL, 0);
+
+            Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-code", -1));
+            Jim_ListAppendElement(interp, optListObj,
+                Jim_NewIntObj(interp, exitCode == JIM_RETURN ? interp->returnCode : exitCode));
+            Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-level", -1));
+            Jim_ListAppendElement(interp, optListObj, Jim_NewIntObj(interp, interp->returnLevel));
+            if (exitCode == JIM_ERR) {
+                Jim_Obj *errorCode;
+                Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorinfo",
+                    -1));
+                Jim_ListAppendElement(interp, optListObj, interp->stackTrace);
+
+                errorCode = Jim_GetGlobalVariableStr(interp, "errorCode", JIM_NONE);
+                if (errorCode) {
+                    Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorcode", -1));
+                    Jim_ListAppendElement(interp, optListObj, errorCode);
+                }
+            }
+            if (Jim_SetVariable(interp, argv[2], optListObj) != JIM_OK) {
+                return JIM_ERR;
+            }
+        }
+    }
+    Jim_SetResultInt(interp, exitCode);
+    return JIM_OK;
+}
+
+#ifdef JIM_REFERENCES
+
+/* [ref] */
+static int Jim_RefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 3 && argc != 4) {
+        Jim_WrongNumArgs(interp, 1, argv, "string tag ?finalizer?");
+        return JIM_ERR;
+    }
+    if (argc == 3) {
+        Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2], NULL));
+    }
+    else {
+        Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2], argv[3]));
+    }
+    return JIM_OK;
+}
+
+/* [getref] */
+static int Jim_GetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Reference *refPtr;
+
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "reference");
+        return JIM_ERR;
+    }
+    if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL)
+        return JIM_ERR;
+    Jim_SetResult(interp, refPtr->objPtr);
+    return JIM_OK;
+}
+
+/* [setref] */
+static int Jim_SetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Reference *refPtr;
+
+    if (argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "reference newValue");
+        return JIM_ERR;
+    }
+    if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL)
+        return JIM_ERR;
+    Jim_IncrRefCount(argv[2]);
+    Jim_DecrRefCount(interp, refPtr->objPtr);
+    refPtr->objPtr = argv[2];
+    Jim_SetResult(interp, argv[2]);
+    return JIM_OK;
+}
+
+/* [collect] */
+static int Jim_CollectCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 1) {
+        Jim_WrongNumArgs(interp, 1, argv, "");
+        return JIM_ERR;
+    }
+    Jim_SetResultInt(interp, Jim_Collect(interp));
+
+    /* Free all the freed objects. */
+    while (interp->freeList) {
+        Jim_Obj *nextObjPtr = interp->freeList->nextObjPtr;
+        Jim_Free(interp->freeList);
+        interp->freeList = nextObjPtr;
+    }
+
+    return JIM_OK;
+}
+
+/* [finalize] reference ?newValue? */
+static int Jim_FinalizeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "reference ?finalizerProc?");
+        return JIM_ERR;
+    }
+    if (argc == 2) {
+        Jim_Obj *cmdNamePtr;
+
+        if (Jim_GetFinalizer(interp, argv[1], &cmdNamePtr) != JIM_OK)
+            return JIM_ERR;
+        if (cmdNamePtr != NULL) /* otherwise the null string is returned. */
+            Jim_SetResult(interp, cmdNamePtr);
+    }
+    else {
+        if (Jim_SetFinalizer(interp, argv[1], argv[2]) != JIM_OK)
+            return JIM_ERR;
+        Jim_SetResult(interp, argv[2]);
+    }
+    return JIM_OK;
+}
+
+/* [info references] */
+static int JimInfoReferences(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *listObjPtr;
+    Jim_HashTableIterator *htiter;
+    Jim_HashEntry *he;
+
+    listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+    htiter = Jim_GetHashTableIterator(&interp->references);
+    while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+        char buf[JIM_REFERENCE_SPACE];
+        Jim_Reference *refPtr = he->u.val;
+        const jim_wide *refId = he->key;
+
+        JimFormatReference(buf, refPtr, *refId);
+        Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, buf, -1));
+    }
+    Jim_FreeHashTableIterator(htiter);
+    Jim_SetResult(interp, listObjPtr);
+    return JIM_OK;
+}
+#endif
+
+/* [rename] */
+static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *oldName, *newName;
+
+    if (argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "oldName newName");
+        return JIM_ERR;
+    }
+
+    if (JimValidName(interp, "new procedure", argv[2])) {
+        return JIM_ERR;
+    }
+
+    oldName = Jim_String(argv[1]);
+    newName = Jim_String(argv[2]);
+    return Jim_RenameCommand(interp, oldName, newName);
+}
+
+int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj)
+{
+    int i;
+    int len;
+    Jim_Obj *resultObj;
+    Jim_Obj *dictObj;
+    Jim_Obj **dictValuesObj;
+
+    if (Jim_DictKeysVector(interp, objPtr, NULL, 0, &dictObj, JIM_ERRMSG) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    /* XXX: Could make the exact-match case much more efficient here.
+     *      See JimCommandsList()
+     */
+    if (Jim_DictPairs(interp, dictObj, &dictValuesObj, &len) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    /* Only return the matching values */
+    resultObj = Jim_NewListObj(interp, NULL, 0);
+
+    for (i = 0; i < len; i += 2) {
+        if (patternObj == NULL || Jim_StringMatchObj(interp, patternObj, dictValuesObj[i], 0)) {
+            Jim_ListAppendElement(interp, resultObj, dictValuesObj[i]);
+        }
+    }
+    Jim_Free(dictValuesObj);
+
+    Jim_SetResult(interp, resultObj);
+    return JIM_OK;
+}
+
+int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    if (SetDictFromAny(interp, objPtr) != JIM_OK) {
+        return -1;
+    }
+    return ((Jim_HashTable *)objPtr->internalRep.ptr)->used;
+}
+
+/* [dict] */
+static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr;
+    int option;
+    static const char * const options[] = {
+        "create", "get", "set", "unset", "exists", "keys", "merge", "size", "with", NULL
+    };
+    enum
+    {
+        OPT_CREATE, OPT_GET, OPT_SET, OPT_UNSET, OPT_EXIST, OPT_KEYS, OPT_MERGE, OPT_SIZE, OPT_WITH,
+    };
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "subcommand ?arguments ...?");
+        return JIM_ERR;
+    }
+
+    if (Jim_GetEnum(interp, argv[1], options, &option, "subcommand", JIM_ERRMSG) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    switch (option) {
+        case OPT_GET:
+            if (argc < 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "varName ?key ...?");
+                return JIM_ERR;
+            }
+            if (Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr,
+                    JIM_ERRMSG) != JIM_OK) {
+                return JIM_ERR;
+            }
+            Jim_SetResult(interp, objPtr);
+            return JIM_OK;
+
+        case OPT_SET:
+            if (argc < 5) {
+                Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...? value");
+                return JIM_ERR;
+            }
+            return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG);
+
+        case OPT_EXIST:
+            if (argc < 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "varName ?key ...?");
+                return JIM_ERR;
+            }
+            Jim_SetResultBool(interp, Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3,
+                    &objPtr, JIM_ERRMSG) == JIM_OK);
+            return JIM_OK;
+
+        case OPT_UNSET:
+            if (argc < 4) {
+                Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...?");
+                return JIM_ERR;
+            }
+            return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_NONE);
+
+        case OPT_KEYS:
+            if (argc != 3 && argc != 4) {
+                Jim_WrongNumArgs(interp, 2, argv, "dictVar ?pattern?");
+                return JIM_ERR;
+            }
+            return Jim_DictKeys(interp, argv[2], argc == 4 ? argv[3] : NULL);
+
+        case OPT_SIZE: {
+            int size;
+
+            if (argc != 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "dictVar");
+                return JIM_ERR;
+            }
+
+            size = Jim_DictSize(interp, argv[2]);
+            if (size < 0) {
+                return JIM_ERR;
+            }
+            Jim_SetResultInt(interp, size);
+            return JIM_OK;
+        }
+
+        case OPT_MERGE:
+            if (argc == 2) {
+                return JIM_OK;
+            }
+            else if (argv[2]->typePtr != &dictObjType && SetDictFromAny(interp, argv[2]) != JIM_OK) {
+                return JIM_ERR;
+            }
+            else {
+                return Jim_EvalPrefix(interp, "dict merge", argc - 2, argv + 2);
+            }
+
+        case OPT_WITH:
+            if (argc < 4) {
+                Jim_WrongNumArgs(interp, 2, argv, "dictVar ?key ...? script");
+                return JIM_ERR;
+            }
+            else if (Jim_GetVariable(interp, argv[2], JIM_ERRMSG) == NULL) {
+                return JIM_ERR;
+            }
+            else {
+                return Jim_EvalPrefix(interp, "dict with", argc - 2, argv + 2);
+            }
+
+        case OPT_CREATE:
+            if (argc % 2) {
+                Jim_WrongNumArgs(interp, 2, argv, "?key value ...?");
+                return JIM_ERR;
+            }
+            objPtr = Jim_NewDictObj(interp, argv + 2, argc - 2);
+            Jim_SetResult(interp, objPtr);
+            return JIM_OK;
+
+        default:
+            abort();
+    }
+}
+
+/* [subst] */
+static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    static const char * const options[] = {
+        "-nobackslashes", "-nocommands", "-novariables", NULL
+    };
+    enum
+    { OPT_NOBACKSLASHES, OPT_NOCOMMANDS, OPT_NOVARIABLES };
+    int i;
+    int flags = JIM_SUBST_FLAG;
+    Jim_Obj *objPtr;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "?options? string");
+        return JIM_ERR;
+    }
+    for (i = 1; i < (argc - 1); i++) {
+        int option;
+
+        if (Jim_GetEnum(interp, argv[i], options, &option, NULL,
+                JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+            return JIM_ERR;
+        }
+        switch (option) {
+            case OPT_NOBACKSLASHES:
+                flags |= JIM_SUBST_NOESC;
+                break;
+            case OPT_NOCOMMANDS:
+                flags |= JIM_SUBST_NOCMD;
+                break;
+            case OPT_NOVARIABLES:
+                flags |= JIM_SUBST_NOVAR;
+                break;
+        }
+    }
+    if (Jim_SubstObj(interp, argv[argc - 1], &objPtr, flags) != JIM_OK) {
+        return JIM_ERR;
+    }
+    Jim_SetResult(interp, objPtr);
+    return JIM_OK;
+}
+
+/* [info] */
+static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int cmd;
+    Jim_Obj *objPtr;
+    int mode = 0;
+
+    static const char * const commands[] = {
+        "body", "commands", "procs", "channels", "exists", "globals", "level", "frame", "locals",
+        "vars", "version", "patchlevel", "complete", "args", "hostname",
+        "script", "source", "stacktrace", "nameofexecutable", "returncodes",
+        "references", NULL
+    };
+    enum
+    { INFO_BODY, INFO_COMMANDS, INFO_PROCS, INFO_CHANNELS, INFO_EXISTS, INFO_GLOBALS, INFO_LEVEL,
+        INFO_FRAME, INFO_LOCALS, INFO_VARS, INFO_VERSION, INFO_PATCHLEVEL, INFO_COMPLETE, INFO_ARGS,
+        INFO_HOSTNAME, INFO_SCRIPT, INFO_SOURCE, INFO_STACKTRACE, INFO_NAMEOFEXECUTABLE,
+        INFO_RETURNCODES, INFO_REFERENCES,
+    };
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "subcommand ?args ...?");
+        return JIM_ERR;
+    }
+    if (Jim_GetEnum(interp, argv[1], commands, &cmd, "subcommand", JIM_ERRMSG | JIM_ENUM_ABBREV)
+        != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    /* Test for the the most common commands first, just in case it makes a difference */
+    switch (cmd) {
+        case INFO_EXISTS:{
+                if (argc != 3) {
+                    Jim_WrongNumArgs(interp, 2, argv, "varName");
+                    return JIM_ERR;
+                }
+                Jim_SetResultBool(interp, Jim_GetVariable(interp, argv[2], 0) != NULL);
+                break;
+            }
+
+        case INFO_CHANNELS:
+#ifndef jim_ext_aio
+            Jim_SetResultString(interp, "aio not enabled", -1);
+            return JIM_ERR;
+#endif
+        case INFO_COMMANDS:
+        case INFO_PROCS:
+            if (argc != 2 && argc != 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
+                return JIM_ERR;
+            }
+            Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL,
+                    (cmd - INFO_COMMANDS)));
+            break;
+
+        case INFO_VARS:
+            mode++;             /* JIM_VARLIST_VARS */
+        case INFO_LOCALS:
+            mode++;             /* JIM_VARLIST_LOCALS */
+        case INFO_GLOBALS:
+            /* mode 0 => JIM_VARLIST_GLOBALS */
+            if (argc != 2 && argc != 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
+                return JIM_ERR;
+            }
+            Jim_SetResult(interp, JimVariablesList(interp, argc == 3 ? argv[2] : NULL, mode));
+            break;
+
+        case INFO_SCRIPT:
+            if (argc != 2) {
+                Jim_WrongNumArgs(interp, 2, argv, "");
+                return JIM_ERR;
+            }
+            Jim_SetResult(interp, Jim_GetScript(interp, interp->currentScriptObj)->fileNameObj);
+            break;
+
+        case INFO_SOURCE:{
+                int line;
+                Jim_Obj *resObjPtr;
+                Jim_Obj *fileNameObj;
+
+                if (argc != 3) {
+                    Jim_WrongNumArgs(interp, 2, argv, "source");
+                    return JIM_ERR;
+                }
+                if (argv[2]->typePtr == &sourceObjType) {
+                    fileNameObj = argv[2]->internalRep.sourceValue.fileNameObj;
+                    line = argv[2]->internalRep.sourceValue.lineNumber;
+                }
+                else if (argv[2]->typePtr == &scriptObjType) {
+                    ScriptObj *script = Jim_GetScript(interp, argv[2]);
+                    fileNameObj = script->fileNameObj;
+                    line = script->line;
+                }
+                else {
+                    fileNameObj = interp->emptyObj;
+                    line = 1;
+                }
+                resObjPtr = Jim_NewListObj(interp, NULL, 0);
+                Jim_ListAppendElement(interp, resObjPtr, fileNameObj);
+                Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line));
+                Jim_SetResult(interp, resObjPtr);
+                break;
+            }
+
+        case INFO_STACKTRACE:
+            Jim_SetResult(interp, interp->stackTrace);
+            break;
+
+        case INFO_LEVEL:
+        case INFO_FRAME:
+            switch (argc) {
+                case 2:
+                    Jim_SetResultInt(interp, interp->framePtr->level);
+                    break;
+
+                case 3:
+                    if (JimInfoLevel(interp, argv[2], &objPtr, cmd == INFO_LEVEL) != JIM_OK) {
+                        return JIM_ERR;
+                    }
+                    Jim_SetResult(interp, objPtr);
+                    break;
+
+                default:
+                    Jim_WrongNumArgs(interp, 2, argv, "?levelNum?");
+                    return JIM_ERR;
+            }
+            break;
+
+        case INFO_BODY:
+        case INFO_ARGS:{
+                Jim_Cmd *cmdPtr;
+
+                if (argc != 3) {
+                    Jim_WrongNumArgs(interp, 2, argv, "procname");
+                    return JIM_ERR;
+                }
+                if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) {
+                    return JIM_ERR;
+                }
+                if (!cmdPtr->isproc) {
+                    Jim_SetResultFormatted(interp, "command \"%#s\" is not a procedure", argv[2]);
+                    return JIM_ERR;
+                }
+                Jim_SetResult(interp,
+                    cmd == INFO_BODY ? cmdPtr->u.proc.bodyObjPtr : cmdPtr->u.proc.argListObjPtr);
+                break;
+            }
+
+        case INFO_VERSION:
+        case INFO_PATCHLEVEL:{
+                char buf[(JIM_INTEGER_SPACE * 2) + 1];
+
+                sprintf(buf, "%d.%d", JIM_VERSION / 100, JIM_VERSION % 100);
+                Jim_SetResultString(interp, buf, -1);
+                break;
+            }
+
+        case INFO_COMPLETE:
+            if (argc != 3 && argc != 4) {
+                Jim_WrongNumArgs(interp, 2, argv, "script ?missing?");
+                return JIM_ERR;
+            }
+            else {
+                int len;
+                const char *s = Jim_GetString(argv[2], &len);
+                char missing;
+
+                Jim_SetResultBool(interp, Jim_ScriptIsComplete(s, len, &missing));
+                if (missing != ' ' && argc == 4) {
+                    Jim_SetVariable(interp, argv[3], Jim_NewStringObj(interp, &missing, 1));
+                }
+            }
+            break;
+
+        case INFO_HOSTNAME:
+            /* Redirect to os.gethostname if it exists */
+            return Jim_Eval(interp, "os.gethostname");
+
+        case INFO_NAMEOFEXECUTABLE:
+            /* Redirect to Tcl proc */
+            return Jim_Eval(interp, "{info nameofexecutable}");
+
+        case INFO_RETURNCODES:
+            if (argc == 2) {
+                int i;
+                Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+                for (i = 0; jimReturnCodes[i]; i++) {
+                    Jim_ListAppendElement(interp, listObjPtr, Jim_NewIntObj(interp, i));
+                    Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp,
+                            jimReturnCodes[i], -1));
+                }
+
+                Jim_SetResult(interp, listObjPtr);
+            }
+            else if (argc == 3) {
+                long code;
+                const char *name;
+
+                if (Jim_GetLong(interp, argv[2], &code) != JIM_OK) {
+                    return JIM_ERR;
+                }
+                name = Jim_ReturnCode(code);
+                if (*name == '?') {
+                    Jim_SetResultInt(interp, code);
+                }
+                else {
+                    Jim_SetResultString(interp, name, -1);
+                }
+            }
+            else {
+                Jim_WrongNumArgs(interp, 2, argv, "?code?");
+                return JIM_ERR;
+            }
+            break;
+        case INFO_REFERENCES:
+#ifdef JIM_REFERENCES
+            return JimInfoReferences(interp, argc, argv);
+#else
+            Jim_SetResultString(interp, "not supported", -1);
+            return JIM_ERR;
+#endif
+    }
+    return JIM_OK;
+}
+
+/* [exists] */
+static int Jim_ExistsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr;
+
+    static const char * const options[] = {
+        "-command", "-proc", "-var", NULL
+    };
+    enum
+    {
+        OPT_COMMAND, OPT_PROC, OPT_VAR
+    };
+    int option;
+
+    if (argc == 2) {
+        option = OPT_VAR;
+        objPtr = argv[1];
+    }
+    else if (argc == 3) {
+        if (Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+            return JIM_ERR;
+        }
+        objPtr = argv[2];
+    }
+    else {
+        Jim_WrongNumArgs(interp, 1, argv, "?option? name");
+        return JIM_ERR;
+    }
+
+    /* Test for the the most common commands first, just in case it makes a difference */
+    switch (option) {
+        case OPT_VAR:
+            Jim_SetResultBool(interp, Jim_GetVariable(interp, objPtr, 0) != NULL);
+            break;
+
+        case OPT_COMMAND:
+        case OPT_PROC: {
+            Jim_Cmd *cmd = Jim_GetCommand(interp, objPtr, JIM_NONE);
+            Jim_SetResultBool(interp, cmd != NULL && (option == OPT_COMMAND || cmd->isproc));
+            break;
+        }
+    }
+    return JIM_OK;
+}
+
+/* [split] */
+static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *str, *splitChars, *noMatchStart;
+    int splitLen, strLen;
+    Jim_Obj *resObjPtr;
+    int c;
+    int len;
+
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "string ?splitChars?");
+        return JIM_ERR;
+    }
+
+    str = Jim_GetString(argv[1], &len);
+    if (len == 0) {
+        return JIM_OK;
+    }
+    strLen = Jim_Utf8Length(interp, argv[1]);
+
+    /* Init */
+    if (argc == 2) {
+        splitChars = " \n\t\r";
+        splitLen = 4;
+    }
+    else {
+        splitChars = Jim_String(argv[2]);
+        splitLen = Jim_Utf8Length(interp, argv[2]);
+    }
+
+    noMatchStart = str;
+    resObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+    /* Split */
+    if (splitLen) {
+        Jim_Obj *objPtr;
+        while (strLen--) {
+            const char *sc = splitChars;
+            int scLen = splitLen;
+            int sl = utf8_tounicode(str, &c);
+            while (scLen--) {
+                int pc;
+                sc += utf8_tounicode(sc, &pc);
+                if (c == pc) {
+                    objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart));
+                    Jim_ListAppendElement(interp, resObjPtr, objPtr);
+                    noMatchStart = str + sl;
+                    break;
+                }
+            }
+            str += sl;
+        }
+        objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart));
+        Jim_ListAppendElement(interp, resObjPtr, objPtr);
+    }
+    else {
+        /* This handles the special case of splitchars eq {}
+         * Optimise by sharing common (ASCII) characters
+         */
+        Jim_Obj **commonObj = NULL;
+#define NUM_COMMON (128 - 9)
+        while (strLen--) {
+            int n = utf8_tounicode(str, &c);
+#ifdef JIM_OPTIMIZATION
+            if (c >= 9 && c < 128) {
+                /* Common ASCII char. Note that 9 is the tab character */
+                c -= 9;
+                if (!commonObj) {
+                    commonObj = Jim_Alloc(sizeof(*commonObj) * NUM_COMMON);
+                    memset(commonObj, 0, sizeof(*commonObj) * NUM_COMMON);
+                }
+                if (!commonObj[c]) {
+                    commonObj[c] = Jim_NewStringObj(interp, str, 1);
+                }
+                Jim_ListAppendElement(interp, resObjPtr, commonObj[c]);
+                str++;
+                continue;
+            }
+#endif
+            Jim_ListAppendElement(interp, resObjPtr, Jim_NewStringObjUtf8(interp, str, 1));
+            str += n;
+        }
+        Jim_Free(commonObj);
+    }
+
+    Jim_SetResult(interp, resObjPtr);
+    return JIM_OK;
+}
+
+/* [join] */
+static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *joinStr;
+    int joinStrLen, i, listLen;
+    Jim_Obj *resObjPtr;
+
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?");
+        return JIM_ERR;
+    }
+    /* Init */
+    if (argc == 2) {
+        joinStr = " ";
+        joinStrLen = 1;
+    }
+    else {
+        joinStr = Jim_GetString(argv[2], &joinStrLen);
+    }
+    listLen = Jim_ListLength(interp, argv[1]);
+    resObjPtr = Jim_NewStringObj(interp, NULL, 0);
+    /* Split */
+    for (i = 0; i < listLen; i++) {
+        Jim_Obj *objPtr = 0;
+
+        Jim_ListIndex(interp, argv[1], i, &objPtr, JIM_NONE);
+        Jim_AppendObj(interp, resObjPtr, objPtr);
+        if (i + 1 != listLen) {
+            Jim_AppendString(interp, resObjPtr, joinStr, joinStrLen);
+        }
+    }
+    Jim_SetResult(interp, resObjPtr);
+    return JIM_OK;
+}
+
+/* [format] */
+static int Jim_FormatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "formatString ?arg arg ...?");
+        return JIM_ERR;
+    }
+    objPtr = Jim_FormatString(interp, argv[1], argc - 2, argv + 2);
+    if (objPtr == NULL)
+        return JIM_ERR;
+    Jim_SetResult(interp, objPtr);
+    return JIM_OK;
+}
+
+/* [scan] */
+static int Jim_ScanCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *listPtr, **outVec;
+    int outc, i;
+
+    if (argc < 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "string format ?varName varName ...?");
+        return JIM_ERR;
+    }
+    if (argv[2]->typePtr != &scanFmtStringObjType)
+        SetScanFmtFromAny(interp, argv[2]);
+    if (FormatGetError(argv[2]) != 0) {
+        Jim_SetResultString(interp, FormatGetError(argv[2]), -1);
+        return JIM_ERR;
+    }
+    if (argc > 3) {
+        int maxPos = FormatGetMaxPos(argv[2]);
+        int count = FormatGetCnvCount(argv[2]);
+
+        if (maxPos > argc - 3) {
+            Jim_SetResultString(interp, "\"%n$\" argument index out of range", -1);
+            return JIM_ERR;
+        }
+        else if (count > argc - 3) {
+            Jim_SetResultString(interp, "different numbers of variable names and "
+                "field specifiers", -1);
+            return JIM_ERR;
+        }
+        else if (count < argc - 3) {
+            Jim_SetResultString(interp, "variable is not assigned by any "
+                "conversion specifiers", -1);
+            return JIM_ERR;
+        }
+    }
+    listPtr = Jim_ScanString(interp, argv[1], argv[2], JIM_ERRMSG);
+    if (listPtr == 0)
+        return JIM_ERR;
+    if (argc > 3) {
+        int rc = JIM_OK;
+        int count = 0;
+
+        if (listPtr != 0 && listPtr != (Jim_Obj *)EOF) {
+            int len = Jim_ListLength(interp, listPtr);
+
+            if (len != 0) {
+                JimListGetElements(interp, listPtr, &outc, &outVec);
+                for (i = 0; i < outc; ++i) {
+                    if (Jim_Length(outVec[i]) > 0) {
+                        ++count;
+                        if (Jim_SetVariable(interp, argv[3 + i], outVec[i]) != JIM_OK) {
+                            rc = JIM_ERR;
+                        }
+                    }
+                }
+            }
+            Jim_FreeNewObj(interp, listPtr);
+        }
+        else {
+            count = -1;
+        }
+        if (rc == JIM_OK) {
+            Jim_SetResultInt(interp, count);
+        }
+        return rc;
+    }
+    else {
+        if (listPtr == (Jim_Obj *)EOF) {
+            Jim_SetResult(interp, Jim_NewListObj(interp, 0, 0));
+            return JIM_OK;
+        }
+        Jim_SetResult(interp, listPtr);
+    }
+    return JIM_OK;
+}
+
+/* [error] */
+static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "message ?stacktrace?");
+        return JIM_ERR;
+    }
+    Jim_SetResult(interp, argv[1]);
+    if (argc == 3) {
+        JimSetStackTrace(interp, argv[2]);
+        return JIM_ERR;
+    }
+    interp->addStackTrace++;
+    return JIM_ERR;
+}
+
+/* [lrange] */
+static int Jim_LrangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr;
+
+    if (argc != 4) {
+        Jim_WrongNumArgs(interp, 1, argv, "list first last");
+        return JIM_ERR;
+    }
+    if ((objPtr = Jim_ListRange(interp, argv[1], argv[2], argv[3])) == NULL)
+        return JIM_ERR;
+    Jim_SetResult(interp, objPtr);
+    return JIM_OK;
+}
+
+/* [lrepeat] */
+static int Jim_LrepeatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr;
+    long count;
+
+    if (argc < 2 || Jim_GetLong(interp, argv[1], &count) != JIM_OK || count < 0) {
+        Jim_WrongNumArgs(interp, 1, argv, "count ?value ...?");
+        return JIM_ERR;
+    }
+
+    if (count == 0 || argc == 2) {
+        return JIM_OK;
+    }
+
+    argc -= 2;
+    argv += 2;
+
+    objPtr = Jim_NewListObj(interp, argv, argc);
+    while (--count) {
+        int i;
+
+        for (i = 0; i < argc; i++) {
+            ListAppendElement(objPtr, argv[i]);
+        }
+    }
+
+    Jim_SetResult(interp, objPtr);
+    return JIM_OK;
+}
+
+char **Jim_GetEnviron(void)
+{
+#if defined(HAVE__NSGETENVIRON)
+    return *_NSGetEnviron();
+#else
+    #if !defined(NO_ENVIRON_EXTERN)
+    extern char **environ;
+    #endif
+
+    return environ;
+#endif
+}
+
+void Jim_SetEnviron(char **env)
+{
+#if defined(HAVE__NSGETENVIRON)
+    *_NSGetEnviron() = env;
+#else
+    #if !defined(NO_ENVIRON_EXTERN)
+    extern char **environ;
+    #endif
+
+    environ = env;
+#endif
+}
+
+/* [env] */
+static int Jim_EnvCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *key;
+    const char *val;
+
+    if (argc == 1) {
+        char **e = Jim_GetEnviron();
+
+        int i;
+        Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+        for (i = 0; e[i]; i++) {
+            const char *equals = strchr(e[i], '=');
+
+            if (equals) {
+                Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, e[i],
+                        equals - e[i]));
+                Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, equals + 1, -1));
+            }
+        }
+
+        Jim_SetResult(interp, listObjPtr);
+        return JIM_OK;
+    }
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "varName ?default?");
+        return JIM_ERR;
+    }
+    key = Jim_String(argv[1]);
+    val = getenv(key);
+    if (val == NULL) {
+        if (argc < 3) {
+            Jim_SetResultFormatted(interp, "environment variable \"%#s\" does not exist", argv[1]);
+            return JIM_ERR;
+        }
+        val = Jim_String(argv[2]);
+    }
+    Jim_SetResult(interp, Jim_NewStringObj(interp, val, -1));
+    return JIM_OK;
+}
+
+/* [source] */
+static int Jim_SourceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int retval;
+
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "fileName");
+        return JIM_ERR;
+    }
+    retval = Jim_EvalFile(interp, Jim_String(argv[1]));
+    if (retval == JIM_RETURN)
+        return JIM_OK;
+    return retval;
+}
+
+/* [lreverse] */
+static int Jim_LreverseCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *revObjPtr, **ele;
+    int len;
+
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "list");
+        return JIM_ERR;
+    }
+    JimListGetElements(interp, argv[1], &len, &ele);
+    len--;
+    revObjPtr = Jim_NewListObj(interp, NULL, 0);
+    while (len >= 0)
+        ListAppendElement(revObjPtr, ele[len--]);
+    Jim_SetResult(interp, revObjPtr);
+    return JIM_OK;
+}
+
+static int JimRangeLen(jim_wide start, jim_wide end, jim_wide step)
+{
+    jim_wide len;
+
+    if (step == 0)
+        return -1;
+    if (start == end)
+        return 0;
+    else if (step > 0 && start > end)
+        return -1;
+    else if (step < 0 && end > start)
+        return -1;
+    len = end - start;
+    if (len < 0)
+        len = -len;             /* abs(len) */
+    if (step < 0)
+        step = -step;           /* abs(step) */
+    len = 1 + ((len - 1) / step);
+    /* We can truncate safely to INT_MAX, the range command
+     * will always return an error for a such long range
+     * because Tcl lists can't be so long. */
+    if (len > INT_MAX)
+        len = INT_MAX;
+    return (int)((len < 0) ? -1 : len);
+}
+
+/* [range] */
+static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    jim_wide start = 0, end, step = 1;
+    int len, i;
+    Jim_Obj *objPtr;
+
+    if (argc < 2 || argc > 4) {
+        Jim_WrongNumArgs(interp, 1, argv, "?start? end ?step?");
+        return JIM_ERR;
+    }
+    if (argc == 2) {
+        if (Jim_GetWide(interp, argv[1], &end) != JIM_OK)
+            return JIM_ERR;
+    }
+    else {
+        if (Jim_GetWide(interp, argv[1], &start) != JIM_OK ||
+            Jim_GetWide(interp, argv[2], &end) != JIM_OK)
+            return JIM_ERR;
+        if (argc == 4 && Jim_GetWide(interp, argv[3], &step) != JIM_OK)
+            return JIM_ERR;
+    }
+    if ((len = JimRangeLen(start, end, step)) == -1) {
+        Jim_SetResultString(interp, "Invalid (infinite?) range specified", -1);
+        return JIM_ERR;
+    }
+    objPtr = Jim_NewListObj(interp, NULL, 0);
+    for (i = 0; i < len; i++)
+        ListAppendElement(objPtr, Jim_NewIntObj(interp, start + i * step));
+    Jim_SetResult(interp, objPtr);
+    return JIM_OK;
+}
+
+/* [rand] */
+static int Jim_RandCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    jim_wide min = 0, max = 0, len, maxMul;
+
+    if (argc < 1 || argc > 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "?min? max");
+        return JIM_ERR;
+    }
+    if (argc == 1) {
+        max = JIM_WIDE_MAX;
+    } else if (argc == 2) {
+        if (Jim_GetWide(interp, argv[1], &max) != JIM_OK)
+            return JIM_ERR;
+    } else if (argc == 3) {
+        if (Jim_GetWide(interp, argv[1], &min) != JIM_OK ||
+            Jim_GetWide(interp, argv[2], &max) != JIM_OK)
+            return JIM_ERR;
+    }
+    len = max-min;
+    if (len < 0) {
+        Jim_SetResultString(interp, "Invalid arguments (max < min)", -1);
+        return JIM_ERR;
+    }
+    maxMul = JIM_WIDE_MAX - (len ? (JIM_WIDE_MAX%len) : 0);
+    while (1) {
+        jim_wide r;
+
+        JimRandomBytes(interp, &r, sizeof(jim_wide));
+        if (r < 0 || r >= maxMul) continue;
+        r = (len == 0) ? 0 : r%len;
+        Jim_SetResultInt(interp, min+r);
+        return JIM_OK;
+    }
+}
+
+static const struct {
+    const char *name;
+    Jim_CmdProc cmdProc;
+} Jim_CoreCommandsTable[] = {
+    {"set", Jim_SetCoreCommand},
+    {"unset", Jim_UnsetCoreCommand},
+    {"puts", Jim_PutsCoreCommand},
+    {"+", Jim_AddCoreCommand},
+    {"*", Jim_MulCoreCommand},
+    {"-", Jim_SubCoreCommand},
+    {"/", Jim_DivCoreCommand},
+    {"incr", Jim_IncrCoreCommand},
+    {"while", Jim_WhileCoreCommand},
+    {"loop", Jim_LoopCoreCommand},
+    {"for", Jim_ForCoreCommand},
+    {"foreach", Jim_ForeachCoreCommand},
+    {"lmap", Jim_LmapCoreCommand},
+    {"if", Jim_IfCoreCommand},
+    {"switch", Jim_SwitchCoreCommand},
+    {"list", Jim_ListCoreCommand},
+    {"lindex", Jim_LindexCoreCommand},
+    {"lset", Jim_LsetCoreCommand},
+    {"lsearch", Jim_LsearchCoreCommand},
+    {"llength", Jim_LlengthCoreCommand},
+    {"lappend", Jim_LappendCoreCommand},
+    {"linsert", Jim_LinsertCoreCommand},
+    {"lreplace", Jim_LreplaceCoreCommand},
+    {"lsort", Jim_LsortCoreCommand},
+    {"append", Jim_AppendCoreCommand},
+    {"debug", Jim_DebugCoreCommand},
+    {"eval", Jim_EvalCoreCommand},
+    {"uplevel", Jim_UplevelCoreCommand},
+    {"expr", Jim_ExprCoreCommand},
+    {"break", Jim_BreakCoreCommand},
+    {"continue", Jim_ContinueCoreCommand},
+    {"proc", Jim_ProcCoreCommand},
+    {"concat", Jim_ConcatCoreCommand},
+    {"return", Jim_ReturnCoreCommand},
+    {"upvar", Jim_UpvarCoreCommand},
+    {"global", Jim_GlobalCoreCommand},
+    {"string", Jim_StringCoreCommand},
+    {"time", Jim_TimeCoreCommand},
+    {"exit", Jim_ExitCoreCommand},
+    {"catch", Jim_CatchCoreCommand},
+#ifdef JIM_REFERENCES
+    {"ref", Jim_RefCoreCommand},
+    {"getref", Jim_GetrefCoreCommand},
+    {"setref", Jim_SetrefCoreCommand},
+    {"finalize", Jim_FinalizeCoreCommand},
+    {"collect", Jim_CollectCoreCommand},
+#endif
+    {"rename", Jim_RenameCoreCommand},
+    {"dict", Jim_DictCoreCommand},
+    {"subst", Jim_SubstCoreCommand},
+    {"info", Jim_InfoCoreCommand},
+    {"exists", Jim_ExistsCoreCommand},
+    {"split", Jim_SplitCoreCommand},
+    {"join", Jim_JoinCoreCommand},
+    {"format", Jim_FormatCoreCommand},
+    {"scan", Jim_ScanCoreCommand},
+    {"error", Jim_ErrorCoreCommand},
+    {"lrange", Jim_LrangeCoreCommand},
+    {"lrepeat", Jim_LrepeatCoreCommand},
+    {"env", Jim_EnvCoreCommand},
+    {"source", Jim_SourceCoreCommand},
+    {"lreverse", Jim_LreverseCoreCommand},
+    {"range", Jim_RangeCoreCommand},
+    {"rand", Jim_RandCoreCommand},
+    {"tailcall", Jim_TailcallCoreCommand},
+    {"local", Jim_LocalCoreCommand},
+    {"upcall", Jim_UpcallCoreCommand},
+    {NULL, NULL},
+};
+
+void Jim_RegisterCoreCommands(Jim_Interp *interp)
+{
+    int i = 0;
+
+    while (Jim_CoreCommandsTable[i].name != NULL) {
+        Jim_CreateCommand(interp,
+            Jim_CoreCommandsTable[i].name, Jim_CoreCommandsTable[i].cmdProc, NULL, NULL);
+        i++;
+    }
+}
+
+/* -----------------------------------------------------------------------------
+ * Interactive prompt
+ * ---------------------------------------------------------------------------*/
+void Jim_MakeErrorMessage(Jim_Interp *interp)
+{
+    Jim_Obj *argv[2];
+
+    argv[0] = Jim_NewStringObj(interp, "errorInfo", -1);
+    argv[1] = interp->result;
+
+    Jim_EvalObjVector(interp, 2, argv);
+}
+
+static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
+    const char *prefix, const char *const *tablePtr, const char *name)
+{
+    int count;
+    char **tablePtrSorted;
+    int i;
+
+    for (count = 0; tablePtr[count]; count++) {
+    }
+
+    if (name == NULL) {
+        name = "option";
+    }
+
+    Jim_SetResultFormatted(interp, "%s%s \"%s\": must be ", badtype, name, arg);
+    tablePtrSorted = Jim_Alloc(sizeof(char *) * count);
+    memcpy(tablePtrSorted, tablePtr, sizeof(char *) * count);
+    qsort(tablePtrSorted, count, sizeof(char *), qsortCompareStringPointers);
+    for (i = 0; i < count; i++) {
+        if (i + 1 == count && count > 1) {
+            Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1);
+        }
+        Jim_AppendStrings(interp, Jim_GetResult(interp), prefix, tablePtrSorted[i], NULL);
+        if (i + 1 != count) {
+            Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1);
+        }
+    }
+    Jim_Free(tablePtrSorted);
+}
+
+int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
+    const char *const *tablePtr, int *indexPtr, const char *name, int flags)
+{
+    const char *bad = "bad ";
+    const char *const *entryPtr = NULL;
+    int i;
+    int match = -1;
+    int arglen;
+    const char *arg = Jim_GetString(objPtr, &arglen);
+
+    *indexPtr = -1;
+
+    for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) {
+        if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) {
+            /* Found an exact match */
+            *indexPtr = i;
+            return JIM_OK;
+        }
+        if (flags & JIM_ENUM_ABBREV) {
+            /* Accept an unambiguous abbreviation.
+             * Note that '-' doesnt' consitute a valid abbreviation
+             */
+            if (strncmp(arg, *entryPtr, arglen) == 0) {
+                if (*arg == '-' && arglen == 1) {
+                    break;
+                }
+                if (match >= 0) {
+                    bad = "ambiguous ";
+                    goto ambiguous;
+                }
+                match = i;
+            }
+        }
+    }
+
+    /* If we had an unambiguous partial match */
+    if (match >= 0) {
+        *indexPtr = match;
+        return JIM_OK;
+    }
+
+  ambiguous:
+    if (flags & JIM_ERRMSG) {
+        JimSetFailedEnumResult(interp, arg, bad, "", tablePtr, name);
+    }
+    return JIM_ERR;
+}
+
+int Jim_FindByName(const char *name, const char * const array[], size_t len)
+{
+    int i;
+
+    for (i = 0; i < (int)len; i++) {
+        if (array[i] && strcmp(array[i], name) == 0) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+int Jim_IsDict(Jim_Obj *objPtr)
+{
+    return objPtr->typePtr == &dictObjType;
+}
+
+int Jim_IsList(Jim_Obj *objPtr)
+{
+    return objPtr->typePtr == &listObjType;
+}
+
+/**
+ * Very simple printf-like formatting, designed for error messages.
+ *
+ * The format may contain up to 5 '%s' or '%#s', corresponding to variable arguments.
+ * The resulting string is created and set as the result.
+ *
+ * Each '%s' should correspond to a regular string parameter.
+ * Each '%#s' should correspond to a (Jim_Obj *) parameter.
+ * Any other printf specifier is not allowed (but %% is allowed for the % character).
+ *
+ * e.g. Jim_SetResultFormatted(interp, "Bad option \"%#s\" in proc \"%#s\"", optionObjPtr, procNamePtr);
+ *
+ * Note: We take advantage of the fact that printf has the same behaviour for both %s and %#s
+ */
+void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...)
+{
+    /* Initial space needed */
+    int len = strlen(format);
+    int extra = 0;
+    int n = 0;
+    const char *params[5];
+    char *buf;
+    va_list args;
+    int i;
+
+    va_start(args, format);
+
+    for (i = 0; i < len && n < 5; i++) {
+        int l;
+
+        if (strncmp(format + i, "%s", 2) == 0) {
+            params[n] = va_arg(args, char *);
+
+            l = strlen(params[n]);
+        }
+        else if (strncmp(format + i, "%#s", 3) == 0) {
+            Jim_Obj *objPtr = va_arg(args, Jim_Obj *);
+
+            params[n] = Jim_GetString(objPtr, &l);
+        }
+        else {
+            if (format[i] == '%') {
+                i++;
+            }
+            continue;
+        }
+        n++;
+        extra += l;
+    }
+
+    len += extra;
+    buf = Jim_Alloc(len + 1);
+    len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]);
+
+    Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
+}
+
+/* stubs */
+#ifndef jim_ext_package
+int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
+{
+    return JIM_OK;
+}
+#endif
+#ifndef jim_ext_aio
+FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *fhObj)
+{
+    Jim_SetResultString(interp, "aio not enabled", -1);
+    return NULL;
+}
+#endif
+
+
+/*
+ * Local Variables: ***
+ * c-basic-offset: 4 ***
+ * tab-width: 4 ***
+ * End: ***
+ */
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jim.h b/android/external/usb_modeswitch/usb_modeswitch/jim/jim.h
new file mode 100755
index 0000000..fdc9db9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jim.h
@@ -0,0 +1,917 @@
+/* Jim - A small embeddable Tcl interpreter
+ *
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
+ * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
+ * Copyright 2008 oharboe - �yvind Harboe - oyvind.harboe@zylin.com
+ * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
+ * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
+ * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ *
+ *--- Inline Header File Documentation ---
+ *    [By Duane Ellis, openocd@duaneellis.com, 8/18/8]
+ *
+ * Belief is "Jim" would greatly benifit if Jim Internals where
+ * documented in some way - form whatever, and perhaps - the package:
+ * 'doxygen' is the correct approach to do that.
+ *
+ *   Details, see: http://www.stack.nl/~dimitri/doxygen/
+ *
+ * To that end please follow these guide lines:
+ *
+ *    (A) Document the PUBLIC api in the .H file.
+ *
+ *    (B) Document JIM Internals, in the .C file.
+ *
+ *    (C) Remember JIM is embedded in other packages, to that end do
+ *    not assume that your way of documenting is the right way, Jim's
+ *    public documentation should be agnostic, such that it is some
+ *    what agreeable with the "package" that is embedding JIM inside
+ *    of it's own doxygen documentation.
+ *
+ *    (D) Use minimal Doxygen tags.
+ *
+ * This will be an "ongoing work in progress" for some time.
+ **/
+
+#ifndef __JIM__H
+#define __JIM__H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <time.h>
+#include <limits.h>
+#include <stdio.h>  /* for the FILE typedef definition */
+#include <stdlib.h> /* In order to export the Jim_Free() macro */
+#include <stdarg.h> /* In order to get type va_list */
+
+/* -----------------------------------------------------------------------------
+ * System configuration
+ * autoconf (configure) will set these
+ * ---------------------------------------------------------------------------*/
+#include <jim-win32compat.h>
+
+#ifndef HAVE_NO_AUTOCONF
+#include <jim-config.h>
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Compiler specific fixes.
+ * ---------------------------------------------------------------------------*/
+
+/* Long Long type and related issues */
+#ifndef jim_wide
+#  ifdef HAVE_LONG_LONG
+#    define jim_wide long long
+#    ifndef LLONG_MAX
+#      define LLONG_MAX    9223372036854775807LL
+#    endif
+#    ifndef LLONG_MIN
+#      define LLONG_MIN    (-LLONG_MAX - 1LL)
+#    endif
+#    define JIM_WIDE_MIN LLONG_MIN
+#    define JIM_WIDE_MAX LLONG_MAX
+#  else
+#    define jim_wide long
+#    define JIM_WIDE_MIN LONG_MIN
+#    define JIM_WIDE_MAX LONG_MAX
+#  endif
+
+/* -----------------------------------------------------------------------------
+ * LIBC specific fixes
+ * ---------------------------------------------------------------------------*/
+
+#  ifdef HAVE_LONG_LONG
+#    define JIM_WIDE_MODIFIER "lld"
+#  else
+#    define JIM_WIDE_MODIFIER "ld"
+#    define strtoull strtoul
+#  endif
+#endif
+
+#define UCHAR(c) ((unsigned char)(c))
+
+/* -----------------------------------------------------------------------------
+ * Exported defines
+ * ---------------------------------------------------------------------------*/
+
+/* Jim version numbering: every version of jim is marked with a
+ * successive integer number. This is version 0. The first
+ * stable version will be 1, then 2, 3, and so on. */
+#define JIM_VERSION 72
+
+#define JIM_OK 0
+#define JIM_ERR 1
+#define JIM_RETURN 2
+#define JIM_BREAK 3
+#define JIM_CONTINUE 4
+#define JIM_SIGNAL 5
+#define JIM_EXIT 6
+/* The following are internal codes and should never been seen/used */
+#define JIM_EVAL 7
+
+#define JIM_MAX_NESTING_DEPTH 1000 /* default max nesting depth */
+
+/* Some function get an integer argument with flags to change
+ * the behaviour. */
+#define JIM_NONE 0    /* no flags set */
+#define JIM_ERRMSG 1    /* set an error message in the interpreter. */
+
+#define JIM_UNSHARED 4 /* Flag to Jim_GetVariable() */
+
+/* Flags for Jim_SubstObj() */
+#define JIM_SUBST_NOVAR 1 /* don't perform variables substitutions */
+#define JIM_SUBST_NOCMD 2 /* don't perform command substitutions */
+#define JIM_SUBST_NOESC 4 /* don't perform escapes substitutions */
+#define JIM_SUBST_FLAG 128 /* flag to indicate that this is a real substition object */
+
+/* Unused arguments generate annoying warnings... */
+#define JIM_NOTUSED(V) ((void) V)
+
+/* Flags for Jim_GetEnum() */
+#define JIM_ENUM_ABBREV 2    /* Allow unambiguous abbreviation */
+
+/* Flags used by API calls getting a 'nocase' argument. */
+#define JIM_CASESENS    0   /* case sensitive */
+#define JIM_NOCASE      1   /* no case */
+
+/* Filesystem related */
+#define JIM_PATH_LEN 1024
+
+/* Newline, some embedded system may need -DJIM_CRLF */
+#ifdef JIM_CRLF
+#define JIM_NL "\r\n"
+#else
+#define JIM_NL "\n"
+#endif
+
+#define JIM_LIBPATH "auto_path"
+#define JIM_INTERACTIVE "tcl_interactive"
+
+/* -----------------------------------------------------------------------------
+ * Stack
+ * ---------------------------------------------------------------------------*/
+
+typedef struct Jim_Stack {
+    int len;
+    int maxlen;
+    void **vector;
+} Jim_Stack;
+
+/* -----------------------------------------------------------------------------
+ * Hash table
+ * ---------------------------------------------------------------------------*/
+
+typedef struct Jim_HashEntry {
+    const void *key;
+    union {
+        void *val;
+        int intval;
+    } u;
+    struct Jim_HashEntry *next;
+} Jim_HashEntry;
+
+typedef struct Jim_HashTableType {
+    unsigned int (*hashFunction)(const void *key);
+    const void *(*keyDup)(void *privdata, const void *key);
+    void *(*valDup)(void *privdata, const void *obj);
+    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
+    void (*keyDestructor)(void *privdata, const void *key);
+    void (*valDestructor)(void *privdata, void *obj);
+} Jim_HashTableType;
+
+typedef struct Jim_HashTable {
+    Jim_HashEntry **table;
+    const Jim_HashTableType *type;
+    unsigned int size;
+    unsigned int sizemask;
+    unsigned int used;
+    unsigned int collisions;
+    void *privdata;
+} Jim_HashTable;
+
+typedef struct Jim_HashTableIterator {
+    Jim_HashTable *ht;
+    int index;
+    Jim_HashEntry *entry, *nextEntry;
+} Jim_HashTableIterator;
+
+/* This is the initial size of every hash table */
+#define JIM_HT_INITIAL_SIZE     16
+
+/* ------------------------------- Macros ------------------------------------*/
+#define Jim_FreeEntryVal(ht, entry) \
+    if ((ht)->type->valDestructor) \
+        (ht)->type->valDestructor((ht)->privdata, (entry)->u.val)
+
+#define Jim_SetHashVal(ht, entry, _val_) do { \
+    if ((ht)->type->valDup) \
+        entry->u.val = (ht)->type->valDup((ht)->privdata, _val_); \
+    else \
+        entry->u.val = (_val_); \
+} while(0)
+
+#define Jim_FreeEntryKey(ht, entry) \
+    if ((ht)->type->keyDestructor) \
+        (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
+
+#define Jim_SetHashKey(ht, entry, _key_) do { \
+    if ((ht)->type->keyDup) \
+        entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \
+    else \
+        entry->key = (_key_); \
+} while(0)
+
+#define Jim_CompareHashKeys(ht, key1, key2) \
+    (((ht)->type->keyCompare) ? \
+        (ht)->type->keyCompare((ht)->privdata, key1, key2) : \
+        (key1) == (key2))
+
+#define Jim_HashKey(ht, key) (ht)->type->hashFunction(key)
+
+#define Jim_GetHashEntryKey(he) ((he)->key)
+#define Jim_GetHashEntryVal(he) ((he)->val)
+#define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
+#define Jim_GetHashTableSize(ht) ((ht)->size)
+#define Jim_GetHashTableUsed(ht) ((ht)->used)
+
+/* -----------------------------------------------------------------------------
+ * Jim_Obj structure
+ * ---------------------------------------------------------------------------*/
+
+/* -----------------------------------------------------------------------------
+ * Jim object. This is mostly the same as Tcl_Obj itself,
+ * with the addition of the 'prev' and 'next' pointers.
+ * In Jim all the objects are stored into a linked list for GC purposes,
+ * so that it's possible to access every object living in a given interpreter
+ * sequentially. When an object is freed, it's moved into a different
+ * linked list, used as object pool.
+ *
+ * The refcount of a freed object is always -1.
+ * ---------------------------------------------------------------------------*/
+typedef struct Jim_Obj {
+    int refCount; /* reference count */
+    char *bytes; /* string representation buffer. NULL = no string repr. */
+    int length; /* number of bytes in 'bytes', not including the numterm. */
+    const struct Jim_ObjType *typePtr; /* object type. */
+    /* Internal representation union */
+    union {
+        /* integer number type */
+        jim_wide wideValue;
+        /* hashed object type value */
+        int hashValue;
+        /* index type */
+        int indexValue;
+        /* return code type */
+        int returnCode;
+        /* double number type */
+        double doubleValue;
+        /* Generic pointer */
+        void *ptr;
+        /* Generic two pointers value */
+        struct {
+            void *ptr1;
+            void *ptr2;
+        } twoPtrValue;
+        /* Variable object */
+        struct {
+            unsigned jim_wide callFrameId;
+            struct Jim_Var *varPtr;
+        } varValue;
+        /* Command object */
+        struct {
+            unsigned jim_wide procEpoch;
+            struct Jim_Cmd *cmdPtr;
+        } cmdValue;
+        /* List object */
+        struct {
+            struct Jim_Obj **ele;    /* Elements vector */
+            int len;        /* Length */
+            int maxLen;        /* Allocated 'ele' length */
+        } listValue;
+        /* String type */
+        struct {
+            int maxLength;
+            int charLength;     /* utf-8 char length. -1 if unknown */
+        } strValue;
+        /* Reference type */
+        struct {
+            jim_wide id;
+            struct Jim_Reference *refPtr;
+        } refValue;
+        /* Source type */
+        struct {
+            struct Jim_Obj *fileNameObj;
+            int lineNumber;
+        } sourceValue;
+        /* Dict substitution type */
+        struct {
+            struct Jim_Obj *varNameObjPtr;
+            struct Jim_Obj *indexObjPtr;
+        } dictSubstValue;
+        /* tagged binary type */
+        struct {
+            unsigned char *data;
+            size_t         len;
+        } binaryValue;
+        /* Regular expression pattern */
+        struct {
+            unsigned flags;
+            void *compre;       /* really an allocated (regex_t *) */
+        } regexpValue;
+        struct {
+            int line;
+            int argc;
+        } scriptLineValue;
+    } internalRep;
+    /* This are 8 or 16 bytes more for every object
+     * but this is required for efficient garbage collection
+     * of Jim references. */
+    struct Jim_Obj *prevObjPtr; /* pointer to the prev object. */
+    struct Jim_Obj *nextObjPtr; /* pointer to the next object. */
+} Jim_Obj;
+
+/* Jim_Obj related macros */
+#define Jim_IncrRefCount(objPtr) \
+    ++(objPtr)->refCount
+#define Jim_DecrRefCount(interp, objPtr) \
+    if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr)
+#define Jim_IsShared(objPtr) \
+    ((objPtr)->refCount > 1)
+
+/* This macro is used when we allocate a new object using
+ * Jim_New...Obj(), but for some error we need to destroy it.
+ * Instead to use Jim_IncrRefCount() + Jim_DecrRefCount() we
+ * can just call Jim_FreeNewObj. To call Jim_Free directly
+ * seems too raw, the object handling may change and we want
+ * that Jim_FreeNewObj() can be called only against objects
+ * that are belived to have refcount == 0. */
+#define Jim_FreeNewObj Jim_FreeObj
+
+/* Free the internal representation of the object. */
+#define Jim_FreeIntRep(i,o) \
+    if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \
+        (o)->typePtr->freeIntRepProc(i, o)
+
+/* Get the internal representation pointer */
+#define Jim_GetIntRepPtr(o) (o)->internalRep.ptr
+
+/* Set the internal representation pointer */
+#define Jim_SetIntRepPtr(o, p) \
+    (o)->internalRep.ptr = (p)
+
+/* The object type structure.
+ * There are four methods.
+ *
+ * - FreeIntRep is used to free the internal representation of the object.
+ *   Can be NULL if there is nothing to free.
+ * - DupIntRep is used to duplicate the internal representation of the object.
+ *   If NULL, when an object is duplicated, the internalRep union is
+ *   directly copied from an object to another.
+ *   Note that it's up to the caller to free the old internal repr of the
+ *   object before to call the Dup method.
+ * - UpdateString is used to create the string from the internal repr.
+ * - setFromAny is used to convert the current object into one of this type.
+ */
+
+struct Jim_Interp;
+
+typedef void (Jim_FreeInternalRepProc)(struct Jim_Interp *interp,
+        struct Jim_Obj *objPtr);
+typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp,
+        struct Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr);
+
+typedef struct Jim_ObjType {
+    const char *name; /* The name of the type. */
+    Jim_FreeInternalRepProc *freeIntRepProc;
+    Jim_DupInternalRepProc *dupIntRepProc;
+    Jim_UpdateStringProc *updateStringProc;
+    int flags;
+} Jim_ObjType;
+
+/* Jim_ObjType flags */
+#define JIM_TYPE_NONE 0        /* No flags */
+#define JIM_TYPE_REFERENCES 1    /* The object may contain referneces. */
+
+/* Starting from 1 << 20 flags are reserved for private uses of
+ * different calls. This way the same 'flags' argument may be used
+ * to pass both global flags and private flags. */
+#define JIM_PRIV_FLAG_SHIFT 20
+
+/* -----------------------------------------------------------------------------
+ * Call frame, vars, commands structures
+ * ---------------------------------------------------------------------------*/
+
+/* Call frame */
+typedef struct Jim_CallFrame {
+    unsigned jim_wide id; /* Call Frame ID. Used for caching. */
+    int level; /* Level of this call frame. 0 = global */
+    struct Jim_HashTable vars; /* Where local vars are stored */
+    struct Jim_HashTable *staticVars; /* pointer to procedure static vars */
+    struct Jim_CallFrame *parentCallFrame;
+    Jim_Obj *const *argv; /* object vector of the current procedure call. */
+    int argc; /* number of args of the current procedure call. */
+    Jim_Obj *procArgsObjPtr; /* arglist object of the running procedure */
+    Jim_Obj *procBodyObjPtr; /* body object of the running procedure */
+    struct Jim_CallFrame *nextFramePtr;
+    Jim_Obj *fileNameObj;       /* file and line of caller of this proc (if available) */
+    int line;
+} Jim_CallFrame;
+
+/* The var structure. It just holds the pointer of the referenced
+ * object. If linkFramePtr is not NULL the variable is a link
+ * to a variable of name store on objPtr living on the given callframe
+ * (this happens when the [global] or [upvar] command is used).
+ * The interp in order to always know how to free the Jim_Obj associated
+ * with a given variable because In Jim objects memory managment is
+ * bound to interpreters. */
+typedef struct Jim_Var {
+    Jim_Obj *objPtr;
+    struct Jim_CallFrame *linkFramePtr;
+} Jim_Var;
+
+/* The cmd structure. */
+typedef int (*Jim_CmdProc)(struct Jim_Interp *interp, int argc,
+    Jim_Obj *const *argv);
+typedef void (*Jim_DelCmdProc)(struct Jim_Interp *interp, void *privData);
+
+
+
+/* A command is implemented in C if funcPtr is != NULL, otherwise
+ * it's a Tcl procedure with the arglist and body represented by the
+ * two objects referenced by arglistObjPtr and bodyoObjPtr. */
+typedef struct Jim_Cmd {
+    int inUse;           /* Reference count */
+    int isproc;          /* Is this a procedure? */
+    union {
+        struct {
+            /* native (C) command */
+            Jim_CmdProc cmdProc; /* The command implementation */
+            Jim_DelCmdProc delProc; /* Called when the command is deleted if != NULL */
+            void *privData; /* command-private data available via Jim_CmdPrivData() */
+        } native;
+        struct {
+            /* Tcl procedure */
+            Jim_Obj *argListObjPtr;
+            Jim_Obj *bodyObjPtr;
+            Jim_HashTable *staticVars;  /* Static vars hash table. NULL if no statics. */
+            struct Jim_Cmd *prevCmd;    /* Previous command defn if proc created 'local' */
+            int argListLen;             /* Length of argListObjPtr */
+            int reqArity;               /* Number of required parameters */
+            int optArity;               /* Number of optional parameters */
+            int argsPos;                /* Position of 'args', if specified, or -1 */
+            int upcall;                 /* True if proc is currently in upcall */
+            struct Jim_ProcArg {
+                Jim_Obj *nameObjPtr;    /* Name of this arg */
+                Jim_Obj *defaultObjPtr; /* Default value, (or rename for $args) */
+            } *arglist;
+        } proc;
+    } u;
+} Jim_Cmd;
+
+/* Pseudo Random Number Generator State structure */
+typedef struct Jim_PrngState {
+    unsigned char sbox[256];
+    unsigned int i, j;
+} Jim_PrngState;
+
+/* -----------------------------------------------------------------------------
+ * Jim interpreter structure.
+ * Fields similar to the real Tcl interpreter structure have the same names.
+ * ---------------------------------------------------------------------------*/
+typedef struct Jim_Interp {
+    Jim_Obj *result; /* object returned by the last command called. */
+    int errorLine; /* Error line where an error occurred. */
+    Jim_Obj *errorFileNameObj; /* Error file where an error occurred. */
+    int addStackTrace; /* > 0 If a level should be added to the stack trace */
+    int maxNestingDepth; /* Used for infinite loop detection. */
+    int returnCode; /* Completion code to return on JIM_RETURN. */
+    int returnLevel; /* Current level of 'return -level' */
+    int exitCode; /* Code to return to the OS on JIM_EXIT. */
+    long id; /* Hold unique id for various purposes */
+    int signal_level; /* A nesting level of catch -signal */
+    jim_wide sigmask;  /* Bit mask of caught signals, or 0 if none */
+    int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask); /* Set a result for the sigmask */
+    Jim_CallFrame *framePtr; /* Pointer to the current call frame */
+    Jim_CallFrame *topFramePtr; /* toplevel/global frame pointer. */
+    struct Jim_HashTable commands; /* Commands hash table */
+    unsigned jim_wide procEpoch; /* Incremented every time the result
+                of procedures names lookup caching
+                may no longer be valid. */
+    unsigned jim_wide callFrameEpoch; /* Incremented every time a new
+                callframe is created. This id is used for the
+                'ID' field contained in the Jim_CallFrame
+                structure. */
+    int local; /* If 'local' is in effect, newly defined procs keep a reference to the old defn */
+    Jim_Obj *liveList; /* Linked list of all the live objects. */
+    Jim_Obj *freeList; /* Linked list of all the unused objects. */
+    Jim_Obj *currentScriptObj; /* Script currently in execution. */
+    Jim_Obj *emptyObj; /* Shared empty string object. */
+    Jim_Obj *trueObj; /* Shared true int object. */
+    Jim_Obj *falseObj; /* Shared false int object. */
+    unsigned jim_wide referenceNextId; /* Next id for reference. */
+    struct Jim_HashTable references; /* References hash table. */
+    jim_wide lastCollectId; /* reference max Id of the last GC
+                execution. It's set to -1 while the collection
+                is running as sentinel to avoid to recursive
+                calls via the [collect] command inside
+                finalizers. */
+    time_t lastCollectTime; /* unix time of the last GC execution */
+    Jim_Obj *stackTrace; /* Stack trace object. */
+    Jim_Obj *errorProc; /* Name of last procedure which returned an error */
+    Jim_Obj *unknown; /* Unknown command cache */
+    int unknown_called; /* The unknown command has been invoked */
+    int errorFlag; /* Set if an error occurred during execution. */
+    void *cmdPrivData; /* Used to pass the private data pointer to
+                  a command. It is set to what the user specified
+                  via Jim_CreateCommand(). */
+
+    struct Jim_CallFrame *freeFramesList; /* list of CallFrame structures. */
+    struct Jim_HashTable assocData; /* per-interp storage for use by packages */
+    Jim_PrngState *prngState; /* per interpreter Random Number Gen. state. */
+    struct Jim_HashTable packages; /* Provided packages hash table */
+    Jim_Stack *localProcs; /* procs to be destroyed on end of evaluation */
+    Jim_Stack *loadHandles; /* handles of loaded modules [load] */
+} Jim_Interp;
+
+/* Currently provided as macro that performs the increment.
+ * At some point may be a real function doing more work.
+ * The proc epoch is used in order to know when a command lookup
+ * cached can no longer considered valid. */
+#define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++
+#define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
+#define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
+/* Note: Using trueObj and falseObj here makes some things slower...*/
+#define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b)
+#define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj)
+#define Jim_GetResult(i) ((i)->result)
+#define Jim_CmdPrivData(i) ((i)->cmdPrivData)
+#define Jim_String(o) Jim_GetString((o), NULL)
+
+/* Note that 'o' is expanded only one time inside this macro,
+ * so it's safe to use side effects. */
+#define Jim_SetResult(i,o) do {     \
+    Jim_Obj *_resultObjPtr_ = (o);    \
+    Jim_IncrRefCount(_resultObjPtr_); \
+    Jim_DecrRefCount(i,(i)->result);  \
+    (i)->result = _resultObjPtr_;     \
+} while(0)
+
+/* Use this for filehandles, etc. which need a unique id */
+#define Jim_GetId(i) (++(i)->id)
+
+/* Reference structure. The interpreter pointer is held within privdata member in HashTable */
+#define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference
+                                  string representation must be fixed length. */
+typedef struct Jim_Reference {
+    Jim_Obj *objPtr;
+    Jim_Obj *finalizerCmdNamePtr;
+    char tag[JIM_REFERENCE_TAGLEN+1];
+} Jim_Reference;
+
+/* -----------------------------------------------------------------------------
+ * Exported API prototypes.
+ * ---------------------------------------------------------------------------*/
+
+/* Macros that are common for extensions and core. */
+#define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
+
+/* The core includes real prototypes, extensions instead
+ * include a global function pointer for every function exported.
+ * Once the extension calls Jim_InitExtension(), the global
+ * functon pointers are set to the value of the STUB table
+ * contained in the Jim_Interp structure.
+ *
+ * This makes Jim able to load extensions even if it is statically
+ * linked itself, and to load extensions compiled with different
+ * versions of Jim (as long as the API is still compatible.) */
+
+/* Macros are common for core and extensions */
+#define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
+
+#define JIM_EXPORT
+
+/* Memory allocation */
+JIM_EXPORT void *Jim_Alloc (int size);
+JIM_EXPORT void *Jim_Realloc(void *ptr, int size);
+JIM_EXPORT void Jim_Free (void *ptr);
+JIM_EXPORT char * Jim_StrDup (const char *s);
+JIM_EXPORT char *Jim_StrDupLen(const char *s, int l);
+
+/* environment */
+JIM_EXPORT char **Jim_GetEnviron(void);
+JIM_EXPORT void Jim_SetEnviron(char **env);
+
+/* evaluation */
+JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);
+/* in C code, you can do this and get better error messages */
+/*   Jim_EvalSource( interp, __FILE__, __LINE__ , "some tcl commands"); */
+JIM_EXPORT int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script);
+/* Backwards compatibility */
+#define Jim_Eval_Named(I, S, F, L) Jim_EvalSource((I), (F), (L), (S))
+
+JIM_EXPORT int Jim_EvalGlobal(Jim_Interp *interp, const char *script);
+JIM_EXPORT int Jim_EvalFile(Jim_Interp *interp, const char *filename);
+JIM_EXPORT int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename);
+JIM_EXPORT int Jim_EvalObj (Jim_Interp *interp, Jim_Obj *scriptObjPtr);
+JIM_EXPORT int Jim_EvalObjVector (Jim_Interp *interp, int objc,
+        Jim_Obj *const *objv);
+JIM_EXPORT int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix,
+        int objc, Jim_Obj *const *objv);
+#define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
+JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr,
+        Jim_Obj **resObjPtrPtr, int flags);
+
+/* stack */
+JIM_EXPORT void Jim_InitStack(Jim_Stack *stack);
+JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack);
+JIM_EXPORT int Jim_StackLen(Jim_Stack *stack);
+JIM_EXPORT void Jim_StackPush(Jim_Stack *stack, void *element);
+JIM_EXPORT void * Jim_StackPop(Jim_Stack *stack);
+JIM_EXPORT void * Jim_StackPeek(Jim_Stack *stack);
+JIM_EXPORT void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr));
+
+/* hash table */
+JIM_EXPORT int Jim_InitHashTable (Jim_HashTable *ht,
+        const Jim_HashTableType *type, void *privdata);
+JIM_EXPORT int Jim_ExpandHashTable (Jim_HashTable *ht,
+        unsigned int size);
+JIM_EXPORT int Jim_AddHashEntry (Jim_HashTable *ht, const void *key,
+        void *val);
+JIM_EXPORT int Jim_ReplaceHashEntry (Jim_HashTable *ht,
+        const void *key, void *val);
+JIM_EXPORT int Jim_DeleteHashEntry (Jim_HashTable *ht,
+        const void *key);
+JIM_EXPORT int Jim_FreeHashTable (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashEntry * Jim_FindHashEntry (Jim_HashTable *ht,
+        const void *key);
+JIM_EXPORT int Jim_ResizeHashTable (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashTableIterator *Jim_GetHashTableIterator
+        (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashEntry * Jim_NextHashEntry
+        (Jim_HashTableIterator *iter);
+
+/* objects */
+JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp);
+JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr);
+JIM_EXPORT void Jim_InitStringRep (Jim_Obj *objPtr, const char *bytes,
+        int length);
+JIM_EXPORT Jim_Obj * Jim_DuplicateObj (Jim_Interp *interp,
+        Jim_Obj *objPtr);
+JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr,
+        int *lenPtr);
+JIM_EXPORT int Jim_Length(Jim_Obj *objPtr);
+
+/* string object */
+JIM_EXPORT Jim_Obj * Jim_NewStringObj (Jim_Interp *interp,
+        const char *s, int len);
+JIM_EXPORT Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp,
+        const char *s, int charlen);
+JIM_EXPORT Jim_Obj * Jim_NewStringObjNoAlloc (Jim_Interp *interp,
+        char *s, int len);
+JIM_EXPORT void Jim_AppendString (Jim_Interp *interp, Jim_Obj *objPtr,
+        const char *str, int len);
+JIM_EXPORT void Jim_AppendObj (Jim_Interp *interp, Jim_Obj *objPtr,
+        Jim_Obj *appendObjPtr);
+JIM_EXPORT void Jim_AppendStrings (Jim_Interp *interp,
+        Jim_Obj *objPtr, ...);
+JIM_EXPORT int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr);
+JIM_EXPORT int Jim_StringMatchObj (Jim_Interp *interp, Jim_Obj *patternObjPtr,
+        Jim_Obj *objPtr, int nocase);
+JIM_EXPORT Jim_Obj * Jim_StringRangeObj (Jim_Interp *interp,
+        Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr,
+        Jim_Obj *lastObjPtr);
+JIM_EXPORT Jim_Obj * Jim_FormatString (Jim_Interp *interp,
+        Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv);
+JIM_EXPORT Jim_Obj * Jim_ScanString (Jim_Interp *interp, Jim_Obj *strObjPtr,
+        Jim_Obj *fmtObjPtr, int flags);
+JIM_EXPORT int Jim_CompareStringImmediate (Jim_Interp *interp,
+        Jim_Obj *objPtr, const char *str);
+JIM_EXPORT int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr,
+        Jim_Obj *secondObjPtr, int nocase);
+JIM_EXPORT int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr);
+
+/* reference object */
+JIM_EXPORT Jim_Obj * Jim_NewReference (Jim_Interp *interp,
+        Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr);
+JIM_EXPORT Jim_Reference * Jim_GetReference (Jim_Interp *interp,
+        Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr);
+JIM_EXPORT int Jim_GetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr);
+
+/* interpreter */
+JIM_EXPORT Jim_Interp * Jim_CreateInterp (void);
+JIM_EXPORT void Jim_FreeInterp (Jim_Interp *i);
+JIM_EXPORT int Jim_GetExitCode (Jim_Interp *interp);
+JIM_EXPORT const char *Jim_ReturnCode(int code);
+JIM_EXPORT void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...);
+
+/* commands */
+JIM_EXPORT void Jim_RegisterCoreCommands (Jim_Interp *interp);
+JIM_EXPORT int Jim_CreateCommand (Jim_Interp *interp,
+        const char *cmdName, Jim_CmdProc cmdProc, void *privData,
+         Jim_DelCmdProc delProc);
+JIM_EXPORT int Jim_DeleteCommand (Jim_Interp *interp,
+        const char *cmdName);
+JIM_EXPORT int Jim_RenameCommand (Jim_Interp *interp,
+        const char *oldName, const char *newName);
+JIM_EXPORT Jim_Cmd * Jim_GetCommand (Jim_Interp *interp,
+        Jim_Obj *objPtr, int flags);
+JIM_EXPORT int Jim_SetVariable (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr);
+JIM_EXPORT int Jim_SetVariableStr (Jim_Interp *interp,
+        const char *name, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetGlobalVariableStr (Jim_Interp *interp,
+        const char *name, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetVariableStrWithStr (Jim_Interp *interp,
+        const char *name, const char *val);
+JIM_EXPORT int Jim_SetVariableLink (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr,
+        Jim_CallFrame *targetCallFrame);
+JIM_EXPORT Jim_Obj * Jim_GetVariable (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetGlobalVariable (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetVariableStr (Jim_Interp *interp,
+        const char *name, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetGlobalVariableStr (Jim_Interp *interp,
+        const char *name, int flags);
+JIM_EXPORT int Jim_UnsetVariable (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, int flags);
+
+/* call frame */
+JIM_EXPORT Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp,
+        Jim_Obj *levelObjPtr);
+
+/* garbage collection */
+JIM_EXPORT int Jim_Collect (Jim_Interp *interp);
+JIM_EXPORT void Jim_CollectIfNeeded (Jim_Interp *interp);
+
+/* index object */
+JIM_EXPORT int Jim_GetIndex (Jim_Interp *interp, Jim_Obj *objPtr,
+        int *indexPtr);
+
+/* list object */
+JIM_EXPORT Jim_Obj * Jim_NewListObj (Jim_Interp *interp,
+        Jim_Obj *const *elements, int len);
+JIM_EXPORT void Jim_ListInsertElements (Jim_Interp *interp,
+        Jim_Obj *listPtr, int listindex, int objc, Jim_Obj *const *objVec);
+JIM_EXPORT void Jim_ListAppendElement (Jim_Interp *interp,
+        Jim_Obj *listPtr, Jim_Obj *objPtr);
+JIM_EXPORT void Jim_ListAppendList (Jim_Interp *interp,
+        Jim_Obj *listPtr, Jim_Obj *appendListPtr);
+JIM_EXPORT int Jim_ListLength (Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_ListIndex (Jim_Interp *interp, Jim_Obj *listPrt,
+        int listindex, Jim_Obj **objPtrPtr, int seterr);
+JIM_EXPORT int Jim_SetListIndex (Jim_Interp *interp,
+        Jim_Obj *varNamePtr, Jim_Obj *const *indexv, int indexc,
+        Jim_Obj *newObjPtr);
+JIM_EXPORT Jim_Obj * Jim_ConcatObj (Jim_Interp *interp, int objc,
+        Jim_Obj *const *objv);
+
+/* dict object */
+JIM_EXPORT Jim_Obj * Jim_NewDictObj (Jim_Interp *interp,
+        Jim_Obj *const *elements, int len);
+JIM_EXPORT int Jim_DictKey (Jim_Interp *interp, Jim_Obj *dictPtr,
+        Jim_Obj *keyPtr, Jim_Obj **objPtrPtr, int flags);
+JIM_EXPORT int Jim_DictKeysVector (Jim_Interp *interp,
+        Jim_Obj *dictPtr, Jim_Obj *const *keyv, int keyc,
+        Jim_Obj **objPtrPtr, int flags);
+JIM_EXPORT int Jim_SetDictKeysVector (Jim_Interp *interp,
+        Jim_Obj *varNamePtr, Jim_Obj *const *keyv, int keyc,
+        Jim_Obj *newObjPtr, int flags);
+JIM_EXPORT int Jim_DictPairs(Jim_Interp *interp,
+        Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len);
+JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
+        Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr);
+JIM_EXPORT int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj);
+JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr);
+
+/* return code object */
+JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr,
+        int *intPtr);
+
+/* expression object */
+JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp,
+        Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr);
+JIM_EXPORT int Jim_GetBoolFromExpr (Jim_Interp *interp,
+        Jim_Obj *exprObjPtr, int *boolPtr);
+
+/* integer object */
+JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr,
+        jim_wide *widePtr);
+JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr,
+        long *longPtr);
+#define Jim_NewWideObj  Jim_NewIntObj
+JIM_EXPORT Jim_Obj * Jim_NewIntObj (Jim_Interp *interp,
+        jim_wide wideValue);
+
+/* double object */
+JIM_EXPORT int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
+        double *doublePtr);
+JIM_EXPORT void Jim_SetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
+        double doubleValue);
+JIM_EXPORT Jim_Obj * Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue);
+
+/* shared strings */
+JIM_EXPORT const char * Jim_GetSharedString (Jim_Interp *interp,
+        const char *str);
+JIM_EXPORT void Jim_ReleaseSharedString (Jim_Interp *interp,
+        const char *str);
+
+/* commands utilities */
+JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc,
+        Jim_Obj *const *argv, const char *msg);
+JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr,
+        const char * const *tablePtr, int *indexPtr, const char *name, int flags);
+JIM_EXPORT int Jim_ScriptIsComplete (const char *s, int len,
+        char *stateCharPtr);
+/**
+ * Find a matching name in the array of the given length.
+ *
+ * NULL entries are ignored.
+ *
+ * Returns the matching index if found, or -1 if not.
+ */
+JIM_EXPORT int Jim_FindByName(const char *name, const char * const array[], size_t len);
+
+/* package utilities */
+typedef void (Jim_InterpDeleteProc)(Jim_Interp *interp, void *data);
+JIM_EXPORT void * Jim_GetAssocData(Jim_Interp *interp, const char *key);
+JIM_EXPORT int Jim_SetAssocData(Jim_Interp *interp, const char *key,
+        Jim_InterpDeleteProc *delProc, void *data);
+JIM_EXPORT int Jim_DeleteAssocData(Jim_Interp *interp, const char *key);
+
+/* Packages C API */
+/* jim-package.c */
+JIM_EXPORT int Jim_PackageProvide (Jim_Interp *interp,
+        const char *name, const char *ver, int flags);
+JIM_EXPORT int Jim_PackageRequire (Jim_Interp *interp,
+        const char *name, int flags);
+
+/* error messages */
+JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp);
+
+/* interactive mode */
+JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp);
+
+/* Misc */
+JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
+JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base);
+
+/* jim-load.c */
+JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName);
+JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp);
+
+/* jim-aio.c */
+JIM_EXPORT FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command);
+
+
+/* type inspection - avoid where possible */
+JIM_EXPORT int Jim_IsDict(Jim_Obj *objPtr);
+JIM_EXPORT int Jim_IsList(Jim_Obj *objPtr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __JIM__H */
+
+/*
+ * Local Variables: ***
+ * c-basic-offset: 4 ***
+ * tab-width: 4 ***
+ * End: ***
+ */
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jimautoconf.h.in b/android/external/usb_modeswitch/usb_modeswitch/jim/jimautoconf.h.in
new file mode 100755
index 0000000..f4eb0e5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jimautoconf.h.in
@@ -0,0 +1,145 @@
+/* jimautoconf.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the `backtrace' function. */
+#undef HAVE_BACKTRACE
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Have the dlopen function */
+#undef HAVE_DLOPEN
+
+/* Define to 1 if you have the `fork' function. */
+#undef HAVE_FORK
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `geteuid' function. */
+#undef HAVE_GETEUID
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#undef HAVE_INET_NTOP
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if the system has the type `long long'. */
+#undef HAVE_LONG_LONG
+
+/* Define to 1 if you have the `lstat' function. */
+#undef HAVE_LSTAT
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `mkstemp' function. */
+#undef HAVE_MKSTEMP
+
+/* Define to 1 if you have the `opendir' function. */
+#undef HAVE_OPENDIR
+
+/* Define to 1 if you have the `pipe' function. */
+#undef HAVE_PIPE
+
+/* Have libreadline */
+#undef HAVE_READLINE
+
+/* Define to 1 if you have the `readlink' function. */
+#undef HAVE_READLINK
+
+/* Define to 1 if you have the `realpath' function. */
+#undef HAVE_REALPATH
+
+/* Define to 1 if you have the `regcomp' function. */
+#undef HAVE_REGCOMP
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the `sleep' function. */
+#undef HAVE_SLEEP
+
+/* Have libsqlite */
+#undef HAVE_SQLITE
+
+/* Have libsqlite3 */
+#undef HAVE_SQLITE3
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strptime' function. */
+#undef HAVE_STRPTIME
+
+/* Define to 1 if you have the `sysinfo' function. */
+#undef HAVE_SYSINFO
+
+/* Define to 1 if you have the `syslog' function. */
+#undef HAVE_SYSLOG
+
+/* Define to 1 if you have the `sys_siglist' function. */
+#undef HAVE_SYS_SIGLIST
+
+/* Define to 1 if you have the `sys_signame' function. */
+#undef HAVE_SYS_SIGNAME
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#undef HAVE_SYS_UN_H
+
+/* Define to 1 if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define to 1 if you have the `ualarm' function. */
+#undef HAVE_UALARM
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `usleep' function. */
+#undef HAVE_USLEEP
+
+/* Define to 1 if you have the `vfork' function. */
+#undef HAVE_VFORK
+
+/* Define to 1 if you have the `waitpid' function. */
+#undef HAVE_WAITPID
+
+/* No need to declare extern 'environ'. */
+#undef NO_ENVIRON_EXTERN
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jimregexp.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jimregexp.c
new file mode 100755
index 0000000..c652ad4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jimregexp.c
@@ -0,0 +1,1756 @@
+/*
+ * regcomp and regexec -- regsub and regerror are elsewhere
+ *
+ *	Copyright (c) 1986 by University of Toronto.
+ *	Written by Henry Spencer.  Not derived from licensed software.
+ *
+ *	Permission is granted to anyone to use this software for any
+ *	purpose on any computer system, and to redistribute it freely,
+ *	subject to the following restrictions:
+ *
+ *	1. The author is not responsible for the consequences of use of
+ *		this software, no matter how awful, even if they arise
+ *		from defects in it.
+ *
+ *	2. The origin of this software must not be misrepresented, either
+ *		by explicit claim or by omission.
+ *
+ *	3. Altered versions must be plainly marked as such, and must not
+ *		be misrepresented as being the original software.
+ *** THIS IS AN ALTERED VERSION.  It was altered by John Gilmore,
+ *** hoptoad!gnu, on 27 Dec 1986, to add \n as an alternative to |
+ *** to assist in implementing egrep.
+ *** THIS IS AN ALTERED VERSION.  It was altered by John Gilmore,
+ *** hoptoad!gnu, on 27 Dec 1986, to add \< and \> for word-matching
+ *** as in BSD grep and ex.
+ *** THIS IS AN ALTERED VERSION.  It was altered by John Gilmore,
+ *** hoptoad!gnu, on 28 Dec 1986, to optimize characters quoted with \.
+ *** THIS IS AN ALTERED VERSION.  It was altered by James A. Woods,
+ *** ames!jaw, on 19 June 1987, to quash a regcomp() redundancy.
+ *** THIS IS AN ALTERED VERSION.  It was altered by Christopher Seiwald
+ *** seiwald@vix.com, on 28 August 1993, for use in jam.  Regmagic.h
+ *** was moved into regexp.h, and the include of regexp.h now uses "'s
+ *** to avoid conflicting with the system regexp.h.  Const, bless its
+ *** soul, was removed so it can compile everywhere.  The declaration
+ *** of strchr() was in conflict on AIX, so it was removed (as it is
+ *** happily defined in string.h).
+ *** THIS IS AN ALTERED VERSION.  It was altered by Christopher Seiwald
+ *** seiwald@perforce.com, on 20 January 2000, to use function prototypes.
+ *** THIS IS AN ALTERED VERSION.  It was altered by Christopher Seiwald
+ *** seiwald@perforce.com, on 05 November 2002, to const string literals.
+ *
+ *   THIS IS AN ALTERED VERSION.  It was altered by Steve Bennett <steveb@workware.net.au>
+ *   on 16 October 2010, to remove static state and add better Tcl ARE compatibility.
+ *   This includes counted repetitions, UTF-8 support, character classes,
+ *   shorthand character classes, increased number of parentheses to 100,
+ *   backslash escape sequences. It also removes \n as an alternative to |.
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions.  Serious changes in
+ * regular-expression syntax might require a total rethink.
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "jimregexp.h"
+#include "utf8.h"
+
+#if !defined(HAVE_REGCOMP) || defined(JIM_REGEXP)
+
+/*
+ * Structure for regexp "program".  This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology).  Each node is an opcode
+ * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
+ * all nodes except BRANCH implement concatenation; a "next" pointer with
+ * a BRANCH on both ends of it is connecting two alternatives.  (Here we
+ * have one of the subtle syntax dependencies:  an individual BRANCH (as
+ * opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence.)  The operand of some types of node is
+ * a literal string; for others, it is a node leading into a sub-FSM.  In
+ * particular, the operand of a BRANCH node is the first node of the branch.
+ * (NB this is *not* a tree structure:  the tail of the branch connects
+ * to the thing following the set of BRANCHes.)  The opcodes are:
+ */
+
+/* This *MUST* be less than (255-20)/2=117 */
+#define REG_MAX_PAREN 100
+
+/* definition	number	opnd?	meaning */
+#define	END	0	/* no	End of program. */
+#define	BOL	1	/* no	Match "" at beginning of line. */
+#define	EOL	2	/* no	Match "" at end of line. */
+#define	ANY	3	/* no	Match any one character. */
+#define	ANYOF	4	/* str	Match any character in this string. */
+#define	ANYBUT	5	/* str	Match any character not in this string. */
+#define	BRANCH	6	/* node	Match this alternative, or the next... */
+#define	BACK	7	/* no	Match "", "next" ptr points backward. */
+#define	EXACTLY	8	/* str	Match this string. */
+#define	NOTHING	9	/* no	Match empty string. */
+#define	REP		10	/* max,min	Match this (simple) thing [min,max] times. */
+#define	REPMIN	11	/* max,min	Match this (simple) thing [min,max] times, mininal match. */
+#define	REPX	12	/* max,min	Match this (complex) thing [min,max] times. */
+#define	REPXMIN	13	/* max,min	Match this (complex) thing [min,max] times, minimal match. */
+
+#define	WORDA	15	/* no	Match "" at wordchar, where prev is nonword */
+#define	WORDZ	16	/* no	Match "" at nonwordchar, where prev is word */
+#define	OPEN	20	/* no	Mark this point in input as start of #n. */
+			/*	OPEN+1 is number 1, etc. */
+#define	CLOSE	(OPEN+REG_MAX_PAREN)	/* no	Analogous to OPEN. */
+#define	CLOSE_END	(CLOSE+REG_MAX_PAREN)
+
+/*
+ * The first byte of the regexp internal "program" is actually this magic
+ * number; the start node begins in the second byte.
+ */
+#define	REG_MAGIC	0xFADED00D
+
+/*
+ * Opcode notes:
+ *
+ * BRANCH	The set of branches constituting a single choice are hooked
+ *		together with their "next" pointers, since precedence prevents
+ *		anything being concatenated to any individual branch.  The
+ *		"next" pointer of the last BRANCH in a choice points to the
+ *		thing following the whole choice.  This is also where the
+ *		final "next" pointer of each individual branch points; each
+ *		branch starts with the operand node of a BRANCH node.
+ *
+ * BACK		Normal "next" pointers all implicitly point forward; BACK
+ *		exists to make loop structures possible.
+ *
+ * STAR,PLUS	'?', and complex '*' and '+', are implemented as circular
+ *		BRANCH structures using BACK.  Simple cases (one character
+ *		per match) are implemented with STAR and PLUS for speed
+ *		and to minimize recursive plunges.
+ *
+ * OPEN,CLOSE	...are numbered at compile time.
+ */
+
+/*
+ * A node is one char of opcode followed by two chars of "next" pointer.
+ * "Next" pointers are stored as two 8-bit pieces, high order first.  The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node.  (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "next" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ */
+#define	OP(preg, p)	(preg->program[p])
+#define	NEXT(preg, p)	(preg->program[p + 1])
+#define	OPERAND(p)	((p) + 2)
+
+/*
+ * See regmagic.h for one further detail of program structure.
+ */
+
+
+/*
+ * Utility definitions.
+ */
+
+#define	FAIL(R,M)	{ (R)->err = (M); return (M); }
+#define	ISMULT(c)	((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
+#define	META	"^$.[()|?{+*"
+
+/*
+ * Flags to be passed up and down.
+ */
+#define	HASWIDTH	01	/* Known never to match null string. */
+#define	SIMPLE		02	/* Simple enough to be STAR/PLUS operand. */
+#define	SPSTART		04	/* Starts with * or +. */
+#define	WORST		0	/* Worst case. */
+
+#define MAX_REP_COUNT 1000000
+
+/*
+ * Forward declarations for regcomp()'s friends.
+ */
+static int reg(regex_t *preg, int paren /* Parenthesized? */, int *flagp );
+static int regpiece(regex_t *preg, int *flagp );
+static int regbranch(regex_t *preg, int *flagp );
+static int regatom(regex_t *preg, int *flagp );
+static int regnode(regex_t *preg, int op );
+static int regnext(regex_t *preg, int p );
+static void regc(regex_t *preg, int b );
+static int reginsert(regex_t *preg, int op, int size, int opnd );
+static void regtail_(regex_t *preg, int p, int val, int line );
+static void regoptail(regex_t *preg, int p, int val );
+#define regtail(PREG, P, VAL) regtail_(PREG, P, VAL, __LINE__)
+
+static int reg_range_find(const int *string, int c);
+static const char *str_find(const char *string, int c, int nocase);
+static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase);
+
+/*#define DEBUG*/
+#ifdef DEBUG
+int regnarrate = 0;
+static void regdump(regex_t *preg);
+static const char *regprop( int op );
+#endif
+
+
+/**
+ * Returns the length of the null-terminated integer sequence.
+ */
+static int str_int_len(const int *seq)
+{
+	int n = 0;
+	while (*seq++) {
+		n++;
+	}
+	return n;
+}
+
+/*
+ - regcomp - compile a regular expression into internal code
+ *
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code.  So we cheat:  we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it.  (Note that it has to be in
+ * one piece because free() must be able to free it all.)
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp.
+ */
+int regcomp(regex_t *preg, const char *exp, int cflags)
+{
+	int scan;
+	int longest;
+	unsigned len;
+	int flags;
+
+#ifdef DEBUG
+	fprintf(stderr, "Compiling: '%s'\n", exp);
+#endif
+	memset(preg, 0, sizeof(*preg));
+
+	if (exp == NULL)
+		FAIL(preg, REG_ERR_NULL_ARGUMENT);
+
+	/* First pass: determine size, legality. */
+	preg->cflags = cflags;
+	preg->regparse = exp;
+	/* XXX: For now, start unallocated */
+	preg->program = NULL;
+	preg->proglen = 0;
+
+#if 1
+	/* Allocate space. */
+	preg->proglen = (strlen(exp) + 1) * 5;
+	preg->program = malloc(preg->proglen * sizeof(int));
+	if (preg->program == NULL)
+		FAIL(preg, REG_ERR_NOMEM);
+#endif
+
+	/* Note that since we store a magic value as the first item in the program,
+	 * program offsets will never be 0
+	 */
+	regc(preg, REG_MAGIC);
+	if (reg(preg, 0, &flags) == 0) {
+		return preg->err;
+	}
+
+	/* Small enough for pointer-storage convention? */
+	if (preg->re_nsub >= REG_MAX_PAREN)		/* Probably could be 65535L. */
+		FAIL(preg,REG_ERR_TOO_BIG);
+
+	/* Dig out information for optimizations. */
+	preg->regstart = 0;	/* Worst-case defaults. */
+	preg->reganch = 0;
+	preg->regmust = 0;
+	preg->regmlen = 0;
+	scan = 1;			/* First BRANCH. */
+	if (OP(preg, regnext(preg, scan)) == END) {		/* Only one top-level choice. */
+		scan = OPERAND(scan);
+
+		/* Starting-point info. */
+		if (OP(preg, scan) == EXACTLY) {
+			preg->regstart = preg->program[OPERAND(scan)];
+		}
+		else if (OP(preg, scan) == BOL)
+			preg->reganch++;
+
+		/*
+		 * If there's something expensive in the r.e., find the
+		 * longest literal string that must appear and make it the
+		 * regmust.  Resolve ties in favor of later strings, since
+		 * the regstart check works with the beginning of the r.e.
+		 * and avoiding duplication strengthens checking.  Not a
+		 * strong reason, but sufficient in the absence of others.
+		 */
+		if (flags&SPSTART) {
+			longest = 0;
+			len = 0;
+			for (; scan != 0; scan = regnext(preg, scan)) {
+				if (OP(preg, scan) == EXACTLY) {
+					int plen = str_int_len(preg->program + OPERAND(scan));
+					if (plen >= len) {
+						longest = OPERAND(scan);
+						len = plen;
+					}
+				}
+			}
+			preg->regmust = longest;
+			preg->regmlen = len;
+		}
+	}
+
+#ifdef DEBUG
+	regdump(preg);
+#endif
+
+	return 0;
+}
+
+/*
+ - reg - regular expression, i.e. main body or parenthesized thing
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+static int reg(regex_t *preg, int paren /* Parenthesized? */, int *flagp )
+{
+	int ret;
+	int br;
+	int ender;
+	int parno = 0;
+	int flags;
+
+	*flagp = HASWIDTH;	/* Tentatively. */
+
+	/* Make an OPEN node, if parenthesized. */
+	if (paren) {
+		parno = ++preg->re_nsub;
+		ret = regnode(preg, OPEN+parno);
+	} else
+		ret = 0;
+
+	/* Pick up the branches, linking them together. */
+	br = regbranch(preg, &flags);
+	if (br == 0)
+		return 0;
+	if (ret != 0)
+		regtail(preg, ret, br);	/* OPEN -> first. */
+	else
+		ret = br;
+	if (!(flags&HASWIDTH))
+		*flagp &= ~HASWIDTH;
+	*flagp |= flags&SPSTART;
+	while (*preg->regparse == '|') {
+		preg->regparse++;
+		br = regbranch(preg, &flags);
+		if (br == 0)
+			return 0;
+		regtail(preg, ret, br);	/* BRANCH -> BRANCH. */
+		if (!(flags&HASWIDTH))
+			*flagp &= ~HASWIDTH;
+		*flagp |= flags&SPSTART;
+	}
+
+	/* Make a closing node, and hook it on the end. */
+	ender = regnode(preg, (paren) ? CLOSE+parno : END);
+	regtail(preg, ret, ender);
+
+	/* Hook the tails of the branches to the closing node. */
+	for (br = ret; br != 0; br = regnext(preg, br))
+		regoptail(preg, br, ender);
+
+	/* Check for proper termination. */
+	if (paren && *preg->regparse++ != ')') {
+		preg->err = REG_ERR_UNMATCHED_PAREN;
+		return 0;
+	} else if (!paren && *preg->regparse != '\0') {
+		if (*preg->regparse == ')') {
+			preg->err = REG_ERR_UNMATCHED_PAREN;
+			return 0;
+		} else {
+			preg->err = REG_ERR_JUNK_ON_END;
+			return 0;
+		}
+	}
+
+	return(ret);
+}
+
+/*
+ - regbranch - one alternative of an | operator
+ *
+ * Implements the concatenation operator.
+ */
+static int regbranch(regex_t *preg, int *flagp )
+{
+	int ret;
+	int chain;
+	int latest;
+	int flags;
+
+	*flagp = WORST;		/* Tentatively. */
+
+	ret = regnode(preg, BRANCH);
+	chain = 0;
+	while (*preg->regparse != '\0' && *preg->regparse != ')' &&
+	       *preg->regparse != '|') {
+		latest = regpiece(preg, &flags);
+		if (latest == 0)
+			return 0;
+		*flagp |= flags&HASWIDTH;
+		if (chain == 0) {/* First piece. */
+			*flagp |= flags&SPSTART;
+		}
+		else {
+			regtail(preg, chain, latest);
+		}
+		chain = latest;
+	}
+	if (chain == 0)	/* Loop ran zero times. */
+		(void) regnode(preg, NOTHING);
+
+	return(ret);
+}
+
+/*
+ - regpiece - something followed by possible [*+?]
+ *
+ * Note that the branching code sequences used for ? and the general cases
+ * of * and + are somewhat optimized:  they use the same NOTHING node as
+ * both the endmarker for their branch list and the body of the last branch.
+ * It might seem that this node could be dispensed with entirely, but the
+ * endmarker role is not redundant.
+ */
+static int regpiece(regex_t *preg, int *flagp)
+{
+	int ret;
+	char op;
+	int next;
+	int flags;
+	int chain = 0;
+	int min;
+	int max;
+
+	ret = regatom(preg, &flags);
+	if (ret == 0)
+		return 0;
+
+	op = *preg->regparse;
+	if (!ISMULT(op)) {
+		*flagp = flags;
+		return(ret);
+	}
+
+	if (!(flags&HASWIDTH) && op != '?') {
+		preg->err = REG_ERR_OPERAND_COULD_BE_EMPTY;
+		return 0;
+	}
+
+	/* Handle braces (counted repetition) by expansion */
+	if (op == '{') {
+		char *end;
+
+		min = strtoul(preg->regparse + 1, &end, 10);
+		if (end == preg->regparse + 1) {
+			preg->err = REG_ERR_BAD_COUNT;
+			return 0;
+		}
+		if (*end == '}') {
+			max = min;
+		}
+		else {
+			preg->regparse = end;
+			max = strtoul(preg->regparse + 1, &end, 10);
+			if (*end != '}') {
+				preg->err = REG_ERR_UNMATCHED_BRACES;
+				return 0;
+			}
+		}
+		if (end == preg->regparse + 1) {
+			max = MAX_REP_COUNT;
+		}
+		else if (max < min || max >= 100) {
+			preg->err = REG_ERR_BAD_COUNT;
+			return 0;
+		}
+		if (min >= 100) {
+			preg->err = REG_ERR_BAD_COUNT;
+			return 0;
+		}
+
+		preg->regparse = strchr(preg->regparse, '}');
+	}
+	else {
+		min = (op == '+');
+		max = (op == '?' ? 1 : MAX_REP_COUNT);
+	}
+
+	if (preg->regparse[1] == '?') {
+		preg->regparse++;
+		next = reginsert(preg, flags & SIMPLE ? REPMIN : REPXMIN, 5, ret);
+	}
+	else {
+		next = reginsert(preg, flags & SIMPLE ? REP: REPX, 5, ret);
+	}
+	preg->program[ret + 2] = max;
+	preg->program[ret + 3] = min;
+	preg->program[ret + 4] = 0;
+
+	*flagp = (min) ? (WORST|HASWIDTH) : (WORST|SPSTART);
+
+	if (!(flags & SIMPLE)) {
+		int back = regnode(preg, BACK);
+		regtail(preg, back, ret);
+		regtail(preg, next, back);
+	}
+
+	preg->regparse++;
+	if (ISMULT(*preg->regparse)) {
+		preg->err = REG_ERR_NESTED_COUNT;
+		return 0;
+	}
+
+	return chain ? chain : ret;
+}
+
+/**
+ * Add all characters in the inclusive range between lower and upper.
+ *
+ * Handles a swapped range (upper < lower).
+ */
+static void reg_addrange(regex_t *preg, int lower, int upper)
+{
+	if (lower > upper) {
+		reg_addrange(preg, upper, lower);
+	}
+	/* Add a range as length, start */
+	regc(preg, upper - lower + 1);
+	regc(preg, lower);
+}
+
+/**
+ * Add a null-terminated literal string as a set of ranges.
+ */
+static void reg_addrange_str(regex_t *preg, const char *str)
+{
+	while (*str) {
+		reg_addrange(preg, *str, *str);
+		str++;
+	}
+}
+
+/**
+ * Extracts the next unicode char from utf8.
+ *
+ * If 'upper' is set, converts the char to uppercase.
+ */
+static int reg_utf8_tounicode_case(const char *s, int *uc, int upper)
+{
+	int l = utf8_tounicode(s, uc);
+	if (upper) {
+		*uc = utf8_upper(*uc);
+	}
+	return l;
+}
+
+/**
+ * Converts a hex digit to decimal.
+ *
+ * Returns -1 for an invalid hex digit.
+ */
+static int hexdigitval(int c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	if (c >= 'A' && c <= 'F')
+		return c - 'A' + 10;
+	return -1;
+}
+
+/**
+ * Parses up to 'n' hex digits at 's' and stores the result in *uc.
+ *
+ * Returns the number of hex digits parsed.
+ * If there are no hex digits, returns 0 and stores nothing.
+ */
+static int parse_hex(const char *s, int n, int *uc)
+{
+	int val = 0;
+	int k;
+
+	for (k = 0; k < n; k++) {
+		int c = hexdigitval(*s++);
+		if (c == -1) {
+			break;
+		}
+		val = (val << 4) | c;
+	}
+	if (k) {
+		*uc = val;
+	}
+	return k;
+}
+
+/**
+ * Call for chars after a backlash to decode the escape sequence.
+ *
+ * Stores the result in *ch.
+ *
+ * Returns the number of bytes consumed.
+ */
+static int reg_decode_escape(const char *s, int *ch)
+{
+	int n;
+	const char *s0 = s;
+
+	*ch = *s++;
+
+	switch (*ch) {
+		case 'b': *ch = '\b'; break;
+		case 'e': *ch = 27; break;
+		case 'f': *ch = '\f'; break;
+		case 'n': *ch = '\n'; break;
+		case 'r': *ch = '\r'; break;
+		case 't': *ch = '\t'; break;
+		case 'v': *ch = '\v'; break;
+		case 'u':
+			if ((n = parse_hex(s, 4, ch)) > 0) {
+				s += n;
+			}
+			break;
+		case 'x':
+			if ((n = parse_hex(s, 2, ch)) > 0) {
+				s += n;
+			}
+			break;
+		case '\0':
+			s--;
+			*ch = '\\';
+			break;
+	}
+	return s - s0;
+}
+
+/*
+ - regatom - the lowest level
+ *
+ * Optimization:  gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run.  Backslashed characters are exceptions, each becoming a
+ * separate node; the code is simpler that way and it's not worth fixing.
+ */
+static int regatom(regex_t *preg, int *flagp)
+{
+	int ret;
+	int flags;
+	int nocase = (preg->cflags & REG_ICASE);
+
+	int ch;
+	int n = reg_utf8_tounicode_case(preg->regparse, &ch, nocase);
+
+	*flagp = WORST;		/* Tentatively. */
+
+	preg->regparse += n;
+	switch (ch) {
+	/* FIXME: these chars only have meaning at beg/end of pat? */
+	case '^':
+		ret = regnode(preg, BOL);
+		break;
+	case '$':
+		ret = regnode(preg, EOL);
+		break;
+	case '.':
+		ret = regnode(preg, ANY);
+		*flagp |= HASWIDTH|SIMPLE;
+		break;
+	case '[': {
+			const char *pattern = preg->regparse;
+
+			if (*pattern == '^') {	/* Complement of range. */
+				ret = regnode(preg, ANYBUT);
+				pattern++;
+			} else
+				ret = regnode(preg, ANYOF);
+
+			/* Special case. If the first char is ']' or '-', it is part of the set */
+			if (*pattern == ']' || *pattern == '-') {
+				reg_addrange(preg, *pattern, *pattern);
+				pattern++;
+			}
+
+			while (*pattern && *pattern != ']') {
+				/* Is this a range? a-z */
+				int start;
+				int end;
+
+				pattern += reg_utf8_tounicode_case(pattern, &start, nocase);
+				if (start == '\\') {
+					pattern += reg_decode_escape(pattern, &start);
+					if (start == 0) {
+						preg->err = REG_ERR_NULL_CHAR;
+						return 0;
+					}
+				}
+				if (pattern[0] == '-' && pattern[1]) {
+					/* skip '-' */
+					pattern += utf8_tounicode(pattern, &end);
+					pattern += reg_utf8_tounicode_case(pattern, &end, nocase);
+					if (end == '\\') {
+						pattern += reg_decode_escape(pattern, &end);
+						if (end == 0) {
+							preg->err = REG_ERR_NULL_CHAR;
+							return 0;
+						}
+					}
+
+					reg_addrange(preg, start, end);
+					continue;
+				}
+				if (start == '[') {
+					if (strncmp(pattern, ":alpha:]", 8) == 0) {
+						if ((preg->cflags & REG_ICASE) == 0) {
+							reg_addrange(preg, 'a', 'z');
+						}
+						reg_addrange(preg, 'A', 'Z');
+						pattern += 8;
+						continue;
+					}
+					if (strncmp(pattern, ":alnum:]", 8) == 0) {
+						if ((preg->cflags & REG_ICASE) == 0) {
+							reg_addrange(preg, 'a', 'z');
+						}
+						reg_addrange(preg, 'A', 'Z');
+						reg_addrange(preg, '0', '9');
+						pattern += 8;
+						continue;
+					}
+					if (strncmp(pattern, ":space:]", 8) == 0) {
+						reg_addrange_str(preg, " \t\r\n\f\v");
+						pattern += 8;
+						continue;
+					}
+				}
+				/* Not a range, so just add the char */
+				reg_addrange(preg, start, start);
+			}
+			regc(preg, '\0');
+
+			if (*pattern) {
+				pattern++;
+			}
+			preg->regparse = pattern;
+
+			*flagp |= HASWIDTH|SIMPLE;
+		}
+		break;
+	case '(':
+		ret = reg(preg, 1, &flags);
+		if (ret == 0)
+			return 0;
+		*flagp |= flags&(HASWIDTH|SPSTART);
+		break;
+	case '\0':
+	case '|':
+	case ')':
+		preg->err = REG_ERR_INTERNAL;
+		return 0;	/* Supposed to be caught earlier. */
+	case '?':
+	case '+':
+	case '*':
+	case '{':
+		preg->err = REG_ERR_COUNT_FOLLOWS_NOTHING;
+		return 0;
+	case '\\':
+		switch (*preg->regparse++) {
+		case '\0':
+			preg->err = REG_ERR_TRAILING_BACKSLASH;
+			return 0;
+		case '<':
+		case 'm':
+			ret = regnode(preg, WORDA);
+			break;
+		case '>':
+		case 'M':
+			ret = regnode(preg, WORDZ);
+			break;
+		case 'd':
+			ret = regnode(preg, ANYOF);
+			reg_addrange(preg, '0', '9');
+			regc(preg, '\0');
+			*flagp |= HASWIDTH|SIMPLE;
+			break;
+		case 'w':
+			ret = regnode(preg, ANYOF);
+			if ((preg->cflags & REG_ICASE) == 0) {
+				reg_addrange(preg, 'a', 'z');
+			}
+			reg_addrange(preg, 'A', 'Z');
+			reg_addrange(preg, '0', '9');
+			reg_addrange(preg, '_', '_');
+			regc(preg, '\0');
+			*flagp |= HASWIDTH|SIMPLE;
+			break;
+		case 's':
+			ret = regnode(preg, ANYOF);
+			reg_addrange_str(preg," \t\r\n\f\v");
+			regc(preg, '\0');
+			*flagp |= HASWIDTH|SIMPLE;
+			break;
+		/* FIXME: Someday handle \1, \2, ... */
+		default:
+			/* Handle general quoted chars in exact-match routine */
+			/* Back up to include the backslash */
+			preg->regparse--;
+			goto de_fault;
+		}
+		break;
+	de_fault:
+	default: {
+			/*
+			 * Encode a string of characters to be matched exactly.
+			 */
+			int added = 0;
+
+			/* Back up to pick up the first char of interest */
+			preg->regparse -= n;
+
+			ret = regnode(preg, EXACTLY);
+
+			/* Note that a META operator such as ? or * consumes the
+			 * preceding char.
+			 * Thus we must be careful to look ahead by 2 and add the
+			 * last char as it's own EXACTLY if necessary
+			 */
+
+			/* Until end of string or a META char is reached */
+			while (*preg->regparse && strchr(META, *preg->regparse) == NULL) {
+				n = reg_utf8_tounicode_case(preg->regparse, &ch, (preg->cflags & REG_ICASE));
+				if (ch == '\\' && preg->regparse[n]) {
+					/* Non-trailing backslash.
+					 * Is this a special escape, or a regular escape?
+					 */
+					if (strchr("<>mMwds", preg->regparse[n])) {
+						/* A special escape. All done with EXACTLY */
+						break;
+					}
+					/* Decode it. Note that we add the length for the escape
+					 * sequence to the length for the backlash so we can skip
+					 * the entire sequence, or not as required.
+					 */
+					n += reg_decode_escape(preg->regparse + n, &ch);
+					if (ch == 0) {
+						preg->err = REG_ERR_NULL_CHAR;
+						return 0;
+					}
+				}
+
+				/* Now we have one char 'ch' of length 'n'.
+				 * Check to see if the following char is a MULT
+				 */
+
+				if (ISMULT(preg->regparse[n])) {
+					/* Yes. But do we already have some EXACTLY chars? */
+					if (added) {
+						/* Yes, so return what we have and pick up the current char next time around */
+						break;
+					}
+					/* No, so add this single char and finish */
+					regc(preg, ch);
+					added++;
+					preg->regparse += n;
+					break;
+				}
+
+				/* No, so just add this char normally */
+				regc(preg, ch);
+				added++;
+				preg->regparse += n;
+			}
+			regc(preg, '\0');
+
+			*flagp |= HASWIDTH;
+			if (added == 1)
+				*flagp |= SIMPLE;
+			break;
+		}
+		break;
+	}
+
+	return(ret);
+}
+
+static void reg_grow(regex_t *preg, int n)
+{
+	if (preg->p + n >= preg->proglen) {
+		preg->proglen = (preg->p + n) * 2;
+		preg->program = realloc(preg->program, preg->proglen * sizeof(int));
+	}
+}
+
+/*
+ - regnode - emit a node
+ */
+/* Location. */
+static int regnode(regex_t *preg, int op)
+{
+	reg_grow(preg, 2);
+
+	preg->program[preg->p++] = op;
+	preg->program[preg->p++] = 0;
+
+	/* Return the start of the node */
+	return preg->p - 2;
+}
+
+/*
+ - regc - emit (if appropriate) a byte of code
+ */
+static void regc(regex_t *preg, int b )
+{
+	reg_grow(preg, 1);
+	preg->program[preg->p++] = b;
+}
+
+/*
+ - reginsert - insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ * Returns the new location of the original operand.
+ */
+static int reginsert(regex_t *preg, int op, int size, int opnd )
+{
+	reg_grow(preg, size);
+
+	/* Move everything from opnd up */
+	memmove(preg->program + opnd + size, preg->program + opnd, sizeof(int) * (preg->p - opnd));
+	/* Zero out the new space */
+	memset(preg->program + opnd, 0, sizeof(int) * size);
+
+	preg->program[opnd] = op;
+
+	preg->p += size;
+
+	return opnd + size;
+}
+
+/*
+ - regtail - set the next-pointer at the end of a node chain
+ */
+static void regtail_(regex_t *preg, int p, int val, int line )
+{
+	int scan;
+	int temp;
+	int offset;
+
+	/* Find last node. */
+	scan = p;
+	for (;;) {
+		temp = regnext(preg, scan);
+		if (temp == 0)
+			break;
+		scan = temp;
+	}
+
+	if (OP(preg, scan) == BACK)
+		offset = scan - val;
+	else
+		offset = val - scan;
+
+	preg->program[scan + 1] = offset;
+}
+
+/*
+ - regoptail - regtail on operand of first argument; nop if operandless
+ */
+
+static void regoptail(regex_t *preg, int p, int val )
+{
+	/* "Operandless" and "op != BRANCH" are synonymous in practice. */
+	if (p != 0 && OP(preg, p) == BRANCH) {
+		regtail(preg, OPERAND(p), val);
+	}
+}
+
+/*
+ * regexec and friends
+ */
+
+/*
+ * Forwards.
+ */
+static int regtry(regex_t *preg, const char *string );
+static int regmatch(regex_t *preg, int prog);
+static int regrepeat(regex_t *preg, int p, int max);
+
+/*
+ - regexec - match a regexp against a string
+ */
+int regexec(regex_t  *preg,  const  char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
+{
+	const char *s;
+	int scan;
+
+	/* Be paranoid... */
+	if (preg == NULL || preg->program == NULL || string == NULL) {
+		return REG_ERR_NULL_ARGUMENT;
+	}
+
+	/* Check validity of program. */
+	if (*preg->program != REG_MAGIC) {
+		return REG_ERR_CORRUPTED;
+	}
+
+#ifdef DEBUG
+	fprintf(stderr, "regexec: %s\n", string);
+	regdump(preg);
+#endif
+
+	preg->eflags = eflags;
+	preg->pmatch = pmatch;
+	preg->nmatch = nmatch;
+	preg->start = string;	/* All offsets are computed from here */
+
+	/* Must clear out the embedded repeat counts */
+	for (scan = OPERAND(1); scan != 0; scan = regnext(preg, scan)) {
+		switch (OP(preg, scan)) {
+		case REP:
+		case REPMIN:
+		case REPX:
+		case REPXMIN:
+			preg->program[scan + 4] = 0;
+			break;
+		}
+	}
+
+	/* If there is a "must appear" string, look for it. */
+	if (preg->regmust != 0) {
+		s = string;
+		while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) {
+			if (prefix_cmp(preg->program + preg->regmust, preg->regmlen, s, preg->cflags & REG_ICASE) >= 0) {
+				break;
+			}
+			s++;
+		}
+		if (s == NULL)	/* Not present. */
+			return REG_NOMATCH;
+	}
+
+	/* Mark beginning of line for ^ . */
+	preg->regbol = string;
+
+	/* Simplest case:  anchored match need be tried only once (maybe per line). */
+	if (preg->reganch) {
+		if (eflags & REG_NOTBOL) {
+			/* This is an anchored search, but not an BOL, so possibly skip to the next line */
+			goto nextline;
+		}
+		while (1) {
+			int ret = regtry(preg, string);
+			if (ret) {
+				return REG_NOERROR;
+			}
+			if (*string) {
+nextline:
+				if (preg->cflags & REG_NEWLINE) {
+					/* Try the next anchor? */
+					string = strchr(string, '\n');
+					if (string) {
+						preg->regbol = ++string;
+						continue;
+					}
+				}
+			}
+			return REG_NOMATCH;
+		}
+	}
+
+	/* Messy cases:  unanchored match. */
+	s = string;
+	if (preg->regstart != '\0') {
+		/* We know what char it must start with. */
+		while ((s = str_find(s, preg->regstart, preg->cflags & REG_ICASE)) != NULL) {
+			if (regtry(preg, s))
+				return REG_NOERROR;
+			s++;
+		}
+	}
+	else
+		/* We don't -- general case. */
+		while (1) {
+			if (regtry(preg, s))
+				return REG_NOERROR;
+			if (*s == '\0') {
+				break;
+			}
+			s += utf8_charlen(*s);
+		}
+
+	/* Failure. */
+	return REG_NOMATCH;
+}
+
+/*
+ - regtry - try match at specific point
+ */
+			/* 0 failure, 1 success */
+static int regtry( regex_t *preg, const char *string )
+{
+	int i;
+
+	preg->reginput = string;
+
+	for (i = 0; i < preg->nmatch; i++) {
+		preg->pmatch[i].rm_so = -1;
+		preg->pmatch[i].rm_eo = -1;
+	}
+	if (regmatch(preg, 1)) {
+		preg->pmatch[0].rm_so = string - preg->start;
+		preg->pmatch[0].rm_eo = preg->reginput - preg->start;
+		return(1);
+	} else
+		return(0);
+}
+
+/**
+ * Returns bytes matched if 'pattern' is a prefix of 'string'.
+ *
+ * If 'nocase' is non-zero, does a case-insensitive match.
+ *
+ * Returns -1 on not found.
+ */
+static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase)
+{
+	const char *s = string;
+	while (proglen && *s) {
+		int ch;
+		int n = reg_utf8_tounicode_case(s, &ch, nocase);
+		if (ch != *prog) {
+			return -1;
+		}
+		prog++;
+		s += n;
+		proglen--;
+	}
+	if (proglen == 0) {
+		return s - string;
+	}
+	return -1;
+}
+
+/**
+ * Searchs for 'c' in the range 'range'.
+ *
+ * Returns 1 if found, or 0 if not.
+ */
+static int reg_range_find(const int *range, int c)
+{
+	while (*range) {
+		/*printf("Checking %d in range [%d,%d]\n", c, range[1], (range[0] + range[1] - 1));*/
+		if (c >= range[1] && c <= (range[0] + range[1] - 1)) {
+			return 1;
+		}
+		range += 2;
+	}
+	return 0;
+}
+
+/**
+ * Search for the character 'c' in the utf-8 string 'string'.
+ *
+ * If 'nocase' is set, the 'string' is assumed to be uppercase
+ * and 'c' is converted to uppercase before matching.
+ *
+ * Returns the byte position in the string where the 'c' was found, or
+ * NULL if not found.
+ */
+static const char *str_find(const char *string, int c, int nocase)
+{
+	if (nocase) {
+		/* The "string" should already be converted to uppercase */
+		c = utf8_upper(c);
+	}
+	while (*string) {
+		int ch;
+		int n = reg_utf8_tounicode_case(string, &ch, nocase);
+		if (c == ch) {
+			return string;
+		}
+		string += n;
+	}
+	return NULL;
+}
+
+/**
+ * Returns true if 'ch' is an end-of-line char.
+ *
+ * In REG_NEWLINE mode, \n is considered EOL in
+ * addition to \0
+ */
+static int reg_iseol(regex_t *preg, int ch)
+{
+	if (preg->cflags & REG_NEWLINE) {
+		return ch == '\0' || ch == '\n';
+	}
+	else {
+		return ch == '\0';
+	}
+}
+
+static int regmatchsimplerepeat(regex_t *preg, int scan, int matchmin)
+{
+	int nextch = '\0';
+	const char *save;
+	int no;
+	int c;
+
+	int max = preg->program[scan + 2];
+	int min = preg->program[scan + 3];
+	int next = regnext(preg, scan);
+
+	/*
+	 * Lookahead to avoid useless match attempts
+	 * when we know what character comes next.
+	 */
+	if (OP(preg, next) == EXACTLY) {
+		nextch = preg->program[OPERAND(next)];
+	}
+	save = preg->reginput;
+	no = regrepeat(preg, scan + 5, max);
+	if (no < min) {
+		return 0;
+	}
+	if (matchmin) {
+		/* from min up to no */
+		max = no;
+		no = min;
+	}
+	/* else from no down to min */
+	while (1) {
+		if (matchmin) {
+			if (no > max) {
+				break;
+			}
+		}
+		else {
+			if (no < min) {
+				break;
+			}
+		}
+		preg->reginput = save + utf8_index(save, no);
+		reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
+		/* If it could work, try it. */
+		if (reg_iseol(preg, nextch) || c == nextch) {
+			if (regmatch(preg, next)) {
+				return(1);
+			}
+		}
+		if (matchmin) {
+			/* Couldn't or didn't, add one more */
+			no++;
+		}
+		else {
+			/* Couldn't or didn't -- back up. */
+			no--;
+		}
+	}
+	return(0);
+}
+
+static int regmatchrepeat(regex_t *preg, int scan, int matchmin)
+{
+	int *scanpt = preg->program + scan;
+
+	int max = scanpt[2];
+	int min = scanpt[3];
+
+	/* Have we reached min? */
+	if (scanpt[4] < min) {
+		/* No, so get another one */
+		scanpt[4]++;
+		if (regmatch(preg, scan + 5)) {
+			return 1;
+		}
+		scanpt[4]--;
+		return 0;
+	}
+	if (scanpt[4] > max) {
+		return 0;
+	}
+
+	if (matchmin) {
+		/* minimal, so try other branch first */
+		if (regmatch(preg, regnext(preg, scan))) {
+			return 1;
+		}
+		/* No, so try one more */
+		scanpt[4]++;
+		if (regmatch(preg, scan + 5)) {
+			return 1;
+		}
+		scanpt[4]--;
+		return 0;
+	}
+	/* maximal, so try this branch again */
+	if (scanpt[4] < max) {
+		scanpt[4]++;
+		if (regmatch(preg, scan + 5)) {
+			return 1;
+		}
+		scanpt[4]--;
+	}
+	/* At this point we are at max with no match. Try the other branch */
+	return regmatch(preg, regnext(preg, scan));
+}
+
+/*
+ - regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple:  check to see whether the current
+ * node matches, call self recursively to see whether the rest matches,
+ * and then act accordingly.  In practice we make some effort to avoid
+ * recursion, in particular by going through "ordinary" nodes (that don't
+ * need to know whether the rest of the match failed) by a loop instead of
+ * by recursion.
+ */
+/* 0 failure, 1 success */
+static int regmatch(regex_t *preg, int prog)
+{
+	int scan;	/* Current node. */
+	int next;		/* Next node. */
+
+	scan = prog;
+
+#ifdef DEBUG
+	if (scan != 0 && regnarrate)
+		fprintf(stderr, "%s(\n", regprop(scan));
+#endif
+	while (scan != 0) {
+		int n;
+		int c;
+#ifdef DEBUG
+		if (regnarrate) {
+			fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan)));	/* Where, what. */
+		}
+#endif
+		next = regnext(preg, scan);
+		n = reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
+
+		switch (OP(preg, scan)) {
+		case BOL:
+			if (preg->reginput != preg->regbol)
+				return(0);
+			break;
+		case EOL:
+			if (!reg_iseol(preg, c)) {
+				return(0);
+			}
+			break;
+		case WORDA:
+			/* Must be looking at a letter, digit, or _ */
+			if ((!isalnum(UCHAR(c))) && c != '_')
+				return(0);
+			/* Prev must be BOL or nonword */
+			if (preg->reginput > preg->regbol &&
+				(isalnum(UCHAR(preg->reginput[-1])) || preg->reginput[-1] == '_'))
+				return(0);
+			break;
+		case WORDZ:
+			/* Can't match at BOL */
+			if (preg->reginput > preg->regbol) {
+				/* Current must be EOL or nonword */
+				if (reg_iseol(preg, c) || !isalnum(UCHAR(c)) || c != '_') {
+					c = preg->reginput[-1];
+					/* Previous must be word */
+					if (isalnum(UCHAR(c)) || c == '_') {
+						break;
+					}
+				}
+			}
+			/* No */
+			return(0);
+
+		case ANY:
+			if (reg_iseol(preg, c))
+				return 0;
+			preg->reginput += n;
+			break;
+		case EXACTLY: {
+				int opnd;
+				int len;
+				int slen;
+
+				opnd = OPERAND(scan);
+				len = str_int_len(preg->program + opnd);
+
+				slen = prefix_cmp(preg->program + opnd, len, preg->reginput, preg->cflags & REG_ICASE);
+				if (slen < 0) {
+					return(0);
+				}
+				preg->reginput += slen;
+			}
+			break;
+		case ANYOF:
+			if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) == 0) {
+				return(0);
+			}
+			preg->reginput += n;
+			break;
+		case ANYBUT:
+			if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) != 0) {
+				return(0);
+			}
+			preg->reginput += n;
+			break;
+		case NOTHING:
+			break;
+		case BACK:
+			break;
+		case BRANCH: {
+				const char *save;
+
+				if (OP(preg, next) != BRANCH)		/* No choice. */
+					next = OPERAND(scan);	/* Avoid recursion. */
+				else {
+					do {
+						save = preg->reginput;
+						if (regmatch(preg, OPERAND(scan))) {
+							return(1);
+						}
+						preg->reginput = save;
+						scan = regnext(preg, scan);
+					} while (scan != 0 && OP(preg, scan) == BRANCH);
+					return(0);
+					/* NOTREACHED */
+				}
+			}
+			break;
+		case REP:
+		case REPMIN:
+			return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN);
+
+		case REPX:
+		case REPXMIN:
+			return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN);
+
+		case END:
+			return(1);	/* Success! */
+			break;
+		default:
+			if (OP(preg, scan) >= OPEN+1 && OP(preg, scan) < CLOSE_END) {
+				const char *save;
+
+				save = preg->reginput;
+
+				if (regmatch(preg, next)) {
+					int no;
+					/*
+					 * Don't set startp if some later
+					 * invocation of the same parentheses
+					 * already has.
+					 */
+					if (OP(preg, scan) < CLOSE) {
+						no = OP(preg, scan) - OPEN;
+						if (no < preg->nmatch && preg->pmatch[no].rm_so == -1) {
+							preg->pmatch[no].rm_so = save - preg->start;
+						}
+					}
+					else {
+						no = OP(preg, scan) - CLOSE;
+						if (no < preg->nmatch && preg->pmatch[no].rm_eo == -1) {
+							preg->pmatch[no].rm_eo = save - preg->start;
+						}
+					}
+					return(1);
+				} else
+					return(0);
+			}
+			return REG_ERR_INTERNAL;
+		}
+
+		scan = next;
+	}
+
+	/*
+	 * We get here only if there's trouble -- normally "case END" is
+	 * the terminating point.
+	 */
+	return REG_ERR_INTERNAL;
+}
+
+/*
+ - regrepeat - repeatedly match something simple, report how many
+ */
+static int regrepeat(regex_t *preg, int p, int max)
+{
+	int count = 0;
+	const char *scan;
+	int opnd;
+	int ch;
+	int n;
+
+	scan = preg->reginput;
+	opnd = OPERAND(p);
+	switch (OP(preg, p)) {
+	case ANY:
+		/* No need to handle utf8 specially here */
+		while (!reg_iseol(preg, *scan) && count < max) {
+			count++;
+			scan++;
+		}
+		break;
+	case EXACTLY:
+		while (count < max) {
+			n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+			if (preg->program[opnd] != ch) {
+				break;
+			}
+			count++;
+			scan += n;
+		}
+		break;
+	case ANYOF:
+		while (count < max) {
+			n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+			if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) == 0) {
+				break;
+			}
+			count++;
+			scan += n;
+		}
+		break;
+	case ANYBUT:
+		while (count < max) {
+			n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+			if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) != 0) {
+				break;
+			}
+			count++;
+			scan += n;
+		}
+		break;
+	default:		/* Oh dear.  Called inappropriately. */
+		preg->err = REG_ERR_INTERNAL;
+		count = 0;	/* Best compromise. */
+		break;
+	}
+	preg->reginput = scan;
+
+	return(count);
+}
+
+/*
+ - regnext - dig the "next" pointer out of a node
+ */
+static int regnext(regex_t *preg, int p )
+{
+	int offset;
+
+	offset = NEXT(preg, p);
+
+	if (offset == 0)
+		return 0;
+
+	if (OP(preg, p) == BACK)
+		return(p-offset);
+	else
+		return(p+offset);
+}
+
+#if defined(DEBUG) && !defined(JIM_BOOTSTRAP)
+
+/*
+ - regdump - dump a regexp onto stdout in vaguely comprehensible form
+ */
+static void regdump(regex_t *preg)
+{
+	int s;
+	int op = EXACTLY;	/* Arbitrary non-END op. */
+	int next;
+	char buf[4];
+
+	int i;
+	for (i = 1; i < preg->p; i++) {
+		printf("%02x ", preg->program[i]);
+		if (i % 16 == 15) {
+			printf("\n");
+		}
+	}
+	printf("\n");
+
+	s = 1;
+	while (op != END && s < preg->p) {	/* While that wasn't END last time... */
+		op = OP(preg, s);
+		printf("%3d: %s", s, regprop(op));	/* Where, what. */
+		next = regnext(preg, s);
+		if (next == 0)		/* Next ptr. */
+			printf("(0)");
+		else
+			printf("(%d)", next);
+		s += 2;
+		if (op == REP || op == REPMIN || op == REPX || op == REPXMIN) {
+			int max = preg->program[s];
+			int min = preg->program[s + 1];
+			if (max == 65535) {
+				printf("{%d,*}", min);
+			}
+			else {
+				printf("{%d,%d}", min, max);
+			}
+			printf(" %d", preg->program[s + 2]);
+			s += 3;
+		}
+		else if (op == ANYOF || op == ANYBUT) {
+			/* set of ranges */
+
+			while (preg->program[s]) {
+				int len = preg->program[s++];
+				int first = preg->program[s++];
+				buf[utf8_fromunicode(buf, first)] = 0;
+				printf("%s", buf);
+				if (len > 1) {
+					buf[utf8_fromunicode(buf, first + len - 1)] = 0;
+					printf("-%s", buf);
+				}
+			}
+			s++;
+		}
+		else if (op == EXACTLY) {
+			/* Literal string, where present. */
+
+			while (preg->program[s]) {
+				buf[utf8_fromunicode(buf, preg->program[s])] = 0;
+				printf("%s", buf);
+				s++;
+			}
+			s++;
+		}
+		putchar('\n');
+	}
+
+	if (op == END) {
+		/* Header fields of interest. */
+		if (preg->regstart) {
+			buf[utf8_fromunicode(buf, preg->regstart)] = 0;
+			printf("start '%s' ", buf);
+		}
+		if (preg->reganch)
+			printf("anchored ");
+		if (preg->regmust != 0) {
+			int i;
+			printf("must have:");
+			for (i = 0; i < preg->regmlen; i++) {
+				putchar(preg->program[preg->regmust + i]);
+			}
+			putchar('\n');
+		}
+	}
+	printf("\n");
+}
+
+/*
+ - regprop - printable representation of opcode
+ */
+static const char *regprop( int op )
+{
+	static char buf[50];
+
+	switch (op) {
+	case BOL:
+		return "BOL";
+	case EOL:
+		return "EOL";
+	case ANY:
+		return "ANY";
+	case ANYOF:
+		return "ANYOF";
+	case ANYBUT:
+		return "ANYBUT";
+	case BRANCH:
+		return "BRANCH";
+	case EXACTLY:
+		return "EXACTLY";
+	case NOTHING:
+		return "NOTHING";
+	case BACK:
+		return "BACK";
+	case END:
+		return "END";
+	case REP:
+		return "REP";
+	case REPMIN:
+		return "REPMIN";
+	case REPX:
+		return "REPX";
+	case REPXMIN:
+		return "REPXMIN";
+	case WORDA:
+		return "WORDA";
+	case WORDZ:
+		return "WORDZ";
+	default:
+		if (op >= OPEN && op < CLOSE) {
+			snprintf(buf, sizeof(buf), "OPEN%d", op-OPEN);
+		}
+		else if (op >= CLOSE && op < CLOSE_END) {
+			snprintf(buf, sizeof(buf), "CLOSE%d", op-CLOSE);
+		}
+		else {
+			snprintf(buf, sizeof(buf), "?%d?\n", op);
+		}
+		return(buf);
+	}
+}
+#endif /* JIM_BOOTSTRAP */
+
+size_t regerror(int errcode, const regex_t *preg, char *errbuf,  size_t errbuf_size)
+{
+	static const char *error_strings[] = {
+		"success",
+		"no match",
+		"bad pattern",
+		"null argument",
+		"unknown error",
+		"too big",
+		"out of memory",
+		"too many ()",
+		"parentheses () not balanced",
+		"braces {} not balanced",
+		"invalid repetition count(s)",
+		"extra characters",
+		"*+ of empty atom",
+		"nested count",
+		"internal error",
+		"count follows nothing",
+		"trailing backslash",
+		"corrupted program",
+		"contains null char",
+	};
+	const char *err;
+
+	if (errcode < 0 || errcode >= REG_ERR_NUM) {
+		err = "Bad error code";
+	}
+	else {
+		err = error_strings[errcode];
+	}
+
+	return snprintf(errbuf, errbuf_size, "%s", err);
+}
+
+void regfree(regex_t *preg)
+{
+	free(preg->program);
+}
+
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jimregexp.h b/android/external/usb_modeswitch/usb_modeswitch/jim/jimregexp.h
new file mode 100755
index 0000000..79a87e5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jimregexp.h
@@ -0,0 +1,117 @@
+#ifndef JIMREGEXP_H
+#define JIMREGEXP_H
+
+#ifndef _JIMAUTOCONF_H
+#error Need jimautoconf.h
+#endif
+
+#if defined(HAVE_REGCOMP) && !defined(JIM_REGEXP)
+/* Use POSIX regex */
+#include <regex.h>
+
+#else
+
+#include <stdlib.h>
+
+/*
+ * Definitions etc. for regexp(3) routines.
+ *
+ * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof],
+ * not the System V one.
+ *
+ * 11/04/02 (seiwald) - const-ing for string literals
+ */
+
+typedef struct {
+	int rm_so;
+	int rm_eo;
+} regmatch_t;
+
+/*
+ * The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases.  They are:
+ *
+ * regstart	char that must begin a match; '\0' if none obvious
+ * reganch	is the match anchored (at beginning-of-line only)?
+ * regmust	string (pointer into program) that match must include, or NULL
+ * regmlen	length of regmust string
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot.  Regmust permits fast rejection
+ * of lines that cannot possibly match.  The regmust tests are costly enough
+ * that regcomp() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup).  Regmlen is
+ * supplied because the test in regexec() needs it and regcomp() is computing
+ * it anyway.
+ */
+
+typedef struct regexp {
+	/* -- public -- */
+	int re_nsub;		/* number of parenthesized subexpressions */
+
+	/* -- private -- */
+	int cflags;			/* Flags used when compiling */
+	int err;			/* Any error which occurred during compile */
+	int regstart;		/* Internal use only. */
+	int reganch;		/* Internal use only. */
+	int regmust;		/* Internal use only. */
+	int regmlen;		/* Internal use only. */
+	int *program;		/* Allocated */
+
+	/* working state - compile */
+	const char *regparse;		/* Input-scan pointer. */
+	int p;				/* Current output pos in program */
+	int proglen;		/* Allocated program size */
+
+	/* working state - exec */
+	int eflags;				/* Flags used when executing */
+	const char *start;		/* Initial string pointer. */
+	const char *reginput;	/* Current input pointer. */
+	const char *regbol;		/* Beginning of input, for ^ check. */
+
+	/* Input to regexec() */
+	regmatch_t *pmatch;		/* submatches will be stored here */
+	int nmatch;				/* size of pmatch[] */
+} regexp;
+
+typedef regexp regex_t;
+
+#define REG_EXTENDED 0
+#define REG_NEWLINE 1
+#define REG_ICASE 2
+
+#define REG_NOTBOL 16
+
+enum {
+	REG_NOERROR,      /* Success.  */
+	REG_NOMATCH,      /* Didn't find a match (for regexec).  */
+	REG_BADPAT,		  /* >= REG_BADPAT is an error */
+	REG_ERR_NULL_ARGUMENT,
+	REG_ERR_UNKNOWN,
+	REG_ERR_TOO_BIG,
+	REG_ERR_NOMEM,
+	REG_ERR_TOO_MANY_PAREN,
+	REG_ERR_UNMATCHED_PAREN,
+	REG_ERR_UNMATCHED_BRACES,
+	REG_ERR_BAD_COUNT,
+	REG_ERR_JUNK_ON_END,
+	REG_ERR_OPERAND_COULD_BE_EMPTY,
+	REG_ERR_NESTED_COUNT,
+	REG_ERR_INTERNAL,
+	REG_ERR_COUNT_FOLLOWS_NOTHING,
+	REG_ERR_TRAILING_BACKSLASH,
+	REG_ERR_CORRUPTED,
+	REG_ERR_NULL_CHAR,
+	REG_ERR_NUM
+};
+
+int regcomp(regex_t *preg, const char *regex, int cflags);
+int regexec(regex_t  *preg,  const  char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
+size_t regerror(int errcode, const regex_t *preg, char *errbuf,  size_t errbuf_size);
+void regfree(regex_t *preg);
+
+#endif
+
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/jimsh.c b/android/external/usb_modeswitch/usb_modeswitch/jim/jimsh.c
new file mode 100755
index 0000000..2c94468
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/jimsh.c
@@ -0,0 +1,111 @@
+
+/* Jimsh - An interactive shell for Jim
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2009 Steve Bennett <steveb@workware.net.au>
+ *
+ * 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
+ *
+ * A copy of the license is also included in the source distribution
+ * of Jim, as a TXT file name called LICENSE.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+
+/* From initjimsh.tcl */
+extern int Jim_initjimshInit(Jim_Interp *interp);
+
+static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[])
+{
+    int n;
+    Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
+    /* Populate argv global var */
+    for (n = 0; n < argc; n++) {
+        Jim_Obj *obj = Jim_NewStringObj(interp, argv[n], -1);
+
+        Jim_ListAppendElement(interp, listObj, obj);
+    }
+
+    Jim_SetVariableStr(interp, "argv", listObj);
+    Jim_SetVariableStr(interp, "argc", Jim_NewIntObj(interp, argc));
+}
+
+int main(int argc, char *const argv[])
+{
+    int retcode;
+    Jim_Interp *interp;
+
+    if (argc > 1 && strcmp(argv[1], "--version") == 0) {
+        printf("%d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
+        return 0;
+    }
+
+    /* Create and initialize the interpreter */
+    interp = Jim_CreateInterp();
+    Jim_RegisterCoreCommands(interp);
+
+    /* Register static extensions */
+    if (Jim_InitStaticExtensions(interp) != JIM_OK) {
+        Jim_MakeErrorMessage(interp);
+        fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
+    }
+
+    Jim_SetVariableStrWithStr(interp, "jim_argv0", argv[0]);
+    Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0");
+    retcode = Jim_initjimshInit(interp);
+
+    if (argc == 1) {
+        if (retcode == JIM_ERR) {
+            Jim_MakeErrorMessage(interp);
+            fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
+        }
+        if (retcode != JIM_EXIT) {
+            JimSetArgv(interp, 0, NULL);
+            retcode = Jim_InteractivePrompt(interp);
+        }
+    }
+    else {
+        if (argc > 2 && strcmp(argv[1], "-e") == 0) {
+            JimSetArgv(interp, argc - 3, argv + 3);
+            retcode = Jim_Eval(interp, argv[2]);
+            if (retcode != JIM_ERR) {
+                printf("%s\n", Jim_String(Jim_GetResult(interp)));
+            }
+        }
+        else {
+            Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1));
+            JimSetArgv(interp, argc - 2, argv + 2);
+            retcode = Jim_EvalFile(interp, argv[1]);
+        }
+        if (retcode == JIM_ERR) {
+            Jim_MakeErrorMessage(interp);
+            fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
+        }
+    }
+    if (retcode == JIM_EXIT) {
+        retcode = Jim_GetExitCode(interp);
+    }
+    else if (retcode == JIM_ERR) {
+        retcode = 1;
+    }
+    else {
+        retcode = 0;
+    }
+    Jim_FreeInterp(interp);
+    return retcode;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/linenoise.c b/android/external/usb_modeswitch/usb_modeswitch/jim/linenoise.c
new file mode 100755
index 0000000..4065d06
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/linenoise.c
@@ -0,0 +1,1379 @@
+/* linenoise.c -- guerrilla line editing library against the idea that a
+ * line editing lib needs to be 20,000 lines of C code.
+ *
+ * You can find the latest source code at:
+ *
+ *   http://github.com/antirez/linenoise
+ *
+ * Does a number of crazy assumptions that happen to be true in 99.9999% of
+ * the 2010 UNIX computers around.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  *  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *  *  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * References:
+ * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+ * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
+ *
+ * Todo list:
+ * - Win32 support
+ * - Save and load history containing newlines
+ *
+ * Bloat:
+ * - Completion?
+ *
+ * List of escape sequences used by this program, we do everything just
+ * a few sequences. In order to be so cheap we may have some
+ * flickering effect with some slow terminal, but the lesser sequences
+ * the more compatible.
+ *
+ * CHA (Cursor Horizontal Absolute)
+ *    Sequence: ESC [ n G
+ *    Effect: moves cursor to column n (1 based)
+ *
+ * EL (Erase Line)
+ *    Sequence: ESC [ n K
+ *    Effect: if n is 0 or missing, clear from cursor to end of line
+ *    Effect: if n is 1, clear from beginning of line to cursor
+ *    Effect: if n is 2, clear entire line
+ *
+ * CUF (CUrsor Forward)
+ *    Sequence: ESC [ n C
+ *    Effect: moves cursor forward of n chars
+ *
+ * The following are used to clear the screen: ESC [ H ESC [ 2 J
+ * This is actually composed of two sequences:
+ *
+ * cursorhome
+ *    Sequence: ESC [ H
+ *    Effect: moves the cursor to upper left corner
+ *
+ * ED2 (Clear entire screen)
+ *    Sequence: ESC [ 2 J
+ *    Effect: clear the whole screen
+ *
+ * == For highlighting control characters, we also use the following two ==
+ * SO (enter StandOut)
+ *    Sequence: ESC [ 7 m
+ *    Effect: Uses some standout mode such as reverse video
+ *
+ * SE (Standout End)
+ *    Sequence: ESC [ 0 m
+ *    Effect: Exit standout mode
+ *
+ * == Only used if TIOCGWINSZ fails ==
+ * DSR/CPR (Report cursor position)
+ *    Sequence: ESC [ 6 n
+ *    Effect: reports current cursor position as ESC [ NNN ; MMM R
+ */
+
+#ifdef __MINGW32__
+#include <windows.h>
+#include <fcntl.h>
+#define USE_WINCONSOLE
+#else
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#define USE_TERMIOS
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "linenoise.h"
+
+#include "jim-config.h"
+#ifdef JIM_UTF8
+#define USE_UTF8
+#endif
+#include "utf8.h"
+
+#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
+#define LINENOISE_MAX_LINE 4096
+
+#define ctrl(C) ((C) - '@')
+
+/* Use -ve numbers here to co-exist with normal unicode chars */
+enum {
+    SPECIAL_NONE,
+    SPECIAL_UP = -20,
+    SPECIAL_DOWN = -21,
+    SPECIAL_LEFT = -22,
+    SPECIAL_RIGHT = -23,
+    SPECIAL_DELETE = -24,
+    SPECIAL_HOME = -25,
+    SPECIAL_END = -26,
+};
+
+static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
+static int history_len = 0;
+static char **history = NULL;
+
+/* Structure to contain the status of the current (being edited) line */
+struct current {
+    char *buf;  /* Current buffer. Always null terminated */
+    int bufmax; /* Size of the buffer, including space for the null termination */
+    int len;    /* Number of bytes in 'buf' */
+    int chars;  /* Number of chars in 'buf' (utf-8 chars) */
+    int pos;    /* Cursor position, measured in chars */
+    int cols;   /* Size of the window, in chars */
+    const char *prompt;
+#if defined(USE_TERMIOS)
+    int fd;     /* Terminal fd */
+#elif defined(USE_WINCONSOLE)
+    HANDLE outh; /* Console output handle */
+    HANDLE inh; /* Console input handle */
+    int rows;   /* Screen rows */
+    int x;      /* Current column during output */
+    int y;      /* Current row */
+#endif
+};
+
+static int fd_read(struct current *current);
+static int getWindowSize(struct current *current);
+
+void linenoiseHistoryFree(void) {
+    if (history) {
+        int j;
+
+        for (j = 0; j < history_len; j++)
+            free(history[j]);
+        free(history);
+        history = NULL;
+    }
+}
+
+#if defined(USE_TERMIOS)
+static void linenoiseAtExit(void);
+static struct termios orig_termios; /* in order to restore at exit */
+static int rawmode = 0; /* for atexit() function to check if restore is needed*/
+static int atexit_registered = 0; /* register atexit just 1 time */
+
+static const char *unsupported_term[] = {"dumb","cons25",NULL};
+
+static int isUnsupportedTerm(void) {
+    char *term = getenv("TERM");
+
+    if (term) {
+        int j;
+        for (j = 0; unsupported_term[j]; j++) {
+            if (strcasecmp(term, unsupported_term[j]) == 0) {
+                return 1;
+            }
+        }
+    }
+    return 0;
+}
+
+static int enableRawMode(struct current *current) {
+    struct termios raw;
+
+    current->fd = STDIN_FILENO;
+
+    if (!isatty(current->fd) || isUnsupportedTerm() ||
+        tcgetattr(current->fd, &orig_termios) == -1) {
+fatal:
+        errno = ENOTTY;
+        return -1;
+    }
+
+    if (!atexit_registered) {
+        atexit(linenoiseAtExit);
+        atexit_registered = 1;
+    }
+
+    raw = orig_termios;  /* modify the original mode */
+    /* input modes: no break, no CR to NL, no parity check, no strip char,
+     * no start/stop output control. */
+    raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+    /* output modes - disable post processing */
+    raw.c_oflag &= ~(OPOST);
+    /* control modes - set 8 bit chars */
+    raw.c_cflag |= (CS8);
+    /* local modes - choing off, canonical off, no extended functions,
+     * no signal chars (^Z,^C) */
+    raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+    /* control chars - set return condition: min number of bytes and timer.
+     * We want read to return every single byte, without timeout. */
+    raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
+
+    /* put terminal in raw mode after flushing */
+    if (tcsetattr(current->fd,TCSADRAIN,&raw) < 0) {
+        goto fatal;
+    }
+    rawmode = 1;
+
+    current->cols = 0;
+    return 0;
+}
+
+static void disableRawMode(struct current *current) {
+    /* Don't even check the return value as it's too late. */
+    if (rawmode && tcsetattr(current->fd,TCSADRAIN,&orig_termios) != -1)
+        rawmode = 0;
+}
+
+/* At exit we'll try to fix the terminal to the initial conditions. */
+static void linenoiseAtExit(void) {
+    if (rawmode) {
+        tcsetattr(STDIN_FILENO, TCSADRAIN, &orig_termios);
+    }
+    linenoiseHistoryFree();
+}
+
+/* gcc/glibc insists that we care about the return code of write! */
+#define IGNORE_RC(EXPR) if (EXPR) {}
+
+/* This is fdprintf() on some systems, but use a different
+ * name to avoid conflicts
+ */
+static void fd_printf(int fd, const char *format, ...)
+{
+    va_list args;
+    char buf[64];
+    int n;
+
+    va_start(args, format);
+    n = vsnprintf(buf, sizeof(buf), format, args);
+    va_end(args);
+    IGNORE_RC(write(fd, buf, n));
+}
+
+static void clearScreen(struct current *current)
+{
+    fd_printf(current->fd, "\x1b[H\x1b[2J");
+}
+
+static void cursorToLeft(struct current *current)
+{
+    fd_printf(current->fd, "\x1b[1G");
+}
+
+static int outputChars(struct current *current, const char *buf, int len)
+{
+    return write(current->fd, buf, len);
+}
+
+static void outputControlChar(struct current *current, char ch)
+{
+    fd_printf(current->fd, "\033[7m^%c\033[0m", ch);
+}
+
+static void eraseEol(struct current *current)
+{
+    fd_printf(current->fd, "\x1b[0K");
+}
+
+static void setCursorPos(struct current *current, int x)
+{
+    fd_printf(current->fd, "\x1b[1G\x1b[%dC", x);
+}
+
+/**
+ * Reads a char from 'fd', waiting at most 'timeout' milliseconds.
+ *
+ * A timeout of -1 means to wait forever.
+ *
+ * Returns -1 if no char is received within the time or an error occurs.
+ */
+static int fd_read_char(int fd, int timeout)
+{
+    struct pollfd p;
+    unsigned char c;
+
+    p.fd = fd;
+    p.events = POLLIN;
+
+    if (poll(&p, 1, timeout) == 0) {
+        /* timeout */
+        return -1;
+    }
+    if (read(fd, &c, 1) != 1) {
+        return -1;
+    }
+    return c;
+}
+
+/**
+ * Reads a complete utf-8 character
+ * and returns the unicode value, or -1 on error.
+ */
+static int fd_read(struct current *current)
+{
+#ifdef USE_UTF8
+    char buf[4];
+    int n;
+    int i;
+    int c;
+
+    if (read(current->fd, &buf[0], 1) != 1) {
+        return -1;
+    }
+    n = utf8_charlen(buf[0]);
+    if (n < 1 || n > 3) {
+        return -1;
+    }
+    for (i = 1; i < n; i++) {
+        if (read(current->fd, &buf[i], 1) != 1) {
+            return -1;
+        }
+    }
+    buf[n] = 0;
+    /* decode and return the character */
+    utf8_tounicode(buf, &c);
+    return c;
+#else
+    return fd_read_char(current->fd, -1);
+#endif
+}
+
+static int getWindowSize(struct current *current)
+{
+    struct winsize ws;
+
+    if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && ws.ws_col != 0) {
+        current->cols = ws.ws_col;
+        return 0;
+    }
+
+    /* Failed to query the window size. Perhaps we are on a serial terminal.
+     * Try to query the width by sending the cursor as far to the right
+     * and reading back the cursor position.
+     * Note that this is only done once per call to linenoise rather than
+     * every time the line is refreshed for efficiency reasons.
+     */
+    if (current->cols == 0) {
+        current->cols = 80;
+
+        /* Move cursor far right and report cursor position */
+        fd_printf(current->fd, "\x1b[999G" "\x1b[6n");
+
+        /* Parse the response: ESC [ rows ; cols R */
+        if (fd_read_char(current->fd, 100) == 0x1b && fd_read_char(current->fd, 100) == '[') {
+            int n = 0;
+            while (1) {
+                int ch = fd_read_char(current->fd, 100);
+                if (ch == ';') {
+                    /* Ignore rows */
+                    n = 0;
+                }
+                else if (ch == 'R') {
+                    /* Got cols */
+                    if (n != 0 && n < 1000) {
+                        current->cols = n;
+                    }
+                    break;
+                }
+                else if (ch >= 0 && ch <= '9') {
+                    n = n * 10 + ch - '0';
+                }
+                else {
+                    break;
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+/**
+ * If escape (27) was received, reads subsequent
+ * chars to determine if this is a known special key.
+ *
+ * Returns SPECIAL_NONE if unrecognised, or -1 if EOF.
+ *
+ * If no additional char is received within a short time,
+ * 27 is returned.
+ */
+static int check_special(int fd)
+{
+    int c = fd_read_char(fd, 50);
+    int c2;
+
+    if (c < 0) {
+        return 27;
+    }
+
+    c2 = fd_read_char(fd, 50);
+    if (c2 < 0) {
+        return c2;
+    }
+    if (c == '[' || c == 'O') {
+        /* Potential arrow key */
+        switch (c2) {
+            case 'A':
+                return SPECIAL_UP;
+            case 'B':
+                return SPECIAL_DOWN;
+            case 'C':
+                return SPECIAL_RIGHT;
+            case 'D':
+                return SPECIAL_LEFT;
+            case 'F':
+                return SPECIAL_END;
+            case 'H':
+                return SPECIAL_HOME;
+        }
+    }
+    if (c == '[' && c2 >= '1' && c2 <= '6') {
+        /* extended escape */
+        int c3 = fd_read_char(fd, 50);
+        if (c2 == '3' && c3 == '~') {
+            /* delete char under cursor */
+            return SPECIAL_DELETE;
+        }
+        while (c3 != -1 && c3 != '~') {
+            /* .e.g \e[12~ or '\e[11;2~   discard the complete sequence */
+            c3 = fd_read_char(fd, 50);
+        }
+    }
+
+    return SPECIAL_NONE;
+}
+#elif defined(USE_WINCONSOLE)
+
+static DWORD orig_consolemode = 0;
+
+static int enableRawMode(struct current *current) {
+    DWORD n;
+    INPUT_RECORD irec;
+
+    current->outh = GetStdHandle(STD_OUTPUT_HANDLE);
+    current->inh = GetStdHandle(STD_INPUT_HANDLE);
+
+    if (!PeekConsoleInput(current->inh, &irec, 1, &n)) {
+        return -1;
+    }
+    if (getWindowSize(current) != 0) {
+        return -1;
+    }
+    if (GetConsoleMode(current->inh, &orig_consolemode)) {
+        SetConsoleMode(current->inh, ENABLE_PROCESSED_INPUT);
+    }
+    return 0;
+}
+
+static void disableRawMode(struct current *current)
+{
+    SetConsoleMode(current->inh, orig_consolemode);
+}
+
+static void clearScreen(struct current *current)
+{
+    COORD topleft = { 0, 0 };
+    DWORD n;
+
+    FillConsoleOutputCharacter(current->outh, ' ',
+        current->cols * current->rows, topleft, &n);
+    FillConsoleOutputAttribute(current->outh,
+        FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN,
+        current->cols * current->rows, topleft, &n);
+    SetConsoleCursorPosition(current->outh, topleft);
+}
+
+static void cursorToLeft(struct current *current)
+{
+    COORD pos = { 0, current->y };
+    DWORD n;
+
+    FillConsoleOutputAttribute(current->outh,
+        FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN, current->cols, pos, &n);
+    current->x = 0;
+}
+
+static int outputChars(struct current *current, const char *buf, int len)
+{
+    COORD pos = { current->x, current->y };
+    WriteConsoleOutputCharacter(current->outh, buf, len, pos, 0);
+    current->x += len;
+    return 0;
+}
+
+static void outputControlChar(struct current *current, char ch)
+{
+    COORD pos = { current->x, current->y };
+    DWORD n;
+
+    FillConsoleOutputAttribute(current->outh, BACKGROUND_INTENSITY, 2, pos, &n);
+    outputChars(current, "^", 1);
+    outputChars(current, &ch, 1);
+}
+
+static void eraseEol(struct current *current)
+{
+    COORD pos = { current->x, current->y };
+    DWORD n;
+
+    FillConsoleOutputCharacter(current->outh, ' ', current->cols - current->x, pos, &n);
+}
+
+static void setCursorPos(struct current *current, int x)
+{
+    COORD pos = { x, current->y };
+
+    SetConsoleCursorPosition(current->outh, pos);
+    current->x = x;
+}
+
+static int fd_read(struct current *current)
+{
+    while (1) {
+        INPUT_RECORD irec;
+        DWORD n;
+        if (WaitForSingleObject(current->inh, INFINITE) != WAIT_OBJECT_0) {
+            break;
+        }
+        if (!ReadConsoleInput (current->inh, &irec, 1, &n)) {
+            break;
+        }
+        if (irec.EventType == KEY_EVENT && irec.Event.KeyEvent.bKeyDown) {
+            KEY_EVENT_RECORD *k = &irec.Event.KeyEvent;
+            if (k->dwControlKeyState & ENHANCED_KEY) {
+                switch (k->wVirtualKeyCode) {
+                 case VK_LEFT:
+                    return SPECIAL_LEFT;
+                 case VK_RIGHT:
+                    return SPECIAL_RIGHT;
+                 case VK_UP:
+                    return SPECIAL_UP;
+                 case VK_DOWN:
+                    return SPECIAL_DOWN;
+                 case VK_DELETE:
+                    return SPECIAL_DELETE;
+                 case VK_HOME:
+                    return SPECIAL_HOME;
+                 case VK_END:
+                    return SPECIAL_END;
+                }
+            }
+            /* Note that control characters are already translated in AsciiChar */
+            else {
+#ifdef USE_UTF8
+                return k->uChar.UnicodeChar;
+#else
+                return k->uChar.AsciiChar;
+#endif
+            }
+        }
+    }
+    return -1;
+}
+
+static int getWindowSize(struct current *current)
+{
+    CONSOLE_SCREEN_BUFFER_INFO info;
+    if (!GetConsoleScreenBufferInfo(current->outh, &info)) {
+        return -1;
+    }
+    current->cols = info.dwSize.X;
+    current->rows = info.dwSize.Y;
+    if (current->cols <= 0 || current->rows <= 0) {
+        current->cols = 80;
+        return -1;
+    }
+    current->y = info.dwCursorPosition.Y;
+    current->x = info.dwCursorPosition.X;
+    return 0;
+}
+#endif
+
+static int utf8_getchars(char *buf, int c)
+{
+#ifdef USE_UTF8
+    return utf8_fromunicode(buf, c);
+#else
+    *buf = c;
+    return 1;
+#endif
+}
+
+/**
+ * Returns the unicode character at the given offset,
+ * or -1 if none.
+ */
+static int get_char(struct current *current, int pos)
+{
+    if (pos >= 0 && pos < current->chars) {
+        int c;
+        int i = utf8_index(current->buf, pos);
+        (void)utf8_tounicode(current->buf + i, &c);
+        return c;
+    }
+    return -1;
+}
+
+static void refreshLine(const char *prompt, struct current *current)
+{
+    int plen;
+    int pchars;
+    int backup = 0;
+    int i;
+    const char *buf = current->buf;
+    int chars = current->chars;
+    int pos = current->pos;
+    int b;
+    int ch;
+    int n;
+
+    /* Should intercept SIGWINCH. For now, just get the size every time */
+    getWindowSize(current);
+
+    plen = strlen(prompt);
+    pchars = utf8_strlen(prompt, plen);
+
+    /* Account for a line which is too long to fit in the window.
+     * Note that control chars require an extra column
+     */
+
+    /* How many cols are required to the left of 'pos'?
+     * The prompt, plus one extra for each control char
+     */
+    n = pchars + utf8_strlen(buf, current->len);
+    b = 0;
+    for (i = 0; i < pos; i++) {
+        b += utf8_tounicode(buf + b, &ch);
+        if (ch < ' ') {
+            n++;
+        }
+    }
+
+    /* If too many are need, strip chars off the front of 'buf'
+     * until it fits. Note that if the current char is a control character,
+     * we need one extra col.
+     */
+    if (current->pos < current->chars && get_char(current, current->pos) < ' ') {
+        n++;
+    }
+
+    while (n >= current->cols) {
+        b = utf8_tounicode(buf, &ch);
+        if (ch < ' ') {
+            n--;
+        }
+        n--;
+        buf += b;
+        pos--;
+        chars--;
+    }
+
+    /* Cursor to left edge, then the prompt */
+    cursorToLeft(current);
+    outputChars(current, prompt, plen);
+
+    /* Now the current buffer content */
+
+    /* Need special handling for control characters.
+     * If we hit 'cols', stop.
+     */
+    b = 0; /* unwritted bytes */
+    n = 0; /* How many control chars were written */
+    for (i = 0; i < chars; i++) {
+        int ch;
+        int w = utf8_tounicode(buf + b, &ch);
+        if (ch < ' ') {
+            n++;
+        }
+        if (pchars + i + n >= current->cols) {
+            break;
+        }
+        if (ch < ' ') {
+            /* A control character, so write the buffer so far */
+            outputChars(current, buf, b);
+            buf += b + w;
+            b = 0;
+            outputControlChar(current, ch + '@');
+            if (i < pos) {
+                backup++;
+            }
+        }
+        else {
+            b += w;
+        }
+    }
+    outputChars(current, buf, b);
+
+    /* Erase to right, move cursor to original position */
+    eraseEol(current);
+    setCursorPos(current, pos + pchars + backup);
+}
+
+static void set_current(struct current *current, const char *str)
+{
+    strncpy(current->buf, str, current->bufmax);
+    current->buf[current->bufmax - 1] = 0;
+    current->len = strlen(current->buf);
+    current->pos = current->chars = utf8_strlen(current->buf, current->len);
+}
+
+static int has_room(struct current *current, int bytes)
+{
+    return current->len + bytes < current->bufmax - 1;
+}
+
+/**
+ * Removes the char at 'pos'.
+ *
+ * Returns 1 if the line needs to be refreshed, 2 if not
+ * and 0 if nothing was removed
+ */
+static int remove_char(struct current *current, int pos)
+{
+    if (pos >= 0 && pos < current->chars) {
+        int p1, p2;
+        int ret = 1;
+        p1 = utf8_index(current->buf, pos);
+        p2 = p1 + utf8_index(current->buf + p1, 1);
+
+#ifdef USE_TERMIOS
+        /* optimise remove char in the case of removing the last char */
+        if (current->pos == pos + 1 && current->pos == current->chars) {
+            if (current->buf[pos] >= ' ' && utf8_strlen(current->prompt, -1) + utf8_strlen(current->buf, current->len) < current->cols - 1) {
+                ret = 2;
+                fd_printf(current->fd, "\b \b");
+            }
+        }
+#endif
+
+        /* Move the null char too */
+        memmove(current->buf + p1, current->buf + p2, current->len - p2 + 1);
+        current->len -= (p2 - p1);
+        current->chars--;
+
+        if (current->pos > pos) {
+            current->pos--;
+        }
+        return ret;
+    }
+    return 0;
+}
+
+/**
+ * Insert 'ch' at position 'pos'
+ *
+ * Returns 1 if the line needs to be refreshed, 2 if not
+ * and 0 if nothing was inserted (no room)
+ */
+static int insert_char(struct current *current, int pos, int ch)
+{
+    char buf[3];
+    int n = utf8_getchars(buf, ch);
+
+    if (has_room(current, n) && pos >= 0 && pos <= current->chars) {
+        int p1, p2;
+        int ret = 1;
+        p1 = utf8_index(current->buf, pos);
+        p2 = p1 + n;
+
+#ifdef USE_TERMIOS
+        /* optimise the case where adding a single char to the end and no scrolling is needed */
+        if (current->pos == pos && current->chars == pos) {
+            if (ch >= ' ' && utf8_strlen(current->prompt, -1) + utf8_strlen(current->buf, current->len) < current->cols - 1) {
+                IGNORE_RC(write(current->fd, buf, n));
+                ret = 2;
+            }
+        }
+#endif
+
+        memmove(current->buf + p2, current->buf + p1, current->len - p1);
+        memcpy(current->buf + p1, buf, n);
+        current->len += n;
+
+        current->chars++;
+        if (current->pos >= pos) {
+            current->pos++;
+        }
+        return ret;
+    }
+    return 0;
+}
+
+/**
+ * Returns 0 if no chars were removed or non-zero otherwise.
+ */
+static int remove_chars(struct current *current, int pos, int n)
+{
+    int removed = 0;
+    while (n-- && remove_char(current, pos)) {
+        removed++;
+    }
+    return removed;
+}
+
+#ifndef NO_COMPLETION
+static linenoiseCompletionCallback *completionCallback = NULL;
+
+static void beep() {
+#ifdef USE_TERMIOS
+    fprintf(stderr, "\x7");
+    fflush(stderr);
+#endif
+}
+
+static void freeCompletions(linenoiseCompletions *lc) {
+    size_t i;
+    for (i = 0; i < lc->len; i++)
+        free(lc->cvec[i]);
+    free(lc->cvec);
+}
+
+static int completeLine(struct current *current) {
+    linenoiseCompletions lc = { 0, NULL };
+    int c = 0;
+
+    completionCallback(current->buf,&lc);
+    if (lc.len == 0) {
+        beep();
+    } else {
+        size_t stop = 0, i = 0;
+
+        while(!stop) {
+            /* Show completion or original buffer */
+            if (i < lc.len) {
+                struct current tmp = *current;
+                tmp.buf = lc.cvec[i];
+                tmp.pos = tmp.len = strlen(tmp.buf);
+                tmp.chars = utf8_strlen(tmp.buf, tmp.len);
+                refreshLine(current->prompt, &tmp);
+            } else {
+                refreshLine(current->prompt, current);
+            }
+
+            c = fd_read(current);
+            if (c == -1) {
+                break;
+            }
+
+            switch(c) {
+                case '\t': /* tab */
+                    i = (i+1) % (lc.len+1);
+                    if (i == lc.len) beep();
+                    break;
+                case 27: /* escape */
+                    /* Re-show original buffer */
+                    if (i < lc.len) {
+                        refreshLine(current->prompt, current);
+                    }
+                    stop = 1;
+                    break;
+                default:
+                    /* Update buffer and return */
+                    if (i < lc.len) {
+                        set_current(current,lc.cvec[i]);
+                    }
+                    stop = 1;
+                    break;
+            }
+        }
+    }
+
+    freeCompletions(&lc);
+    return c; /* Return last read character */
+}
+
+/* Register a callback function to be called for tab-completion. */
+void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
+    completionCallback = fn;
+}
+
+void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
+    lc->cvec = (char **)realloc(lc->cvec,sizeof(char*)*(lc->len+1));
+    lc->cvec[lc->len++] = strdup(str);
+}
+
+#endif
+
+static int linenoisePrompt(struct current *current) {
+    int history_index = 0;
+
+    /* The latest history entry is always our current buffer, that
+     * initially is just an empty string. */
+    linenoiseHistoryAdd("");
+
+    set_current(current, "");
+    refreshLine(current->prompt, current);
+
+    while(1) {
+        int dir = -1;
+        int c = fd_read(current);
+
+#ifndef NO_COMPLETION
+        /* Only autocomplete when the callback is set. It returns < 0 when
+         * there was an error reading from fd. Otherwise it will return the
+         * character that should be handled next. */
+        if (c == 9 && completionCallback != NULL) {
+            c = completeLine(current);
+            /* Return on errors */
+            if (c < 0) return current->len;
+            /* Read next character when 0 */
+            if (c == 0) continue;
+        }
+#endif
+
+process_char:
+        if (c == -1) return current->len;
+#ifdef USE_TERMIOS
+        if (c == 27) {   /* escape sequence */
+            c = check_special(current->fd);
+        }
+#endif
+        switch(c) {
+        case '\r':    /* enter */
+            history_len--;
+            free(history[history_len]);
+            return current->len;
+        case ctrl('C'):     /* ctrl-c */
+            errno = EAGAIN;
+            return -1;
+        case 127:   /* backspace */
+        case ctrl('H'):
+            if (remove_char(current, current->pos - 1) == 1) {
+                refreshLine(current->prompt, current);
+            }
+            break;
+        case ctrl('D'):     /* ctrl-d */
+            if (current->len == 0) {
+                /* Empty line, so EOF */
+                history_len--;
+                free(history[history_len]);
+                return -1;
+            }
+            /* Otherwise delete char to right of cursor */
+            if (remove_char(current, current->pos)) {
+                refreshLine(current->prompt, current);
+            }
+            break;
+        case ctrl('W'):    /* ctrl-w */
+            /* eat any spaces on the left */
+            {
+                int pos = current->pos;
+                while (pos > 0 && get_char(current, pos - 1) == ' ') {
+                    pos--;
+                }
+
+                /* now eat any non-spaces on the left */
+                while (pos > 0 && get_char(current, pos - 1) != ' ') {
+                    pos--;
+                }
+
+                if (remove_chars(current, pos, current->pos - pos)) {
+                    refreshLine(current->prompt, current);
+                }
+            }
+            break;
+        case ctrl('R'):    /* ctrl-r */
+            {
+                /* Display the reverse-i-search prompt and process chars */
+                char rbuf[50];
+                char rprompt[80];
+                int rchars = 0;
+                int rlen = 0;
+                int searchpos = history_len - 1;
+
+                rbuf[0] = 0;
+                while (1) {
+                    int n = 0;
+                    const char *p = NULL;
+                    int skipsame = 0;
+                    int searchdir = -1;
+
+                    snprintf(rprompt, sizeof(rprompt), "(reverse-i-search)'%s': ", rbuf);
+                    refreshLine(rprompt, current);
+                    c = fd_read(current);
+                    if (c == ctrl('H') || c == 127) {
+                        if (rchars) {
+                            int p = utf8_index(rbuf, --rchars);
+                            rbuf[p] = 0;
+                            rlen = strlen(rbuf);
+                        }
+                        continue;
+                    }
+#ifdef USE_TERMIOS
+                    if (c == 27) {
+                        c = check_special(current->fd);
+                    }
+#endif
+                    if (c == ctrl('P') || c == SPECIAL_UP) {
+                        /* Search for the previous (earlier) match */
+                        if (searchpos > 0) {
+                            searchpos--;
+                        }
+                        skipsame = 1;
+                    }
+                    else if (c == ctrl('N') || c == SPECIAL_DOWN) {
+                        /* Search for the next (later) match */
+                        if (searchpos < history_len) {
+                            searchpos++;
+                        }
+                        searchdir = 1;
+                        skipsame = 1;
+                    }
+                    else if (c >= ' ') {
+                        if (rlen >= (int)sizeof(rbuf) + 3) {
+                            continue;
+                        }
+
+                        n = utf8_getchars(rbuf + rlen, c);
+                        rlen += n;
+                        rchars++;
+                        rbuf[rlen] = 0;
+
+                        /* Adding a new char resets the search location */
+                        searchpos = history_len - 1;
+                    }
+                    else {
+                        /* Exit from incremental search mode */
+                        break;
+                    }
+
+                    /* Now search through the history for a match */
+                    for (; searchpos >= 0 && searchpos < history_len; searchpos += searchdir) {
+                        p = strstr(history[searchpos], rbuf);
+                        if (p) {
+                            /* Found a match */
+                            if (skipsame && strcmp(history[searchpos], current->buf) == 0) {
+                                /* But it is identical, so skip it */
+                                continue;
+                            }
+                            /* Copy the matching line and set the cursor position */
+                            set_current(current,history[searchpos]);
+                            current->pos = utf8_strlen(history[searchpos], p - history[searchpos]);
+                            break;
+                        }
+                    }
+                    if (!p && n) {
+                        /* No match, so don't add it */
+                        rchars--;
+                        rlen -= n;
+                        rbuf[rlen] = 0;
+                    }
+                }
+                if (c == ctrl('G') || c == ctrl('C')) {
+                    /* ctrl-g terminates the search with no effect */
+                    set_current(current, "");
+                    c = 0;
+                }
+                else if (c == ctrl('J')) {
+                    /* ctrl-j terminates the search leaving the buffer in place */
+                    c = 0;
+                }
+                /* Go process the char normally */
+                refreshLine(current->prompt, current);
+                goto process_char;
+            }
+            break;
+        case ctrl('T'):    /* ctrl-t */
+            if (current->pos > 0 && current->pos < current->chars) {
+                c = get_char(current, current->pos);
+                remove_char(current, current->pos);
+                insert_char(current, current->pos - 1, c);
+                refreshLine(current->prompt, current);
+            }
+            break;
+        case ctrl('V'):    /* ctrl-v */
+            if (has_room(current, 3)) {
+                /* Insert the ^V first */
+                if (insert_char(current, current->pos, c)) {
+                    refreshLine(current->prompt, current);
+                    /* Now wait for the next char. Can insert anything except \0 */
+                    c = fd_read(current);
+
+                    /* Remove the ^V first */
+                    remove_char(current, current->pos - 1);
+                    if (c != -1) {
+                        /* Insert the actual char */
+                        insert_char(current, current->pos, c);
+                    }
+                    refreshLine(current->prompt, current);
+                }
+            }
+            break;
+        case ctrl('B'):
+        case SPECIAL_LEFT:
+            if (current->pos > 0) {
+                current->pos--;
+                refreshLine(current->prompt, current);
+            }
+            break;
+        case ctrl('F'):
+        case SPECIAL_RIGHT:
+            if (current->pos < current->chars) {
+                current->pos++;
+                refreshLine(current->prompt, current);
+            }
+            break;
+        case ctrl('P'):
+        case SPECIAL_UP:
+            dir = 1;
+        case ctrl('N'):
+        case SPECIAL_DOWN:
+            if (history_len > 1) {
+                /* Update the current history entry before to
+                 * overwrite it with tne next one. */
+                free(history[history_len-1-history_index]);
+                history[history_len-1-history_index] = strdup(current->buf);
+                /* Show the new entry */
+                history_index += dir;
+                if (history_index < 0) {
+                    history_index = 0;
+                    break;
+                } else if (history_index >= history_len) {
+                    history_index = history_len-1;
+                    break;
+                }
+                set_current(current, history[history_len-1-history_index]);
+                refreshLine(current->prompt, current);
+            }
+            break;
+
+        case SPECIAL_DELETE:
+            if (remove_char(current, current->pos) == 1) {
+                refreshLine(current->prompt, current);
+            }
+            break;
+        case SPECIAL_HOME:
+            current->pos = 0;
+            refreshLine(current->prompt, current);
+            break;
+        case SPECIAL_END:
+            current->pos = current->chars;
+            refreshLine(current->prompt, current);
+            break;
+        default:
+            /* Only tab is allowed without ^V */
+            if (c == '\t' || c >= ' ') {
+                if (insert_char(current, current->pos, c) == 1) {
+                    refreshLine(current->prompt, current);
+                }
+            }
+            break;
+        case ctrl('U'): /* Ctrl+u, delete to beginning of line. */
+            if (remove_chars(current, 0, current->pos)) {
+                refreshLine(current->prompt, current);
+            }
+            break;
+        case ctrl('K'): /* Ctrl+k, delete from current to end of line. */
+            if (remove_chars(current, current->pos, current->chars - current->pos)) {
+                refreshLine(current->prompt, current);
+            }
+            break;
+        case ctrl('A'): /* Ctrl+a, go to the start of the line */
+            current->pos = 0;
+            refreshLine(current->prompt, current);
+            break;
+        case ctrl('E'): /* ctrl+e, go to the end of the line */
+            current->pos = current->chars;
+            refreshLine(current->prompt, current);
+            break;
+        case ctrl('L'): /* Ctrl+L, clear screen */
+            /* clear screen */
+            clearScreen(current);
+            /* Force recalc of window size for serial terminals */
+            current->cols = 0;
+            refreshLine(current->prompt, current);
+            break;
+        }
+    }
+    return current->len;
+}
+
+char *linenoise(const char *prompt)
+{
+    int count;
+    struct current current;
+    char buf[LINENOISE_MAX_LINE];
+
+    if (enableRawMode(&current) == -1) {
+	printf("%s", prompt);
+        fflush(stdout);
+        if (fgets(buf, sizeof(buf), stdin) == NULL) {
+		return NULL;
+        }
+        count = strlen(buf);
+        if (count && buf[count-1] == '\n') {
+            count--;
+            buf[count] = '\0';
+        }
+    }
+    else
+    {
+        current.buf = buf;
+        current.bufmax = sizeof(buf);
+        current.len = 0;
+        current.chars = 0;
+        current.pos = 0;
+        current.prompt = prompt;
+
+        count = linenoisePrompt(&current);
+        disableRawMode(&current);
+        printf("\n");
+        if (count == -1) {
+            return NULL;
+        }
+    }
+    return strdup(buf);
+}
+
+/* Using a circular buffer is smarter, but a bit more complex to handle. */
+int linenoiseHistoryAdd(const char *line) {
+    char *linecopy;
+
+    if (history_max_len == 0) return 0;
+    if (history == NULL) {
+        history = (char**)malloc(sizeof(char*)*history_max_len);
+        if (history == NULL) return 0;
+        memset(history,0,(sizeof(char*)*history_max_len));
+    }
+    linecopy = strdup(line);
+    if (!linecopy) return 0;
+    if (history_len == history_max_len) {
+        free(history[0]);
+        memmove(history,history+1,sizeof(char*)*(history_max_len-1));
+        history_len--;
+    }
+    history[history_len] = linecopy;
+    history_len++;
+    return 1;
+}
+
+int linenoiseHistorySetMaxLen(int len) {
+    char **newHistory;
+
+    if (len < 1) return 0;
+    if (history) {
+        int tocopy = history_len;
+
+        newHistory = (char**)malloc(sizeof(char*)*len);
+        if (newHistory == NULL) return 0;
+        if (len < tocopy) tocopy = len;
+        memcpy(newHistory,history+(history_max_len-tocopy), sizeof(char*)*tocopy);
+        free(history);
+        history = newHistory;
+    }
+    history_max_len = len;
+    if (history_len > history_max_len)
+        history_len = history_max_len;
+    return 1;
+}
+
+/* Save the history in the specified file. On success 0 is returned
+ * otherwise -1 is returned. */
+int linenoiseHistorySave(const char *filename) {
+    FILE *fp = fopen(filename,"w");
+    int j;
+
+    if (fp == NULL) return -1;
+    for (j = 0; j < history_len; j++) {
+        const char *str = history[j];
+        /* Need to encode backslash, nl and cr */
+        while (*str) {
+            if (*str == '\\') {
+                fputs("\\\\", fp);
+            }
+            else if (*str == '\n') {
+                fputs("\\n", fp);
+            }
+            else if (*str == '\r') {
+                fputs("\\r", fp);
+            }
+            else {
+                fputc(*str, fp);
+            }
+            str++;
+        }
+        fputc('\n', fp);
+    }
+
+    fclose(fp);
+    return 0;
+}
+
+/* Load the history from the specified file. If the file does not exist
+ * zero is returned and no operation is performed.
+ *
+ * If the file exists and the operation succeeded 0 is returned, otherwise
+ * on error -1 is returned. */
+int linenoiseHistoryLoad(const char *filename) {
+    FILE *fp = fopen(filename,"r");
+    char buf[LINENOISE_MAX_LINE];
+
+    if (fp == NULL) return -1;
+
+    while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
+        char *src, *dest;
+
+        /* Decode backslash escaped values */
+        for (src = dest = buf; *src; src++) {
+            char ch = *src;
+
+            if (ch == '\\') {
+                src++;
+                if (*src == 'n') {
+                    ch = '\n';
+                }
+                else if (*src == 'r') {
+                    ch = '\r';
+                } else {
+                    ch = *src;
+                }
+            }
+            *dest++ = ch;
+        }
+        /* Remove trailing newline */
+        if (dest != buf && (dest[-1] == '\n' || dest[-1] == '\r')) {
+            dest--;
+        }
+        *dest = 0;
+
+        linenoiseHistoryAdd(buf);
+    }
+    fclose(fp);
+    return 0;
+}
+
+/* Provide access to the history buffer.
+ *
+ * If 'len' is not NULL, the length is stored in *len.
+ */
+char **linenoiseHistory(int *len) {
+    if (len) {
+        *len = history_len;
+    }
+    return history;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/linenoise.h b/android/external/usb_modeswitch/usb_modeswitch/jim/linenoise.h
new file mode 100755
index 0000000..dcf22f7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/linenoise.h
@@ -0,0 +1,62 @@
+/* linenoise.h -- guerrilla line editing library against the idea that a
+ * line editing lib needs to be 20,000 lines of C code.
+ *
+ * See linenoise.c for more information.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  *  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *  *  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LINENOISE_H
+#define __LINENOISE_H
+
+/* Currently never enable completion */
+#define NO_COMPLETION
+
+#ifndef NO_COMPLETION
+typedef struct linenoiseCompletions {
+  size_t len;
+  char **cvec;
+} linenoiseCompletions;
+
+typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
+void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
+void linenoiseAddCompletion(linenoiseCompletions *, const char *);
+#endif
+
+char *linenoise(const char *prompt);
+int linenoiseHistoryAdd(const char *line);
+int linenoiseHistorySetMaxLen(int len);
+int linenoiseHistorySave(const char *filename);
+int linenoiseHistoryLoad(const char *filename);
+void linenoiseHistoryFree(void);
+char **linenoiseHistory(int *len);
+
+#endif /* __LINENOISE_H */
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/make-bootstrap-jim b/android/external/usb_modeswitch/usb_modeswitch/jim/make-bootstrap-jim
new file mode 100755
index 0000000..cc2cd5d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/make-bootstrap-jim
@@ -0,0 +1,104 @@
+#!/bin/sh
+
+# This script writes to stdout, a single source file (e.g. jimsh0.c)
+# which can be compiled to provide a bootstrap version of jimsh.
+# e.g. cc -o jimsh0 jimsh0.c
+
+makeext()
+{
+	source="$1"
+	basename=`basename "$source" .tcl`
+cat <<EOF
+int Jim_${basename}Init(Jim_Interp *interp)
+{
+	if (Jim_PackageProvide(interp, "$basename", "1.0", JIM_ERRMSG))
+		return JIM_ERR;
+
+	return Jim_EvalSource(interp, "$source", 1,
+EOF
+
+# Note: Keep newlines so that line numbers match in error messages
+sed -e 's/^[ 	]*#.*//' -e 's@\\@\\\\@g' -e 's@"@\\"@g' -e 's@^\(.*\)$@"\1\\n"@' $source
+
+echo ");"
+echo "}"
+}
+
+makeloadexts()
+{
+cat <<EOF
+int Jim_InitStaticExtensions(Jim_Interp *interp)
+EOF
+    echo "{"
+    for ext in $*; do
+        echo "extern int Jim_${ext}Init(Jim_Interp *);"
+    done
+    for ext in $*; do
+        echo "Jim_${ext}Init(interp);"
+    done
+    echo "return JIM_OK;"
+    echo "}"
+}
+
+cexts="aio readdir regexp file exec clock array"
+tclexts="bootstrap initjimsh glob stdlib tclcompat"
+
+# Note ordering
+allexts="bootstrap aio readdir glob regexp file exec clock array stdlib tclcompat"
+
+echo "/* This is single source file, bootstrap version of Jim Tcl. See http://jim.berlios.de/ */"
+
+# define some core features
+for i in _GNU_SOURCE JIM_TCL_COMPAT JIM_REFERENCES JIM_ANSIC JIM_REGEXP HAVE_NO_AUTOCONF _JIMAUTOCONF_H; do
+	echo "#define $i"
+done
+echo '#define TCL_LIBRARY "."'
+# and extensions
+for i in $allexts; do
+	echo "#define jim_ext_$i"
+done
+
+# Can we make a bootstrap jimsh work even on mingw32?
+cat <<EOF
+#if defined(__MINGW32__)
+#define TCL_PLATFORM_OS "mingw"
+#define TCL_PLATFORM_PLATFORM "windows"
+#define TCL_PLATFORM_PATH_SEPARATOR ";"
+#define HAVE_MKDIR_ONE_ARG
+#define HAVE_SYSTEM
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#else
+#define TCL_PLATFORM_OS "unknown"
+#define TCL_PLATFORM_PLATFORM "unix"
+#define TCL_PLATFORM_PATH_SEPARATOR ":"
+#define HAVE_VFORK
+#define HAVE_WAITPID
+#endif
+EOF
+
+outputsource()
+{
+        sed -e '/#include.*jim/d' -e '/#include.*utf8/d' \
+                -e '/^#.*if.*JIM_BOOTSTRAP/,/^#endif.*JIM_BOOTSTRAP/d' \
+                -e 's/\/\*.*\*\///' -e '/^[ 	]*\/\*/,/\*\//d' $1
+}
+
+# Now output header files, removing references to jim header files
+for i in utf8.h jim.h jim-subcmd.h jimregexp.h ; do
+	outputsource $i
+done
+
+# Now extension source code
+for i in $tclexts; do
+	makeext $i.tcl
+done
+for i in $cexts; do
+	outputsource jim-$i.c
+done
+makeloadexts $allexts
+
+# And finally the core source code
+for i in jim.c jim-subcmd.c utf8.c jim-interactive.c jim-format.c jimregexp.c jimsh.c; do
+	outputsource $i
+done
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/make-c-ext.tcl b/android/external/usb_modeswitch/usb_modeswitch/jim/make-c-ext.tcl
new file mode 100755
index 0000000..fd1a056
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/make-c-ext.tcl
@@ -0,0 +1,38 @@
+#!/usr/bin/env tclsh
+
+# Usage: make-c-ext.tcl source.tcl >jim-source.c
+
+# Converts a Tcl source file into C source suitable
+# for loading as a static extension.
+
+lassign $argv source
+
+if {![string match *.tcl $source]} {
+	error "Source $source is not a .tcl file"
+}
+
+# Read the Tcl source and convert to C
+# Note that no lines are removed in order to preserve line numbering
+set sourcelines {}
+set f [open $source]
+while {[gets $f buf] >= 0} {
+	# Remove comment lines
+	regsub {^[ \t]*#.*$} $buf "" buf
+	# Escape quotes and backlashes
+	set buf [string map [list \\ \\\\ \" \\"] $buf]
+	lappend sourcelines \"$buf\\n\"
+}
+close $f
+
+lappend lines {/* autogenerated - do not edit */}
+lappend lines {#include <jim.h>}
+set basename [file tail $source]
+set pkgname [file rootname $basename]
+
+lappend lines "int Jim_${pkgname}Init(Jim_Interp *interp)"
+lappend lines "\{"
+lappend lines "\tif (Jim_PackageProvide(interp, \"$pkgname\", \"1.0\", JIM_ERRMSG)) return JIM_ERR;"
+lappend lines "\treturn Jim_EvalSource(interp, \"$basename\", 1, [join $sourcelines \n]);"
+lappend lines "\}"
+
+puts [join $lines \n]
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/make-index b/android/external/usb_modeswitch/usb_modeswitch/jim/make-index
new file mode 100755
index 0000000..8dba920
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/make-index
@@ -0,0 +1,70 @@
+#!/usr/bin/env tclsh
+# vim:se syn=tcl:
+
+set filename [lindex $argv 0]
+set f [open $filename]
+
+# Read the file looking for command definitions
+set lines {}
+set commands {}
+array set cdict {}
+set c 0
+
+while {[gets $f buf] >= 0} {
+	if {[string match "~~*" $buf]} {
+		if {[string match "*:*" $prev]} {
+			incr c
+			set target cmd_$c
+			set lines [linsert $lines end-1 "\[\[$target\]\]"]
+		} else {
+			set target _$prev
+		}
+		foreach cmd [split $prev ":,"] {
+			set cmd [string trim $cmd]
+			if {[regexp {^[a-z.]+$} $cmd]} {
+				lappend commands [list $cmd $target]
+				set cdict($cmd) $target
+			}
+		}
+	}
+	lappend lines $buf
+	set prev $buf
+}
+close $f
+
+# Build the command index in the list: $index
+lappend index {[frame="none",grid="none"]}
+lappend index {|=========================}
+set i 0
+set row {}
+foreach command [lsort $commands] {
+	lassign $command cmd target
+
+	append row "|<<$target,*`$cmd`*>> "
+	incr i
+	if {$i % 8 == 0} {
+		lappend index $row
+		set row {}
+	}
+}
+while {$i % 8 != 0} {
+	incr i
+	append row "| "
+}
+lappend index $row
+lappend index {|=========================}
+
+# Map all `cmd` to <<$target,`cmd`>>
+set mapping {}
+foreach c [array names cdict] {
+	lappend mapping `$c` <<$cdict($c),*`$c`*>>
+	lappend mapping "`$c " "<<$cdict($c),*`$c`*>> `"
+}
+
+# And the command index
+lappend mapping @INSERTINDEX@ [join $index \n]
+
+# Output the result
+foreach line $lines {
+	puts [string map $mapping $line]
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/make-load-static-exts.tcl b/android/external/usb_modeswitch/usb_modeswitch/jim/make-load-static-exts.tcl
new file mode 100755
index 0000000..9185e77
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/make-load-static-exts.tcl
@@ -0,0 +1,48 @@
+#!/usr/bin/env tclsh
+
+# Usage: make-load-static-exts extname ... >load-static-exts.c
+
+# Creates load-static-exts.c based on the configured static extensions
+
+# There are some dependencies on static extensions which require
+# a certain load order. Do this by setting priorities and sorting.
+
+array set pri {
+    stdlib 0
+    readdir 1
+    glob 2
+    oo 1
+    tree 2
+    pack 1
+    binary 2
+}
+
+foreach i $argv {
+    set p 1
+    if {[info exists pri($i)]} {
+        set p $pri($i)
+    }
+    lappend exts [list $p $i]
+}
+set exts [lsort $exts]
+
+puts {
+/* autogenerated - do not edit */
+#include "jim.h"
+#include "jimautoconf.h"
+int Jim_InitStaticExtensions(Jim_Interp *interp)
+}
+puts \{
+
+foreach e $exts {
+    set ext [lindex $e 1]
+    puts "\textern int Jim_${ext}Init(Jim_Interp *);"
+}
+foreach e $exts {
+    set ext [lindex $e 1]
+    puts "\tJim_${ext}Init(interp);"
+}
+
+puts "\treturn JIM_OK;"
+
+puts \}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/parse-unidata.tcl b/android/external/usb_modeswitch/usb_modeswitch/jim/parse-unidata.tcl
new file mode 100755
index 0000000..4b5ec3a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/parse-unidata.tcl
@@ -0,0 +1,64 @@
+#!/usr/bin/env tclsh
+
+# Generate UTF-8 case mapping tables
+#
+# (c) 2010 Steve Bennett <steveb@workware.net.au>
+#
+# See LICENCE for licence details.
+#/
+
+# Parse the unicode data from: http://unicode.org/Public/UNIDATA/UnicodeData.txt
+# to generate case mapping tables
+
+set f [open [lindex $argv 0]]
+set extoff 0
+puts "static const struct casemap unicode_case_mapping\[\] = \{"
+while {[gets $f buf] >= 0} {
+	foreach {code name class x x x x x x x x x upper lower} [split $buf ";"] break
+	set code 0x$code
+	if {$code <= 0x7f} {
+		continue
+	}
+	if {$code > 0xffff} {
+		break
+	}
+	if {$class ne "Lu" && $class ne "Ll"} {
+		continue
+	}
+	if {$upper eq ""} {
+		set upper $code
+	} else {
+		set upper 0x$upper
+	}
+	if {$lower eq ""} {
+		set lower $code
+	} else {
+		set lower 0x$lower
+	}
+	if {$upper == $code && $lower == $code} {
+		continue
+	}
+	set l [expr {$lower - $code}]
+	set u [expr {$upper - $code}]
+	if {abs($u) > 127 || abs($l) > 127} {
+		# Can't encode both in one byte, so use indirection
+		lappend jumptable $code $lower $upper
+		set l -128
+		set u $extoff
+		incr extoff
+		if {$extoff > 0xff} {
+			error "Too many entries in the offset table!"
+		}
+	}
+	set entry [string tolower "$code, $l, $u"]
+	puts "    { $entry },"
+}
+close $f
+puts "\};\n"
+
+# Now the jump table
+puts "static const struct caseextmap unicode_extmap\[\] = \{"
+foreach {c l u} $jumptable {
+	puts "    { $l, $u },"
+}
+puts "\};\n"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/regtest.tcl b/android/external/usb_modeswitch/usb_modeswitch/jim/regtest.tcl
new file mode 100755
index 0000000..de796d9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/regtest.tcl
@@ -0,0 +1,158 @@
+# REGTEST 1
+# 27Jan2005 - SIGSEGV for bug on Jim_DuplicateObj().
+
+for {set i 0} {$i < 100} {incr i} {
+    set a "x"
+    lappend a n
+}
+puts "TEST 1 PASSED"
+
+# REGTEST 2
+# 29Jan2005 - SEGFAULT parsing script composed of just one comment.
+eval {#foobar}
+puts "TEST 2 PASSED"
+
+# REGTEST 3
+# 29Jan2005 - "Error in Expression" with correct expression
+set x 5
+expr {$x-5}
+puts "TEST 3 PASSED"
+
+# REGTEST 4
+# 29Jan2005 - SIGSEGV when run this code, due to expr's bug.
+proc fibonacci {x} {
+    if {$x <= 1} {
+    expr 1
+    } else {
+    expr {[fibonacci [expr {$x-1}]] + [fibonacci [expr {$x-2}]]}
+    }
+}
+fibonacci 6
+puts "TEST 4 PASSED"
+
+# REGTEST 5
+# 06Mar2005 - This looped forever...
+for {set i 0} {$i < 10} {incr i} {continue}
+puts "TEST 5 PASSED"
+
+# REGTEST 6
+# 07Mar2005 - Unset create variable + dict is using dict syntax sugar at
+#             currently non-existing variable
+catch {unset thisvardoesnotexists(thiskeytoo)}
+if {[catch {set thisvardoesnotexists}] == 0} {
+  puts "TEST 6 FAILED - unset created dict for non-existing variable"
+  break
+}
+puts "TEST 6 PASSED"
+
+# REGTEST 7
+# 04Nov2008 - variable parsing does not eat last brace
+set a 1
+list ${a}
+puts "TEST 7 PASSED"
+
+# REGTEST 8
+# 04Nov2008 - string toupper/tolower do not convert to string rep
+string tolower [list a]
+string toupper [list a]
+puts "TEST 8 PASSED"
+
+# REGTEST 9
+# 04Nov2008 - crash on exit when replacing Tcl proc with C command.
+# Requires the clock extension to be built as a loadable module.
+proc clock {args} {}
+catch {package require clock}
+# Note, crash on exit, so don't say we passed!
+
+# REGTEST 10
+# 05Nov2008 - incorrect lazy expression evaluation with unary not
+expr {1 || !0}
+puts "TEST 10 PASSED"
+
+# REGTEST 11
+# 14 Feb 2010 - access static variable in deleted proc
+proc a {} {{x 1}} { rename a ""; incr x }
+a
+puts "TEST 11 PASSED"
+
+# REGTEST 12
+# 13 Sep 2010 - reference with invalid tag
+set a b[ref value "tag name"]
+getref [string range $a 1 end]
+puts "TEST 12 PASSED"
+
+# REGTEST 13
+# 14 Sep 2010 - parse list with trailing backslash
+set x "switch -0 \$on \\"
+lindex $x 1
+puts "TEST 13 PASSED"
+
+# REGTEST 14
+# 14 Sep 2010 - command expands to nothing
+eval "{*}{}"
+puts "TEST 14 PASSED"
+
+# REGTEST 15
+# 24 Feb 2010 - bad reference counting of the stack trace in 'error'
+proc a {msg stack} {
+    tailcall error $msg $stack
+}
+catch {fail} msg opts
+catch {a $msg $opts(-errorinfo)}
+
+# REGTEST 16
+# 24 Feb 2010 - rename the current proc
+# Leaves unfreed objects on the stack
+proc a {} { rename a newa}
+a
+
+# REGTEST 17
+# 26 Nov 2010 - crashes on invalid dict sugar
+catch {eval {$x(}}
+puts "TEST 17 PASSED"
+
+# REGTEST 18
+# 12 Apr 2011 - crashes on unset for loop var
+catch {
+    for {set i 0} {$i < 5} {incr i} {unset i}
+}
+puts "TEST 18 PASSED"
+
+# REGTEST 19
+# 25 May 2011 - crashes with double colon
+catch {
+    expr {5 ne ::}
+}
+puts "TEST 19 PASSED"
+
+# REGTEST 20
+# 26 May 2011 - infinite recursion
+proc a {} { global ::blah; set ::blah test }
+a
+puts "TEST 20 PASSED"
+
+# REGTEST 21
+# 26 May 2011 - infinite loop with null byte in subst
+subst "abc\0def"
+puts "TEST 21 PASSED"
+
+# REGTEST 22
+# 21 June 2011 - crashes on lappend to to value with script rep
+set x rand
+eval $x
+lappend x b
+puts "TEST 22 PASSED"
+
+# REGTEST 23
+# 27 July 2011 - unfreed objects on exit
+catch {
+    set x abc
+    subst $x
+    regexp $x $x
+}
+# Actually, the test passes if no objects leaked on exit
+puts "TEST 23 PASSED"
+
+# TAKE THE FOLLOWING puts AS LAST LINE
+
+puts "--- ALL TESTS PASSED ---"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/rlprompt.tcl b/android/external/usb_modeswitch/usb_modeswitch/jim/rlprompt.tcl
new file mode 100755
index 0000000..cdd78d4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/rlprompt.tcl
@@ -0,0 +1,45 @@
+# Readline-based interactive shell for Jim
+# Copyright(C) 2005 Salvatore Sanfilippo <antirez@invece.org>
+#
+# In order to automatically have readline-editing features
+# put this in your $HOME/.jimrc
+#
+# if {$jim_interactive} {
+#    if {[catch {package require rlprompt}] == 0} {
+#       rlprompt.shell
+#    }
+# }
+package require readline
+
+proc rlprompt.shell {} {
+    puts "Readline shell loaded"
+    puts "Welcome to Jim [info version]!"
+    set prompt ". "
+    set buf ""
+    while 1 {
+        set line [readline.readline $prompt]
+
+        if {[string length $line] == 0} {
+            continue
+        }
+        if {$buf eq ""} {
+            set buf $line
+        } else {
+            append buf \n $line
+        }
+        if {![info complete $buf]} {
+            set prompt "> "
+            continue
+        }
+        readline.addhistory $buf
+
+        catch {
+            uplevel #0 $buf
+        } error
+        if {$error ne ""} {
+            puts $error
+        }
+        set buf ""
+        set prompt ". "
+    }
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/stdlib.tcl b/android/external/usb_modeswitch/usb_modeswitch/jim/stdlib.tcl
new file mode 100755
index 0000000..3abeb3e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/stdlib.tcl
@@ -0,0 +1,150 @@
+# Create a single word alias (proc) for one or more words
+# e.g. alias x info exists
+# if {[x var]} ...
+proc alias {name args} {
+	set prefix $args
+	proc $name args prefix {
+		tailcall {*}$prefix {*}$args
+	}
+}
+
+# Creates an anonymous procedure
+proc lambda {arglist args} {
+	set name [ref {} function lambda.finalizer]
+	tailcall proc $name $arglist {*}$args
+}
+
+proc lambda.finalizer {name val} {
+	rename $name {}
+}
+
+# Like alias, but creates and returns an anonyous procedure
+proc curry {args} {
+	set prefix $args
+	lambda args prefix {
+		tailcall {*}$prefix {*}$args
+	}
+}
+
+# Returns the given argument.
+# Useful with 'local' as follows:
+#   proc a {} {...}
+#   local function a 
+#
+#   set x [lambda ...]
+#   local function $x
+#
+proc function {value} {
+	return $value
+}
+
+# Tcl 8.5 lassign
+proc lassign {list args} {
+	# in case the list is empty...
+	lappend list {}
+	uplevel 1 [list foreach $args $list break]
+	lrange $list [llength $args] end-1
+}
+
+# Returns a list of proc filename line ...
+# with 3 entries for each stack frame (proc),
+# (deepest level first)
+proc stacktrace {} {
+	set trace {}
+	foreach level [range 1 [info level]] {
+		lassign [info frame -$level] p f l
+		lappend trace $p $f $l
+	}
+	return $trace
+}
+
+# Returns a human-readable version of a stack trace
+proc stackdump {stacktrace} {
+	set result {}
+	set count 0
+	foreach {l f p} [lreverse $stacktrace] {
+		if {$count} {
+			append result \n
+		}
+		incr count
+		if {$p ne ""} {
+			append result "in procedure '$p' "
+			if {$f ne ""} {
+				append result "called "
+			}
+		}
+		if {$f ne ""} {
+			append result "at file \"$f\", line $l"
+		}
+	}
+	return $result
+}
+
+# Sort of replacement for $::errorInfo
+# Usage: errorInfo error ?stacktrace?
+proc errorInfo {msg {stacktrace ""}} {
+	if {$stacktrace eq ""} {
+		set stacktrace [info stacktrace]
+	}
+	lassign $stacktrace p f l
+	if {$f ne ""} {
+		set result "Runtime Error: $f:$l: "
+	}
+	append result "$msg\n"
+	append result [stackdump $stacktrace]
+
+	# Remove the trailing newline
+	string trim $result
+}
+
+# Finds the current executable by searching along the path
+# Returns the empty string if not found.
+proc {info nameofexecutable} {} {
+	if {[info exists ::jim_argv0]} {
+		if {[string match "*/*" $::jim_argv0]} {
+			return [file join [pwd] $::jim_argv0]
+		}
+		foreach path [split [env PATH ""] $::tcl_platform(pathSeparator)] {
+			set exec [file join [pwd] $path $::jim_argv0]
+			if {[file executable $exec]} {
+				return $exec
+			}
+		}
+	}
+	return ""
+}
+
+# Script-based implementation of 'dict with'
+proc {dict with} {dictVar args script} {
+	upvar $dictVar dict
+	set keys {}
+	foreach {n v} [dict get $dict {*}$args] {
+		upvar $n var_$n
+		set var_$n $v
+		lappend keys $n
+	}
+	catch {uplevel 1 $script} msg opts
+	if {[info exists dict] && [dict exists $dict {*}$args]} {
+		foreach n $keys {
+			if {[info exists var_$n]} {
+				dict set dict {*}$args $n [set var_$n]
+			} else {
+				dict unset dict {*}$args $n
+			}
+		}
+	}
+	return {*}$opts $msg
+}
+
+# Script-based implementation of 'dict merge'
+# This won't get called in the trivial case of no args
+proc {dict merge} {dict args} {
+	foreach d $args {
+		# Check for a valid dict
+		dict size $d
+		foreach {k v} $d {
+			dict set dict $k $v
+		}
+	}
+	return $dict
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/tcl.license.terms b/android/external/usb_modeswitch/usb_modeswitch/jim/tcl.license.terms
new file mode 100755
index 0000000..f1dcaa5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/tcl.license.terms
@@ -0,0 +1,40 @@
+This software is copyrighted by the Regents of the University of
+California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
+Corporation and other parties.  The following terms apply to all files
+associated with the software unless explicitly disclaimed in
+individual files.
+
+The authors hereby grant permission to use, copy, modify, distribute,
+and license this software and its documentation for any purpose, provided
+that existing copyright notices are retained in all copies and that this
+notice is included verbatim in any distributions. No written agreement,
+license, or royalty fee is required for any of the authorized uses.
+Modifications to this software may be copyrighted by their authors
+and need not follow the licensing terms described here, provided that
+the new terms are clearly indicated on the first page of each file where
+they apply.
+
+IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
+IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+MODIFICATIONS.
+
+GOVERNMENT USE: If you are acquiring this software on behalf of the
+U.S. government, the Government shall have only "Restricted Rights"
+in the software and related documentation as defined in the Federal 
+Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
+are acquiring the software on behalf of the Department of Defense, the
+software shall be classified as "Commercial Computer Software" and the
+Government shall have only "Restricted Rights" as defined in Clause
+252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
+authors grant the U.S. Government and others acting in its behalf
+permission to use and distribute the software in accordance with the
+terms specified in this license. 
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/tclcompat.tcl b/android/external/usb_modeswitch/usb_modeswitch/jim/tclcompat.tcl
new file mode 100755
index 0000000..8e5b128
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/tclcompat.tcl
@@ -0,0 +1,279 @@
+# (c) 2008 Steve Bennett <steveb@workware.net.au>
+#
+# Loads some Tcl-compatible features.
+# I/O commands, case, lassign, parray, errorInfo, ::tcl_platform, ::env
+# try, throw, file copy, file delete -force
+
+# Set up the ::env array
+set env [env]
+
+if {[info commands stdout] ne ""} {
+	# Tcl-compatible I/O commands
+	foreach p {gets flush close eof seek tell} {
+		proc $p {chan args} {p} {
+			tailcall $chan $p {*}$args
+		}
+	}
+	unset p
+
+	# puts is complicated by -nonewline
+	#
+	proc puts {{-nonewline {}} {chan stdout} msg} {
+		if {${-nonewline} ni {-nonewline {}}} {
+			tailcall ${-nonewline} puts $msg
+		}
+		tailcall $chan puts {*}${-nonewline} $msg
+	}
+
+	# read is complicated by -nonewline
+	#
+	# read chan ?maxchars?
+	# read -nonewline chan
+	proc read {{-nonewline {}} chan} {
+		if {${-nonewline} ni {-nonewline {}}} {
+			tailcall ${-nonewline} read {*}${chan}
+		}
+		tailcall $chan read {*}${-nonewline}
+	}
+
+	proc fconfigure {f args} {
+		foreach {n v} $args {
+			switch -glob -- $n {
+				-bl* {
+					$f ndelay $v
+				}
+				-bu* {
+					$f buffering $v
+				}
+				-tr* {
+					# Just ignore -translation
+				}
+				default {
+					return -code error "fconfigure: unknown option $n"
+				}
+			}
+		}
+	}
+}
+
+# case var ?in? pattern action ?pattern action ...?
+proc case {var args} {
+	# Skip dummy parameter
+	if {[lindex $args 0] eq "in"} {
+		set args [lrange $args 1 end]
+	}
+
+	# Check for single arg form
+	if {[llength $args] == 1} {
+		set args [lindex $args 0]
+	}
+
+	# Check for odd number of args
+	if {[llength $args] % 2 != 0} {
+		return -code error "extra case pattern with no body"
+	}
+
+	# Internal function to match a value agains a list of patterns
+	local proc case.checker {value pattern} {
+		string match $pattern $value
+	}
+
+	foreach {value action} $args {
+		if {$value eq "default"} {
+			set do_action $action
+			continue
+		} elseif {[lsearch -bool -command case.checker $value $var]} {
+			set do_action $action
+			break
+		}
+	}
+
+	if {[info exists do_action]} {
+		set rc [catch [list uplevel 1 $do_action] result opts]
+		if {$rc} {
+			incr opts(-level)
+		}
+		return {*}$opts $result
+	}
+}
+
+# fileevent isn't needed in Jim, but provide it for compatibility
+proc fileevent {args} {
+	tailcall {*}$args
+}
+
+# Second, option argument is a glob pattern
+# Third, optional argument is a "putter" function
+# 
+proc parray {arrayname {pattern *} {puts puts}} {
+	upvar $arrayname a
+
+	set max 0
+	foreach name [array names a $pattern]] {
+		if {[string length $name] > $max} {
+			set max [string length $name]
+		}
+	}
+	incr max [string length $arrayname]
+	incr max 2
+	foreach name [lsort [array names a $pattern]] {
+		$puts [format "%-${max}s = %s" $arrayname\($name\) $a($name)]
+	}
+}
+
+# Implements 'file copy' - single file mode only
+proc {file copy} {{force {}} source target} {
+	try {
+		if {$force ni {{} -force}} {
+			error "bad option \"$force\": should be -force"
+		}
+
+		set in [open $source]
+
+		if {$force eq "" && [file exists $target]} {
+			$in close
+			error "error copying \"$source\" to \"$target\": file already exists"
+		}
+		set out [open $target w]
+		$in copyto $out
+		$out close
+	} on error {msg opts} {
+		incr opts(-level)
+		return {*}$opts $msg
+	} finally {
+		catch {$in close}
+	}
+}
+
+# 'open "|..." ?mode?" will invoke this wrapper around exec/pipe
+# Note that we return a lambda which also provides the 'pid' command
+proc popen {cmd {mode r}} {
+	lassign [socket pipe] r w
+	try {
+		if {[string match "w*" $mode]} {
+			lappend cmd <@$r &
+			set pids [exec {*}$cmd]
+			$r close
+			set f $w
+		} else {
+			lappend cmd >@$w &
+			set pids [exec {*}$cmd]
+			$w close
+			set f $r
+		}
+		lambda {cmd args} {f pids} {
+			if {$cmd eq "pid"} {
+				return $pids
+			}
+			if {$cmd eq "close"} {
+				$f close
+				# And wait for the child processes to complete
+				foreach p $pids { os.wait $p }
+				return
+			}
+			tailcall $f $cmd {*}$args
+		}
+	} on error {error opts} {
+		$r close
+		$w close
+		error $error
+	}
+}
+
+# A wrapper around 'pid' which can return the pids for 'popen'
+local proc pid {{chan {}}} {
+	if {$chan eq ""} {
+		tailcall upcall pid
+	}
+	if {[catch {$chan tell}]} {
+		return -code error "can not find channel named \"$chan\""
+	}
+	if {[catch {$chan pid} pids]} {
+		return ""
+	}
+	return $pids
+}
+
+# try/on/finally conceptually similar to Tcl 8.6
+#
+# Usage: try ?catchopts? script ?onclause ...? ?finallyclause?
+#
+# Where:
+#   onclause is:       on codes {?resultvar? ?optsvar?} script
+#
+#   codes is: a list of return codes (ok, error, etc. or integers), or * for any
+#
+#   finallyclause is:  finally script
+#
+#
+# Where onclause is: on codes {?resultvar? ?optsvar?}
+proc try {args} {
+	set catchopts {}
+	while {[string match -* [lindex $args 0]]} {
+		set args [lassign $args opt]
+		if {$opt eq "--"} {
+			break
+		}
+		lappend catchopts $opt
+	}
+	if {[llength $args] == 0} {
+		return -code error {wrong # args: should be "try ?options? script ?argument ...?"}
+	}
+	set args [lassign $args script]
+	set code [catch -eval {*}$catchopts [list uplevel 1 $script] msg opts]
+
+	set handled 0
+
+	foreach {on codes vars script} $args {
+		switch -- $on \
+			on {
+				if {!$handled && ($codes eq "*" || [info returncode $code] in $codes)} {
+					lassign $vars msgvar optsvar
+					if {$msgvar ne ""} {
+						upvar $msgvar hmsg
+						set hmsg $msg
+					}
+					if {$optsvar ne ""} {
+						upvar $optsvar hopts
+						set hopts $opts
+					}
+					# Override any body result
+					set code [catch [list uplevel 1 $script] msg opts]
+					incr handled
+				}
+			} \
+			finally {
+				set finalcode [catch [list uplevel 1 $codes] finalmsg finalopts]
+				if {$finalcode} {
+					# Override any body or handler result
+					set code $finalcode
+					set msg $finalmsg
+					set opts $finalopts
+				}
+				break
+			} \
+			default {
+				return -code error "try: expected 'on' or 'finally', got '$on'"
+			}
+	}
+
+	if {$code} {
+		incr opts(-level)
+		return {*}$opts $msg
+	}
+	return $msg
+}
+
+# Generates an exception with the given code (ok, error, etc. or an integer)
+# and the given message
+proc throw {code {msg ""}} {
+	return -code $code $msg
+}
+
+# Helper for "file delete -force"
+proc {file delete force} {path} {
+	foreach e [readdir $path] {
+		file delete -force $path/$e
+	}
+	file delete $path
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/tree.tcl b/android/external/usb_modeswitch/usb_modeswitch/jim/tree.tcl
new file mode 100755
index 0000000..01fc167
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/tree.tcl
@@ -0,0 +1,219 @@
+# Conceptually compatible with tcllib ::struct::tree
+# but uses an object based interface.
+# To mimic tcllib, do:
+#   rename [tree] mytree
+
+package require oo
+
+# set pt [tree]
+#
+#   Create a tree
+#   This automatically creates a node named "root"
+#
+# $pt destroy
+#
+#   Destroy the tree and all it's nodes
+#
+# $pt set <nodename> <key> <value>
+#
+#   Set the value for the given key
+#
+# $pt lappend <nodename> <key> <value> ...
+#
+#   Append to the (list) value(s) for the given key, or set if not yet set
+#
+# $pt keyexists <nodename> <key>
+#
+#   Returns 1 if the given key exists
+#
+# $pt get <nodename> <key>
+#
+#   Returns the value associated with the given key
+# 
+# $pt getall <nodename>
+#
+#   Returns the entire attribute dictionary associated with the given key
+# 
+# $pt depth <nodename>
+#
+#   Returns the depth of the given node. The depth of "root" is 0.
+#
+# $pt parent <nodename>
+#
+#   Returns the name of the parent node, or "" for the root node.
+# 
+# $pt numchildren <nodename>
+#
+#   Returns the number of child nodes.
+# 
+# $pt children <nodename>
+#
+#   Returns a list of the child nodes.
+# 
+# $pt next <nodename>
+#
+#   Returns the next sibling node, or "" if none.
+# 
+# $pt insert <nodename> ?index?
+#
+#   Add a new child node to the given node.
+#   THe default index is "end"
+#   Returns the name of the newly added node
+#
+# $pt walk <nodename> dfs|bfs {actionvar nodevar} <code>
+#
+#   Walks the tree starting from the given node, either breadth first (bfs)
+#   depth first (dfs).
+#   The value "enter" or "exit" is stored in variable $actionvar
+#   The name of each node is stored in $nodevar.
+#   The script $code is evaluated twice for each node, on entry and exit.
+#
+# $pt dump
+#
+#   Dumps the tree contents to stdout
+
+#------------------------------------------
+# Internal implementation.
+# The tree class has 4 instance variables.
+# - tree is a dictionary. key=node, value=node value dictionary
+# - parent is a dictionary. key=node, value=parent of this node
+# - children is a dictionary. key=node, value=list of child nodes for this node
+# - nodeid is an integer which increments to give each node a unique id
+
+# Construct a tree with a single root node with no parent and no children
+class tree {
+	tree {root {}}
+	parents {root {}}
+	children {root {}}
+	nodeid 0
+}
+
+# Simply walk up the tree to get the depth
+tree method depth {node} {
+	set depth 0
+	while {$node ne "root"} {
+		incr depth
+		set node [dict get $parents $node]
+	}
+	return $depth
+}
+
+tree method parent {node} {
+	dict get $parents $node
+}
+
+tree method children {node} {
+	dict get $children $node
+}
+
+tree method numchildren {node} {
+	llength [dict get $children $node]
+}
+
+tree method next {node} {
+	# My siblings are my parents children
+	set siblings [dict get $children [dict get $parents $node]]
+	# Find me
+	set i [lsearch $siblings $node]
+	incr i
+	lindex $siblings $i
+}
+
+tree method set {node key value} {
+	dict set tree $node $key $value
+	return $value
+}
+
+tree method get {node key} {
+	dict get $tree $node $key
+}
+
+tree method keyexists {node key} {
+	dict exists $tree $node $key
+}
+
+tree method getall {node} {
+	dict get $tree $node
+}
+
+tree method insert {node {index end}} {
+
+	# Make a new node and add it to the tree
+	set childname node[incr nodeid]
+	dict set tree $childname {}
+
+	# The new node has no children
+	dict set children $childname {}
+
+	# Set the parent
+	dict set parents $childname $node
+
+	# And add it as a child
+	set nodes [dict get $children $node]
+	dict set children $node [linsert $nodes $index $childname]
+
+	return $childname
+}
+
+tree method lappend {node key args} {
+	if {[dict exists $tree $node $key]} {
+		set result [dict get $tree $node $key]
+	}
+	lappend result {*}$args
+	dict set tree $node $key $result
+	return $result
+}
+
+# $tree walk node bfs|dfs {action loopvar} <code>
+#
+tree method walk {node type vars code} {
+	# set up vars
+	lassign $vars actionvar namevar
+
+	set n $node
+
+	if {$type ne "child"} {
+		upvar 2 $namevar name $actionvar action
+
+		# Enter this node
+		set name $node
+		set action enter
+
+		uplevel 2 $code
+	}
+
+	if {$type eq "dfs"} {
+		# Depth-first so do the children
+		foreach child [$self children $n] {
+			uplevel 2 [list $self walk $child $type $vars $code]
+		}
+	} elseif {$type ne "none"} {
+		# Breadth-first so do the children to one level only
+		foreach child [$self children $n] {
+			uplevel 2 [list $self walk $child none $vars $code]
+		}
+
+		# Now our grandchildren
+		foreach child [$self children $n] {
+			uplevel 2 [list $self walk $child child $vars $code]
+		}
+	}
+
+	if {$type ne "child"} {
+		# Exit this node
+		set name $node
+		set action exit
+
+		uplevel 2 $code
+	}
+}
+
+tree method dump {} {
+	$self walk root dfs {action n} {
+		set indent [string repeat "  " [$self depth $n]]
+		if {$action eq "enter"} {
+			puts "$indent$n ([$self getall $n])"
+		}
+	}
+	puts ""
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/utf8.c b/android/external/usb_modeswitch/usb_modeswitch/jim/utf8.c
new file mode 100755
index 0000000..a81b3de
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/utf8.c
@@ -0,0 +1,192 @@
+/**
+ * UTF-8 utility functions
+ *
+ * (c) 2010 Steve Bennett <steveb@workware.net.au>
+ *
+ * See LICENCE for licence details.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include "utf8.h"
+
+/* This one is always implemented */
+int utf8_fromunicode(char *p, unsigned short uc)
+{
+    if (uc <= 0x7f) {
+        *p = uc;
+        return 1;
+    }
+    else if (uc <= 0x7ff) {
+        *p++ = 0xc0 | ((uc & 0x7c0) >> 6);
+        *p = 0x80 | (uc & 0x3f);
+        return 2;
+    }
+    else {
+        *p++ = 0xe0 | ((uc & 0xf000) >> 12);
+        *p++ = 0x80 | ((uc & 0xfc0) >> 6);
+        *p = 0x80 | (uc & 0x3f);
+        return 3;
+    }
+}
+
+#if defined(JIM_UTF8) && !defined(JIM_BOOTSTRAP)
+int utf8_charlen(int c)
+{
+    if ((c & 0x80) == 0) {
+        return 1;
+    }
+    if ((c & 0xe0) == 0xc0) {
+        return 2;
+    }
+    if ((c & 0xf0) == 0xe0) {
+        return 3;
+    }
+    if ((c & 0xf8) == 0xf0) {
+        return 4;
+    }
+    /* Invalid sequence */
+    return -1;
+}
+
+int utf8_strlen(const char *str, int bytelen)
+{
+    int charlen = 0;
+    if (bytelen < 0) {
+        bytelen = strlen(str);
+    }
+    while (bytelen) {
+        int c;
+        int l = utf8_tounicode(str, &c);
+        charlen++;
+        str += l;
+        bytelen -= l;
+    }
+    return charlen;
+}
+
+int utf8_index(const char *str, int index)
+{
+    const char *s = str;
+    while (index--) {
+        int c;
+        s += utf8_tounicode(s, &c);
+    }
+    return s - str;
+}
+
+int utf8_charequal(const char *s1, const char *s2)
+{
+    int c1, c2;
+
+    utf8_tounicode(s1, &c1);
+    utf8_tounicode(s2, &c2);
+
+    return c1 == c2;
+}
+
+int utf8_prev_len(const char *str, int len)
+{
+    int n = 1;
+
+    assert(len > 0);
+
+    /* Look up to len chars backward for a start-of-char byte */
+    while (--len) {
+        if ((str[-n] & 0x80) == 0) {
+            /* Start of a 1-byte char */
+            break;
+        }
+        if ((str[-n] & 0xc0) == 0xc0) {
+            /* Start of a multi-byte char */
+            break;
+        }
+        n++;
+    }
+    return n;
+}
+
+int utf8_tounicode(const char *str, int *uc)
+{
+    unsigned const char *s = (unsigned const char *)str;
+
+    if (s[0] < 0xc0) {
+        *uc = s[0];
+        return 1;
+    }
+    if (s[0] < 0xe0) {
+        if ((s[1] & 0xc0) == 0x80) {
+            *uc = ((s[0] & ~0xc0) << 6) | (s[1] & ~0x80);
+            return 2;
+        }
+    }
+    else if (s[0] < 0xf0) {
+        if (((str[1] & 0xc0) == 0x80) && ((str[2] & 0xc0) == 0x80)) {
+            *uc = ((s[0] & ~0xe0) << 12) | ((s[1] & ~0x80) << 6) | (s[2] & ~0x80);
+            return 3;
+        }
+    }
+
+    /* Invalid sequence, so just return the byte */
+    *uc = *s;
+    return 1;
+}
+
+struct casemap {
+    unsigned short code;    /* code point */
+    signed char lowerdelta; /* add for lowercase, or if -128 use the ext table */
+    signed char upperdelta; /* add for uppercase, or offset into the ext table */
+};
+
+/* Extended table for codepoints where |delta| > 127 */
+struct caseextmap {
+    unsigned short lower;
+    unsigned short upper;
+};
+
+/* Generated mapping tables */
+#include "_unicode_mapping.c"
+
+#define NUMCASEMAP sizeof(unicode_case_mapping) / sizeof(*unicode_case_mapping)
+
+static int cmp_casemap(const void *key, const void *cm)
+{
+    return *(int *)key - (int)((const struct casemap *)cm)->code;
+}
+
+static int utf8_map_case(int uc, int upper)
+{
+    const struct casemap *cm = bsearch(&uc, unicode_case_mapping, NUMCASEMAP, sizeof(*unicode_case_mapping), cmp_casemap);
+
+    if (cm) {
+        if (cm->lowerdelta == -128) {
+            uc = upper ? unicode_extmap[cm->upperdelta].upper : unicode_extmap[cm->upperdelta].lower;
+        }
+        else {
+            uc += upper ? cm->upperdelta : cm->lowerdelta;
+        }
+    }
+    return uc;
+}
+
+int utf8_upper(int uc)
+{
+    if (isascii(uc)) {
+        return toupper(uc);
+    }
+    return utf8_map_case(uc, 1);
+}
+
+int utf8_lower(int uc)
+{
+    if (isascii(uc)) {
+        return tolower(uc);
+    }
+
+    return utf8_map_case(uc, 0);
+}
+
+#endif /* JIM_BOOTSTRAP */
diff --git a/android/external/usb_modeswitch/usb_modeswitch/jim/utf8.h b/android/external/usb_modeswitch/usb_modeswitch/jim/utf8.h
new file mode 100755
index 0000000..9ada93f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/jim/utf8.h
@@ -0,0 +1,110 @@
+#ifndef UTF8_UTIL_H
+#define UTF8_UTIL_H
+/**
+ * UTF-8 utility functions
+ *
+ * (c) 2010 Steve Bennett <steveb@workware.net.au>
+ *
+ * See LICENCE for licence details.
+ */
+#include <jim-config.h>
+
+/**
+ * Converts the given unicode codepoint (0 - 0xffff) to utf-8
+ * and stores the result at 'p'.
+ *
+ * Returns the number of utf-8 characters (1-3).
+ */
+int utf8_fromunicode(char *p, unsigned short uc);
+
+#ifndef JIM_UTF8
+#include <ctype.h>
+
+/* No utf-8 support. 1 byte = 1 char */
+#define utf8_strlen(S, B) ((B) < 0 ? strlen(S) : (B))
+#define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
+#define utf8_upper(C) toupper(C)
+#define utf8_lower(C) tolower(C)
+#define utf8_index(C, I) (I)
+#define utf8_charlen(C) 1
+#define utf8_prev_len(S, L) 1
+
+#else
+#if !defined(JIM_BOOTSTRAP)
+/**
+ * Returns the length of the utf-8 sequence starting with 'c'.
+ *
+ * Returns 1-4, or -1 if this is not a valid start byte.
+ *
+ * Note that charlen=4 is not supported by the rest of the API.
+ */
+int utf8_charlen(int c);
+
+/**
+ * Returns the number of characters in the utf-8
+ * string of the given byte length.
+ *
+ * Any bytes which are not part of an valid utf-8
+ * sequence are treated as individual characters.
+ *
+ * The string *must* be null terminated.
+ *
+ * Does not support unicode code points > \uffff
+ */
+int utf8_strlen(const char *str, int bytelen);
+
+/**
+ * Returns the byte index of the given character in the utf-8 string.
+ *
+ * The string *must* be null terminated.
+ *
+ * This will return the byte length of a utf-8 string
+ * if given the char length.
+ */
+int utf8_index(const char *str, int charindex);
+
+/**
+ * Returns the unicode codepoint corresponding to the
+ * utf-8 sequence 'str'.
+ *
+ * Stores the result in *uc and returns the number of bytes
+ * consumed.
+ *
+ * If 'str' is null terminated, then an invalid utf-8 sequence
+ * at the end of the string will be returned as individual bytes.
+ *
+ * If it is not null terminated, the length *must* be checked first.
+ *
+ * Does not support unicode code points > \uffff
+ */
+int utf8_tounicode(const char *str, int *uc);
+
+/**
+ * Returns the number of bytes before 'str' that the previous
+ * utf-8 character sequence starts (which may be the middle of a sequence).
+ *
+ * Looks back at most 'len' bytes backwards, which must be > 0.
+ * If no start char is found, returns -len
+ */
+int utf8_prev_len(const char *str, int len);
+
+/**
+ * Returns the upper-case variant of the given unicode codepoint.
+ *
+ * Does not support unicode code points > \uffff
+ */
+int utf8_upper(int uc);
+
+/**
+ * Returns the lower-case variant of the given unicode codepoint.
+ *
+ * NOTE: Use utf8_upper() in preference for case-insensitive matching.
+ *
+ * Does not support unicode code points > \uffff
+ */
+int utf8_lower(int uc);
+#endif /* JIM_BOOTSTRAP */
+
+#endif
+
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/make_string.tcl b/android/external/usb_modeswitch/usb_modeswitch/make_string.tcl
new file mode 100755
index 0000000..5a1b5ff
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/make_string.tcl
@@ -0,0 +1,31 @@
+#!/usr/bin/env tclsh
+
+# (c) Josua Dietze 2012
+#
+# Usage: make_string.tcl source.tcl >jim-source.c
+
+# Converts a Tcl source file into C source suitable
+# for using as an embedded script.
+
+set source [lindex $argv 0]
+
+if {![string match *.tcl $source]} {
+	error "Source $source is not a .tcl file"
+}
+
+# Read the Tcl source and convert to C macro
+set sourcelines {}
+set f [open $source]
+while {[gets $f buf] >= 0} {
+	# Remove comment lines
+	regsub {^[ \t]*#.*$} $buf "" buf
+	# Remove leading whitespaces
+	set buf [string trimleft $buf]
+	# Escape quotes and backlashes
+	set buf [string map [list \\ \\\\ \" \\"] $buf]
+	if [string length $buf] {
+		lappend sourcelines "$buf\\n"
+	}
+}
+close $f
+puts "#define RAW \"[join $sourcelines ""]\""
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb-modeswitch-upstart.conf b/android/external/usb_modeswitch/usb_modeswitch/usb-modeswitch-upstart.conf
new file mode 100755
index 0000000..570ca65
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb-modeswitch-upstart.conf
@@ -0,0 +1,5 @@
+start on usb-modeswitch-upstart
+task
+script
+	exec /usr/sbin/usb_modeswitch_dispatcher --switch-upstart $UMS_PARAM
+end script
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/Android.mk b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/Android.mk
new file mode 100755
index 0000000..f9fb9cf
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/Android.mk
@@ -0,0 +1,47 @@
+LOCAL_PATH:= $(call my-dir)
+
+common_src_files := \
+	NetlinkManager.cpp \
+	NetlinkHandler.cpp \
+	MiscManager.cpp \
+	Misc.cpp \
+	G3Dev.cpp
+
+common_shared_libraries := \
+	libsysutils \
+	libbinder \
+	libcutils \
+	liblog \
+	libselinux \
+	libutils \
+	libbase \
+	libhwbinder
+
+common_cflags := -Wall -Wno-missing-field-initializers -Wno-unused-variable -Wno-unused-parameter
+
+#common_local_tidy_flags := -warnings-as-errors=clang-analyzer-security*,cert-*
+common_local_tidy_checks := -*,clang-analyzer-security*,cert-*,-cert-err34-c,-cert-err58-cpp
+common_local_tidy_checks += ,-cert-env33-c
+
+include $(CLEAR_VARS)
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_MODULE := usb_dongle
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_CLANG := true
+LOCAL_TIDY := true
+LOCAL_TIDY_FLAGS := $(common_local_tidy_flags)
+LOCAL_TIDY_CHECKS := $(common_local_tidy_checks)
+LOCAL_SRC_FILES := \
+	main.cpp \
+	$(common_src_files)
+
+LOCAL_INIT_RC := usb_dongle.rc
+
+LOCAL_CFLAGS := $(common_cflags)
+#LOCAL_CFLAGS += -Werror=format
+LOCAL_CFLAGS += -DUSE_USB_MODE_SWITCH
+
+LOCAL_SHARED_LIBRARIES := $(common_shared_libraries)
+
+include $(BUILD_EXECUTABLE)
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/G3Dev.cpp b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/G3Dev.cpp
new file mode 100755
index 0000000..55d928d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/G3Dev.cpp
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+
+#define LOG_TAG "USB_DONGLE"
+
+#include <cutils/log.h>
+#include <sysutils/NetlinkEvent.h>
+
+#include "G3Dev.h"
+#include "MiscManager.h"
+#include <unistd.h>
+
+#if PLATFORM_SDK_VERSION >= 16
+#define LOGV(fmt,args...) ALOGV(fmt,##args)
+#define LOGD(fmt,args...) ALOGD(fmt,##args)
+#define LOGI(fmt,args...) ALOGI(fmt,##args)
+#define LOGW(fmt,args...) ALOGW(fmt,##args)
+#define LOGE(fmt,args...) ALOGE(fmt,##args)
+#endif
+
+static char modeswitch_cmd[256] = "";
+
+
+G3Dev::G3Dev(MiscManager *mm):Misc(mm)
+{
+	
+}
+
+G3Dev::~G3Dev() {
+}
+
+int G3Dev::handleUsbEvent(NetlinkEvent *evt) {
+ const char *devtype = evt->findParam("DEVTYPE");
+    if( devtype!=NULL &&strcmp(devtype, "usb_device") )
+        return 0;
+	pid_t status ;
+
+	NetlinkEvent::Action action = evt->getAction();
+	if( action == NetlinkEvent::Action::kAdd)
+	{
+        const char *product = evt->findParam("PRODUCT");
+        if(product!=NULL && product[0] != 0 && devtype[0] != 0 )
+        {
+            // ��ȡVID/PID
+            int vid = 0;
+            int pid = 0;
+            char * next = (char*)product;
+            vid = strtol(product, &next, 16);
+		
+			//char pre[]="sVe.GT";
+            ++next;
+            pid = strtol(next, NULL, 16);
+
+            SLOGD("== current usb device: %04X/%04X ===", vid, pid);
+
+            char configure_file[2048];
+			
+			
+            sprintf(configure_file, "/vendor/etc/usb_modeswitch.d/%04x_%04x", vid, pid);
+            if( access(configure_file, 0) == 0 )
+            {
+		sprintf(modeswitch_cmd, "/vendor/bin/usb_modeswitch -W -v %04x -p %04x -c %s &", vid, pid,configure_file);
+	    	SLOGD("=== USB Switch: %s", modeswitch_cmd);
+                system(modeswitch_cmd);
+            }
+        }
+	}
+	
+    return 0;
+}
+int G3Dev::handleScsiEvent(NetlinkEvent *evt) {
+/*
+    ��һ��������usb_device ���event��ִ�е�usb_modeswitchû�гɹ�����Ϊ����
+    �ֶΣ���SCSI���event���ٴ�ִ��usb_modeswitch
+ */
+    if(evt->getAction()==NetlinkEvent::Action::kAdd && modeswitch_cmd[0] != 0)
+    {
+        SLOGD("=== SCSI Switch: %s", modeswitch_cmd);
+        system(modeswitch_cmd);
+        modeswitch_cmd[0] = 0;
+    }
+
+    return 0;
+}
+int G3Dev::handleUsb(){
+
+ 
+ char configure_file[2048];
+ int pid,vid;
+ this->get_tty_id(&vid,& pid);
+  
+ sprintf(configure_file, "/vendor/etc/usb_modeswitch.d/%04x_%04x", vid,pid);
+ SLOGD("=== config_file is: %04x_%04x", vid ,pid);
+ if( access(configure_file, 0) == 0 )
+ {
+	sprintf(modeswitch_cmd, "/vendor/bin/usb_modeswitch -W -v %04x -p %04x -c %s &", vid, pid,configure_file);
+	SLOGD("=== USB Switch: %s", modeswitch_cmd);
+	system(modeswitch_cmd);
+ 
+  }
+ return 0;
+ }
+int G3Dev:: get_tty_id(int *vid, int* pid)
+{
+   
+	   char linkto[1024]="";
+	   //SLOGD("began find device path");
+	  // SLOGD("device path: %s", tty_path);////	  
+	   		   
+	   //  LOGD("USB device path: %s", plink);
+	   char pidpath[PATH_MAX]="/sys/bus/usb/devices/1-1";
+	   
+		   FILE* fp = NULL;
+		   char buf[5] = {0};
+		   strlcat(pidpath, "/idVendor",PATH_MAX);
+	   	 SLOGD("Vendor path: %s", pidpath);
+		   fp = fopen(pidpath, "r");
+		   if(fp == NULL)
+			   return -2;
+		   if(fread(buf, 1, 4, fp) != 4)
+		   {
+			   fclose(fp);
+			   return -2;
+		   }
+		   fclose(fp);
+		   *vid = atox(buf, 16);
+	   char vidpath[PATH_MAX]="/sys/bus/usb/devices/1-1";
+	//sys/bus/usb/devices/1-1	
+		   strlcat(vidpath, "/idProduct",PATH_MAX);
+	   //	 LOGD("Product path: %s", plink);
+		   fp = fopen(vidpath, "r");
+		   if(fp == NULL)
+			   return -3;
+		   if(fread(buf, 1, 4, fp) != 4)
+		   {
+			   fclose(fp);
+			   return -3;
+		   }
+		   fclose(fp);
+		   *pid =atox(buf, 16);
+
+    return 0;
+}
+#define EATCHAR(x, c) for (; *(x) == (c); (x)++) ; 
+/* -1:error. */
+int G3Dev:: atox( const char * line, int f_base )
+{
+    int base = 10;
+    char max = '9';
+    int v = 0;
+
+    EATCHAR(line, ' ');
+    if(*line == 0) return 0;
+    
+    if( line[1] == 'x' || line[1] == 'X' ){
+        base = 16;
+        max = 'f';      /* F*/
+        line += 2;
+    }
+    else if(f_base==16)
+    {
+        base = 16;
+        max = 'f';      /* F*/
+    }
+    
+    if( base == 10 ) {
+            while( *line >= '0' && *line <= max ) {
+                        v *= base ;
+                        v += *line-'0';
+                        line++;
+            }
+    } else {
+            while( *line >= '0' && *line <= max ) {
+                        v *= base ;
+                        if( *line >= 'a' )
+                                v += *line-'a'+10;
+                        else if ( *line >= 'A' )
+                                v += *line-'A'+10;
+                        else
+                                v += *line-'0';
+                        line++;
+                }
+    }
+    return v;
+}
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/G3Dev.h b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/G3Dev.h
new file mode 100755
index 0000000..2010dcb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/G3Dev.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#ifndef _G3DEV_H
+#define _G3DEV_H
+
+#include <utils/List.h>
+
+#include "Misc.h"
+class NetlinkEvent;
+
+class G3Dev : public Misc {
+public:
+    G3Dev(MiscManager *mm);
+    virtual ~G3Dev();
+    NetlinkEvent *env;
+    int handleUsbEvent(NetlinkEvent *evt);
+    int handleScsiEvent(NetlinkEvent *evt);
+    int handleUsb();
+    int get_tty_id(int *vid, int* pid);
+    int atox( const char * line, int f_base );
+};
+
+#endif
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/Misc.cpp b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/Misc.cpp
new file mode 100755
index 0000000..519201e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/Misc.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <cutils/properties.h>
+
+#define LOG_TAG "USB_DONGLE"
+
+#include <cutils/log.h>
+
+#include "Misc.h"
+
+Misc::Misc(MiscManager *mm)
+{
+    mMm = mm;
+    mDebug = false;
+}
+
+Misc::~Misc()
+{
+}
+
+void Misc::setDebug(bool enable) {
+    mDebug = enable;
+}
+/*
+	�ú�����������ʵ��
+ */
+int Misc::handleUsbEvent(NetlinkEvent *evt) {
+    errno = ENOSYS;
+    return -1;
+}
+
+/*
+	�ú�����������ʵ��
+ */
+int Misc::handleScsiEvent(NetlinkEvent *evt) {
+    errno = ENOSYS;
+    return -1;
+}
+
+int Misc::handleUsb()
+{  errno = ENOSYS;
+    return -1;}
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/Misc.h b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/Misc.h
new file mode 100755
index 0000000..e3d4f93
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/Misc.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#ifndef _MISC_H
+#define _MISC_H
+
+#include <utils/List.h>
+
+class NetlinkEvent;
+class MiscManager;
+
+class Misc {
+protected:
+    MiscManager *mMm;
+    bool mDebug;
+
+public:
+    Misc(MiscManager *mm);
+    virtual ~Misc();
+
+    virtual int handleUsbEvent(NetlinkEvent *evt);
+    virtual int handleScsiEvent(NetlinkEvent *evt);
+	virtual int handleUsb();
+    void setDebug(bool enable);
+};
+
+typedef android::List<Misc *> MiscCollection;
+
+#endif
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/MiscManager.cpp b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/MiscManager.cpp
new file mode 100755
index 0000000..06173e0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/MiscManager.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define LOG_TAG "USB_DONGLE"
+
+#include <cutils/log.h>
+
+#include <sysutils/NetlinkEvent.h>
+
+#include "MiscManager.h"
+
+
+MiscManager *MiscManager::sInstance = NULL;
+
+MiscManager *MiscManager::Instance() {
+    if (!sInstance)
+        sInstance = new MiscManager();
+    return sInstance;
+}
+
+MiscManager::MiscManager() {
+    mDebug = false;
+    mMiscs = new MiscCollection();
+    mBroadcaster = NULL;
+}
+
+MiscManager::~MiscManager() {
+    delete mMiscs;
+}
+
+void MiscManager::setDebug(bool enable) {
+    mDebug = enable;
+    MiscCollection::iterator it;
+    for (it = mMiscs->begin(); it != mMiscs->end(); ++it) {
+        (*it)->setDebug(enable);
+    }
+}
+
+int MiscManager::start() {
+    return 0;
+}
+
+int MiscManager::stop() {
+    return 0;
+}
+
+int MiscManager::addMisc(Misc *m) {
+    mMiscs->push_back(m);
+    return 0;
+}
+
+void MiscManager::handleEvent(NetlinkEvent *evt) {
+	const char *subsys = evt->getSubsystem();
+    MiscCollection::iterator it;
+    bool hit = false;
+
+	SLOGD("%s, %d", subsys, evt->getAction());
+	
+		
+    for (it = mMiscs->begin(); it != mMiscs->end(); ++it) {
+	    if (!strcmp(subsys, "usb")) {
+			(*it)->handleUsbEvent(evt);
+	    } else if (!strcmp(subsys, "scsi_device")) {
+	    	(*it)->handleScsiEvent(evt);
+	    }
+    }
+}
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/MiscManager.h b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/MiscManager.h
new file mode 100755
index 0000000..a7cee2b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/MiscManager.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#ifndef _MISCMANAGER_H
+#define _MISCMANAGER_H
+
+#include <pthread.h>
+
+#include <utils/List.h>
+#include <sysutils/SocketListener.h>
+#include "Misc.h"
+
+class MiscManager {
+private:
+    static MiscManager *sInstance;
+
+private:
+    SocketListener        *mBroadcaster;
+    MiscCollection        *mMiscs;
+    bool                   mDebug;
+
+public:
+    virtual ~MiscManager();
+
+    int start();
+    int stop();
+
+    void handleEvent(NetlinkEvent *evt);
+
+    int addMisc(Misc *v);
+    
+    void setDebug(bool enable);
+
+    void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
+    SocketListener *getBroadcaster() { return mBroadcaster; }
+
+    static MiscManager *Instance();
+
+private:
+    MiscManager();
+    Misc *lookupMisc(const char *label);
+};
+#endif
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/NetlinkHandler.cpp b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/NetlinkHandler.cpp
new file mode 100755
index 0000000..32b5180
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/NetlinkHandler.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#define LOG_TAG "USB_DONGLE"
+
+#include <cutils/log.h>
+
+#include <sysutils/NetlinkEvent.h>
+#include "NetlinkHandler.h"
+#include "MiscManager.h"
+NetlinkHandler::NetlinkHandler(int listenerSocket) :
+                NetlinkListener(listenerSocket) {
+}
+
+NetlinkHandler::~NetlinkHandler() {
+}
+
+int NetlinkHandler::start() {
+    return this->startListener();
+}
+
+int NetlinkHandler::stop() {
+    return this->stopListener();
+}
+
+void NetlinkHandler::onEvent(NetlinkEvent *evt) {
+    const char *subsys = evt->getSubsystem();
+
+    if (!subsys) {
+        SLOGW("No subsystem found in netlink event");
+        return;
+    }
+
+#ifdef USE_USB_MODE_SWITCH
+    if (!strcmp(subsys, "usb") || !strcmp(subsys, "scsi_device")) {
+        SLOGW("subsystem found in netlink event");
+        MiscManager *mm = MiscManager::Instance();
+        mm->handleEvent(evt);
+#endif
+    }
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/NetlinkHandler.h b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/NetlinkHandler.h
new file mode 100755
index 0000000..56eb23c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/NetlinkHandler.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef _NETLINKHANDLER_H
+#define _NETLINKHANDLER_H
+
+#include <sysutils/NetlinkListener.h>
+
+class NetlinkHandler: public NetlinkListener {
+
+public:
+    explicit NetlinkHandler(int listenerSocket);
+    virtual ~NetlinkHandler();
+
+    int start(void);
+    int stop(void);
+
+protected:
+    virtual void onEvent(NetlinkEvent *evt);
+};
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/NetlinkManager.cpp b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/NetlinkManager.cpp
new file mode 100755
index 0000000..63e7475
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/NetlinkManager.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include <linux/netlink.h>
+
+#define LOG_TAG "USB_DONGLE"
+
+#include <android-base/logging.h>
+
+#include "NetlinkManager.h"
+#include "NetlinkHandler.h"
+
+NetlinkManager *NetlinkManager::sInstance = NULL;
+
+NetlinkManager *NetlinkManager::Instance() {
+    if (!sInstance)
+        sInstance = new NetlinkManager();
+    return sInstance;
+}
+
+NetlinkManager::NetlinkManager() {
+    mBroadcaster = NULL;
+}
+
+NetlinkManager::~NetlinkManager() {
+}
+
+int NetlinkManager::start() {
+    struct sockaddr_nl nladdr;
+    int sz = 64 * 1024;
+    int on = 1;
+
+    memset(&nladdr, 0, sizeof(nladdr));
+    nladdr.nl_family = AF_NETLINK;
+    nladdr.nl_pid = getpid();
+    nladdr.nl_groups = 0xffffffff;
+
+    if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,
+            NETLINK_KOBJECT_UEVENT)) < 0) {
+        PLOG(ERROR) << "Unable to create uevent socket";
+        return -1;
+    }
+
+    // When running in a net/user namespace, SO_RCVBUFFORCE will fail because
+    // it will check for the CAP_NET_ADMIN capability in the root namespace.
+    // Try using SO_RCVBUF if that fails.
+    if ((setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) &&
+        (setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0)) {
+        PLOG(ERROR) << "Unable to set uevent socket SO_RCVBUF/SO_RCVBUFFORCE option";
+        goto out;
+    }
+
+    if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
+        PLOG(ERROR) << "Unable to set uevent socket SO_PASSCRED option";
+        goto out;
+    }
+
+    if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
+        PLOG(ERROR) << "Unable to bind uevent socket";
+        goto out;
+    }
+
+    mHandler = new NetlinkHandler(mSock);
+    if (mHandler->start()) {
+        PLOG(ERROR) << "Unable to start NetlinkHandler";
+        goto out;
+    }
+
+    return 0;
+
+out:
+    close(mSock);
+    return -1;
+}
+
+int NetlinkManager::stop() {
+    int status = 0;
+
+    if (mHandler->stop()) {
+        PLOG(ERROR) << "Unable to stop NetlinkHandler";
+        status = -1;
+    }
+    delete mHandler;
+    mHandler = NULL;
+
+    close(mSock);
+    mSock = -1;
+
+    return status;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/NetlinkManager.h b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/NetlinkManager.h
new file mode 100755
index 0000000..9c7ba11
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/NetlinkManager.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#ifndef _NETLINKMANAGER_H
+#define _NETLINKMANAGER_H
+
+#include <sysutils/SocketListener.h>
+#include <sysutils/NetlinkListener.h>
+
+class NetlinkHandler;
+
+class NetlinkManager {
+private:
+    static NetlinkManager *sInstance;
+
+private:
+    SocketListener       *mBroadcaster;
+    NetlinkHandler       *mHandler;
+    int                  mSock;
+
+public:
+    virtual ~NetlinkManager();
+
+    int start();
+    int stop();
+
+    void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
+    SocketListener *getBroadcaster() { return mBroadcaster; }
+
+    static NetlinkManager *Instance();
+
+private:
+    NetlinkManager();
+};
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/main.cpp b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/main.cpp
new file mode 100755
index 0000000..1e29146
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/main.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+#include "NetlinkManager.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <cutils/klog.h>
+#include <cutils/properties.h>
+#include <cutils/sockets.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#ifdef USE_USB_MODE_SWITCH
+#include "G3Dev.h"
+#include  "MiscManager.h"
+#endif
+
+#define LOG_TAG "USB_DONGLE"
+
+static void coldboot(const char *path);
+
+struct fstab *fstab;
+
+struct selabel_handle *sehandle;
+
+using android::base::StringPrintf;
+
+int main(int argc, char** argv) {
+    setenv("ANDROID_LOG_TAGS", "*:v", 1);
+    android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
+
+    LOG(INFO) << "USB_MODE_SWITCH";
+
+    NetlinkManager *nm;
+
+
+    klog_set_level(6);
+
+    if (!(nm = NetlinkManager::Instance())) {
+        LOG(ERROR) << "Unable to create NetlinkManager";
+        exit(1);
+    }
+
+    if (nm->start()) {
+        PLOG(ERROR) << "Unable to start NetlinkManager";
+        exit(1);
+    }
+
+#ifdef USE_USB_MODE_SWITCH
+	MiscManager *mm;
+	if (!(mm = MiscManager::Instance())) {
+		PLOG(ERROR) << "Unable to create MiscManager";
+		exit(1);
+	};
+	//mm->setBroadcaster((SocketListener *) cl);
+	if (mm->start()) {
+		LOG(ERROR) << "Unable to start MiscManager";
+		exit(1);
+	}
+	G3Dev* g3 = new G3Dev(mm);
+	g3->handleUsb();
+	mm->addMisc(g3);
+#endif
+    // Do coldboot here so it won't block booting,
+    // also the cold boot is needed in case we have flash drive
+    coldboot("/sys/block");
+    // Eventually we'll become the monitoring thread
+    while(1) {
+        pause();
+    }
+
+    LOG(ERROR) << "USB_MODE_SWITCH exiting";
+    exit(0);
+}
+
+static void do_coldboot(DIR *d, int lvl) {
+    struct dirent *de;
+    int dfd, fd;
+
+    dfd = dirfd(d);
+
+    fd = openat(dfd, "uevent", O_WRONLY | O_CLOEXEC);
+    if(fd >= 0) {
+        write(fd, "add\n", 4);
+        close(fd);
+    }
+
+    while((de = readdir(d))) {
+        DIR *d2;
+
+        if (de->d_name[0] == '.')
+            continue;
+
+        if (de->d_type != DT_DIR && lvl > 0)
+            continue;
+
+        fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+        if(fd < 0)
+            continue;
+
+        d2 = fdopendir(fd);
+        if(d2 == 0)
+            close(fd);
+        else {
+            do_coldboot(d2, lvl + 1);
+            closedir(d2);
+        }
+    }
+}
+
+static void coldboot(const char *path) {
+    DIR *d = opendir(path);
+    if(d) {
+        do_coldboot(d, 0);
+        closedir(d);
+    }
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/usb_dongle.rc b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/usb_dongle.rc
new file mode 100755
index 0000000..c20f161
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_dongle/usb_dongle.rc
@@ -0,0 +1,4 @@
+service usb_dongle /vendor/bin/usb_dongle
+    class main
+    oneshot
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.1 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.1
new file mode 100755
index 0000000..fecac7c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.1
@@ -0,0 +1,172 @@
+.TH "USB_MODESWITCH" "1"
+.SH "NAME"
+usb_modeswitch - control the mode of 'multi-state' USB devices
+.SH "SYNOPSIS"
+.PP
+\fBusb_modeswitch\fR [\fB\-heWQDIvpVPmM23rwKdHSOBGTNALnsRiuagft\fP] [\fB\-c \fIfilename\fP]
+.SH "DESCRIPTION"
+.PP
+Several new USB devices have their proprietary Windows drivers onboard,
+most of them WWAN and WLAN  dongles. When plugged in for the first time,
+they act like a flash storage and start installing the Windows driver from
+there. If the driver is already installed, it makes the storage device
+disappear and a new device, mainly composite with modem ports, shows up.
+.PP
+On Linux, in most cases the drivers are available as kernel modules,
+such as "usbserial" or "option". However, the device initially binds to
+"usb-storage" by default. \fBusb_modeswitch\fR can then send a provided bulk
+message (most likely a mass storage command) to the device; this message
+has to be determined by analyzing the actions of the Windows driver.
+.PP
+In some cases, USB control commands are used for switching. These cases are
+handled by custom functions, and no bulk message needs to be provided.
+.PP
+Usually, the program is distributed with a set of configurations for many
+known devices, which allows a fully automatic handling of a device upon
+insertion, made possible by combining usb_modeswitch with the wrapper script
+\fBusb_modeswitch_dispatcher\fR which is launched by the udev daemon.
+.PP
+Note that \fBusb_modeswitch\fR itself has no specific Linux dependencies.
+
+.SH "OPTIONS"
+.PP
+This program follows the usual GNU command line syntax,
+with long options starting with two dashes ('--').  A summary of
+options is included below.
+.IP "\fB-h\fP \fB\-\-help\fP         " 10
+Show summary of options.
+.IP "\fB-e\fP \fB\-\-version\fP         " 10
+Print version information and exit
+.IP "\fB-v\fP \fB\-\-default-vendor NUM\fP         " 10
+Vendor ID to look for (mandatory), usually given as hex number (example: 0x12d1).
+Each USB device is identified by a number
+officialy assigned to the vendor by the USB association and a number for the
+respective model (product ID) chosen by the vendor
+.IP "\fB-p\fP \fB\-\-default-product NUM\fP         " 10
+Product ID to look for (mandatory)
+.IP "\fB-V\fP \fB\-\-target-vendor NUM\fP         " 10
+Target vendor ID. When given will be searched for and detected initially
+for information purposes. If success checking (option \-s) is active,
+providing target IDs (vendor/product) or target class is recommended
+.IP "\fB-j\fP \fB\-\-find-mbim\fP         " 10
+Return configuration number with MBIM interface and exit.
+.IP "\fB-P\fP \fB\-\-target-product NUM\fP         " 10
+Target product ID
+.IP "\fB-b\fP \fB\-\-bus-num NUM\fP         " 10
+.IP "\fB-g\fP \fB\-\-device-num NUM\fP         " 10
+If bus and device number are provided, the handling of a specific device on
+a specific USB port is guaranteed, in contrast to using only the USB ID. This
+is important if there are multiple similar devices on a system
+.IP "\fB-C\fP \fB\-\-target-class NUM\fP         " 10
+Target Device Class according to the USB specification. Some devices keep
+their original vendor/product ID after successful switching. To prevent
+them from being treated again, the device class can be checked.
+For unswitched devices it is always 8 (storage class), for switched
+modems it is often 0xff (vendor specific). In composite modes,
+the class of the first interface is watched
+.IP "\fB-m\fP \fB\-\-message-endpoint NUM\fP         " 10
+A specific endpoint to use for data transfers. Only for testing purposes; usually
+endpoints are determined from the device attributes
+.IP "\fB-M\fP \fB\-\-message-content STRING\fP         " 10
+A bulk message to send as a switching command. Provided as a hexadecimal string
+.IP "\fB-2, -3\fP  \fB\-\-message-content2, \-\-message-content3 STRING\fP         " 10
+Additional bulk messages to send as switching commands. Provided as hexadecimal strings.
+When used with mass storage commands, setting \fB\-\-need-response\fR is
+strongly advised to comply with specifications and to avoid likely errors
+.IP "\fB-w\fP \fB\-\-release-delay NUM\fP         " 10
+After issuing all bulk messages, wait for NUM milliseconds before releasing the interface.
+Required for some modems on older systems (especially after an EJECT message)
+.IP "\fB-n\fP \fB\-\-need-response\fP         " 10
+Obsolete. CSW is always attempted to being read after mass storage transfers. No downside
+.IP "\fB-r\fP \fB\-\-response-endpoint NUM\fP         " 10
+Try to read the response to a storage command from there. Only for testing purposes;
+usually endpoints are determined from the device attributes
+.IP "\fB-K\fP \fB\-\-std-eject\fP         " 10
+Apply the standard SCSI sequence of "Allow Medium Removal" and
+"Eject". Implies \fB-n\fP. One 'Message' can be added with \fB-M\fP
+that will be transmitted after the eject sequence. Used by many modems
+.IP "\fB-d\fP \fB\-\-detach-only\fP         " 10
+Just detach the current driver. This is sufficient for some early
+devices to switch successfully. Otherwise this feature can
+be used as a 'scalpel' for special cases, like separating the
+driver from individual interfaces
+.IP "\fB-H\fP \fB\-\-huawei-mode\fP         " 10
+Send a special control message used by older Huawei devices
+.IP "\fB-J\fP \fB\-\-huawei-new-mode\fP         " 10
+Send a specific bulk message used by all newer Huawei devices
+.IP "\fB-S\fP \fB\-\-sierra-mode\fP         " 10
+Send a special control message used by Sierra devices
+.IP "\fB-G\fP \fB\-\-gct-mode\fP         " 10
+Send a special control message used by GCT chipsets
+.IP "\fB-T\fP \fB\-\-kobil-mode\fP         " 10
+Send a special control message used by Kobil devices
+.IP "\fB-N\fP \fB\-\-sequans-mode\fP         " 10
+Send a special control message used by Sequans chipset
+.IP "\fB-A\fP \fB\-\-mobileaction-mode\fP         " 10
+Send a special control message used by the MobileAction device
+.IP "\fB-B\fP \fB\-\-qisda-mode\fP         " 10
+Send a special control message used by Qisda devices
+.IP "\fB-E\fP \fB\-\-quanta-mode\fP         " 10
+Send a special control message used by Quanta devices
+.IP "\fB-F\fP \fB\-\-pantech-mode NUM\fP         " 10
+Send a special control message used by Pantech devices.
+Value NUM will be used in control message as 'wValue'
+.IP "\fB-Z\fP \fB\-\-blackberry-mode\fP         " 10
+Send a special control message used by some newer Blackberry devices
+.IP "\fB-S\fP \fB\-\-option-mode\fP         " 10
+Send a special control message used by all Option devices
+.IP "\fB-O\fP \fB\-\-sony-mode\fP         " 10
+Apply a special sequence used by Sony Ericsson devices. Implies option \--check-success
+.IP "\fB-L\fP \fB\-\-cisco-mode\fP         " 10
+Send a sequence of bulk messages used by Cisco devices
+.IP "\fB-R\fP \fB\-\-reset-usb\fP         " 10
+Send a USB reset command to the device. Can be combined with any switching
+method or stand alone. It is always done as the last step of all device
+interactions.
+Few devices need it to complete the switching; apart from that it may be
+useful during testing
+.IP "\fB-c\fP \fB\-\-config-file FILENAME\fP         " 10
+Use a specific config file. If any ID or switching options are given as
+command line parameters, this option is ignored.
+In that case all mandatory parameters have to be provided on
+the command line
+.IP "\fB-f\fP \fB\-\-long-config STRING\fP         " 10
+Provide device details in config file syntax as a multiline string
+on the command line
+.IP "\fB-t\fP \fB\-\-stdinput\fP         " 10
+Read the device details in config file syntax from standard input, e.g. redirected from
+a command pipe (multiline text)
+.IP "\fB-Q\fP \fB\-\-quiet\fP         " 10
+Don't show progress or error messages 
+.IP "\fB-W\fP \fB\-\-verbose\fP         " 10
+Print all settings before running and show libusb debug messages 
+.IP "\fB-D\fP \fB\-\-sysmode\fP         " 10
+Changes the behaviour of the program slightly. A success message including the
+effective target device ID is put out and a syslog notice is issued. Mainly for
+integration with a wrapper script
+.IP "\fB-s\fP \fB\-\-check-success NUM\fP         " 10
+After switching, keep checking for the result up to max. NUM seconds. If target IDs
+or target class were provided, their appearance indicates certain success. Otherwise
+the disconnection of the original device is rated as likely proof
+.IP "\fB-I\fP \fB\-\-inquire\fP         " 10
+Obsolete. Formerly obtained SCSI attributes, now ignored
+.IP "\fB-i\fP \fB\-\-interface NUM\fP         " 10
+Select initial USB interface (default: 0). Only for testing purposes
+.IP "\fB-u\fP \fB\-\-configuration NUM\fP         " 10
+Select USB configuration (applied after any other possible switching actions)
+.IP "\fB-a\fP \fB\-\-altsetting NUM\fP         " 10
+Select alternative USB interface setting (applied after switching). Mainly
+for testing
+.SH "AUTHOR"
+.PP
+This manual page was originally written by Didier Raboud (didier@raboud.com) for
+the \fBDebian\fP system. Additions made by Josua Dietze. Permission is
+granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 or any
+later version published by the Free Software Foundation.
+
+.PP
+The complete text of the current GNU General Public
+License can be found in http://www.gnu.org/licenses/gpl.txt
+
+.\" last edited 2016-01-11 for version 2.3.0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.c
new file mode 100755
index 0000000..ba5be82
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.c
@@ -0,0 +1,2095 @@
+/*
+  Mode switching tool for controlling mode of 'multi-state' USB devices
+  Version 2.4.0, 2016/06/12
+
+  Copyright (C) 2007 - 2016 Josua Dietze (mail to "usb_admin" at the domain
+  of the home page; or write a personal message through the forum to "Josh".
+  NO SUPPORT VIA E-MAIL - please use the forum for that)
+
+  Major contributions:
+
+  Command line parsing, decent usage/config output/handling, bugfixes and advanced
+  options added by:
+    Joakim Wennergren
+
+  TargetClass parameter implementation to support new Option devices/firmware:
+    Paul Hardwick (http://www.pharscape.org)
+
+  Created with initial help from:
+    "usbsnoop2libusb.pl" by Timo Lindfors (http://iki.fi/lindi/usb/usbsnoop2libusb.pl)
+
+  Config file parsing code borrowed from:
+    Guillaume Dargaud (http://www.gdargaud.net/Hack/SourceCode.html)
+
+  Hexstr2bin function borrowed from:
+    Jouni Malinen (http://hostap.epitest.fi/wpa_supplicant, from "common.c")
+
+  Other contributions: see README
+
+  Device information contributors are named in the "device_reference.txt" file. See
+  homepage.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details:
+
+  http://www.gnu.org/licenses/gpl.txt
+
+*/
+
+/* Recommended tab size: 4 */
+
+#define VERSION "2.4.0"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "usb_modeswitch.h"
+
+
+// Little helpers
+
+int usb_bulk_io(struct libusb_device_handle *handle, int ep, unsigned char *bytes,
+		int size, int timeout)
+{
+	int actual_length;
+	int r;
+//	usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout);
+	r = libusb_bulk_transfer(handle, ep & 0xff, bytes, size,
+		&actual_length, timeout);
+
+	/* if we timed out but did transfer some data, report as successful short
+	 * read. FIXME: is this how libusb-0.1 works? */
+	if (r == 0 || (r == LIBUSB_ERROR_TIMEOUT && actual_length > 0))
+		return actual_length;
+
+	return r;
+}
+
+
+static int usb_interrupt_io(libusb_device_handle *handle, int ep, unsigned char *bytes,
+		int size, int timeout)
+{
+	int actual_length;
+	int r;
+//	usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout);
+	r = libusb_interrupt_transfer(handle, ep & 0xff, bytes, size,
+		&actual_length, timeout);
+
+	/* if we timed out but did transfer some data, report as successful short
+	 * read. FIXME: is this how libusb-0.1 works? */
+	if (r == 0 || (r == LIBUSB_ERROR_TIMEOUT && actual_length > 0))
+		return actual_length;
+
+	return (r);
+}
+
+
+#define LINE_DIM 1024
+#define MSG_DIM 11
+#define MAXLINES 50
+#define BUF_SIZE 4096
+#define DESCR_MAX 129
+
+#define SEARCH_DEFAULT 0
+#define SEARCH_TARGET 1
+#define SEARCH_BUSDEV 2
+
+#define SWITCH_CONFIG_MAXTRIES   5
+
+#define SHOW_PROGRESS if (show_progress) fprintf
+
+char *TempPP=NULL;
+
+static struct libusb_context *ctx = NULL;
+static struct libusb_device *dev = NULL;
+static struct libusb_device_handle *devh = NULL;
+static struct libusb_config_descriptor *active_config = NULL;
+
+int DefaultVendor=0, DefaultProduct=0, TargetVendor=0, TargetProduct=-1, TargetClass=0;
+int MessageEndpoint=0, ResponseEndpoint=0, ReleaseDelay=0;
+int targetDeviceCount=0, searchMode;
+int devnum=-1, busnum=-1;
+
+unsigned int ModeMap = 0;
+#define DETACHONLY_MODE		0x00000001
+#define HUAWEI_MODE			0x00000002
+#define SIERRA_MODE			0x00000004
+#define SONY_MODE			0x00000008
+#define GCT_MODE			0x00000010
+#define KOBIL_MODE			0x00000020
+#define SEQUANS_MODE		0x00000040
+#define MOBILEACTION_MODE	0x00000080
+#define CISCO_MODE			0x00000100
+#define QISDA_MODE			0x00000200
+#define QUANTA_MODE			0x00000400
+#define BLACKBERRY_MODE		0x00000800
+#define PANTECH_MODE		0x00001000
+#define HUAWEINEW_MODE		0x00002000
+#define OPTION_MODE			0x00004000
+
+
+int PantechMode=0;
+char verbose=0, show_progress=1, ResetUSB=0, CheckSuccess=0, config_read=0;
+char NoDriverLoading=0, sysmode=0, mbim=0;
+char StandardEject=0;
+
+char MessageContent[LINE_DIM];
+char MessageContent2[LINE_DIM];
+char MessageContent3[LINE_DIM];
+char TargetProductList[LINE_DIM];
+char DefaultProductList[5];
+unsigned char ByteString[LINE_DIM/2];
+unsigned char buffer[BUF_SIZE];
+char **Messages = NULL;
+
+FILE *output;
+
+
+/* Settable Interface and Configuration (for debugging mostly) (jmw) */
+int Interface = -1, Configuration = 0, AltSetting = -1;
+
+
+static struct option long_options[] = {
+	{"help",				no_argument, 0, 'h'},
+	{"version",				no_argument, 0, 'e'},
+	{"default-vendor",		required_argument, 0, 'v'},
+	{"default-product",		required_argument, 0, 'p'},
+	{"target-vendor",		required_argument, 0, 'V'},
+	{"target-product",		required_argument, 0, 'P'},
+	{"target-class",		required_argument, 0, 'C'},
+	{"message-endpoint",	required_argument, 0, 'm'},
+	{"message-content",		required_argument, 0, 'M'},
+	{"message-content2",	required_argument, 0, '2'},
+	{"message-content3",	required_argument, 0, '3'},
+	{"release-delay",		required_argument, 0, 'w'},
+	{"response-endpoint",	required_argument, 0, 'r'},
+	{"bus-num",				required_argument, 0, 'b'},
+	{"device-num",			required_argument, 0, 'g'},
+	{"detach-only",			no_argument, 0, 'd'},
+	{"huawei-mode",			no_argument, 0, 'H'},
+	{"huawei-new-mode",		no_argument, 0, 'J'},
+	{"sierra-mode",			no_argument, 0, 'S'},
+	{"sony-mode",			no_argument, 0, 'O'},
+	{"qisda-mode",			no_argument, 0, 'B'},
+	{"quanta-mode",			no_argument, 0, 'E'},
+	{"kobil-mode",			no_argument, 0, 'T'},
+	{"gct-mode",			no_argument, 0, 'G'},
+	{"sequans-mode",		no_argument, 0, 'N'},
+	{"mobileaction-mode",	no_argument, 0, 'A'},
+	{"cisco-mode",	        no_argument, 0, 'L'},
+	{"blackberry-mode",		no_argument, 0, 'Z'},
+	{"option-mode",			no_argument, 0, 'U'},
+	{"pantech-mode",		required_argument, 0, 'F'},
+	{"std-eject",			no_argument, 0, 'K'},
+	{"need-response",		no_argument, 0, 'n'},
+	{"reset-usb",			no_argument, 0, 'R'},
+	{"config-file",			required_argument, 0, 'c'},
+	{"verbose",				no_argument, 0, 'W'},
+	{"quiet",				no_argument, 0, 'Q'},
+	{"sysmode",				no_argument, 0, 'D'},
+	{"inquire",				no_argument, 0, 'I'},
+	{"stdinput",			no_argument, 0, 't'},
+	{"find-mbim",			no_argument, 0, 'j'},
+	{"long-config",			required_argument, 0, 'f'},
+	{"check-success",		required_argument, 0, 's'},
+	{"interface",			required_argument, 0, 'i'},
+	{"configuration",		required_argument, 0, 'u'},
+	{"altsetting",			required_argument, 0, 'a'},
+	{0, 0, 0, 0}
+};
+
+
+void readConfigFile(const char *configFilename)
+{
+	ParseParamHex(configFilename, TargetVendor);
+	ParseParamHex(configFilename, TargetProduct);
+	ParseParamString(configFilename, TargetProductList);
+	ParseParamHex(configFilename, TargetClass);
+	ParseParamHex(configFilename, DefaultVendor);
+	ParseParamHex(configFilename, DefaultProduct);
+	ParseParamBoolMap(configFilename, DetachStorageOnly, ModeMap, DETACHONLY_MODE);
+	ParseParamBoolMap(configFilename, HuaweiMode, ModeMap, HUAWEI_MODE);
+	ParseParamBoolMap(configFilename, HuaweiNewMode, ModeMap, HUAWEINEW_MODE);
+	ParseParamBoolMap(configFilename, SierraMode, ModeMap, SIERRA_MODE);
+	ParseParamBoolMap(configFilename, SonyMode, ModeMap, SONY_MODE);
+	ParseParamBoolMap(configFilename, GCTMode, ModeMap, GCT_MODE);
+	ParseParamBoolMap(configFilename, KobilMode, ModeMap, KOBIL_MODE);
+	ParseParamBoolMap(configFilename, SequansMode, ModeMap, SEQUANS_MODE);
+	ParseParamBoolMap(configFilename, MobileActionMode, ModeMap, MOBILEACTION_MODE);
+	ParseParamBoolMap(configFilename, CiscoMode, ModeMap, CISCO_MODE);
+	ParseParamBoolMap(configFilename, QisdaMode, ModeMap, QISDA_MODE);
+	ParseParamBoolMap(configFilename, QuantaMode, ModeMap, QUANTA_MODE);
+	ParseParamBoolMap(configFilename, OptionMode, ModeMap, OPTION_MODE);
+	ParseParamBoolMap(configFilename, BlackberryMode, ModeMap, BLACKBERRY_MODE);
+	ParseParamInt(configFilename, PantechMode);
+	if (PantechMode)
+		ModeMap |= PANTECH_MODE;
+	ParseParamBool(configFilename, StandardEject);
+	ParseParamBool(configFilename, NoDriverLoading);
+	ParseParamHex(configFilename, MessageEndpoint);
+	ParseParamString(configFilename, MessageContent);
+	ParseParamString(configFilename, MessageContent2);
+	ParseParamString(configFilename, MessageContent3);
+	ParseParamInt(configFilename, ReleaseDelay);
+	ParseParamHex(configFilename, ResponseEndpoint);
+	ParseParamHex(configFilename, ResetUSB);
+	ParseParamInt(configFilename, CheckSuccess);
+	ParseParamHex(configFilename, Interface);
+	ParseParamHex(configFilename, Configuration);
+	ParseParamHex(configFilename, AltSetting);
+
+	/* TargetProductList has priority over TargetProduct */
+	if (TargetProduct != -1 && TargetProductList[0] != '\0') {
+		TargetProduct = -1;
+		SHOW_PROGRESS(output,"Warning: TargetProductList overrides TargetProduct!\n");
+	}
+
+	config_read = 1;
+}
+
+
+void printConfig()
+{
+	if ( DefaultVendor )
+		fprintf (output,"DefaultVendor=  0x%04x\n",	DefaultVendor);
+	if ( DefaultProduct )
+		fprintf (output,"DefaultProduct= 0x%04x\n",	DefaultProduct);
+	if ( TargetVendor )
+		fprintf (output,"TargetVendor=   0x%04x\n",	TargetVendor);
+	if ( TargetProduct > -1 )
+		fprintf (output,"TargetProduct=  0x%04x\n",	TargetProduct);
+	if ( TargetClass )
+		fprintf (output,"TargetClass=    0x%02x\n",	TargetClass);
+	if ( strlen(TargetProductList) )
+		fprintf (output,"TargetProductList=\"%s\"\n", TargetProductList);
+	if (StandardEject)
+		fprintf (output,"\nStandardEject=1\n");
+	if (ModeMap & DETACHONLY_MODE)
+		fprintf (output,"\nDetachStorageOnly=1\n");
+	if (ModeMap & HUAWEI_MODE)
+		fprintf (output,"HuaweiMode=1\n");
+	if (ModeMap & HUAWEINEW_MODE)
+		fprintf (output,"HuaweiNewMode=1\n");
+	if (ModeMap & SIERRA_MODE)
+		fprintf (output,"SierraMode=1\n");
+	if (ModeMap & SONY_MODE)
+		fprintf (output,"SonyMode=1\n");
+	if (ModeMap & QISDA_MODE)
+		fprintf (output,"QisdaMode=1\n");
+	if (ModeMap & QUANTA_MODE)
+		fprintf (output,"QuantaMode=1\n");
+	if (ModeMap & GCT_MODE)
+		fprintf (output,"GCTMode=1\n");
+	if (ModeMap & KOBIL_MODE)
+		fprintf (output,"KobilMode=1\n");
+	if (ModeMap & SEQUANS_MODE)
+		fprintf (output,"SequansMode=1\n");
+	if (ModeMap & MOBILEACTION_MODE)
+		fprintf (output,"MobileActionMode=1\n");
+	if (ModeMap & CISCO_MODE)
+		fprintf (output,"CiscoMode=1\n");
+	if (ModeMap & BLACKBERRY_MODE)
+		fprintf (output,"BlackberryMode=1\n");
+	if (ModeMap & OPTION_MODE)
+		fprintf (output,"OptionMode=1\n");
+	if (ModeMap & PANTECH_MODE)
+		fprintf (output,"PantechMode=1\n");
+	if ( MessageEndpoint )
+		fprintf (output,"MessageEndpoint=0x%02x\n",	MessageEndpoint);
+	if ( strlen(MessageContent) )
+		fprintf (output,"MessageContent=\"%s\"\n",	MessageContent);
+	if ( strlen(MessageContent2) )
+		fprintf (output,"MessageContent2=\"%s\"\n",	MessageContent2);
+	if ( strlen(MessageContent3) )
+		fprintf (output,"MessageContent3=\"%s\"\n",	MessageContent3);
+	if ( ResponseEndpoint )
+		fprintf (output,"ResponseEndpoint=0x%02x\n",	ResponseEndpoint);
+	if ( Interface > -1 )
+		fprintf (output,"Interface=0x%02x\n",			Interface);
+	if ( Configuration > 0 )
+		fprintf (output,"Configuration=0x%02x\n",	Configuration);
+	if ( AltSetting > -1 )
+		fprintf (output,"AltSetting=0x%02x\n",	AltSetting);
+	if ( CheckSuccess )
+		fprintf (output,"Success check enabled, max. wait time %d seconds\n", CheckSuccess);
+	if ( sysmode )
+		fprintf (output,"System integration mode enabled\n");
+}
+
+
+int readArguments(int argc, char **argv)
+{
+	int c, option_index = 0, count=0;
+	char *longConfig = NULL;
+	if (argc==1)
+	{
+		printHelp();
+		printVersion();
+		exit(1);
+	}
+
+	while (1)
+	{
+		c = getopt_long (argc, argv, "hejWQDndKHJSOBEGTNALZUF:RItv:p:V:P:C:m:M:2:3:w:r:c:i:u:a:s:f:b:g:",
+					long_options, &option_index);
+
+		/* Detect the end of the options. */
+		if (c == -1)
+			break;
+		count++;
+		switch (c)
+		{
+			case 'R': ResetUSB = 1; break;
+			case 'v': DefaultVendor = strtol(optarg, NULL, 16); break;
+			case 'p': DefaultProduct = strtol(optarg, NULL, 16); break;
+			case 'V': TargetVendor = strtol(optarg, NULL, 16); break;
+			case 'P': TargetProduct = strtol(optarg, NULL, 16); break;
+			case 'C': TargetClass = strtol(optarg, NULL, 16); break;
+			case 'm': MessageEndpoint = strtol(optarg, NULL, 16); break;
+			case 'M': strncpy(MessageContent, optarg, LINE_DIM); break;
+			case '2': strncpy(MessageContent2, optarg, LINE_DIM); break;
+			case '3': strncpy(MessageContent3, optarg, LINE_DIM); break;
+			case 'w': ReleaseDelay = strtol(optarg, NULL, 10); break;
+			case 'n': break;
+			case 'r': ResponseEndpoint = strtol(optarg, NULL, 16); break;
+			case 'K': StandardEject = 1; break;
+			case 'd': ModeMap = ModeMap + DETACHONLY_MODE; break;
+			case 'H': ModeMap = ModeMap + HUAWEI_MODE; break;
+			case 'J': ModeMap = ModeMap + HUAWEINEW_MODE; break;
+			case 'S': ModeMap = ModeMap + SIERRA_MODE; break;
+			case 'O': ModeMap = ModeMap + SONY_MODE; break;; break;
+			case 'B': ModeMap = ModeMap + QISDA_MODE; break;
+			case 'E': ModeMap = ModeMap + QUANTA_MODE; break;
+			case 'G': ModeMap = ModeMap + GCT_MODE; break;
+			case 'T': ModeMap = ModeMap + KOBIL_MODE; break;
+			case 'N': ModeMap = ModeMap + SEQUANS_MODE; break;
+			case 'A': ModeMap = ModeMap + MOBILEACTION_MODE; break;
+			case 'L': ModeMap = ModeMap + CISCO_MODE; break;
+			case 'Z': ModeMap = ModeMap + BLACKBERRY_MODE; break;
+			case 'U': ModeMap = ModeMap + OPTION_MODE; break;
+			case 'F': ModeMap = ModeMap + PANTECH_MODE;
+						PantechMode = strtol(optarg, NULL, 10); break;
+			case 'c': readConfigFile(optarg); break;
+			case 't': readConfigFile("stdin"); break;
+			case 'W': verbose = 1; show_progress = 1; count--; break;
+			case 'Q': show_progress = 0; verbose = 0; count--; break;
+			case 'D': sysmode = 1; count--; break;
+			case 's': CheckSuccess = strtol(optarg, NULL, 10); count--; break;
+			case 'I': break;
+			case 'b': busnum = strtol(optarg, NULL, 10); break;
+			case 'g': devnum = strtol(optarg, NULL, 10); break;
+
+			case 'i': Interface = strtol(optarg, NULL, 16); break;
+			case 'u': Configuration = strtol(optarg, NULL, 16); break;
+			case 'a': AltSetting = strtol(optarg, NULL, 16); break;
+			case 'j': mbim = 1; break;
+
+			case 'f':
+				longConfig = malloc(strlen(optarg)+5);
+				strcpy(longConfig,"##\n");
+				strcat(longConfig,optarg);
+				strcat(longConfig,"\n");
+				readConfigFile(longConfig);
+				free(longConfig);
+				break;
+
+			case 'e':
+				printVersion();
+				exit(0);
+				break;
+			case 'h':
+				printVersion();
+				printHelp();
+				exit(0);
+				break;
+
+			default: /* Unsupported - error message has already been printed */
+				fprintf (output,"\n");
+				printHelp();
+				exit(1);
+		}
+	}
+	return count;
+}
+
+
+int main(int argc, char **argv)
+{
+	int ret=0, numDefaults=0, sonySuccess=0, i;
+	int currentConfigVal=0, defaultClass=0, interfaceClass=0;
+	struct libusb_device_descriptor descriptor;
+	enum libusb_error libusbError;
+
+	/* Make sure we have empty strings even if not set by config */
+	TargetProductList[0] = '\0';
+	MessageContent[0] = '\0';
+	MessageContent2[0] = '\0';
+	MessageContent3[0] = '\0';
+	DefaultProductList[0] = '\0';
+
+	/* Useful for debugging during boot */
+//	output=fopen("/dev/console", "w");
+	output=stdout;
+
+	signal(SIGTERM, release_usb_device);
+
+	/*
+	 * Parameter parsing, USB preparation/diagnosis, plausibility checks
+	 */
+
+	/* Check command arguments, use params instead of config file when given */
+	switch (readArguments(argc, argv)) {
+		case 0:						/* no argument or -W, -q or -s */
+			break;
+		default:					/* one or more arguments except -W, -q or -s */
+			if (!config_read)		/* if arguments contain -c, the config file was already processed */
+				if (verbose) fprintf(output,"Take all parameters from the command line\n\n");
+	}
+
+	if (verbose) {
+		printVersion();
+		printConfig();
+		fprintf(output,"\n");
+	}
+
+	/* Some sanity checks. The default IDs are mandatory */
+	if (!(DefaultVendor && DefaultProduct)) {
+		SHOW_PROGRESS(output,"No default vendor/product ID given. Abort\n\n");
+		exit(1);
+	}
+
+	if (strlen(MessageContent)) {
+		if (strlen(MessageContent) % 2 != 0) {
+			fprintf(stderr, "Error: MessageContent hex string has uneven length. Abort\n\n");
+			exit(1);
+		}
+		if ( hexstr2bin(MessageContent, ByteString, strlen(MessageContent)/2) == -1) {
+			fprintf(stderr, "Error: MessageContent %s\n is not a hex string. Abort\n\n",
+					MessageContent);
+
+			exit(1);
+		}
+	}
+
+	if (devnum == -1) {
+		searchMode = SEARCH_DEFAULT;
+	} else {
+		SHOW_PROGRESS(output,"Use given bus/device number: %03d/%03d ...\n", busnum, devnum);
+		searchMode = SEARCH_BUSDEV;
+	}
+
+	if (show_progress)
+		if (CheckSuccess && !(TargetVendor || TargetProduct > -1 || TargetProductList[0] != '\0')
+				 && !TargetClass)
+
+			fprintf(output,"Note: No target parameter given; success check limited\n");
+
+	if (TargetProduct > -1 && TargetProductList[0] == '\0') {
+		sprintf(TargetProductList,"%04x",TargetProduct);
+		TargetProduct = -1;
+	}
+
+	/* libusb initialization */
+	if ((libusbError = libusb_init(&ctx)) != LIBUSB_SUCCESS) {
+		//fprintf(stderr, "Error: Failed to initialize libusb. %s (%d)\n\n",
+				//libusb_error_name(libusbError), libusbError);
+		exit(1);
+	}
+
+	if (verbose)
+		libusb_set_debug(ctx, 3);
+
+	if (mbim) {
+		printf("%d\n", findMBIMConfig(DefaultVendor, DefaultProduct, searchMode) );
+		exit(0);
+	}
+
+	/* Count existing target devices, remember for success check */
+	if (searchMode != SEARCH_BUSDEV && (TargetVendor || TargetClass)) {
+		SHOW_PROGRESS(output,"Look for target devices ...\n");
+		search_devices(&targetDeviceCount, TargetVendor, TargetProductList, TargetClass, 0,
+				SEARCH_TARGET);
+
+		if (targetDeviceCount) {
+			SHOW_PROGRESS(output," Found devices in target mode or class (%d)\n", targetDeviceCount);
+		} else
+			SHOW_PROGRESS(output," No devices in target mode or class found\n");
+	}
+
+	/* Count default devices, get the last one found */
+	SHOW_PROGRESS(output,"Look for default devices ...\n");
+
+	sprintf(DefaultProductList,"%04x",DefaultProduct);
+	dev = search_devices(&numDefaults, DefaultVendor, DefaultProductList, TargetClass,
+		Configuration, searchMode);
+
+	if (numDefaults) {
+		SHOW_PROGRESS(output," Found devices in default mode (%d)\n", numDefaults);
+	} else {
+		SHOW_PROGRESS(output," No devices in default mode found. Nothing to do. Bye!\n\n");
+		close_all();
+		exit(0);
+	}
+
+	if (dev == NULL) {
+		SHOW_PROGRESS(output," No bus/device match. Is device connected? Abort\n\n");
+		close_all();
+		exit(0);
+	} else {
+		if (devnum == -1) {
+			devnum = libusb_get_device_address(dev);
+			busnum = libusb_get_bus_number(dev);
+			SHOW_PROGRESS(output,"Access device %03d on bus %03d\n", devnum, busnum);
+		}
+		libusb_open(dev, &devh);
+		if (devh == NULL) {
+			SHOW_PROGRESS(output,"Error opening the device. Abort\n\n");
+			abortExit();
+		}
+	}
+
+	/* Get current configuration of default device, note value if Configuration
+	 * parameter is set. Also sets active_config
+	 */
+	currentConfigVal = get_current_config_value(dev);
+	if (Configuration > -1) {
+		SHOW_PROGRESS(output,"Current configuration number is %d\n", currentConfigVal);
+	} else
+		currentConfigVal = 0;
+
+	libusb_get_device_descriptor(dev, &descriptor);
+	defaultClass = descriptor.bDeviceClass;
+	if (Interface == -1)
+		Interface = active_config->interface[0].altsetting[0].bInterfaceNumber;
+	SHOW_PROGRESS(output,"Use interface number %d\n", Interface);
+
+	/* Get class of default device/interface */
+	interfaceClass = get_interface_class();
+
+	/* Check or get endpoints and alloc message list if needed*/
+	if (strlen(MessageContent) || StandardEject || ModeMap & CISCO_MODE
+				|| ModeMap & HUAWEINEW_MODE || ModeMap & OPTION_MODE) {
+
+		Messages = (char**) calloc(MSG_DIM, sizeof(char*));
+		for (i = 0; i < MSG_DIM; i++) {
+			Messages[i] = (char*) calloc(LINE_DIM, sizeof(char));
+			Messages[i][0] = '\0';
+		}
+
+		if (!MessageEndpoint)
+			MessageEndpoint = find_first_bulk_endpoint(LIBUSB_ENDPOINT_OUT);
+		if (!ResponseEndpoint)
+			ResponseEndpoint = find_first_bulk_endpoint(LIBUSB_ENDPOINT_IN);
+		if (!MessageEndpoint) {
+			fprintf(stderr,"Error: message endpoint not given or found. Abort\n\n");
+			abortExit();
+		}
+		if (!ResponseEndpoint) {
+			fprintf(stderr,"Error: response endpoint not given or found. Abort\n\n");
+			abortExit();
+		}
+		SHOW_PROGRESS(output,"Use endpoints 0x%02x (out) and 0x%02x (in)\n", MessageEndpoint,
+				ResponseEndpoint);
+
+	}
+
+	if (interfaceClass == -1) {
+		fprintf(stderr, "Error: Could not get class of interface %d. Does it exist? Abort\n\n",Interface);
+		abortExit();
+	}
+
+	if (defaultClass == 0 || defaultClass == 0xef)
+		defaultClass = interfaceClass;
+	else
+		if (interfaceClass == LIBUSB_CLASS_MASS_STORAGE && defaultClass != LIBUSB_CLASS_MASS_STORAGE
+				&& defaultClass != LIBUSB_CLASS_VENDOR_SPEC) {
+
+			/* Unexpected default class combined with differing interface class */
+			SHOW_PROGRESS(output,"Bogus Class/InterfaceClass: 0x%02x/0x08\n", defaultClass);
+			defaultClass = 8;
+		}
+
+	if (strlen(MessageContent) && strncmp("55534243",MessageContent,8) == 0)
+		if (defaultClass != 8) {
+			fprintf(stderr, "Error: can't use storage command in MessageContent with interface %d;\n"
+				"       interface class is %d, expected 8. Abort\n\n", Interface, defaultClass);
+			abortExit();
+		}
+
+	if (show_progress) {
+		fprintf(output,"\nUSB description data (for identification)\n");
+		deviceDescription();
+	}
+
+	/* Special modes are exclusive, so check for illegal combinations.
+	 * More than one bit set?
+	 */
+	if ( ModeMap & (ModeMap-1) ) {
+		fprintf(output,"Multiple special modes selected; check configuration. Abort\n\n");
+		abortExit();
+	}
+
+	if ((strlen(MessageContent) || StandardEject) && ModeMap ) {
+		MessageContent[0] = '\0';
+		StandardEject = 0;
+		fprintf(output,"Warning: MessageContent/StandardEject ignored; can't combine with special mode\n");
+	}
+
+	if (StandardEject && (strlen(MessageContent2) || strlen(MessageContent3))) {
+		fprintf(output,"Warning: MessageContent2/3 ignored; only one allowed with StandardEject\n");
+	}
+
+	if ( !ModeMap && !strlen(MessageContent) && AltSetting == -1 && !Configuration && !StandardEject )
+		SHOW_PROGRESS(output,"Warning: no switching method given. See documentation\n");
+
+	/*
+	 * The switching actions
+	 */
+
+	if (sysmode) {
+		openlog("usb_modeswitch", 0, LOG_SYSLOG);
+		syslog(LOG_NOTICE, "switch device %04x:%04x on %03d/%03d", DefaultVendor, DefaultProduct,
+				busnum, devnum);
+
+	}
+
+	if (ModeMap & DETACHONLY_MODE) {
+		SHOW_PROGRESS(output,"Detach storage driver as switching method ...\n");
+		ret = detachDriver();
+		if (ret == 2)
+			SHOW_PROGRESS(output," You may want to remove the storage driver manually\n");
+	}
+
+	if(ModeMap & HUAWEI_MODE) {
+		switchHuaweiMode();
+	}
+	if(ModeMap & SIERRA_MODE) {
+		switchSierraMode();
+	}
+	if(ModeMap & GCT_MODE) {
+		detachDriver();
+		switchGCTMode();
+	}
+	if(ModeMap & QISDA_MODE) {
+		switchQisdaMode();
+	}
+	if(ModeMap & KOBIL_MODE) {
+		detachDriver();
+		switchKobilMode();
+	}
+	if(ModeMap & QUANTA_MODE) {
+		switchQuantaMode();
+	}
+	if(ModeMap & SEQUANS_MODE) {
+		switchSequansMode();
+	}
+	if(ModeMap & MOBILEACTION_MODE) {
+		switchActionMode();
+	}
+	if(ModeMap & CISCO_MODE) {
+		detachDriver();
+		switchCiscoMode();
+	}
+	if(ModeMap & BLACKBERRY_MODE) {
+		detachDriver();
+	    switchBlackberryMode();
+	}
+	if(ModeMap & PANTECH_MODE) {
+		detachDriver();
+		if (PantechMode > 1)
+			switchPantechMode();
+		else
+			SHOW_PROGRESS(output,"Waiting for auto-switch of Pantech modem ...\n");
+	}
+	if(ModeMap & SONY_MODE) {
+		if (CheckSuccess)
+			SHOW_PROGRESS(output,"Note: CheckSuccess ignored; Sony mode does separate checks\n");
+		CheckSuccess = 0; /* separate and implied success control */
+		sonySuccess = switchSonyMode();
+	}
+
+	if (StandardEject) {
+		SHOW_PROGRESS(output,"Sending standard EJECT sequence\n");
+		detachDriver();
+
+		strcpy(Messages[0],"5553424387654321000000000000061e000000000000000000000000000000");
+		strcpy(Messages[1],"5553424397654321000000000000061b000000020000000000000000000000");
+		strcpy(Messages[2],"5553424387654321000000000001061e000000000000000000000000000000");
+		strcpy(Messages[3],"5553424397654321000000000001061b000000020000000000000000000000");
+		if (MessageContent[0] != '\0')
+			strcpy(Messages[4], MessageContent);
+
+		switchSendMessage();
+	} else if (ModeMap & HUAWEINEW_MODE) {
+		SHOW_PROGRESS(output,"Using standard Huawei switching message\n");
+		detachDriver();
+		strcpy(Messages[0],"55534243123456780000000000000011062000000101000100000000000000");
+		switchSendMessage();
+	} else if (ModeMap & OPTION_MODE) {
+		SHOW_PROGRESS(output,"Using standard Option switching message\n");
+		detachDriver();
+//		strcpy(MessageContent,"55534243123456780100000080000601000000000000000000000000000000");
+		strcpy(Messages[0],"55534243123456780000000000000601000000000000000000000000000000");
+		switchSendMessage();
+	} else if (strlen(MessageContent)) {
+		detachDriver();
+		strcpy(Messages[0],MessageContent);
+		switchSendMessage();
+	}
+
+	if (Configuration > 0) {
+		if (currentConfigVal != Configuration) {
+			if (switchConfiguration()) {
+				currentConfigVal = get_current_config_value(dev);
+				if (currentConfigVal == Configuration) {
+					SHOW_PROGRESS(output,"The configuration was set successfully\n");
+				} else {
+					SHOW_PROGRESS(output,"Changing the configuration has failed\n");
+				}
+			}
+		} else {
+			SHOW_PROGRESS(output,"Target configuration %d found. Do nothing\n", currentConfigVal);
+		}
+	}
+
+	if (AltSetting != -1) {
+		switchAltSetting();
+	}
+
+	/* No "removal" check if these are set */
+	if ((Configuration > 0 || AltSetting > -1) && !ResetUSB) {
+		libusb_close(devh);
+		devh = NULL;
+	}
+
+	if (ResetUSB) {
+		resetUSB();
+		devh = NULL;
+	}
+
+	if (searchMode == SEARCH_BUSDEV && sysmode) {
+		printf("ok:busdev\n");
+		close_all();
+		exit(0);
+	}
+
+	if (CheckSuccess) {
+		if (checkSuccess()) {
+			if (sysmode) {
+				if (NoDriverLoading)
+					printf("ok:\n");
+				else
+					if (TargetProduct < 1)
+						printf("ok:no_data\n");
+					else
+						printf("ok:%04x:%04x\n", TargetVendor, TargetProduct);
+			}
+		} else
+			if (sysmode)
+				printf("fail:\n");
+	} else {
+		if (ModeMap & SONY_MODE)
+			if (sonySuccess) {
+				if (sysmode) {
+					syslog(LOG_NOTICE, "switched S.E. MD400 to modem mode");
+					printf("ok:\n"); /* ACM device, no driver action */
+				}
+				SHOW_PROGRESS(output,"-> device should be stable now. Bye!\n\n");
+			} else {
+				if (sysmode)
+					printf("fail:\n");
+				SHOW_PROGRESS(output,"-> switching was probably not completed. Bye!\n\n");
+			}
+		else
+			SHOW_PROGRESS(output,"-> Run lsusb to note any changes. Bye!\n\n");
+	}
+	close_all();
+	exit(0);
+}
+
+
+/* Get descriptor strings if available (identification details) */
+void deviceDescription ()
+{
+	char imanufact[DESCR_MAX], iproduct[DESCR_MAX], iserial[DESCR_MAX];
+	int ret=0;
+	char* c;
+	memset (imanufact, ' ', DESCR_MAX);
+	memset (iproduct, ' ', DESCR_MAX);
+	memset (iserial, ' ', DESCR_MAX);
+
+	struct libusb_device_descriptor descriptor;
+	libusb_get_device_descriptor(dev, &descriptor);
+
+	int iManufacturer = descriptor.iManufacturer;
+	int iProduct = descriptor.iProduct;
+	int iSerialNumber = descriptor.iSerialNumber;
+
+	if (iManufacturer) {
+		ret = libusb_get_string_descriptor_ascii(devh, iManufacturer, (unsigned char *)imanufact, DESCR_MAX);
+		if (ret < 0) {
+			fprintf(stderr, "Error: could not get description string \"manufacturer\"\n");
+			strcpy(imanufact, "read error");
+		}
+	} else
+		strcpy(imanufact, "not provided");
+	c = strstr(imanufact, "    ");
+	if (c)
+		memset((void*)c, '\0', 1);
+
+	if (iProduct) {
+		ret = libusb_get_string_descriptor_ascii(devh, iProduct, (unsigned char *)iproduct, DESCR_MAX);
+		if (ret < 0) {
+			fprintf(stderr, "Error: could not get description string \"product\"\n");
+			strcpy(iproduct, "read error");
+		}
+	} else
+		strcpy(iproduct, "not provided");
+	c = strstr(iproduct, "    ");
+	if (c)
+		memset((void*)c, '\0', 1);
+
+	if (iSerialNumber) {
+		ret = libusb_get_string_descriptor_ascii(devh, iSerialNumber, (unsigned char *)iserial, DESCR_MAX);
+		if (ret < 0) {
+			fprintf(stderr, "Error: could not get description string \"serial number\"\n");
+			strcpy(iserial, "read error");
+		}
+	} else
+		strcpy(iserial, "not provided");
+	c = strstr(iserial, "    ");
+	if (c)
+		memset((void*)c, '\0', 1);
+	fprintf(output,"-------------------------\n");
+	fprintf(output,"Manufacturer: %s\n", imanufact);
+	fprintf(output,"     Product: %s\n", iproduct);
+	fprintf(output,"  Serial No.: %s\n", iserial);
+	fprintf(output,"-------------------------\n");
+}
+
+
+/* Auxiliary function used by the wrapper */
+int findMBIMConfig(int vendor, int product, int mode)
+{
+	struct libusb_device **devs;
+	int resultConfig=0;
+	int i=0, j;
+
+	if (libusb_get_device_list(ctx, &devs) < 0) {
+		perror("Libusb could not access USB. Abort");
+		return 0;
+	}
+
+	SHOW_PROGRESS(output,"Search USB devices ...\n");
+	while ((dev = devs[i++]) != NULL) {
+		struct libusb_device_descriptor descriptor;
+		libusb_get_device_descriptor(dev, &descriptor);
+
+		if (mode == SEARCH_BUSDEV) {
+			if ((libusb_get_bus_number(dev) != busnum) ||
+				(libusb_get_device_address(dev) != devnum)) {
+				continue;
+			} else {
+				if (descriptor.idVendor != vendor)
+					continue;
+				if (product != descriptor.idProduct)
+					continue;
+			}
+		}
+		SHOW_PROGRESS(output,"Found device, search for MBIM configuration...\n");
+
+		// No check if there is only one configuration
+		if (descriptor.bNumConfigurations < 2)
+			return -1;
+
+		// Checking all interfaces of all configurations
+		for (j=0; j<descriptor.bNumConfigurations; j++) {
+			struct libusb_config_descriptor *config;
+
+			libusb_get_config_descriptor(dev, j, &config);
+			resultConfig = config->bConfigurationValue;
+			for (i=0; i<config->bNumInterfaces; i++) {
+				if ( config->interface[i].altsetting[0].bInterfaceClass == 2 )
+					if ( config->interface[i].altsetting[0].bInterfaceSubClass == 0x0e ) {
+						// found MBIM interface in this configuration
+						libusb_free_config_descriptor(config);
+						return resultConfig;
+					}
+			}
+			libusb_free_config_descriptor(config);
+		}
+		return -1;
+	}
+	return 0;
+}
+
+
+void resetUSB ()
+{
+	int success;
+	int bpoint = 0;
+
+	if (!devh) {
+		fprintf(output,"Device handle empty, skip USB reset\n");
+		return;
+	}
+	if (show_progress) {
+		fprintf(output,"Reset USB device ");
+		fflush(output);
+	}
+	sleep( 1 );
+	do {
+		success = libusb_reset_device(devh);
+		if ( ((bpoint % 10) == 0) && show_progress ) {
+			fprintf(output,".");
+			fflush(output);
+		}
+		bpoint++;
+		if (bpoint > 100)
+			success = 1;
+	} while (success < 0);
+
+	if ( success ) {
+		SHOW_PROGRESS(output,"\n Device reset failed.\n");
+	} else
+		SHOW_PROGRESS(output,"\n Device was reset\n");
+}
+
+
+int switchSendMessage ()
+{
+	const char* cmdHead = "55534243";
+	int ret, i;
+/*	char* msg[3];
+	msg[0] = MessageContent;
+	msg[1] = MessageContent2;
+	msg[2] = MessageContent3;
+*/
+	SHOW_PROGRESS(output,"Set up interface %d\n", Interface);
+	ret = libusb_claim_interface(devh, Interface);
+	if (ret != 0) {
+		SHOW_PROGRESS(output," Could not claim interface (error %d). Skip message sending\n", ret);
+		return 0;
+	}
+	libusb_clear_halt(devh, MessageEndpoint);
+	SHOW_PROGRESS(output,"Use endpoint 0x%02x for message sending ...\n", MessageEndpoint);
+	if (show_progress)
+		fflush(stdout);
+
+	for (i=0; i<MSG_DIM; i++) {
+		if ( strlen(Messages[i]) == 0)
+			break;
+
+		if ( sendMessage(Messages[i], i+1) )
+			goto skip;
+
+		if ( strstr(Messages[i],cmdHead) != NULL ) {
+			// UFI command
+			SHOW_PROGRESS(output,"Read the response to message %d (CSW) ...\n", i+1);
+			ret = read_bulk(ResponseEndpoint, ByteString, 13);
+			if (ret >= 0)
+				SHOW_PROGRESS(output,", status %d",ByteString[12]);
+		} else {
+			// Other bulk transfer
+			SHOW_PROGRESS(output,"Read the response to message %d ...\n", i+1);
+			ret = read_bulk(ResponseEndpoint, ByteString, strlen(Messages[i])/2 );
+		}
+		SHOW_PROGRESS(output,"\n");
+		if (ret < 0)
+			goto skip;
+	}
+
+	SHOW_PROGRESS(output,"Reset response endpoint 0x%02x\n", ResponseEndpoint);
+	ret = libusb_clear_halt(devh, ResponseEndpoint);
+	if (ret)
+		SHOW_PROGRESS(output," Could not reset endpoint (probably harmless): %d\n", ret);
+	SHOW_PROGRESS(output,"Reset message endpoint 0x%02x\n", MessageEndpoint);
+	ret = libusb_clear_halt(devh, MessageEndpoint);
+	if (ret)
+		SHOW_PROGRESS(output," Could not reset endpoint (probably harmless): %d\n", ret);
+	usleep(50000);
+
+	if (ReleaseDelay) {
+		SHOW_PROGRESS(output,"Wait for %d ms before releasing interface ...\n", ReleaseDelay);
+		usleep(ReleaseDelay*1000);
+	}
+	ret = libusb_release_interface(devh, Interface);
+	if (ret)
+		goto skip;
+	return 1;
+
+skip:
+	SHOW_PROGRESS(output," Device is gone, skip any further commands\n");
+	libusb_close(devh);
+	devh = NULL;
+	return 2;
+}
+
+
+int switchConfiguration ()
+{
+	int ret, count = SWITCH_CONFIG_MAXTRIES;
+
+	SHOW_PROGRESS(output,"Change configuration to %i ...\n", Configuration);
+	while (((ret = libusb_set_configuration(devh, Configuration)) < 0) && --count) {
+		SHOW_PROGRESS(output," Device is busy, try to detach kernel driver\n");
+		detachDriver();
+	}
+	if (ret < 0 ) {
+		SHOW_PROGRESS(output," Changing the configuration failed (error %d). Try to continue\n", ret);
+		return 0;
+	} else {
+		SHOW_PROGRESS(output," OK, configuration set\n");
+		return 1;
+	}
+}
+
+
+int switchAltSetting ()
+{
+	int ret;
+	SHOW_PROGRESS(output,"Change to alt setting %i ...\n", AltSetting);
+	ret = libusb_claim_interface(devh, Interface);
+	if (ret < 0) {
+		SHOW_PROGRESS(output," Could not claim interface (error %d). Skip AltSetting\n", ret);
+		return 0;
+	}
+	ret = libusb_set_interface_alt_setting(devh, Interface, AltSetting);
+	libusb_release_interface(devh, Interface);
+	if (ret < 0) {
+		SHOW_PROGRESS(output," Change to alt setting returned error %d. Try to continue\n", ret);
+		return 0;
+	} else
+		return 1;
+}
+
+
+void switchHuaweiMode ()
+{
+	int ret;
+	SHOW_PROGRESS(output,"Send old Huawei control message ...\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
+			LIBUSB_REQUEST_SET_FEATURE, 00000001, 0, buffer, 0, 1000);
+
+	if (ret != 0) {
+		fprintf(stderr, "Error: Huawei control message failed (error %d). Abort\n\n", ret);
+		exit(0);
+	}
+}
+
+
+void switchSierraMode ()
+{
+	int ret;
+	SHOW_PROGRESS(output,"Send Sierra control message\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
+		LIBUSB_REQUEST_SET_INTERFACE, 00000001, 0, buffer, 0, 1000);
+	if (ret == LIBUSB_ERROR_PIPE) {
+		SHOW_PROGRESS(output," communication with device stopped. May have switched modes anyway\n");
+	    return;
+	}
+	if (ret < 0) {
+		fprintf(stderr, "Error: Sierra control message failed (error %d). Abort\n\n", ret);
+	    exit(0);
+	}
+}
+
+
+void switchGCTMode ()
+{
+	int ret;
+	ret = libusb_claim_interface(devh, Interface);
+	if (ret != 0) {
+		SHOW_PROGRESS(output," Could not claim interface (error %d). Skip GCT sequence\n", ret);
+		return;
+	}
+	SHOW_PROGRESS(output,"Send GCT control message 1 ...\n type (should be 161/0xA1): %d",
+			LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN);
+
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN,
+			0xa0, 0, Interface, buffer, 1, 1000);
+
+	if (ret < 0) {
+		SHOW_PROGRESS(output," GCT control message 1 failed (error %d), continue anyway ...\n", ret);
+	}
+	SHOW_PROGRESS(output,"Send GCT control message 2 ...\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN,
+			0xfe, 0, Interface, buffer, 1, 1000);
+
+	if (ret < 0) {
+		SHOW_PROGRESS(output," GCT control message 2 failed (error %d). Abort\n\n", ret);
+	}
+	libusb_release_interface(devh, Interface);
+	if (ret < 0)
+		exit(0);
+}
+
+
+void switchKobilMode() {
+	int ret;
+	SHOW_PROGRESS(output,"Send Kobil control message ...\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
+			0x88, 0, 0, buffer, 8, 1000);
+
+	if (ret < 0) {
+		fprintf(stderr, "Error: Kobil control message failed (error %d). Abort\n\n", ret);
+		exit(0);
+	}
+}
+
+
+void switchQisdaMode () {
+	int ret;
+	SHOW_PROGRESS(output,"Sending Qisda control message ...\n");
+	memcpy(buffer, "\x05\x8c\x04\x08\xa0\xee\x20\x00\x5c\x01\x04\x08\x98\xcd\xea\xbf", 16);
+	ret = libusb_control_transfer(devh, 0x40, 0x04, 0, 0, buffer, 16, 1000);
+	if (ret < 0) {
+		fprintf(stderr, "Error: Qisda control message failed (error %d). Abort\n\n", ret);
+		exit(0);
+	}
+}
+
+
+void switchQuantaMode() {
+	int ret;
+	SHOW_PROGRESS(output,"Send Quanta control message ...\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
+			0xff, 0, 0, buffer, 0, 1000);
+
+	if (ret < 0) {
+		SHOW_PROGRESS(output,"Error: Quanta control message failed (error %d). Abort\n\n", ret);
+		exit(0);
+	}
+}
+
+
+void switchBlackberryMode ()
+{
+	int ret;
+	SHOW_PROGRESS(output,"Send Blackberry control message 1 ...\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
+			0xb1, 0x0000, 0, buffer, 8, 1000);
+
+	if (ret != 8) {
+		fprintf(stderr, "Error: Blackberry control message 1 failed (result %d)\n", ret);
+	}
+	SHOW_PROGRESS(output,"Send Blackberry control message 2 ...\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
+			0xa9, 0x000e, 0, buffer, 2, 1000);
+
+	if (ret != 2) {
+		fprintf(stderr, "Error: Blackberry control message 2 failed (result %d). Abort\n\n", ret);
+		exit(0);
+	}
+}
+
+
+void switchPantechMode()
+{
+	int ret;
+	SHOW_PROGRESS(output,"Send Pantech control message, wValue %d ...\n", PantechMode);
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
+			0x70, PantechMode, 0, buffer, 0, 1000);
+
+	if (ret < 0) {
+		SHOW_PROGRESS(output," Error: Pantech control message failed (error %d). Abort\n\n", ret);
+		exit(0);
+	}
+}
+
+
+#define EP_OUT 0x02
+#define EP_IN 0x81
+#define SIZE 0x08
+
+#define MOBILE_ACTION_READLOOP1 63
+#define MOBILE_ACTION_READLOOP2 73
+
+/* The code here is statically derived from sniffing (and confirmed working).
+ * However I bet it could be simplified significantly.
+ */
+
+void switchActionMode ()
+{
+	int ret, i;
+	SHOW_PROGRESS(output,"Send MobileAction control sequence ...\n");
+	memcpy(buffer, "\xb0\x04\x00\x00\x02\x90\x26\x86", SIZE);
+	libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
+			0x09, 0x0300, 0, buffer, SIZE, 1000);
+
+	memcpy(buffer, "\xb0\x04\x00\x00\x02\x90\x26\x86", SIZE);
+	libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
+			0x09, 0x0300, 0, buffer, SIZE, 1000);
+
+	usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	memcpy(buffer, "\x37\x01\xfe\xdb\xc1\x33\x1f\x83", SIZE);
+	usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
+	usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	memcpy(buffer, "\x37\x0e\xb5\x9d\x3b\x8a\x91\x51", SIZE);
+	usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
+	usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	memcpy(buffer, "\x34\x87\xba\x0d\xfc\x8a\x91\x51", SIZE);
+	usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
+	for (i=0; i < MOBILE_ACTION_READLOOP1; i++) {
+		usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	}
+	memcpy(buffer, "\x37\x01\xfe\xdb\xc1\x33\x1f\x83", SIZE);
+	usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
+	usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	memcpy(buffer, "\x37\x0e\xb5\x9d\x3b\x8a\x91\x51", SIZE);
+	usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
+	usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	memcpy(buffer, "\x34\x87\xba\x0d\xfc\x8a\x91\x51", SIZE);
+	usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
+	for (i=0; i < MOBILE_ACTION_READLOOP2; i++) {
+		usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	}
+	memcpy(buffer, "\x33\x04\xfe\x00\xf4\x6c\x1f\xf0", SIZE);
+	usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
+	usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	memcpy(buffer, "\x32\x07\xfe\xf0\x29\xb9\x3a\xf0", SIZE);
+	ret = usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
+	usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	if (ret < 0) {
+		SHOW_PROGRESS(output," MobileAction control sequence did not complete\n"
+			" Last error was %d\n",ret);
+	} else {
+		SHOW_PROGRESS(output," MobileAction control sequence complete\n");
+	}
+}
+
+
+#define SQN_SET_DEVICE_MODE_REQUEST		0x0b
+#define SQN_GET_DEVICE_MODE_REQUEST		0x0a
+
+#define SQN_DEFAULT_DEVICE_MODE			0x00
+#define SQN_MASS_STORAGE_MODE			0x01
+#define SQN_CUSTOM_DEVICE_MODE			0x02
+
+void switchSequansMode()
+{
+
+	int ret;
+	SHOW_PROGRESS(output,"Send Sequans control message\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE
+			| LIBUSB_ENDPOINT_OUT, SQN_SET_DEVICE_MODE_REQUEST, SQN_CUSTOM_DEVICE_MODE,
+			0, buffer, 0, 1000);
+
+	if (ret < 0) {
+		fprintf(stderr, "Error: Sequans request failed (error %d). Abort\n\n", ret);
+	    exit(0);
+	}
+}
+
+
+void switchCiscoMode()
+{
+	int ret, i, j;
+
+	strcpy(Messages[0],"55534243f83bcd810002000080000afd000000030000000100000000000000");
+	strcpy(Messages[1],"55534243984300820002000080000afd000000070000000100000000000000");
+	strcpy(Messages[2],"55534243984300820000000000000afd000100071000000000000000000000");
+	strcpy(Messages[3],"55534243984300820002000080000afd000200230000000100000000000000");
+	strcpy(Messages[4],"55534243984300820000000000000afd000300238200000000000000000000");
+	strcpy(Messages[5],"55534243984300820002000080000afd000200260000000100000000000000");
+	strcpy(Messages[6],"55534243984300820000000000000afd00030026c800000000000000000000");
+	strcpy(Messages[7],"55534243d84c04820002000080000afd000010730000000100000000000000");
+	strcpy(Messages[8],"55534243d84c04820002000080000afd000200240000000100000000000000");
+	strcpy(Messages[9],"55534243d84c04820000000000000afd000300241300000000000000000000");
+	strcpy(Messages[10],"55534243d84c04820000000000000afd000110732400000000000000000000");
+
+	SHOW_PROGRESS(output,"Set up Cisco interface %d\n", Interface);
+	ret = libusb_claim_interface(devh, Interface);
+	if (ret < 0) {
+		SHOW_PROGRESS(output," Could not claim interface (error %d). Abort\n", ret);
+		abortExit();
+	}
+//	libusb_clear_halt(devh, MessageEndpoint);
+	if (show_progress)
+		fflush(output);
+
+//	ret = read_bulk(ResponseEndpoint, ByteString, 13);
+//	SHOW_PROGRESS(output," Extra response (CSW) read, result %d\n",ret);
+
+	for (i=0; i<11; i++) {
+		if ( sendMessage(Messages[i], i+1) )
+			goto skip;
+
+		for (j=1; j<4; j++) {
+
+			SHOW_PROGRESS(output," Read the CSW for bulk message %d (attempt %d) ...\n",i+1,j);
+			ret = read_bulk(ResponseEndpoint, ByteString, 13);
+			SHOW_PROGRESS(output,"\n");
+
+			if (ret < 0)
+				goto skip;
+			if (ret == 13)
+				break;
+		}
+	}
+	libusb_clear_halt(devh, MessageEndpoint);
+	libusb_clear_halt(devh, ResponseEndpoint);
+
+	ReleaseDelay = 2000;
+	SHOW_PROGRESS(output,"Wait for %d ms before releasing interface ...\n", ReleaseDelay);
+	usleep(ReleaseDelay*1000);
+
+	ret = libusb_release_interface(devh, Interface);
+	if (ret < 0)
+		goto skip;
+	return;
+
+skip:
+	SHOW_PROGRESS(output,"Device returned error %d, skip further commands\n", ret);
+	libusb_close(devh);
+	devh = NULL;
+}
+
+
+int switchSonyMode ()
+{
+	int ret, i, found;
+	detachDriver();
+
+	if (CheckSuccess) {
+		CheckSuccess = 0;
+	}
+
+	SHOW_PROGRESS(output,"Send Sony control message\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE
+			| LIBUSB_ENDPOINT_IN, 0x11, 2, 0, buffer, 3, 100);
+
+	if (ret < 0) {
+		fprintf(stderr, "Error: Sony control message failed (error %d). Abort\n\n", ret);
+		exit(0);
+	} else
+		SHOW_PROGRESS(output," OK, control message sent, wait for device to return ...\n");
+
+	libusb_close(devh);
+	devh = NULL;
+
+	/* Now waiting for the device to reappear */
+	devnum=-1;
+	busnum=-1;
+	i=0;
+	dev = 0;
+	while ( dev == 0 && i < 30 ) {
+		if ( i > 5 ) {
+			dev = search_devices(&found, DefaultVendor, DefaultProductList, TargetClass,
+					0, SEARCH_TARGET);
+		}
+		if ( dev != 0 )
+			break;
+		sleep(1);
+		if (show_progress) {
+			fprintf(output,"#");
+			fflush(stdout);
+		}
+		i++;
+	}
+	SHOW_PROGRESS(output,"\n After %d seconds:",i);
+	if ( dev ) {
+		SHOW_PROGRESS(output," device came back, proceed\n");
+		libusb_open(dev, &devh);
+		if (devh == 0) {
+			fprintf(stderr, "Error: could not get handle on device\n");
+			return 0;
+		}
+	} else {
+		SHOW_PROGRESS(output," device still gone, abort\n");
+		return 0;
+	}
+	sleep(1);
+
+	SHOW_PROGRESS(output,"Send Sony control message again ...\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE
+			| LIBUSB_ENDPOINT_IN, 0x11, 2, 0, buffer, 3, 100);
+
+	if (ret < 0) {
+		fprintf(stderr, "Error: Sony control message (2) failed (error %d)\n", ret);
+		return 0;
+	}
+	SHOW_PROGRESS(output," OK, control message sent\n");
+	return 1;
+}
+
+
+/* Detach driver
+ */
+int detachDriver()
+{
+
+	int ret;
+	SHOW_PROGRESS(output,"Looking for active driver ...\n");
+	ret = libusb_kernel_driver_active(devh, 0);
+	if (ret == LIBUSB_ERROR_NOT_SUPPORTED) {
+		fprintf(output," Can't do driver detection on this platform.\n");
+		return 2;
+	}
+	if (ret < 0) {
+		fprintf(output," Driver check failed with error %d. Try to continue\n", ret);
+		return 2;
+	}
+	if (ret == 0) {
+		SHOW_PROGRESS(output," No active driver found. Detached before or never attached\n");
+		return 1;
+	}
+
+	ret = libusb_detach_kernel_driver(devh, Interface);
+	if (ret == LIBUSB_ERROR_NOT_SUPPORTED) {
+		fprintf(output," Can't do driver detaching on this platform.\n");
+		return 2;
+	}
+	if (ret == 0) {
+		SHOW_PROGRESS(output," OK, driver detached\n");
+	} else
+		SHOW_PROGRESS(output," Driver detach failed (error %d). Try to continue\n", ret);
+	return 1;
+}
+
+
+int sendMessage(char* message, int count)
+{
+	int ret, message_length;
+
+	if (strlen(message) % 2 != 0) {
+		fprintf(stderr, "Error: MessageContent %d hex string has uneven length. Skipping ...\n", count);
+		return 1;
+	}
+	message_length = strlen(message) / 2;
+	if ( hexstr2bin(message, ByteString, message_length) == -1) {
+		fprintf(stderr, "Error: MessageContent %d %s\n is not a hex string. Skipping ...\n",
+				count, MessageContent);
+
+		return 1;
+	}
+	SHOW_PROGRESS(output,"Trying to send message %d to endpoint 0x%02x ...\n", count, MessageEndpoint);
+	fflush(output);
+	ret = write_bulk(MessageEndpoint, ByteString, message_length);
+	if (ret == LIBUSB_ERROR_NO_DEVICE)
+		return 1;
+
+	return 0;
+}
+
+
+int checkSuccess()
+{
+	int ret, i;
+	int newTargetCount, success=0;
+
+	SHOW_PROGRESS(output,"\nCheck for mode switch (max. %d times, once per second) ...\n", CheckSuccess);
+	sleep(1);
+
+	/* If target parameters are given, don't check for vanished device
+	 * Changed for Cisco AM10 where a new device is added while the install
+	 * storage device stays active
+	 */
+	if ((TargetVendor || TargetClass) && devh) {
+		libusb_close(devh);
+		devh = NULL;
+	}
+
+	/* if target ID is not given but target class is, assign default as target;
+	 * it will be needed for sysmode output
+	 */
+	if (!TargetVendor && TargetClass) {
+		TargetVendor = DefaultVendor;
+		TargetProduct = DefaultProduct;
+	}
+
+	/* devh is 0 if device vanished during command transmission or if target params were given
+	 */
+	if (devh)
+		for (i=0; i < CheckSuccess; i++) {
+
+			/* Test if default device still can be accessed; positive result does
+			 * not necessarily mean failure
+			 */
+			SHOW_PROGRESS(output," Wait for original device to vanish ...\n");
+
+			ret = libusb_claim_interface(devh, Interface);
+			libusb_release_interface(devh, Interface);
+			if (ret < 0) {
+				SHOW_PROGRESS(output," Original device can't be accessed anymore. Good.\n");
+				libusb_close(devh);
+				devh = NULL;
+				break;
+			}
+			if (i == CheckSuccess-1) {
+				SHOW_PROGRESS(output," Original device still present after the timeout\n\n"
+						"Mode switch most likely failed. Bye!\n\n");
+			} else
+				sleep(1);
+		}
+
+	if ( TargetVendor && (TargetProduct > -1 || TargetProductList[0] != '\0') ) {
+
+		/* Recount target devices (compare with previous count) if target data is given.
+		 * Target device on the same bus with higher device number is returned,
+		 * description is read for syslog message
+		 */
+		for (i=i; i < CheckSuccess; i++) {
+			SHOW_PROGRESS(output," Search for target devices ...\n");
+			dev = search_devices(&newTargetCount, TargetVendor, TargetProductList,
+					TargetClass, 0, SEARCH_TARGET);
+
+			if (dev && (newTargetCount > targetDeviceCount)) {
+				if (verbose) {
+					libusb_open(dev, &devh);
+					fprintf(output,"\nFound target device %03d on bus %03d\n",
+							libusb_get_device_address(dev), libusb_get_bus_number(dev));
+
+					fprintf(output,"\nTarget device description data\n");
+					deviceDescription();
+					libusb_close(devh);
+					devh = NULL;
+				}
+				SHOW_PROGRESS(output," Found correct target device\n\n"
+						"Mode switch succeeded. Bye!\n\n");
+
+				success = 2;
+				break;
+			}
+			if (i == CheckSuccess-1) {
+				SHOW_PROGRESS(output," No new devices in target mode or class found\n\n"
+						"Mode switch has failed. Bye!\n\n");
+			} else
+				sleep(1);
+		}
+	} else
+		/* No target data given, rely on the vanished device */
+		if (!devh) {
+			SHOW_PROGRESS(output," (For a better success check provide target IDs or class)\n");
+			SHOW_PROGRESS(output," Original device vanished after switching\n\n"
+					"Mode switch most likely succeeded. Bye!\n\n");
+			success = 1;
+		}
+
+	switch (success) {
+		case 3: 
+			if (sysmode)
+				syslog(LOG_NOTICE, "switched to new device, but hit libusb1 bug");
+			TargetProduct = -1;
+			success = 1;
+			break;
+		case 2: 
+			if (sysmode)
+				syslog(LOG_NOTICE, "switched to %04x:%04x on %03d/%03d", TargetVendor,
+						TargetProduct, busnum, devnum);
+
+			success = 1;
+			break;
+		case 1:
+			if (sysmode)
+				syslog(LOG_NOTICE, "device seems to have switched");
+		default:
+			;
+	}
+	if (sysmode)
+		closelog();
+
+	return success;
+
+}
+
+
+int write_bulk(int endpoint, unsigned char *message, int length)
+{
+	int ret = usb_bulk_io(devh, endpoint, message, length, 3000);
+	if (ret >= 0 ) {
+		SHOW_PROGRESS(output," OK, message successfully sent\n");
+	} else
+		if (ret == LIBUSB_ERROR_NO_DEVICE) {
+			SHOW_PROGRESS(output," Device seems to have vanished right after sending. Good.\n");
+		} else
+			SHOW_PROGRESS(output," Sending the message returned error %d. Try to continue\n", ret);
+	return ret;
+
+}
+
+
+int read_bulk(int endpoint, unsigned char *buffer, int length)
+{
+	int ret = usb_bulk_io(devh, endpoint, buffer, length, 3000);
+	if (ret >= 0 ) {
+		SHOW_PROGRESS(output," Response successfully read (%d bytes)", ret);
+	} else
+		if (ret == LIBUSB_ERROR_NO_DEVICE) {
+			SHOW_PROGRESS(output," Device seems to have vanished after reading. Good.");
+		} else
+			SHOW_PROGRESS(output," Response reading failed (error %d)", ret);
+	return ret;
+
+}
+
+
+void release_usb_device(int __attribute__((unused)) dummy)
+{
+	SHOW_PROGRESS(output,"Program cancelled by system. Bye!\n\n");
+	if (devh)
+		libusb_release_interface(devh, Interface);
+	close_all();
+	exit(0);
+
+}
+
+
+/* Iterates over busses and devices, counts the ones which match the given
+ * parameters and returns the last one of them
+*/
+struct libusb_device* search_devices( int *numFound, int vendor, char* productList,
+		int targetClass, int configuration, int mode)
+{
+	char *listcopy=NULL, *token;
+	unsigned char buffer[2];
+	int devClass, product;
+	struct libusb_device* right_dev = NULL;
+//	struct libusb_device_handle *testdevh;
+	struct libusb_device **devs;
+	int i=0;
+
+	/* only target class given, target vendor and product assumed unchanged */
+	if ( targetClass && !(vendor || strlen(productList)) ) {
+		vendor = DefaultVendor;
+		productList = DefaultProductList;
+	}
+	*numFound = 0;
+
+	/* Sanity check */
+	if (!vendor || productList == '\0')
+		return NULL;
+
+	listcopy = malloc(strlen(productList)+1);
+
+	if (libusb_get_device_list(ctx, &devs) < 0) {
+		perror("Libusb failed to get USB access!");
+		return 0;
+	}
+
+	while ((dev = devs[i++]) != NULL) {
+		struct libusb_device_descriptor descriptor;
+		libusb_get_device_descriptor(dev, &descriptor);
+
+		if (mode == SEARCH_BUSDEV) {
+			if ((libusb_get_bus_number(dev) != busnum) ||
+				(libusb_get_device_address(dev) != devnum))
+				continue;
+			else
+				SHOW_PROGRESS(output," bus/device number matched\n");
+		}
+
+		if (verbose)
+			fprintf (output,"  found USB ID %04x:%04x\n",
+					descriptor.idVendor, descriptor.idProduct);
+		if (descriptor.idVendor != vendor)
+			continue;
+		if (verbose)
+			fprintf (output,"   vendor ID matched\n");
+
+		strcpy(listcopy, productList);
+		token = strtok(listcopy, ",");
+		while (token != NULL) {
+			if (strlen(token) != 4) {
+				SHOW_PROGRESS(output,"Error: entry in product ID list has wrong length: %s. "
+						"Ignored\n", token);
+
+				goto NextToken;
+			}
+			if ( hexstr2bin(token, buffer, strlen(token)/2) == -1) {
+				SHOW_PROGRESS(output,"Error: entry in product ID list is not a hex string: %s. "
+						"Ignored\n", token);
+
+				goto NextToken;
+			}
+			product = 0;
+			product += (unsigned char)buffer[0];
+			product <<= 8;
+			product += (unsigned char)buffer[1];
+			if (product == descriptor.idProduct) {
+				SHOW_PROGRESS(output,"   product ID matched\n");
+
+				if (targetClass != 0) {
+					// TargetClass is set, check class of first interface
+					struct libusb_device_descriptor descriptor;
+					libusb_get_device_descriptor(dev, &descriptor);
+					devClass = descriptor.bDeviceClass;
+					struct libusb_config_descriptor *config;
+					libusb_get_config_descriptor(dev, 0, &config);
+					int ifaceClass = config->interface[0].altsetting[0].bInterfaceClass;
+					libusb_free_config_descriptor(config);
+					if (devClass == 0)
+						devClass = ifaceClass;
+					else
+						/* Check for some quirky devices */
+						if (devClass != ifaceClass)
+							devClass = ifaceClass;
+					if (devClass == targetClass) {
+						if (verbose)
+							fprintf (output,"   target class %02x matches\n", targetClass);
+						if (mode == SEARCH_TARGET) {
+							(*numFound)++;
+							right_dev = dev;
+							if (verbose)
+								fprintf (output,"   count device\n");
+						} else
+							if (verbose)
+								fprintf (output,"   device not counted, target class reached\n");
+					} else {
+						if (verbose)
+							fprintf (output,"   device class %02x not matching target\n", devClass);
+						if (mode == SEARCH_DEFAULT || mode == SEARCH_BUSDEV) {
+							(*numFound)++;
+							right_dev = dev;
+							if (verbose)
+								fprintf (output,"   count device\n");
+						}
+					}
+				} else if (configuration > 0) {
+					// Configuration parameter is set, check device configuration
+					int testconfig = get_current_config_value(dev);
+					if (testconfig != configuration) {
+						if (verbose)
+							fprintf (output,"   device configuration %d not matching target\n",
+									testconfig);
+
+						(*numFound)++;
+						right_dev = dev;
+						if (verbose)
+							fprintf (output,"   count device\n");
+					} else
+						if (verbose)
+							fprintf (output,"   device not counted, target configuration reached\n");
+				} else {
+					// Neither TargetClass nor Configuration are set
+					(*numFound)++;
+					right_dev = dev;
+					if (mode == SEARCH_BUSDEV)
+						break;
+				}
+			}
+
+			NextToken:
+			token = strtok(NULL, ",");
+		}
+	}
+	if (listcopy != NULL)
+		free(listcopy);
+	return right_dev;
+}
+
+
+/* Autodetect bulk endpoints (ab) */
+
+int find_first_bulk_endpoint(int direction)
+{
+	int i, j;
+	const struct libusb_interface_descriptor *alt;
+	const struct libusb_endpoint_descriptor *ep;
+
+	for (j=0; j < active_config->bNumInterfaces; j++) {
+		alt = &(active_config->interface[j].altsetting[0]);
+		if (alt->bInterfaceNumber == Interface) {
+			for (i=0; i < alt->bNumEndpoints; i++) {
+				ep = &(alt->endpoint[i]);
+				if ( ( (ep->bmAttributes & LIBUSB_ENDPOINT_ADDRESS_MASK) == LIBUSB_TRANSFER_TYPE_BULK)
+						&& ( (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == direction ) ) {
+
+					return ep->bEndpointAddress;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+
+int get_current_config_value()
+{
+	SHOW_PROGRESS(output,"Get the current device configuration ...\n");
+	if (active_config != NULL) {
+		libusb_free_config_descriptor(active_config);
+		active_config = NULL;
+	}
+	int ret = libusb_get_active_config_descriptor(dev, &active_config);
+	if (ret < 0) {
+		SHOW_PROGRESS(output," Determining the active configuration failed (error %d). Abort\n", ret);
+		abortExit();
+	}
+	return active_config->bConfigurationValue;
+}
+
+
+int get_interface_class()
+{
+	int i;
+	for (i=0; i < active_config->bNumInterfaces; i++) {
+		if (active_config->interface[i].altsetting[0].bInterfaceNumber == Interface)
+			return active_config->interface[i].altsetting[0].bInterfaceClass;
+	}
+	return -1;
+}
+
+
+/* Parameter parsing */
+
+char* ReadParseParam(const char* FileName, char *VariableName)
+{
+	static int numLines = 0;
+	static char* ConfigBuffer[MAXLINES];
+	char *VarName, *Comment=NULL, *Equal=NULL;
+	char *FirstQuote, *LastQuote, *P1, *P2;
+	int Line=0;
+	unsigned Len=0, Pos=0;
+	char Str[LINE_DIM], *token, *configPos;
+	FILE *file = NULL;
+
+	// Reading and storing input during the first call
+	if (numLines==0) {
+		if (strncmp(FileName,"##",2) == 0) {
+			if (verbose) fprintf(output,"\nRead long config from command line\n");
+			// "Embedded" configuration data
+			configPos = (char*)FileName;
+			token = strtok(configPos, "\n");
+			strncpy(Str,token,LINE_DIM-1);
+		} else {
+			if (strcmp(FileName, "stdin")==0) {
+				if (verbose) fprintf(output,"\nRead long config from stdin\n");
+				file = stdin;
+			} else {
+				if (verbose) fprintf(output,"\nRead config file: %s\n", FileName);
+				file=fopen(FileName, "r");
+			}
+			if (file==NULL) {
+				fprintf(stderr, "Error: Could not find file %s. Abort\n\n", FileName);
+				abortExit();
+			} else {
+				token = fgets(Str, LINE_DIM-1, file);
+			}
+		}
+		while (token != NULL && numLines < MAXLINES) {
+//			Line++;
+			Len=strlen(Str);
+			if (Len==0)
+				goto NextLine;
+			if (Str[Len-1]=='\n' or Str[Len-1]=='\r')
+				Str[--Len]='\0';
+			Equal = strchr (Str, '=');			// search for equal sign
+			Pos = strcspn (Str, ";#!");			// search for comment
+			Comment = (Pos==Len) ? NULL : Str+Pos;
+			if (Equal==NULL or ( Comment!=NULL and Comment<=Equal))
+				goto NextLine;	// Comment or irrelevant, don't save
+			Len=strlen(Str)+1;
+			ConfigBuffer[numLines] = malloc(Len*sizeof(char));
+			strcpy(ConfigBuffer[numLines],Str);
+			numLines++;
+		NextLine:
+			if (file == NULL) {
+				token = strtok(NULL, "\n");
+				if (token != NULL)
+					strncpy(Str,token,LINE_DIM-1);
+			} else
+				token = fgets(Str, LINE_DIM-1, file);
+		}
+		if (file != NULL)
+			fclose(file);
+	}
+
+	// Now checking for parameters
+	Line=0;
+	while (Line < numLines) {
+		strcpy(Str,ConfigBuffer[Line]);
+		Equal = strchr (Str, '=');			// search for equal sign
+		*Equal++ = '\0';
+
+		// String
+		FirstQuote=strchr (Equal, '"');		// search for double quote char
+		LastQuote=strrchr (Equal, '"');
+		if (FirstQuote!=NULL) {
+			if (LastQuote==NULL) {
+				fprintf(stderr, "Error reading parameters from file %s - "
+						"Missing end quote:\n%s\n", FileName, Str);
+
+				goto Next;
+			}
+			*FirstQuote=*LastQuote='\0';
+			Equal=FirstQuote+1;
+		}
+
+		// removes leading/trailing spaces
+		Pos=strspn (Str, " \t");
+		if (Pos==strlen(Str)) {
+			fprintf(stderr, "Error reading parameters from file %s - "
+					"Missing variable name:\n%s\n", FileName, Str);
+
+			goto Next;
+		}
+		while ((P1=strrchr(Str, ' '))!=NULL or (P2=strrchr(Str, '\t'))!=NULL)
+			if (P1!=NULL) *P1='\0';
+			else if (P2!=NULL) *P2='\0';
+		VarName=Str+Pos;
+
+		Pos=strspn (Equal, " \t");
+		if (Pos==strlen(Equal)) {
+			fprintf(stderr, "Error reading parameter from file %s - "
+					"Missing value:\n%s\n", FileName, Str);
+
+			goto Next;
+		}
+		Equal+=Pos;
+
+		if (strcmp(VarName, VariableName)==0) {		// Found it
+			return Equal;
+		}
+	Next:
+		Line++;
+	}
+
+	return NULL;
+}
+
+
+int hex2num(char c)
+{
+	if (c >= '0' && c <= '9')
+	return c - '0';
+	if (c >= 'a' && c <= 'f')
+	return c - 'a' + 10;
+	if (c >= 'A' && c <= 'F')
+	return c - 'A' + 10;
+	return -1;
+}
+
+
+int hex2byte(const char *hex)
+{
+	int a, b;
+	a = hex2num(*hex++);
+	if (a < 0)
+		return -1;
+	b = hex2num(*hex++);
+	if (b < 0)
+		return -1;
+	return (a << 4) | b;
+}
+
+
+int hexstr2bin(const char *hex, unsigned char *buffer, int len)
+{
+	int i;
+	int a;
+	const char *ipos = hex;
+	unsigned char *opos = buffer;
+
+	for (i = 0; i < len; i++) {
+	a = hex2byte(ipos);
+	if (a < 0)
+		return -1;
+	*opos++ = (unsigned char) a;
+	ipos += 2;
+	}
+	return 0;
+}
+
+
+void close_all()
+{
+	int i;
+	if (Messages) {
+		for ( i = 0; i < MSG_DIM; i++ ) {
+			free(Messages[i]);
+		}
+		free(Messages);
+	}
+	if (active_config)
+		libusb_free_config_descriptor(active_config);
+	if (devh)
+		libusb_close(devh);
+	// libusb_exit will crash on Raspbian 7, crude protection
+#ifndef __ARMEL__
+	libusb_exit(NULL);
+#endif
+	if (sysmode)
+		closelog();
+}
+
+
+void abortExit()
+{
+	close_all();
+	exit(1);
+}
+
+
+void printVersion()
+{
+	char* version = VERSION;
+	fprintf(output,"\n * usb_modeswitch: handle USB devices with multiple modes\n"
+		" * Version %s (C) Josua Dietze 2016\n"
+		" * Based on libusb1/libusbx\n\n"
+		" ! PLEASE REPORT NEW CONFIGURATIONS !\n\n", version);
+}
+
+
+void printHelp()
+{
+	fprintf(output,"\nUsage: usb_modeswitch [<params>] [-c filename]\n\n"
+	" -h, --help                    this help\n"
+	" -e, --version                 print version information and exit\n"
+	" -j, --find-mbim               return config no. with MBIM interface, exit\n\n"
+	" -v, --default-vendor NUM      vendor ID of original mode (mandatory)\n"
+	" -p, --default-product NUM     product ID of original mode (mandatory)\n"
+	" -V, --target-vendor NUM       target mode vendor ID (optional)\n"
+	" -P, --target-product NUM      target mode product ID (optional)\n"
+	" -C, --target-class NUM        target mode device class (optional)\n"
+	" -b, --bus-num NUM             system bus number of device (for hard ID)\n"
+	" -g, --device-num NUM          system device number (for hard ID)\n"
+	" -m, --message-endpoint NUM    direct the message transfer there (optional)\n"
+	" -M, --message-content <msg>   message to send (hex number as string)\n"
+	" -2 <msg>, -3 <msg>            additional messages to send (-n recommended)\n"
+	" -w, --release-delay NUM       wait NUM ms before releasing the interface\n"
+	" -n, --need-response           obsolete, no effect (always on)\n"
+	" -r, --response-endpoint NUM   read response from there (optional)\n"
+	" -K, --std-eject               send standard EJECT sequence\n"
+	" -d, --detach-only             detach the active driver, no further action\n"
+	" -H, --huawei-mode             apply a special procedure\n"
+	" -J, --huawei-new-mode         apply a special procedure\n"
+	" -S, --sierra-mode             apply a special procedure\n"
+	" -O, --sony-mode               apply a special procedure\n"
+	" -G, --gct-mode                apply a special procedure\n"
+	" -N, --sequans-mode            apply a special procedure\n"
+	" -A, --mobileaction-mode       apply a special procedure\n"
+	" -T, --kobil-mode              apply a special procedure\n"
+	" -L, --cisco-mode              apply a special procedure\n"
+	" -B, --qisda-mode              apply a special procedure\n"
+	" -E, --quanta-mode             apply a special procedure\n"
+	" -F, --pantech-mode NUM        apply a special procedure, pass NUM through\n"
+	" -Z, --blackberry-mode         apply a special procedure\n"
+	" -U, --option-mode             apply a special procedure\n"
+	" -R, --reset-usb               reset the device after all other actions\n"
+	" -Q, --quiet                   don't show progress or error messages\n"
+	" -W, --verbose                 print all settings and debug output\n"
+	" -D, --sysmode                 specific result and syslog message\n"
+	" -s, --success <seconds>       switching result check with timeout\n"
+	" -I, --inquire                 obsolete, no effect\n\n"
+	" -c, --config-file <filename>  load long configuration from file\n\n"
+	" -t, --stdinput                read long configuration from stdin\n\n"
+	" -f, --long-config <text>      get long configuration from string\n\n"
+	" -i, --interface NUM           select initial USB interface (default 0)\n"
+	" -u, --configuration NUM       select USB configuration\n"
+	" -a, --altsetting NUM          select alternative USB interface setting\n\n");
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.conf b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.conf
new file mode 100755
index 0000000..7c68993
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.conf
@@ -0,0 +1,31 @@
+# Configuration for the usb_modeswitch package, a mode switching tool for
+# USB devices providing multiple states or modes
+#
+# Evaluated by the wrapper script /usr/sbin/usb_modeswitch_dispatcher
+#
+# To enable an option, set it to "1", "yes" or "true" (case doesn't matter)
+# Everything else counts as "disable"
+
+
+# Disable automatic mode switching globally (e.g. to access the original
+# install storage)
+
+DisableSwitching=0
+
+# Disable check for MBIM module presence and configuration globally (to aid
+# special embedded environments)
+
+DisableMBIMGlobal=0
+
+# Enable logging (results in a extensive report file in /var/log, named
+# "usb_modeswitch_<interface-name>" and probably others
+
+EnableLogging=0
+
+
+# Optional increase of "delay_use" for the usb-storage driver; there are hints
+# that a recent kernel default change to 1 sec. may lead to problems, particu-
+# larly with USB 3.0 ports. Set this to at least 3 (seconds) in that case.
+# Does nothing if the current system value is same or higher
+
+#SetStorageDelay=4
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_002a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_002a
new file mode 100755
index 0000000..9813a20
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_002a
@@ -0,0 +1,4 @@
+# HP LaserJet Professional P1102
+TargetClass=0x07
+MessageContent="555342431234567800000000000006d0000000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_521d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_521d
new file mode 100755
index 0000000..609c7a1
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_521d
@@ -0,0 +1,2 @@
+# HP hs3110
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_531d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_531d
new file mode 100755
index 0000000..8b5a348
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_531d
@@ -0,0 +1,2 @@
+# HP hs3120
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_541d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_541d
new file mode 100755
index 0000000..ecb0c48
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_541d
@@ -0,0 +1,2 @@
+# HP hs3114
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_581d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_581d
new file mode 100755
index 0000000..b2f662d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_581d
@@ -0,0 +1,2 @@
+# HP hs4112
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_631d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_631d
new file mode 100755
index 0000000..ff2dcc7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_631d
@@ -0,0 +1,2 @@
+# HP lt4225
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_641d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_641d
new file mode 100755
index 0000000..131c9d7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_641d
@@ -0,0 +1,2 @@
+# HP lt4226
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_681d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_681d
new file mode 100755
index 0000000..60b7f75
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_681d
@@ -0,0 +1,2 @@
+# HP lt4227
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_911d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_911d
new file mode 100755
index 0000000..b9a6a13
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_911d
@@ -0,0 +1,2 @@
+# HP lt4211
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_931d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_931d
new file mode 100755
index 0000000..08a3290
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_931d
@@ -0,0 +1,2 @@
+# HP lt4110
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_9a1d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_9a1d
new file mode 100755
index 0000000..d3b8b9d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_9a1d
@@ -0,0 +1,2 @@
+# HP lt4114
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_1000
new file mode 100755
index 0000000..089c437
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_1000
@@ -0,0 +1,4 @@
+# Quanta MU-Q101
+TargetVendor=0x0408
+TargetProduct=0xea02
+MessageContent="55534243123456780002000000000a2a000000003300000100000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea17 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea17
new file mode 100755
index 0000000..562377a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea17
@@ -0,0 +1,4 @@
+# Quanta 1KR / USB-lte 7410
+TargetVendor=0x0408
+TargetProduct=0xea16
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea25 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea25
new file mode 100755
index 0000000..9274941
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea25
@@ -0,0 +1,4 @@
+# Quanta 1K3 LTE
+TargetVendor=0x0408
+TargetProduct=0xea26
+QuantaMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea43 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea43
new file mode 100755
index 0000000..5c580e8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea43
@@ -0,0 +1,4 @@
+# Quanta MobileGenie 4G LTE, Quanta 1K6
+TargetVendor=0x0408
+TargetProductList="ea47,ea49,ea4d"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f000
new file mode 100755
index 0000000..3e38133
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f000
@@ -0,0 +1,4 @@
+# MU-Q110
+TargetVendor=0x0408
+TargetProduct=0xea03
+QuantaMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f000_uMa=Yota b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f000_uMa=Yota
new file mode 100755
index 0000000..0b18e44
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f000_uMa=Yota
@@ -0,0 +1,4 @@
+# Yota Router (Quanta 1QDLZZZ0ST2)
+TargetVendor=0x0408
+TargetProduct=0xd009
+MessageContent="5553424312345678000000000000061b004600000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f001
new file mode 100755
index 0000000..3cb57a0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f001
@@ -0,0 +1,4 @@
+# SpeedUp SU-8500U
+TargetVendor=0x0408
+TargetProduct=0xea03
+QuantaMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_060c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_060c
new file mode 100755
index 0000000..be0b8dc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_060c
@@ -0,0 +1,4 @@
+# Nokia CS-10
+TargetVendor=0x0421
+TargetProduct=0x060e
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0610 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0610
new file mode 100755
index 0000000..b2710ad
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0610
@@ -0,0 +1,4 @@
+# Nokia CS-15
+TargetVendor=0x0421
+TargetProduct=0x0612
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0618 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0618
new file mode 100755
index 0000000..80afec0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0618
@@ -0,0 +1,4 @@
+# Nokia CS-12
+TargetVendor=0x0421
+TargetProduct=0x0619
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_061d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_061d
new file mode 100755
index 0000000..98818a2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_061d
@@ -0,0 +1,4 @@
+# Nokia CS-11
+TargetVendor=0x0421
+TargetProduct=0x061e
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0622 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0622
new file mode 100755
index 0000000..465f145
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0622
@@ -0,0 +1,4 @@
+# Nokia CS-17
+TargetVendor=0x0421
+TargetProduct=0x0623
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0627 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0627
new file mode 100755
index 0000000..882893b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0627
@@ -0,0 +1,4 @@
+# Nokia CS-18
+TargetVendor=0x0421
+TargetProductList="0612,0629"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_062c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_062c
new file mode 100755
index 0000000..eb5dbde
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_062c
@@ -0,0 +1,4 @@
+# Nokia CS-19
+TargetVendor=0x0421
+TargetProductList="062d,062f"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0632 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0632
new file mode 100755
index 0000000..5ed6a7f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0632
@@ -0,0 +1,4 @@
+# Nokia CS-7M-01
+TargetVendor=0x0421
+TargetProduct=0x0632
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0637 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0637
new file mode 100755
index 0000000..e1415b7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0637
@@ -0,0 +1,4 @@
+# Nokia CS-21M-02
+TargetVendor=0x0421
+TargetProduct=0x0638
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/046d_c261 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/046d_c261
new file mode 100755
index 0000000..25a45c7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/046d_c261
@@ -0,0 +1,5 @@
+# Logitech G920 Racing Wheel
+MessageEndpoint=0x01
+ResponseEndpoint=0x01
+TargetClass=0x03
+MessageContent="0f00010142"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1210_uMa=Philips b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1210_uMa=Philips
new file mode 100755
index 0000000..74eca5a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1210_uMa=Philips
@@ -0,0 +1,3 @@
+# Philips (?)
+TargetClass=0xff
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1210_uMa=Wisue b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1210_uMa=Wisue
new file mode 100755
index 0000000..b3cd0a7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1210_uMa=Wisue
@@ -0,0 +1,4 @@
+# Vodafone MD950 (Wisue Technology)
+TargetVendor=0x1dbc
+TargetProduct=0x0005
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1237 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1237
new file mode 100755
index 0000000..e48527c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1237
@@ -0,0 +1,4 @@
+# Philips TalkTalk (NXP Semiconductors "Dragonfly")
+TargetVendor=0x0471
+TargetProductList="1206,1234"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0482_024d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0482_024d
new file mode 100755
index 0000000..570794f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0482_024d
@@ -0,0 +1,2 @@
+# Kyocera W06K CDMA modem
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04bb_bccd b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04bb_bccd
new file mode 100755
index 0000000..7c4e229
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04bb_bccd
@@ -0,0 +1,4 @@
+# I-O Data WMX2-U Wimax
+TargetVendor=0x04bb
+TargetProduct=0x0949
+MessageContent="55534243f0298d8124000000800006bc626563240000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_2251 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_2251
new file mode 100755
index 0000000..9d6e469
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_2251
@@ -0,0 +1,4 @@
+# Alcatel-Lucent ABS-T920
+TargetVendor=0x04cc
+TargetProductList="2259,226e"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_225c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_225c
new file mode 100755
index 0000000..3f6e8ab
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_225c
@@ -0,0 +1,2 @@
+# Alcatel-Lucent T930S
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_226e b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_226e
new file mode 100755
index 0000000..fe4bd3a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_226e
@@ -0,0 +1,2 @@
+# Nexperia TM TD-SCDMA
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_226f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_226f
new file mode 100755
index 0000000..a65c5cf
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_226f
@@ -0,0 +1,2 @@
+# Nexperia TM TD-SCDMA (Variant)
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_680c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_680c
new file mode 100755
index 0000000..871cbd8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_680c
@@ -0,0 +1,4 @@
+# Samsung GT-B1110
+TargetVendor=0x04e8
+TargetProduct=0x6792
+MessageContent="0902200001010080fa0904000002080650000705010200020007058102000200"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_689a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_689a
new file mode 100755
index 0000000..55977b9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_689a
@@ -0,0 +1,6 @@
+# Samsung GT-B3730
+TargetVendor=0x04e8
+TargetProduct=0x6889
+MessageContent="55534243785634120100000080000601000000000000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_f000_sMo=U209 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_f000_sMo=U209
new file mode 100755
index 0000000..c445158
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_f000_sMo=U209
@@ -0,0 +1,4 @@
+# Samsung U209
+TargetVendor=0x04e8
+TargetProduct=0x6601
+MessageContent="55534243123456780000000000000616000000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04fc_2140 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04fc_2140
new file mode 100755
index 0000000..35e00a1
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04fc_2140
@@ -0,0 +1,4 @@
+# Sunplus Techn. SU-3200U
+TargetVendor=0x04fc
+TargetProductList="0615,1240"
+MessageContent="55534243123456782400000080000612000024000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/057c_62ff b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/057c_62ff
new file mode 100755
index 0000000..a73effb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/057c_62ff
@@ -0,0 +1,7 @@
+# AVM Fritz!Wlan USB Stick N v2
+TargetVendor=0x057c
+TargetProductList="8501,8502"
+# Std.Eject not working
+MessageContent="5553424312345678000000000000061b000000ff0000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/057c_84ff b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/057c_84ff
new file mode 100755
index 0000000..3da7f76
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/057c_84ff
@@ -0,0 +1,7 @@
+# AVM Fritz!Wlan USB Stick N
+TargetVendor=0x057c
+TargetProduct=0x8401
+# Std.Eject not working
+MessageContent="5553424312345678000000000000061b000000ff0000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_0010 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_0010
new file mode 100755
index 0000000..d7db758
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_0010
@@ -0,0 +1,4 @@
+# Axesstel Modems (w/ initial idProduct 0x0010)
+TargetVendor=0x05c6
+TargetProduct=0x00a0
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_sVe=GT b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_sVe=GT
new file mode 100755
index 0000000..330d07c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_sVe=GT
@@ -0,0 +1,4 @@
+# Option GlobeTrotter GX0201
+TargetVendor=0x0af0
+TargetProduct=0x6701
+OptionMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_sVe=Option b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_sVe=Option
new file mode 100755
index 0000000..c76cde8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_sVe=Option
@@ -0,0 +1,4 @@
+# Older Option devices
+TargetVendor= 0x0af0
+TargetProductList="6901,6701,6600"
+OptionMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=AnyDATA b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=AnyDATA
new file mode 100755
index 0000000..ea414de
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=AnyDATA
@@ -0,0 +1,4 @@
+# AnyDATA devices, Bless UC165
+TargetVendor= 0x16d5
+TargetProduct=0x6502
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=CELOT b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=CELOT
new file mode 100755
index 0000000..044da01
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=CELOT
@@ -0,0 +1,4 @@
+# Celot K-300 a.o.
+TargetVendor=0x211f
+TargetProductList="6801,6802"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Co.,Ltd b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Co.,Ltd
new file mode 100755
index 0000000..a4e70e8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Co.,Ltd
@@ -0,0 +1,4 @@
+# TechFaith Venus VT-18
+TargetVendor=0x1d09
+TargetProduct=0x4306
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=DGT b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=DGT
new file mode 100755
index 0000000..8a787a4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=DGT
@@ -0,0 +1,4 @@
+# Celot CT-680
+TargetVendor=0x211f
+TargetProduct=0x6802
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Option b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Option
new file mode 100755
index 0000000..0f2ce47
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Option
@@ -0,0 +1,4 @@
+# Quirky Option devices
+TargetVendor=0x0af0
+TargetProduct=0x6901
+OptionMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=SAMSUNG b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=SAMSUNG
new file mode 100755
index 0000000..bbd8a30
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=SAMSUNG
@@ -0,0 +1,4 @@
+# Samsung SGH-Z810
+TargetVendor= 0x04e8
+TargetProduct=0x6601
+MessageContent="55534243123456780000000000000616000000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=SSE b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=SSE
new file mode 100755
index 0000000..8ed06ca
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=SSE
@@ -0,0 +1,4 @@
+# Prolink P2000 CDMA
+TargetVendor=0x05c6
+TargetProduct=0x6000
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=StrongRising b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=StrongRising
new file mode 100755
index 0000000..171cae3
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=StrongRising
@@ -0,0 +1,4 @@
+# StrongRising device 
+TargetVendor= 0x028a
+TargetProduct=0x1006
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Vertex b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Vertex
new file mode 100755
index 0000000..8fbcd80
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Vertex
@@ -0,0 +1,4 @@
+# Vertex Wireless 100 Series
+TargetVendor=0x1fe7
+TargetProduct=0x0100
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_2000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_2000
new file mode 100755
index 0000000..65897a8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_2000
@@ -0,0 +1,6 @@
+# Various USB modems
+TargetVendor=0x05c6
+TargetProductList="0015,0016,0018,ce17"
+MessageContent="5553424368032c882400000080000612000000240000000000000000000000"
+NeedResponse=1
+CheckSuccess=40
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_2001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_2001
new file mode 100755
index 0000000..f13efd9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_2001
@@ -0,0 +1,4 @@
+# D-Link DWM-162-U5, DWM-162 C1, Micromax MMX 300c
+TargetVendor=0x1e0e
+TargetProductList="ce16,ce17,cefe"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_6503 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_6503
new file mode 100755
index 0000000..43c6217
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_6503
@@ -0,0 +1,4 @@
+# AnyDATA APE-540H
+TargetVendor=0x16d5
+TargetProduct=0x6502
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_9024 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_9024
new file mode 100755
index 0000000..c809a67
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_9024
@@ -0,0 +1,4 @@
+# Alcatel-sbell ASB TL131 TD-LTE
+TargetVendor=0x05c6
+TargetProduct=0x9025
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_98ff b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_98ff
new file mode 100755
index 0000000..72e252a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_98ff
@@ -0,0 +1,4 @@
+# U901 (LTE modem)
+TargetVendor=0x05c6
+TargetProduct=0x6001
+SierraMode=1
\ No newline at end of file
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_f000
new file mode 100755
index 0000000..d064949
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_f000
@@ -0,0 +1,5 @@
+# Siptune LM-75 ("LinuxModem"), EWangshikong 4G
+TargetVendor=0x05c6
+TargetProductList="0016,6000,9000"
+StandardEject=1
+MessageContent="5553424308306384c000000080000671030000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c7_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c7_1000
new file mode 100755
index 0000000..9db6c68
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c7_1000
@@ -0,0 +1,4 @@
+# Qtronix EVDO 3G Modem (for TianYi)
+TargetVendor=0x05c7
+TargetProduct=0x6000
+MessageContent="5553424312345678c00000008000069f140000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0685_2000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0685_2000
new file mode 100755
index 0000000..d0b85b8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0685_2000
@@ -0,0 +1,5 @@
+# ZE-3G 7.2Mbs HSPA modem
+TargetVendor=0x1c9e
+TargetProduct=0x9603
+MessageContent="5553424368032c882400000080000612000000240000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/072f_100d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/072f_100d
new file mode 100755
index 0000000..95f7c45
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/072f_100d
@@ -0,0 +1,7 @@
+# InfoCert Business Key (SmartCard/Reader emulation)
+TargetVendor=0x072f
+TargetProduct=0x90cc
+MessageEndpoint=0x02
+MessageContent="01b0000000000000000000000000000000000000000000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_a800 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_a800
new file mode 100755
index 0000000..2adc178
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_a800
@@ -0,0 +1,4 @@
+# D-Link DWM-156 HSUPA 3.75G a.o.
+TargetVendor=0x07d1
+TargetProductList="3e01,3e02,7e0c"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_a804 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_a804
new file mode 100755
index 0000000..6fced74
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_a804
@@ -0,0 +1,4 @@
+# D-Link DWM-156 HSUPA 3.75G USB Modem
+TargetVendor=0x07d1
+TargetProduct=0x7e11
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_f000
new file mode 100755
index 0000000..f79dba7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_f000
@@ -0,0 +1,4 @@
+# D-Link DWM-151 A1
+TargetVendor=0x07d1
+TargetProduct=0x7e07
+MessageContent="555342431234567800000000000006bd000000020000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1001
new file mode 100755
index 0000000..86886a2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1001
@@ -0,0 +1,8 @@
+# Dymo LabelManager
+TargetVendor=0x0922
+TargetProduct=0x1002
+MessageEndpoint=0x01
+ResponseEndpoint=0x01
+MessageContent="1b5a01"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1003 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1003
new file mode 100755
index 0000000..82f42e3
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1003
@@ -0,0 +1,6 @@
+# Dymo LabelManager 420P
+TargetVendor= 0x0922
+TargetProduct= 0x1004
+MessageContent="1b5a01"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1007 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1007
new file mode 100755
index 0000000..2b48fb0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1007
@@ -0,0 +1,6 @@
+# Dymo LabelManager Wireless PnP
+TargetVendor= 0x0922
+TargetProduct= 0x1008
+MessageContent="1b5a01"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0930_0d46 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0930_0d46
new file mode 100755
index 0000000..2dcca74
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0930_0d46
@@ -0,0 +1,4 @@
+# Toshiba G450
+TargetVendor=0x0930
+TargetProduct=0x0d45
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0ace_2011 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0ace_2011
new file mode 100755
index 0000000..9b5a78f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0ace_2011
@@ -0,0 +1,4 @@
+# Zydas ZD1211RW WLAN USB, Sphairon HomeLink 1202 (Variant 1)
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0ace_20ff b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0ace_20ff
new file mode 100755
index 0000000..55178af
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0ace_20ff
@@ -0,0 +1,4 @@
+# Zydas ZD1211RW WLAN USB, Sphairon HomeLink 1202 (Variant 2)
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_4007 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_4007
new file mode 100755
index 0000000..d209494
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_4007
@@ -0,0 +1,6 @@
+# Option iCon 711
+TargetVendor=0x0af0
+TargetProduct=0x4005
+SierraMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6711 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6711
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6711
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6731 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6731
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6731
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6751 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6751
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6751
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6771 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6771
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6771
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6791 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6791
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6791
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6811 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6811
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6811
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6911 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6911
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6911
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6951 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6951
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6951
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6971 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6971
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6971
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7011 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7011
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7011
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7031 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7031
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7031
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7051 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7051
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7051
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7071 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7071
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7071
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7111 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7111
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7111
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7211 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7211
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7211
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7251 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7251
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7251
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7271 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7271
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7271
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7301 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7301
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7301
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7311 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7311
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7311
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7361 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7361
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7361
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7381 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7381
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7381
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7401 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7401
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7401
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7501 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7501
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7501
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7601 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7601
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7601
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7701 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7701
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7701
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7706 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7706
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7706
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7801 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7801
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7801
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7901 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7901
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7901
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7a01 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7a01
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7a01
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7a05 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7a05
new file mode 100755
index 0000000..ffaea9c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7a05
@@ -0,0 +1,5 @@
+# Option iCon 461
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8006 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8006
new file mode 100755
index 0000000..ccdd7f5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8006
@@ -0,0 +1,6 @@
+# Option Globetrotter (Variant)
+TargetVendor=0x0af0
+TargetProduct=0x9100
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8200 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8200
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8200
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8201 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8201
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8201
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8300 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8300
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8300
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8302 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8302
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8302
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8304 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8304
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8304
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8400 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8400
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8400
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8600 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8600
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8600
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8700 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8700
new file mode 100755
index 0000000..2d73b1c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8700
@@ -0,0 +1,5 @@
+# Option GI0643 (aka XYFI)
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8800 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8800
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8800
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8900 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8900
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8900
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_9000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_9000
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_9000
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_9200 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_9200
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_9200
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_c031 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_c031
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_c031
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_c100 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_c100
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_c100
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d001
new file mode 100755
index 0000000..4f2b39e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d001
@@ -0,0 +1,6 @@
+# Option GlobeTrotter GI1515
+TargetVendor=0x0af0
+TargetProductList="d157,d255,d257"
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d013 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d013
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d013
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d031 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d031
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d031
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d033 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d033
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d033
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d035 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d035
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d035
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d055 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d055
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d055
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d057 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d057
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d057
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d058 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d058
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d058
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d155 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d155
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d155
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d157 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d157
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d157
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d255 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d255
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d255
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d257 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d257
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d257
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d357 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d357
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d357
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_c700 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_c700
new file mode 100755
index 0000000..fd4da50
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_c700
@@ -0,0 +1,4 @@
+# Olivetti Olicard 100 and others
+TargetVendor=0x0b3c
+TargetProductList="c000,c001,c002"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f000
new file mode 100755
index 0000000..b17d1eb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f000
@@ -0,0 +1,5 @@
+# Olivetti Olicard 145, 155
+TargetVendor=0x0b3c
+TargetProductList="c003,c004"
+MessageContent="5553424312345678c000000080010606f50402527000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f00c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f00c
new file mode 100755
index 0000000..00f1298
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f00c
@@ -0,0 +1,4 @@
+# Olivetti Olicard 160
+TargetVendor=0x0b3c
+TargetProduct=0xc00a
+MessageContent="55534243123456788000000080000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f017 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f017
new file mode 100755
index 0000000..72df51d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f017
@@ -0,0 +1,4 @@
+# Olivetti Olicard 500
+TargetVendor=0x0b3c
+TargetProduct=0xc00b
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0bdb_190d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0bdb_190d
new file mode 100755
index 0000000..aa901b8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0bdb_190d
@@ -0,0 +1,2 @@
+# Ericsson F5521gw
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0bdb_1910 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0bdb_1910
new file mode 100755
index 0000000..5e9049e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0bdb_1910
@@ -0,0 +1,2 @@
+# Ericsson F5521gw (Variant)
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0cf3_20ff b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0cf3_20ff
new file mode 100755
index 0000000..3ce9058
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0cf3_20ff
@@ -0,0 +1,6 @@
+# Atheros Wireless / Netgear WNDA3200
+TargetVendor=0x0cf3
+TargetProduct=0x7010
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0d46_45a1 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0d46_45a1
new file mode 100755
index 0000000..1d82e3f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0d46_45a1
@@ -0,0 +1,4 @@
+# Kobil mIdentity 3G (1)
+TargetVendor=0x0d46
+TargetProduct=0x45a9
+KobilMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0d46_45a5 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0d46_45a5
new file mode 100755
index 0000000..2074a95
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0d46_45a5
@@ -0,0 +1,4 @@
+# Kobil mIdentity 3G (2)
+TargetVendor=0x0d46
+TargetProduct=0x45ad
+KobilMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0df7_0800 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0df7_0800
new file mode 100755
index 0000000..826501c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0df7_0800
@@ -0,0 +1,5 @@
+# Mobile Action ("Smart Cable")
+TargetClass=0xff
+MobileActionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_0002_uPr=MT b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_0002_uPr=MT
new file mode 100755
index 0000000..f23f468
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_0002_uPr=MT
@@ -0,0 +1,4 @@
+# MediaTek MT6276M and others
+TargetVendor=0x0e8d
+TargetProductList="00a1,00a2,00a5"
+MessageContent="555342431234567800000000000006f0010300000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_0002_uPr=Product b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_0002_uPr=Product
new file mode 100755
index 0000000..f36fa83
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_0002_uPr=Product
@@ -0,0 +1,4 @@
+# MediaTek/Medion S4222 and probably others
+TargetVendor=0x0e8d
+TargetProductList="00a1,00a2,00a5"
+MessageContent="555342431234567800000000000006f0010300000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_7109 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_7109
new file mode 100755
index 0000000..a71557f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_7109
@@ -0,0 +1,6 @@
+# MediaTek Wimax USB Card
+TargetVendor=0x0e8d
+TargetProductList="7115,7118"
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fca_8020 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fca_8020
new file mode 100755
index 0000000..7a07ad9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fca_8020
@@ -0,0 +1,4 @@
+# BlackBerry Q10 and Z10
+TargetVendor=0x0fca
+TargetProduct=0x8012
+BlackberryMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0cf b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0cf
new file mode 100755
index 0000000..85dc2c8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0cf
@@ -0,0 +1,2 @@
+# Sony Ericsson MD300
+Configuration=3
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0df b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0df
new file mode 100755
index 0000000..4bb9dca
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0df
@@ -0,0 +1,2 @@
+# Sony Ericsson EC400
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0e1 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0e1
new file mode 100755
index 0000000..f3e9e86
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0e1
@@ -0,0 +1,4 @@
+# Sony Ericsson MD400
+TargetClass=0x02
+SonyMode=1
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d103 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d103
new file mode 100755
index 0000000..cc9e7a4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d103
@@ -0,0 +1,4 @@
+# Sony Ericsson MD400G
+TargetClass=0x02
+SonyMode=1
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fd1_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fd1_1000
new file mode 100755
index 0000000..04101aa
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fd1_1000
@@ -0,0 +1,2 @@
+# GW D301 (Advinne AMC)
+Configuration=3
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_1000
new file mode 100755
index 0000000..4468271
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_1000
@@ -0,0 +1,3 @@
+# LG LDU-1900D EV-DO (Rev. A)
+TargetClass=0xff
+MessageContent="55534243123456780000000000000aff554d53434847000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_607f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_607f
new file mode 100755
index 0000000..25ccde5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_607f
@@ -0,0 +1,5 @@
+# LG HDM-2100 (EVDO Rev.A USB modem)
+TargetVendor=0x1004
+TargetProductList="6000,6114"
+MessageContent="555342431234567803000000800006f1010100000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_610c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_610c
new file mode 100755
index 0000000..dc25e1f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_610c
@@ -0,0 +1,4 @@
+# LG L-02A
+TargetVendor=0x1004
+TargetProduct=0x6109
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_613a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_613a
new file mode 100755
index 0000000..02bc44b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_613a
@@ -0,0 +1,4 @@
+# LG L-05A
+TargetVendor=0x1004
+TargetProduct=0x6124
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_613f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_613f
new file mode 100755
index 0000000..ce75c58
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_613f
@@ -0,0 +1,4 @@
+# LG LUU-2100TI (aka AT&T USBConnect Turbo)
+TargetVendor=0x1004
+TargetProduct=0x6141
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_614e b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_614e
new file mode 100755
index 0000000..0492200
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_614e
@@ -0,0 +1,4 @@
+# LG L-07A
+TargetVendor=0x1004
+TargetProduct=0x6135
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6156 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6156
new file mode 100755
index 0000000..89b1b85
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6156
@@ -0,0 +1,4 @@
+# LG LUU-2110TI
+TargetVendor=0x1004
+TargetProduct=0x6157
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6190 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6190
new file mode 100755
index 0000000..4334c0a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6190
@@ -0,0 +1,5 @@
+# LG AD600
+TargetVendor=0x1004
+TargetProduct=0x61a7
+WaitBefore=10
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61aa b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61aa
new file mode 100755
index 0000000..0db0efb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61aa
@@ -0,0 +1,4 @@
+# LG VL600
+TargetVendor=0x1004
+TargetProduct=0x61a7
+StandardEject=1
\ No newline at end of file
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61dd b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61dd
new file mode 100755
index 0000000..2ccd9bc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61dd
@@ -0,0 +1,4 @@
+# LG L-02C LTE
+TargetVendor=0x1004
+TargetProduct=0x618f
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61e7 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61e7
new file mode 100755
index 0000000..097e7e2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61e7
@@ -0,0 +1,4 @@
+# LG SD711
+TargetVendor=0x1004
+TargetProduct=0x61e6
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61eb b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61eb
new file mode 100755
index 0000000..10f1591
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61eb
@@ -0,0 +1,4 @@
+# LG L-08C (NTT docomo)
+TargetVendor=0x1004
+TargetProduct=0x61ea
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6327 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6327
new file mode 100755
index 0000000..f34ce2a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6327
@@ -0,0 +1,4 @@
+# LG L-03D LTE/3G
+TargetVendor=0x1004
+TargetProduct=0x6326
+MessageContent=555342431234567800000000000005f1010100000000000000000000000000
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1033_0035 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1033_0035
new file mode 100755
index 0000000..2541fd2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1033_0035
@@ -0,0 +1,4 @@
+# Huawei E630
+TargetVendor=0x12d1
+TargetProduct=0x1003
+HuaweiMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b03 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b03
new file mode 100755
index 0000000..4201228
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b03
@@ -0,0 +1,4 @@
+# UTStarcom UM175 (distributor "Alltel")
+TargetVendor=0x106c
+TargetProduct=0x3715
+MessageContent="555342431234567824000000800008ff024445564348470000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b05 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b05
new file mode 100755
index 0000000..e7f732d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b05
@@ -0,0 +1,4 @@
+# Pantech / UTStarcom UMW190 (Verizon)
+TargetVendor=0x106c
+TargetProduct=0x3716
+MessageContent="555342431234567824000000800008ff020000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b06 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b06
new file mode 100755
index 0000000..9351e41
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b06
@@ -0,0 +1,4 @@
+# UTStarcom UM185E (distributor "Alltel")
+TargetVendor=0x106c
+TargetProduct=0x3717
+MessageContent="55534243b82e238c24000000800008ff020000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b11 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b11
new file mode 100755
index 0000000..7ebbf49
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b11
@@ -0,0 +1,4 @@
+# Pantech UML290
+TargetVendor=0x106c
+TargetProduct=0x3718
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b14 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b14
new file mode 100755
index 0000000..eb351af
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b14
@@ -0,0 +1,6 @@
+# Option Beemo / Pantech P4200 LTE
+TargetVendor=0x106c
+TargetProduct=0x3721
+MessageContent="555342431234567824000000800008ff024445564348470000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1076_7f40 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1076_7f40
new file mode 100755
index 0000000..60e9117
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1076_7f40
@@ -0,0 +1,4 @@
+# Sagem F@ST 9520-35-GLR
+TargetVendor=0x1076
+TargetProduct=0x7f00
+GCTMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/109b_f009 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/109b_f009
new file mode 100755
index 0000000..7d1e2c8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/109b_f009
@@ -0,0 +1,4 @@
+# Hisense E910 EVDO Phone
+TargetVendor=0x109b
+TargetProduct=0x9114
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/10a9_606f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/10a9_606f
new file mode 100755
index 0000000..45dda80
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/10a9_606f
@@ -0,0 +1,7 @@
+# Pantech/Verizon UML295
+TargetVendor=0x10a9
+TargetProductList="6064,6074"
+# Use 1 for automatic choice, 2 for RNDIS, 4 for QMI
+PantechMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/10a9_6080 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/10a9_6080
new file mode 100755
index 0000000..3883005
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/10a9_6080
@@ -0,0 +1,4 @@
+# Pantech LTE Modem
+TargetVendor=0x10a9
+TargetProduct=0x6085
+PantechMode=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_0fff b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_0fff
new file mode 100755
index 0000000..88c8882
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_0fff
@@ -0,0 +1,6 @@
+# Sierra devices (specific driver)
+TargetVendor= 0x1199
+TargetProductList="0017,0018,0019,0020,0021,0022,0023,0024,0025,0026,0027,0028,0029,0112,0120,0218,0220,0224,0301,6802,6803,6804,6805,6808,6809,6812,6813,6815,6816,6820,6821,6822,6832,6833,6834,6835,6838,6839,683a,683b,683c,683d,683e,6850,6851,6852,6853,6855,6856,6859,685a,6880,6890,6891,6892,6893,68a2,68a3,68aa,9011,9012,9051"
+SierraMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9011 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9011
new file mode 100755
index 0000000..e1ac1fe
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9011
@@ -0,0 +1,4 @@
+# Sierra MC8305
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9013 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9013
new file mode 100755
index 0000000..d60fac0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9013
@@ -0,0 +1,4 @@
+# Sierra MC8355
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9017 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9017
new file mode 100755
index 0000000..d33a899
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9017
@@ -0,0 +1,4 @@
+# Sierra MC8355 Variant
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901b
new file mode 100755
index 0000000..f291e83
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901b
@@ -0,0 +1,4 @@
+# Sierra MC7770
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901c
new file mode 100755
index 0000000..3a13e2f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901c
@@ -0,0 +1,4 @@
+# Sierra EM7700
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901f
new file mode 100755
index 0000000..ca03f4c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901f
@@ -0,0 +1,4 @@
+# Sierra EM7355
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9041 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9041
new file mode 100755
index 0000000..2389f40
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9041
@@ -0,0 +1,4 @@
+# Sierra EM7305
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9051 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9051
new file mode 100755
index 0000000..0e10ef2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9051
@@ -0,0 +1,4 @@
+# Sierra AC340U
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9053 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9053
new file mode 100755
index 0000000..debd945
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9053
@@ -0,0 +1,4 @@
+# Sierra AC770S
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9063 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9063
new file mode 100755
index 0000000..2389f40
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9063
@@ -0,0 +1,4 @@
+# Sierra EM7305
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1266_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1266_1000
new file mode 100755
index 0000000..cf859d0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1266_1000
@@ -0,0 +1,4 @@
+# Digicom 8E4455 (and all Pirelli devices - EXPERIMENTAL)
+TargetVendor=0x1266
+TargetProductList="1002,1003,1004,1005,1006,1007,1008,1009,100a,100b,100c,100d,100e,100f,1011,1012"
+StandardEject=1
diff --git "a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_\043android" "b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_\043android"
new file mode 100755
index 0000000..f7d7928
--- /dev/null
+++ "b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_\043android"
@@ -0,0 +1,3 @@
+# Huawei generic for Android
+TargetVendor= 0x12d1
+MessageContent="55534243123456780000000000000011063000000100010000000000000000"
diff --git "a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_\043linux" "b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_\043linux"
new file mode 100755
index 0000000..78e7ea5
--- /dev/null
+++ "b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_\043linux"
@@ -0,0 +1,3 @@
+# Huawei generic for Linux (fall-back for unknown products)
+TargetVendor= 0x12d1
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1001
new file mode 100755
index 0000000..273c035
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1001
@@ -0,0 +1,3 @@
+# Huawei E169
+TargetClass=0xff
+HuaweiMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1003 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1003
new file mode 100755
index 0000000..5c37062
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1003
@@ -0,0 +1,3 @@
+# Huawei E220, E230, E270, E870
+TargetClass=0xff
+HuaweiMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1009 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1009
new file mode 100755
index 0000000..2b03464
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1009
@@ -0,0 +1,3 @@
+# Huawei V725 Phone (aka Vodafone 725)
+TargetClass=0xff
+HuaweiMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1010 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1010
new file mode 100755
index 0000000..c7c1d03
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1010
@@ -0,0 +1,3 @@
+# Huawei ETS1201
+TargetClass=0xff
+HuaweiMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_101e b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_101e
new file mode 100755
index 0000000..dae8e2e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_101e
@@ -0,0 +1,3 @@
+# Huawei U7510 / U7517
+TargetClass=0xff
+MessageContent="55534243123456780600000080000601000000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1030 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1030
new file mode 100755
index 0000000..d5c73d7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1030
@@ -0,0 +1,6 @@
+# Huawei U8220, T-Mobile Pulse (Android smartphone)
+TargetVendor=0x12d1
+TargetProduct=0x1034
+MessageContent="55534243123456780600000080010a11060000000000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1031 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1031
new file mode 100755
index 0000000..cc262da
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1031
@@ -0,0 +1,7 @@
+# Huawei U8110 / Joy, Vodafone 845 (Android smartphone)
+TargetVendor=0x12d1
+TargetProduct=0x1035
+MessageContent="55534243123456780600000080010a11060000000000000000000000000000"
+# for Android SDK
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1413 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1413
new file mode 100755
index 0000000..1158582
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1413
@@ -0,0 +1,3 @@
+# Huawei EC168
+TargetClass=0xff
+HuaweiMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1414 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1414
new file mode 100755
index 0000000..742d75d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1414
@@ -0,0 +1,3 @@
+# Huawei E180
+TargetClass=0xff
+HuaweiMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1446 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1446
new file mode 100755
index 0000000..48c6d35
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1446
@@ -0,0 +1,4 @@
+# Huawei, newer modems, and rebrandings
+TargetVendor=0x12d1
+TargetProductList="1001,1404,1406,140b,140c,1412,1417,141b,1429,1432,1433,1436,14ac,1506,150c,1511"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1449 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1449
new file mode 100755
index 0000000..1713857
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1449
@@ -0,0 +1,4 @@
+# Huawei E352
+TargetVendor=0x12d1
+TargetProduct=0x1444
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14ad b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14ad
new file mode 100755
index 0000000..e3d4328
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14ad
@@ -0,0 +1,4 @@
+# Vodafone (Huawei) K3806
+TargetVendor=0x12d1
+TargetProduct=0x14ae
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14b5 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14b5
new file mode 100755
index 0000000..322da5f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14b5
@@ -0,0 +1,4 @@
+# Huawei E173 (Viettel 3G)
+TargetVendor=0x12d1
+TargetProductList="14a8,14aa"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14b7 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14b7
new file mode 100755
index 0000000..e9f7cee
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14b7
@@ -0,0 +1,4 @@
+# Vodafone (Huawei) K4511
+TargetVendor=0x12d1
+TargetProduct=0x14cc
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14ba b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14ba
new file mode 100755
index 0000000..a2c257e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14ba
@@ -0,0 +1,4 @@
+# Huawei E173u-2, E177
+TargetVendor=0x12d1
+TargetProduct=0x14d2
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c1 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c1
new file mode 100755
index 0000000..309830f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c1
@@ -0,0 +1,4 @@
+# Vodafone (Huawei) K4605
+TargetVendor=0x12d1
+TargetProduct=0x14c6
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c3 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c3
new file mode 100755
index 0000000..413e8d2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c3
@@ -0,0 +1,4 @@
+# K5005 Vodafone/Huawei
+TargetVendor=0x12d1
+TargetProduct=0x14c8
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c4 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c4
new file mode 100755
index 0000000..e7ffc66
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c4
@@ -0,0 +1,4 @@
+# Vodafone/Huawei K3771
+TargetVendor=0x12d1
+TargetProduct=0x14ca
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c5 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c5
new file mode 100755
index 0000000..17ecd3c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c5
@@ -0,0 +1,4 @@
+# Vodafone (Huawei) K4510
+TargetVendor=0x12d1
+TargetProduct=0x14cb
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14d1 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14d1
new file mode 100755
index 0000000..2ab14e6
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14d1
@@ -0,0 +1,4 @@
+# Vodafone / Huawei K3770
+TargetVendor=0x12d1
+TargetProduct=0x14c9
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14fe b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14fe
new file mode 100755
index 0000000..9c16d2a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14fe
@@ -0,0 +1,4 @@
+# Huawei E352 (T-Mobile NL), E173s (Variant)
+TargetVendor=0x12d1
+TargetProductList="1506,150f,151d,1c1e"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1505 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1505
new file mode 100755
index 0000000..ab5e1cd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1505
@@ -0,0 +1,4 @@
+# Huawei EC156, Huawei E372u-8
+TargetVendor=0x12d1
+TargetProductList="140b,140c,1506,150f,150a"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_151a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_151a
new file mode 100755
index 0000000..283ae5b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_151a
@@ -0,0 +1,4 @@
+# Huawei E392u-12, E3131 (Variant)
+TargetVendor=0x12d1
+TargetProductList="151b,151d,151e"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1520 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1520
new file mode 100755
index 0000000..d03f821
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1520
@@ -0,0 +1,4 @@
+# Huawei K3765
+TargetVendor=0x12d1
+TargetProduct=0x1465
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1521 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1521
new file mode 100755
index 0000000..620690c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1521
@@ -0,0 +1,4 @@
+# Huawei K4505
+TargetVendor=0x12d1
+TargetProduct=0x1464
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1523 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1523
new file mode 100755
index 0000000..0eb4b7a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1523
@@ -0,0 +1,4 @@
+# Huawei R201
+TargetVendor=0x12d1
+TargetProduct=0x1491
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1526 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1526
new file mode 100755
index 0000000..60b8457
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1526
@@ -0,0 +1,4 @@
+# Vodafone / Huawei K3772
+TargetVendor=0x12d1
+TargetProduct=0x14cf
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1527 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1527
new file mode 100755
index 0000000..84fe445
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1527
@@ -0,0 +1,4 @@
+# Vodafone / Huawei R206 Router 
+TargetVendor=0x12d1
+TargetProduct=0x1594
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1553 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1553
new file mode 100755
index 0000000..0d2552e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1553
@@ -0,0 +1,4 @@
+# Huawei E1553
+TargetVendor=0x12d1
+TargetProduct=0x1001
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1557 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1557
new file mode 100755
index 0000000..beef342
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1557
@@ -0,0 +1,4 @@
+# Huawei E173
+TargetVendor=0x12d1
+TargetProduct=0x14a5
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_155a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_155a
new file mode 100755
index 0000000..451a8f9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_155a
@@ -0,0 +1,4 @@
+# Vodafone (Huawei) R205
+TargetVendor=0x12d1
+TargetProduct=0x14cd
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_155b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_155b
new file mode 100755
index 0000000..d10d02d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_155b
@@ -0,0 +1,4 @@
+# Huawei E171
+TargetVendor=0x12d1
+TargetProduct=0x1506
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_156a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_156a
new file mode 100755
index 0000000..55e6d38
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_156a
@@ -0,0 +1,4 @@
+# Huawei E3276s-151 and E3251
+TargetVendor=0x12d1
+TargetProductList="156b,156c"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1570 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1570
new file mode 100755
index 0000000..5b8ac78
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1570
@@ -0,0 +1,2 @@
+# Huawei ME906E
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1571 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1571
new file mode 100755
index 0000000..2b2eb6b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1571
@@ -0,0 +1,2 @@
+# Huawei EM820W
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1572 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1572
new file mode 100755
index 0000000..20b6e2e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1572
@@ -0,0 +1,2 @@
+# Huawei MU733
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1573 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1573
new file mode 100755
index 0000000..0397c2e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1573
@@ -0,0 +1,2 @@
+# Huawei ME909u-521 (MBIM, handled by kernel, dummy config)
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_157c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_157c
new file mode 100755
index 0000000..35d811d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_157c
@@ -0,0 +1,4 @@
+# Huawei E3276-s150
+TargetVendor=0x12d1
+TargetProduct=0x1506
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_157d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_157d
new file mode 100755
index 0000000..f42d3b8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_157d
@@ -0,0 +1,4 @@
+# Huawei E3331, E3372
+TargetVendor=0x12d1
+TargetProductList="14db,14dc"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1580 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1580
new file mode 100755
index 0000000..9b27048
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1580
@@ -0,0 +1,4 @@
+# Vodafone / Huawei R210 Router
+TargetVendor=0x12d1
+TargetProduct=0x1585
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1581 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1581
new file mode 100755
index 0000000..507ab0e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1581
@@ -0,0 +1,4 @@
+# Vodafone / Huawei R208 Router
+TargetVendor=0x12d1
+TargetProduct=0x1587
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1582 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1582
new file mode 100755
index 0000000..c8588a8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1582
@@ -0,0 +1,4 @@
+# Vodafone / Huawei R215 Router
+TargetVendor=0x12d1
+TargetProduct=0x1588
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1583 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1583
new file mode 100755
index 0000000..d45b089
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1583
@@ -0,0 +1,4 @@
+# Vodafone / Huawei W5101 Router
+TargetVendor=0x12d1
+TargetProduct=0x1589
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1597 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1597
new file mode 100755
index 0000000..0a91c2d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1597
@@ -0,0 +1,4 @@
+# Huawei E327s-150 (Variant)
+TargetVendor=0x12d1
+TargetProduct=0x1598
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15bb b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15bb
new file mode 100755
index 0000000..d6b1add
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15bb
@@ -0,0 +1,2 @@
+# Huawei ME936
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15c0 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15c0
new file mode 100755
index 0000000..c0b7769
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15c0
@@ -0,0 +1,2 @@
+# Huawei ME906C
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15c1 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15c1
new file mode 100755
index 0000000..24e2ec0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15c1
@@ -0,0 +1,2 @@
+# Huawei ME906, ME909 (MBIM, handled by kernel, dummy config)
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15ca b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15ca
new file mode 100755
index 0000000..cf9da86
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15ca
@@ -0,0 +1,4 @@
+# Huawei E3131
+TargetVendor=0x12d1
+TargetProduct=0x1506
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15cd b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15cd
new file mode 100755
index 0000000..28a5fc3
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15cd
@@ -0,0 +1,4 @@
+# Huawei E3372
+TargetVendor=0x12d1
+TargetProduct=0x1506
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15ce b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15ce
new file mode 100755
index 0000000..3ec6ce3
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15ce
@@ -0,0 +1,4 @@
+# Huawei E3531s-2, E3131 (Variant)
+TargetVendor=0x12d1
+TargetProductList="15b1,15b3"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15cf b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15cf
new file mode 100755
index 0000000..7addb2d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15cf
@@ -0,0 +1,4 @@
+# Huawei E3372s-153
+TargetVendor=0x12d1
+TargetProduct=0x1506
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15d0 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15d0
new file mode 100755
index 0000000..5d2ee64
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15d0
@@ -0,0 +1,4 @@
+# Huawei E3131 (Variant)
+TargetVendor=0x12d1
+TargetProduct=0x15d1
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15d2 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15d2
new file mode 100755
index 0000000..94bbbac
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15d2
@@ -0,0 +1,4 @@
+# Huawei E3531 (Variant)
+TargetVendor=0x12d1
+TargetProduct=0x15d3
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15e7 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15e7
new file mode 100755
index 0000000..6be0d6f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15e7
@@ -0,0 +1,4 @@
+# Huawei E3531
+TargetVendor=0x12d1
+TargetProduct=0x1506
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15f0 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15f0
new file mode 100755
index 0000000..c98abfd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15f0
@@ -0,0 +1,2 @@
+# Huawei MU736
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1805 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1805
new file mode 100755
index 0000000..d408152
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1805
@@ -0,0 +1,3 @@
+# Huawei U2800 Phone
+TargetClass=0xff
+MessageContent="55534243123456780600000080000601000000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c0b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c0b
new file mode 100755
index 0000000..c6bb69f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c0b
@@ -0,0 +1,4 @@
+# Huawei E173s
+TargetVendor=0x12d1
+TargetProductList="1c05,1c06,1c07,1c08,1c10"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c1b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c1b
new file mode 100755
index 0000000..3773123
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c1b
@@ -0,0 +1,6 @@
+# Huawei GP02 (E587 Variant)
+TargetVendor=0x12d1
+TargetProduct=0x1506
+HuaweiNewMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c24 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c24
new file mode 100755
index 0000000..3b9f196
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c24
@@ -0,0 +1,4 @@
+# Huawei E173 (Moviestar), E173s (Variant)
+TargetVendor=0x12d1
+TargetProductList="1c12,1c23"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c25 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c25
new file mode 100755
index 0000000..fa88d4d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c25
@@ -0,0 +1,2 @@
+# Huawei MU709s-2 Module
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1d50 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1d50
new file mode 100755
index 0000000..b218355
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1d50
@@ -0,0 +1,2 @@
+# Huawei ET302
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1da1 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1da1
new file mode 100755
index 0000000..3bb1cab
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1da1
@@ -0,0 +1,4 @@
+# Huawei ET8282, Huawei ET127
+TargetVendor=0x12d1
+TargetProduct=0x1d09
+HuaweiMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f01 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f01
new file mode 100755
index 0000000..68cea57
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f01
@@ -0,0 +1,6 @@
+# Huawei E353 (3.se) and others
+TargetVendor=0x12d1
+TargetProductList="14db,14dc"
+HuaweiNewMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f02 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f02
new file mode 100755
index 0000000..32a87b0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f02
@@ -0,0 +1,6 @@
+# Huawei E5377
+TargetVendor=0x12d1
+TargetProduct=0x14dc
+HuaweiNewMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f03 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f03
new file mode 100755
index 0000000..a9db535
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f03
@@ -0,0 +1,6 @@
+# KDDI (Huawei) HWD12 LTE
+TargetVendor=0x12d1
+TargetProduct=0x14db
+HuaweiNewMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f04 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f04
new file mode 100755
index 0000000..aad96a9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f04
@@ -0,0 +1,4 @@
+# Vodafone / Huawei R206_MR Router
+TargetVendor=0x12d1
+TargetProduct=0x15bc
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f05 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f05
new file mode 100755
index 0000000..cbde895
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f05
@@ -0,0 +1,4 @@
+# Vodafone / Huawei R207 Router
+TargetVendor=0x12d1
+TargetProduct=0x15bd
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f06 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f06
new file mode 100755
index 0000000..844e858
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f06
@@ -0,0 +1,4 @@
+# Vodafone / Huawei R215_MR Router
+TargetVendor=0x12d1
+TargetProduct=0x15c7
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f07 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f07
new file mode 100755
index 0000000..0a023f7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f07
@@ -0,0 +1,6 @@
+# Huawei/Vodafone R226
+TargetVendor=0x12d1
+TargetProduct=0x15bf
+HuaweiNewMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f09 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f09
new file mode 100755
index 0000000..6a99608
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f09
@@ -0,0 +1,6 @@
+# Huawei/Vodafone R216
+TargetVendor=0x12d1
+TargetProduct=0x1c50
+HuaweiNewMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f11 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f11
new file mode 100755
index 0000000..0786aad
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f11
@@ -0,0 +1,4 @@
+# Vodafone / Huawei K3773
+TargetVendor=0x12d1
+TargetProduct=0x14bc
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f15 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f15
new file mode 100755
index 0000000..93de9b3
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f15
@@ -0,0 +1,4 @@
+# Vodafone K4305
+TargetVendor=0x12d1
+TargetProductList="1400,14f7"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f16 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f16
new file mode 100755
index 0000000..a32d517
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f16
@@ -0,0 +1,4 @@
+# Vodafone K5150
+TargetVendor=0x12d1
+TargetProductList="14f8,1575"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f17 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f17
new file mode 100755
index 0000000..e31f0b4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f17
@@ -0,0 +1,4 @@
+# Vodafone K4201
+TargetVendor=0x12d1
+TargetProduct=0x1576
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f18 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f18
new file mode 100755
index 0000000..767644a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f18
@@ -0,0 +1,4 @@
+# Vodafone K4202
+TargetVendor=0x12d1
+TargetProduct=0x1577
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f19 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f19
new file mode 100755
index 0000000..b823b1a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f19
@@ -0,0 +1,4 @@
+# Vodafone K4606
+TargetVendor=0x12d1
+TargetProductList="14fa,1575,1578"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1b
new file mode 100755
index 0000000..6068a4c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1b
@@ -0,0 +1,4 @@
+# Vodafone / Huawei Kxxxx
+TargetVendor=0x12d1
+TargetProduct=0x1579
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1c
new file mode 100755
index 0000000..cf43358
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1c
@@ -0,0 +1,4 @@
+# Vodafone / Huawei K4203
+TargetVendor=0x12d1
+TargetProductList="157a,1590"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1d
new file mode 100755
index 0000000..eb4c393
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1d
@@ -0,0 +1,4 @@
+# Vodafone / Huawei Kxxxx
+TargetVendor=0x12d1
+TargetProductList="157b,1591"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1e b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1e
new file mode 100755
index 0000000..a20456a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1e
@@ -0,0 +1,4 @@
+# Vodafone / Huawei K5160
+TargetVendor=0x12d1
+TargetProductList="157f,1592"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_380b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_380b
new file mode 100755
index 0000000..293ec72
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_380b
@@ -0,0 +1,3 @@
+# Huawei BM358 WiMAX
+TargetClass=0x02
+StandardEject=1 
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1307_1169 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1307_1169
new file mode 100755
index 0000000..823c9ec
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1307_1169
@@ -0,0 +1,6 @@
+# Cisco AM10 "Valet Connector"
+TargetVendor=0x13b1
+TargetProduct=0x0031
+CiscoMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5010 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5010
new file mode 100755
index 0000000..56ec385
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5010
@@ -0,0 +1,4 @@
+# Novatel Wireless devices
+TargetVendor=0x1410
+TargetProductList="4100,4400,7030"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5020 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5020
new file mode 100755
index 0000000..884787a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5020
@@ -0,0 +1,4 @@
+# Novatel MC990D
+TargetVendor=0x1410
+TargetProductList="6000,7001"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5023 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5023
new file mode 100755
index 0000000..ffe9b64
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5023
@@ -0,0 +1,4 @@
+# Novatel MC996D
+TargetVendor=0x1410
+TargetProduct=0x7030
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5030 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5030
new file mode 100755
index 0000000..ffc730a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5030
@@ -0,0 +1,4 @@
+# Novatel U760
+TargetVendor=0x1410
+TargetProduct=0x6000
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5031 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5031
new file mode 100755
index 0000000..6f0fe13
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5031
@@ -0,0 +1,4 @@
+# Novatel MC760 3G
+TargetVendor=0x1410
+TargetProduct=0x6002
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5041 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5041
new file mode 100755
index 0000000..747a4ce
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5041
@@ -0,0 +1,4 @@
+# Novatel Generic MiFi 2352 / Vodafone MiFi 2352
+TargetVendor=0x1410
+TargetProductList="7001,7003"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5055 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5055
new file mode 100755
index 0000000..bce995d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5055
@@ -0,0 +1,4 @@
+# Novatel MiFi 4082
+TargetVendor=0x1410
+TargetProduct=0x6032
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5059 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5059
new file mode 100755
index 0000000..e191387
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5059
@@ -0,0 +1,4 @@
+# Novatel Wireless MC545 HSPA, U679 LTE
+TargetVendor=0x1410
+TargetProductList="7031,7042"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_7001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_7001
new file mode 100755
index 0000000..e02f95e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_7001
@@ -0,0 +1,3 @@
+# Novatel Generic MiFi 2372 / Vodafone MiFi 2372
+TargetClass=0xff
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_9020 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_9020
new file mode 100755
index 0000000..ba50114
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_9020
@@ -0,0 +1,2 @@
+# Novatel U620L
+Configuration=4
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/148e_a000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/148e_a000
new file mode 100755
index 0000000..6ff409b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/148e_a000
@@ -0,0 +1,3 @@
+# Sequans SQN1210/SQN1220 (generic chipsets)
+TargetClass=0x02
+SequansMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/148f_2578 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/148f_2578
new file mode 100755
index 0000000..7fd5163
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/148f_2578
@@ -0,0 +1,6 @@
+# Motorola 802.11 bg WLAN (TER/GUSB3-E)
+TargetVendor=0x148f
+TargetProduct=0x9021
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/15eb_7153 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/15eb_7153
new file mode 100755
index 0000000..2969bd8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/15eb_7153
@@ -0,0 +1,4 @@
+# China TeleCom CBP7.0
+TargetVendor=0x15eb
+TargetProduct=0x7152
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1614_0800 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1614_0800
new file mode 100755
index 0000000..9dd94a0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1614_0800
@@ -0,0 +1,5 @@
+# Amoi H-01
+TargetClass=0xff
+MessageContent="55534243123456780000000000000601000000000000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1614_0802 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1614_0802
new file mode 100755
index 0000000..67d5946
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1614_0802
@@ -0,0 +1,5 @@
+# Amoi H-02
+TargetClass=0xff
+MessageContent="55534243123456780000000000000601000000000000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d5_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d5_f000
new file mode 100755
index 0000000..b140d0f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d5_f000
@@ -0,0 +1,4 @@
+# Anydata ADU-890WH
+TargetVendor=0x16d5
+TargetProduct=0x6603
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6281 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6281
new file mode 100755
index 0000000..97c0773
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6281
@@ -0,0 +1,3 @@
+# C-motech CHU-628S
+TargetClass=0xff
+MessageContent="555342431234567824000000800008ff524445564348470000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6803 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6803
new file mode 100755
index 0000000..bbe9bca
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6803
@@ -0,0 +1,3 @@
+# C-motech D-50 (aka "CDU-680", "CNU-680")
+TargetClass=0x02
+MessageContent="555342431234567824000000800008ff524445564348473100000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6804 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6804
new file mode 100755
index 0000000..0b0220b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6804
@@ -0,0 +1,3 @@
+# C-motech CDU-685a
+TargetClass=0xff
+MessageContent="555342431234567824000000800008ff524445564348470000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_700a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_700a
new file mode 100755
index 0000000..f0375c5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_700a
@@ -0,0 +1,3 @@
+# C-motech CHU-629S
+TargetClass=0xff
+MessageContent="55534243123456782400000080000dfe524445564348473d4e444953000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_700b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_700b
new file mode 100755
index 0000000..b006d06
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_700b
@@ -0,0 +1,3 @@
+# C-motech CHU-629S (Variant)
+TargetClass=0xff
+MessageContent="55534243123456782400000080000dfe524445564348473d4e444953000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_f000
new file mode 100755
index 0000000..540292f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_f000
@@ -0,0 +1,4 @@
+# C-motech CGU-628 (aka "Franklin Wireless CGU-628A" aka "4G Systems XS Stick W12")
+TargetVendor=0x16d8
+TargetProduct=0x6006
+MessageContent="55534243d85dd88524000000800008ff524445564348470000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1726_1900 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1726_1900
new file mode 100755
index 0000000..fd8acfd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1726_1900
@@ -0,0 +1,4 @@
+# Axesstel MV210
+TargetVendor=0x1726
+TargetProduct=0x1000
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1726_f00e b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1726_f00e
new file mode 100755
index 0000000..abdbe53
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1726_f00e
@@ -0,0 +1,4 @@
+# Axesstel MU130
+TargetVendor=0x1726
+TargetProduct=0xa000
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1782_0003 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1782_0003
new file mode 100755
index 0000000..22556bd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1782_0003
@@ -0,0 +1,2 @@
+# Spreadtrum SC7702
+Configuration=2
\ No newline at end of file
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1782_0023 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1782_0023
new file mode 100755
index 0000000..e5f0e4a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1782_0023
@@ -0,0 +1,2 @@
+# Spreadtrum SC7702 (Variant)
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/198a_0003 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/198a_0003
new file mode 100755
index 0000000..2a88764
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/198a_0003
@@ -0,0 +1,4 @@
+# JOA Telecom LM-700r
+TargetVendor=0x198a
+TargetProduct=0x0002
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/198f_bccd b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/198f_bccd
new file mode 100755
index 0000000..20e6c85
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/198f_bccd
@@ -0,0 +1,6 @@
+# Beceem BCSM250
+TargetVendor=0x198f
+TargetProduct=0x0220
+MessageContent="55534243f0298d8124000000800006bc626563240000000000000000000000"
+
+
diff --git "a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_\043linux" "b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_\043linux"
new file mode 100755
index 0000000..ec66b7d
--- /dev/null
+++ "b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_\043linux"
@@ -0,0 +1,7 @@
+# ZTE generic for Linux (fall-back for unknown products)
+
+# Uncomment the following lines to activate
+
+#TargetVendor= 0x19d2
+#StandardEject=1
+#MessageContent="55534243123456702000000080000c85010101180101010101000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0003 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0003
new file mode 100755
index 0000000..1e1f24a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0003
@@ -0,0 +1,3 @@
+# ZTE MU351
+TargetClass=0xff
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0026 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0026
new file mode 100755
index 0000000..3d90363
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0026
@@ -0,0 +1,4 @@
+# ZTE AC581
+TargetVendor=0x19d2
+TargetProductList="0073,0094,0152"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0040 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0040
new file mode 100755
index 0000000..6600b33
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0040
@@ -0,0 +1,4 @@
+# Vodafone (ZTE) K2525
+TargetVendor=0x19d2
+TargetProduct=0x0022
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0053 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0053
new file mode 100755
index 0000000..8c19d56
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0053
@@ -0,0 +1,4 @@
+# ZTE MF110 (Variant)
+TargetVendor=0x19d2
+TargetProduct=0x0031
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0083_uPr=WCDMA b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0083_uPr=WCDMA
new file mode 100755
index 0000000..3ce0285
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0083_uPr=WCDMA
@@ -0,0 +1,4 @@
+# ZTE MF110 (Variant)
+TargetVendor=0x19d2
+TargetProduct=0x0124
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0101 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0101
new file mode 100755
index 0000000..4c078d8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0101
@@ -0,0 +1,4 @@
+# Vodafone (ZTE) K4505-Z
+TargetVendor=0x19d2
+TargetProduct=0x0104
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0103 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0103
new file mode 100755
index 0000000..214f5c0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0103
@@ -0,0 +1,4 @@
+# ZTE MF112
+TargetVendor=0x19d2
+TargetProduct=0x0031
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0110 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0110
new file mode 100755
index 0000000..e929a64
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0110
@@ -0,0 +1,5 @@
+# ZTE MF637 (Variant for Orange France)
+TargetVendor=0x19d2
+TargetProduct=0x0121
+StandardEject=1
+ 
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0115 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0115
new file mode 100755
index 0000000..ae1468e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0115
@@ -0,0 +1,4 @@
+# ZTE MF651
+TargetVendor=0x19d2
+TargetProduct=0x0116
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0120 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0120
new file mode 100755
index 0000000..5003cfc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0120
@@ -0,0 +1,7 @@
+#ZTE-T A356
+TargetVendor=0x19d2
+TargetProduct=0x0079
+DetachStorageOnly=0
+StandardEject=1
+Interface=0x00
+NeedResponse=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0146 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0146
new file mode 100755
index 0000000..d7e8196
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0146
@@ -0,0 +1,4 @@
+# ZTE MF652 (Variant)
+TargetVendor=0x19d2
+TargetProductList="0142,0143"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0149 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0149
new file mode 100755
index 0000000..0b06b0f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0149
@@ -0,0 +1,5 @@
+# ZTE MF190 (Variant)
+TargetVendor=0x19d2
+TargetProduct=0x0124
+StandardEject=1
+MessageContent="55534243123456702000000080000c85010101180101010101000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0150 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0150
new file mode 100755
index 0000000..0b7cd3b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0150
@@ -0,0 +1,4 @@
+# ZTE MF656A, MF668A, MF669
+TargetVendor=0x19d2
+TargetProduct=0x0124
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0154 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0154
new file mode 100755
index 0000000..7fb3c05
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0154
@@ -0,0 +1,4 @@
+# ZTE MF190 (Variant) and others
+TargetVendor=0x19d2
+TargetProductList="0017,0117,2003"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0166 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0166
new file mode 100755
index 0000000..8e4414f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0166
@@ -0,0 +1,4 @@
+# ZTE MF820 4G LTE
+TargetVendor=0x19d2
+TargetProduct=0x0167
+MessageContent="55534243123456782400000080000685000000240000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0169 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0169
new file mode 100755
index 0000000..4aac36c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0169
@@ -0,0 +1,4 @@
+# ZTE A371B
+TargetVendor=0x19d2
+TargetProduct=0x0170
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0198 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0198
new file mode 100755
index 0000000..c12e299
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0198
@@ -0,0 +1,4 @@
+# ZTE MF820s, MF832s
+TargetVendor=0x19d2
+TargetProduct=0x0199
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0266 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0266
new file mode 100755
index 0000000..ed2082f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0266
@@ -0,0 +1,5 @@
+# Onda MT8205 LTE
+TargetVendor=0x19d2
+TargetProduct=0x0265
+StandardEject=1
+MessageContent="55534243d8a523862400000080000685000000240000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0304 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0304
new file mode 100755
index 0000000..f93dccd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0304
@@ -0,0 +1,4 @@
+# ZTE MF821D (Variant)
+TargetVendor=0x19d2
+TargetProduct=0x0349
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0318 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0318
new file mode 100755
index 0000000..c5bb6e6
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0318
@@ -0,0 +1,4 @@
+# ZTE MF821D/MF826
+TargetVendor=0x19d2
+TargetProductList="0317,0330"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0325 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0325
new file mode 100755
index 0000000..3c23ebd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0325
@@ -0,0 +1,4 @@
+# ZTE MF821D
+TargetVendor=0x19d2
+TargetProduct=0x0326
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0388 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0388
new file mode 100755
index 0000000..f7a6966
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0388
@@ -0,0 +1,4 @@
+# ZTE MF90 Mobile Hotspot
+TargetVendor=0x19d2
+TargetProduct=0x0447
+MessageContent="55534243123456782400000080000685000000240000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0413 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0413
new file mode 100755
index 0000000..3cf0cca
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0413
@@ -0,0 +1,4 @@
+# Telewell TW-LTE 4G
+TargetVendor=0x19d2
+TargetProduct=0x0412
+MessageContent="55534243d8a523862400000080000685000000240000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1001
new file mode 100755
index 0000000..2d66c17
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1001
@@ -0,0 +1,6 @@
+# Vodafone (ZTE) K3805-Z
+TargetVendor=0x19d2
+TargetProductList="1002,1003"
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1007 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1007
new file mode 100755
index 0000000..61a7f71
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1007
@@ -0,0 +1,4 @@
+# Vodafone (ZTE) K3570-Z
+TargetVendor=0x19d2
+TargetProduct=0x1008
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1009 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1009
new file mode 100755
index 0000000..878fcdd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1009
@@ -0,0 +1,4 @@
+# Vodafone (ZTE) K3571-Z
+TargetVendor=0x19d2
+TargetProduct=0x1010
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1013 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1013
new file mode 100755
index 0000000..58f33cb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1013
@@ -0,0 +1,6 @@
+# Vodafone (ZTE) K3806-Z
+TargetVendor=0x19d2
+TargetProduct=0x1015
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1017 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1017
new file mode 100755
index 0000000..667e00a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1017
@@ -0,0 +1,4 @@
+# Vodafone K5006Z (MF821)
+TargetVendor=0x19d2
+TargetProduct=0x1018
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1019 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1019
new file mode 100755
index 0000000..ef133ca
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1019
@@ -0,0 +1,4 @@
+# Vodafone / ZTE R203 Router
+TargetVendor=0x19d2
+TargetProduct=0x1021
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1020 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1020
new file mode 100755
index 0000000..ef133ca
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1020
@@ -0,0 +1,4 @@
+# Vodafone / ZTE R203 Router
+TargetVendor=0x19d2
+TargetProduct=0x1021
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1022 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1022
new file mode 100755
index 0000000..de52f8c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1022
@@ -0,0 +1,4 @@
+# Vodafone / ZTE K4201-z
+TargetVendor=0x19d2
+TargetProductList="1023,1024"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1026 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1026
new file mode 100755
index 0000000..a6762cc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1026
@@ -0,0 +1,4 @@
+# Vodafone / ZTE R212 Router
+TargetVendor=0x19d2
+TargetProductList="1027,1028,1029"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1030 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1030
new file mode 100755
index 0000000..a00acd1
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1030
@@ -0,0 +1,4 @@
+# Vodafone K5008-z (MF823)
+TargetVendor=0x19d2
+TargetProductList="1031,1032"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1034 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1034
new file mode 100755
index 0000000..03372d1
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1034
@@ -0,0 +1,4 @@
+# Vodafone / ZTE R206-z Router
+TargetVendor=0x19d2
+TargetProductList="1035,1036,1037"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1038 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1038
new file mode 100755
index 0000000..aac2900
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1038
@@ -0,0 +1,4 @@
+# ZTE / Vodafone K4607-Z
+TargetVendor=0x19d2
+TargetProductList="1039,1040"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1042 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1042
new file mode 100755
index 0000000..878b3fc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1042
@@ -0,0 +1,4 @@
+# Vodafone / ZTE R209-z Router
+TargetVendor=0x19d2
+TargetProduct=0x1043
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1046 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1046
new file mode 100755
index 0000000..ebf0d0e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1046
@@ -0,0 +1,4 @@
+# ZTE MF730
+TargetVendor=0x19d2
+TargetProduct=0x1047
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1171 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1171
new file mode 100755
index 0000000..4c722c4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1171
@@ -0,0 +1,6 @@
+# Vodafone (ZTE) K4510-Z
+TargetVendor=0x19d2
+TargetProduct=0x1173
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1175 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1175
new file mode 100755
index 0000000..61ef605
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1175
@@ -0,0 +1,6 @@
+# Vodafone / ZTE K3770-Z
+TargetVendor=0x19d2
+TargetProduct=0x1177
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1179 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1179
new file mode 100755
index 0000000..086ade9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1179
@@ -0,0 +1,6 @@
+# Vodafone (ZTE) K3772-Z
+TargetVendor=0x19d2
+TargetProduct=0x1181
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1201 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1201
new file mode 100755
index 0000000..052d473
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1201
@@ -0,0 +1,4 @@
+# ZTE MF691 (T-Mobile Rocket 2.0)
+TargetVendor=0x19d2
+TargetProduct=0x1203
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1207 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1207
new file mode 100755
index 0000000..f7e1e50d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1207
@@ -0,0 +1,4 @@
+# ZTE MF192 (Variant)
+TargetVendor=0x19d2
+TargetProduct=0x1208
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1210 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1210
new file mode 100755
index 0000000..ef7946c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1210
@@ -0,0 +1,4 @@
+# ZTE MF195
+TargetVendor=0x19d2
+TargetProduct=0x1211
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1216 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1216
new file mode 100755
index 0000000..2634bc1
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1216
@@ -0,0 +1,4 @@
+# ZTE MF192 (Variant)
+TargetVendor=0x19d2
+TargetProduct=0x1217
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1219 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1219
new file mode 100755
index 0000000..f75da93
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1219
@@ -0,0 +1,4 @@
+# ZTE MF192 (Variant)
+TargetVendor=0x19d2
+TargetProductList="1220,1222"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1224 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1224
new file mode 100755
index 0000000..baa492f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1224
@@ -0,0 +1,4 @@
+# ZTE MF190
+TargetVendor=0x19d2
+TargetProduct=0x0082
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1225 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1225
new file mode 100755
index 0000000..90b32f9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1225
@@ -0,0 +1,4 @@
+# ZTE MF668 (Variant), MF70
+TargetVendor=0x19d2
+TargetProduct=0x1405
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1227 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1227
new file mode 100755
index 0000000..3ed950f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1227
@@ -0,0 +1,4 @@
+# ZTE MF680
+TargetVendor=0x19d2
+TargetProduct=0x1252
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1232 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1232
new file mode 100755
index 0000000..086af2c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1232
@@ -0,0 +1,4 @@
+# ZTE MFxxx
+TargetVendor=0x19d2
+TargetProductList="1268,2003"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1233 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1233
new file mode 100755
index 0000000..ac2c702
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1233
@@ -0,0 +1,4 @@
+# ZTE MFxxx
+TargetVendor=0x19d2
+TargetProduct=0x1270
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1237 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1237
new file mode 100755
index 0000000..5b4def7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1237
@@ -0,0 +1,4 @@
+# ZTE / Vodafone K4201
+TargetVendor=0x19d2
+TargetProduct=0x0017
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1238 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1238
new file mode 100755
index 0000000..ff575e6
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1238
@@ -0,0 +1,4 @@
+# ZTE MF825A
+TargetVendor=0x19d2
+TargetProduct=0x0017
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1420 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1420
new file mode 100755
index 0000000..a5d5af4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1420
@@ -0,0 +1,4 @@
+# ZTE MF730
+TargetVendor=0x19d2
+TargetProduct=0x1405
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1511 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1511
new file mode 100755
index 0000000..469143b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1511
@@ -0,0 +1,4 @@
+# ZTE MFxxx
+TargetVendor=0x19d2
+TargetProduct=0x1512
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1514 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1514
new file mode 100755
index 0000000..7f08f33
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1514
@@ -0,0 +1,4 @@
+# ZTE MF192 (Variant)
+TargetVendor=0x19d2
+TargetProduct=0x1515
+MessageContent="5553424348c4758600000000000010ff000000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1517 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1517
new file mode 100755
index 0000000..8a7450e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1517
@@ -0,0 +1,4 @@
+# ZTE MF192 (Variant)
+TargetVendor=0x19d2
+TargetProduct=0x1519
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1520 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1520
new file mode 100755
index 0000000..06c58c5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1520
@@ -0,0 +1,4 @@
+# ZTE MF652
+TargetVendor=0x19d2
+TargetProduct=0x0142
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1523 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1523
new file mode 100755
index 0000000..2a16858
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1523
@@ -0,0 +1,4 @@
+# ZTE MF591 TMobile
+TargetVendor=0x19d2
+TargetProduct=0x1525
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1528 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1528
new file mode 100755
index 0000000..25e78c0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1528
@@ -0,0 +1,4 @@
+# ZTE MF196
+TargetVendor=0x19d2
+TargetProduct=0x1527
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1536 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1536
new file mode 100755
index 0000000..b3617a6
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1536
@@ -0,0 +1,4 @@
+# ZTE MF190J
+TargetVendor=0x19d2
+TargetProductList="1537,1538"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1542 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1542
new file mode 100755
index 0000000..60b06eb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1542
@@ -0,0 +1,4 @@
+# ZTE MF190J
+TargetVendor=0x19d2
+TargetProduct=0x1544
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1580 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1580
new file mode 100755
index 0000000..5b99ce8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1580
@@ -0,0 +1,4 @@
+# ZTE MF195E
+TargetVendor= 0x19d2
+TargetProduct=0x1582
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1588 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1588
new file mode 100755
index 0000000..2cbf979
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1588
@@ -0,0 +1,5 @@
+# ZTE MF710M Variants
+TargetVendor= 0x19d2
+TargetProductList="1589,1591,1592"
+StandardEject=1
+MessageContent="55534243123456702000000080000c85010101180101010101000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1595 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1595
new file mode 100755
index 0000000..13cc530
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1595
@@ -0,0 +1,5 @@
+# ZTE MF710 (Vietnam) a.o.
+TargetVendor= 0x19d2
+TargetProductList="1592,1596,1600"
+StandardEject=1
+MessageContent="55534243123456702000000080000c85010101180101010101000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_2000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_2000
new file mode 100755
index 0000000..067173e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_2000
@@ -0,0 +1,5 @@
+# ZTE devices, some Onda devices
+TargetVendor= 0x19d2
+TargetProductList="0001,0002,0015,0016,0017,0019,0024,0031,0033,0037,0042,0052,0055,0061,0063,0064,0066,0091,0108,0117,0128,0151,0157,0177,1402,2002,2003"
+StandardEject=1
+MessageContent="55534243123456702000000080000c85010101180101010101000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_2004 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_2004
new file mode 100755
index 0000000..5d97b1e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_2004
@@ -0,0 +1,4 @@
+# ZTE MF60
+TargetVendor=0x19d2
+TargetProduct=0x1402
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_bccd b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_bccd
new file mode 100755
index 0000000..dd47bee
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_bccd
@@ -0,0 +1,6 @@
+# ZTE AX226 WiMax
+TargetVendor=0x19d2
+TargetProduct=0x0172
+MessageContent="555342431234567824000000800006bc626563240000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_ffde b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_ffde
new file mode 100755
index 0000000..1beb1df
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_ffde
@@ -0,0 +1,4 @@
+# ZTE AC682 (a.k.a. SmartFren Connex)
+TargetVendor=0x19d2
+TargetProduct=0xffdd
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_ffe6 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_ffe6
new file mode 100755
index 0000000..e0b6d26
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_ffe6
@@ -0,0 +1,4 @@
+# ZTE "ffe" devices 1 (e.g. Cricket A605)
+TargetVendor=0x19d2
+TargetProduct=0xffe5
+MessageContent="5553424330f4cf8124000000800108df200000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_fff5 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_fff5
new file mode 100755
index 0000000..1fa9350
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_fff5
@@ -0,0 +1,4 @@
+# ZTE "ff" devices 1
+TargetVendor=0x19d2
+TargetProductList="ffe4,ffe9,fff1,fffe,ffff"
+MessageContent="5553424312345678c00000008000069f030000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_fff6 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_fff6
new file mode 100755
index 0000000..e894e96
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_fff6
@@ -0,0 +1,4 @@
+# ZTE "fff" devices 2
+TargetVendor=0x19d2
+TargetProduct=0xfff1
+MessageContent="5553424312345678c00000008000069f030000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1a8d_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1a8d_1000
new file mode 100755
index 0000000..3580f54
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1a8d_1000
@@ -0,0 +1,6 @@
+# BandRich BandLuxe C100, C120, C170, C270, C3xx, C508
+TargetVendor=0x1a8d
+TargetProductList="1002,1007,1009,100d,2006"
+StandardEject=1
+ReleaseDelay=4000
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1a8d_2000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1a8d_2000
new file mode 100755
index 0000000..16d85c4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1a8d_2000
@@ -0,0 +1,4 @@
+# BandRich BandLuxe C339
+TargetVendor=0x1a8d
+TargetProduct=0x2006
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ab7_5700 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ab7_5700
new file mode 100755
index 0000000..983903a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ab7_5700
@@ -0,0 +1,4 @@
+# Hummer DTM5731, Aircard 901 
+TargetVendor=0x1ab7
+TargetProductList="2000,5731"
+StandardEject=1 
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1b7d_0700 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1b7d_0700
new file mode 100755
index 0000000..f357fcc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1b7d_0700
@@ -0,0 +1,4 @@
+# EpiValley SEC-7089 (featured by Alegro and Starcomms / iZAP)
+TargetVendor=0x1b7d
+TargetProduct=0x0001
+MessageContent="555342431234567824000000800008FF05B112AEE102000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_000f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_000f
new file mode 100755
index 0000000..c618dce
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_000f
@@ -0,0 +1,4 @@
+# ETCOM E300
+TargetVendor=0x1bbb
+TargetProduct=0x000f
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_00ca b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_00ca
new file mode 100755
index 0000000..df5753b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_00ca
@@ -0,0 +1,3 @@
+# Alcatel OT-X080C
+TargetClass=0xff
+MessageContent="55534243123456788000000080000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_011f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_011f
new file mode 100755
index 0000000..97f7a3a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_011f
@@ -0,0 +1,4 @@
+# Haier EVDO Rev. A
+TargetVendor=0x1bbb
+TargetProduct=0x0106
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_022c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_022c
new file mode 100755
index 0000000..46e4105
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_022c
@@ -0,0 +1,2 @@
+# Alcatel X602D
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_025e b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_025e
new file mode 100755
index 0000000..717aa47
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_025e
@@ -0,0 +1,4 @@
+# Yota 4G LTE W8
+TargetVendor=0x1bbb
+TargetProduct=0x0195
+MessageContent="55534243123456788000000080000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f000
new file mode 100755
index 0000000..bd30b57
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f000
@@ -0,0 +1,4 @@
+# Alcatel X200/X200L/X060S/L100V, Archos G9 3G Key
+TargetVendor=0x1bbb
+TargetProductList="0000,0017,00b7,011e,0191,0195"
+MessageContent="55534243123456788000000080000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f017 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f017
new file mode 100755
index 0000000..d68767d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f017
@@ -0,0 +1,4 @@
+# Alcatel OT-X220D, L100V
+TargetVendor=0x1bbb
+TargetProductList="0017,011e,0203"
+MessageContent="55534243123456788000000080000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f052 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f052
new file mode 100755
index 0000000..11262b0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f052
@@ -0,0 +1,4 @@
+# Alcatel OT X220L
+TargetVendor=0x1bbb
+TargetProduct=0x0052
+MessageContent="55534243123456788000000080000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_1001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_1001
new file mode 100755
index 0000000..d43b947
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_1001
@@ -0,0 +1,4 @@
+# Alcatel One Touch X020
+TargetVendor=0x1c9e
+TargetProductList="6060,6061"
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_6000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_6000
new file mode 100755
index 0000000..77cb169
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_6000
@@ -0,0 +1,5 @@
+# TU930, IVIO IV-2010u
+TargetClass=0xff
+MessageContent="55534243123456780000000000000601000000000000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_6061_uPr=Storage b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_6061_uPr=Storage
new file mode 100755
index 0000000..3d6d53d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_6061_uPr=Storage
@@ -0,0 +1,3 @@
+# Vibe 3G Modem 
+TargetClass=0xff
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9101 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9101
new file mode 100755
index 0000000..ed42e10
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9101
@@ -0,0 +1,4 @@
+# Emobile D12LC
+TargetVendor=0x1c9e
+TargetProduct=0x9104
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9200 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9200
new file mode 100755
index 0000000..d0a1e1d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9200
@@ -0,0 +1,4 @@
+# MyWave SW006 Sport Phone/Modem Combination
+TargetVendor=0x1c9e
+TargetProduct=0x9202
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9401 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9401
new file mode 100755
index 0000000..e02d00d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9401
@@ -0,0 +1,4 @@
+# Emobile D21LC
+TargetVendor=0x1c9e
+TargetProduct=0x9404
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9800 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9800
new file mode 100755
index 0000000..ef03cd9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9800
@@ -0,0 +1,3 @@
+# Longcheer SU9800
+TargetClass=0xff
+MessageContent="55534243123456788000000080000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_98ff b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_98ff
new file mode 100755
index 0000000..80a3146
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_98ff
@@ -0,0 +1,4 @@
+# Telewell TW-3G HSPA+, FS01BU 3G, SmartBro WM66E
+TargetVendor=0x1c9e
+TargetProductList="6801,9801,9803"
+MessageContent="55534243123456780000000080000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9bfe b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9bfe
new file mode 100755
index 0000000..25767f0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9bfe
@@ -0,0 +1,4 @@
+# XS Stick W100 (Omega)
+TargetVendor=0x1c9e
+TargetProduct=0x9b01
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9d00 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9d00
new file mode 100755
index 0000000..f8bbedd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9d00
@@ -0,0 +1,3 @@
+# Prolink PCM100
+TargetClass=0xff
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9e00 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9e00
new file mode 100755
index 0000000..3a03904
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9e00
@@ -0,0 +1,3 @@
+# BSNL Capitel
+TargetClass=0xff
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9e08 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9e08
new file mode 100755
index 0000000..e90fd46
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9e08
@@ -0,0 +1,6 @@
+# Explay Slim
+TargetVendor=0x1c9e
+TargetProduct=0x9e18
+SierraMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f000
new file mode 100755
index 0000000..a5b7a8e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f000
@@ -0,0 +1,5 @@
+# Longcheer/Longsoon (aka Omega Technology) devices
+TargetVendor=0x1c9e
+TargetProductList="9000,9603,9605,9607,9900"
+MessageContent="555342431234567800000000000001ff000000000000000000000000000000"
+WaitBefore=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f000_uMa=USB_Modem b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f000_uMa=USB_Modem
new file mode 100755
index 0000000..a645abc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f000_uMa=USB_Modem
@@ -0,0 +1,5 @@
+# MobiData MBD-200HU and others
+TargetVendor=0x1c9e
+TargetProductList="9000,9603,9605,9607,9900,9a00"
+MessageContent="55534243123456788000000080000606f50402527000000000000000000000"
+WaitBefore=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f010 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f010
new file mode 100755
index 0000000..d1d007b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f010
@@ -0,0 +1,4 @@
+# Micromax MMX400R / 4G Systems XSBOXGO
+TargetVendor=0x1c9e
+TargetProduct=0xf101
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1000
new file mode 100755
index 0000000..62675f7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1000
@@ -0,0 +1,4 @@
+# TechFaith BSNL Capitel
+TargetVendor=0x1d09
+TargetProduct=0x1010
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1021 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1021
new file mode 100755
index 0000000..3af3048
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1021
@@ -0,0 +1,4 @@
+# Aiko 81D
+TargetVendor=0x1d09
+TargetProduct=0x1010
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1025 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1025
new file mode 100755
index 0000000..eb9133c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1025
@@ -0,0 +1,4 @@
+# TechFaith FlyingLARK46
+TargetVendor=0x1d09
+TargetProduct=0x1026
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1da5_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1da5_f000
new file mode 100755
index 0000000..8cb08ae
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1da5_f000
@@ -0,0 +1,4 @@
+# Qisda H21 Flying Beetle
+TargetVendor=0x1da5
+TargetProduct=0x4512
+QisdaMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1dbc_0669 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1dbc_0669
new file mode 100755
index 0000000..c137caa
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1dbc_0669
@@ -0,0 +1,2 @@
+# Wisue W340
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1dd6_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1dd6_1000
new file mode 100755
index 0000000..2ad5e61
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1dd6_1000
@@ -0,0 +1,5 @@
+# Solomon S3Gm-660
+TargetVendor=0x1dd6
+TargetProduct=0x1002
+MessageContent="55534243123456781200000080000603000000020000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1de1_1101 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1de1_1101
new file mode 100755
index 0000000..92145ba
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1de1_1101
@@ -0,0 +1,4 @@
+# Philips PicoPix 1020 Projector
+TargetVendor=0x21e7
+TargetProduct=0x000e
+MessageContent="55534243123456780000000000000cff020000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1e0e_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1e0e_f000
new file mode 100755
index 0000000..04931f9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1e0e_f000
@@ -0,0 +1,5 @@
+# Option iCON 210, PROLiNK PHS100 + PH300, Hyundai MB-810, A-Link 3GU
+TargetVendor=0x1e0e
+TargetProductList="9000,9100,9200"
+MessageContent="555342431234567800000000000006bd000000020000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1e89_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1e89_f000
new file mode 100755
index 0000000..db6a46d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1e89_f000
@@ -0,0 +1,4 @@
+# 3GO 3GO11 HSUPA
+TargetVendor=0x1e89
+TargetProduct=0x1a20
+MessageContent="5553424312345678800000008000060619181a207000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1edf_6003 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1edf_6003
new file mode 100755
index 0000000..eb04ecd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1edf_6003
@@ -0,0 +1,2 @@
+# AirPlus MCD-800
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0003 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0003
new file mode 100755
index 0000000..a292e64
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0003
@@ -0,0 +1,5 @@
+# Onda MV815U
+TargetVendor=0x1ee8
+TargetProduct=0x0004
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0007 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0007
new file mode 100755
index 0000000..9a9fbaa
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0007
@@ -0,0 +1,4 @@
+# Onda POM1051
+TargetVendor=0x1ee8
+TargetProduct=0x000b
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0009 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0009
new file mode 100755
index 0000000..7b7f881
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0009
@@ -0,0 +1,5 @@
+# Onda MW833UP
+TargetVendor=0x1ee8
+TargetProduct=0x000b
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0013 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0013
new file mode 100755
index 0000000..4fc5320
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0013
@@ -0,0 +1,5 @@
+# Onda MW833UP + MW835UP
+TargetVendor=0x1ee8
+TargetProductList="0011,0012,0014"
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0018 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0018
new file mode 100755
index 0000000..d50cde6
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0018
@@ -0,0 +1,5 @@
+# Onda MO835UP
+TargetVendor=0x1ee8
+TargetProduct=0x0017
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0040 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0040
new file mode 100755
index 0000000..251f807
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0040
@@ -0,0 +1,5 @@
+# Onda MW836UP-K
+TargetVendor=0x1ee8
+TargetProductList="003e,003f"
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0045 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0045
new file mode 100755
index 0000000..92b567f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0045
@@ -0,0 +1,5 @@
+# Onda MDC655
+TargetVendor=0x1ee8
+TargetProduct=0x0044
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0048 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0048
new file mode 100755
index 0000000..a0618ab
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0048
@@ -0,0 +1,4 @@
+# Onda MT655
+TargetVendor=0x1ee8
+TargetProduct=0x0049
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_004a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_004a
new file mode 100755
index 0000000..97dd71b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_004a
@@ -0,0 +1,4 @@
+# Onda MDC655
+TargetVendor=0x1ee8
+TargetProduct=0x0049
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_004f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_004f
new file mode 100755
index 0000000..e81eb29
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_004f
@@ -0,0 +1,5 @@
+# Onda MDC655 Variant
+TargetVendor=0x1ee8
+TargetProduct=0x004e
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0054 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0054
new file mode 100755
index 0000000..8638639
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0054
@@ -0,0 +1,5 @@
+# Onda MW875UP
+TargetVendor=0x1ee8
+TargetProduct=0x0053
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
+NeedResponse=1
\ No newline at end of file
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0060 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0060
new file mode 100755
index 0000000..985e4a3
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0060
@@ -0,0 +1,4 @@
+# Onda MSA 14.4 (TIM Brasil)
+TargetVendor=0x1ee8
+TargetProduct=0x005f
+MessageContent="555342431234567800000000000008ff000000000000030000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0063 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0063
new file mode 100755
index 0000000..b46c775
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0063
@@ -0,0 +1,4 @@
+# Onda TM201, CM201
+TargetVendor=0x1ee8
+TargetProductList="0064,0065"
+MessageContent="555342431234567800000000000008ff000000000000030000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0068 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0068
new file mode 100755
index 0000000..da73ac1
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0068
@@ -0,0 +1,4 @@
+# Onda WM301
+TargetVendor=0x1ee8
+TargetProduct=0x0069
+MessageContent="555342431234567800000000000008ff000000000000030000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1f28_0021 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1f28_0021
new file mode 100755
index 0000000..162c20b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1f28_0021
@@ -0,0 +1,4 @@
+# Cricket A600
+TargetVendor=0x1f28
+TargetProduct=0x0020
+MessageContent="555342431234567824000000800108df200000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0032 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0032
new file mode 100755
index 0000000..2eabd0a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0032
@@ -0,0 +1,2 @@
+# Franklin Wireless U210 (Variant)
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0130 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0130
new file mode 100755
index 0000000..100ce55
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0130
@@ -0,0 +1,4 @@
+# Franklin Wireless U210
+TargetVendor=0x1fac
+TargetProduct=0x0131
+MessageContent="555342431234567824000000800108df200000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0150 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0150
new file mode 100755
index 0000000..e04b132
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0150
@@ -0,0 +1,4 @@
+# Franklin Wireless U600
+TargetVendor=0x1fac
+TargetProduct=0x0151
+MessageContent="555342431234567824000000800108df200000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0151 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0151
new file mode 100755
index 0000000..9db4de7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0151
@@ -0,0 +1,2 @@
+# Franklin Wireless U600
+Configuration=2
\ No newline at end of file
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_00a6 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_00a6
new file mode 100755
index 0000000..6362dad
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_00a6
@@ -0,0 +1,4 @@
+# D-Link DWM-157 B1
+TargetVendor=0x2001
+TargetProduct=0x7d02
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_7600 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_7600
new file mode 100755
index 0000000..b1fe1f7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_7600
@@ -0,0 +1,2 @@
+# D-Link DWM-157 C1
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_98ff b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_98ff
new file mode 100755
index 0000000..383e0c7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_98ff
@@ -0,0 +1,5 @@
+# D-Link DWM-221
+TargetVendor=0x2001
+TargetProduct=0x7e16
+MessageContent="55534243f8d2e6838000000080000606f50402527000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a401 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a401
new file mode 100755
index 0000000..8d4e874
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a401
@@ -0,0 +1,4 @@
+# D-Link DWM-221 B1
+TargetVendor=0x2001
+TargetProduct=0x7e19
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a403 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a403
new file mode 100755
index 0000000..d6c4893
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a403
@@ -0,0 +1,4 @@
+# D-Link DWM-156 A8, DWP-157 B1
+TargetVendor=0x2001
+TargetProductList="7d0b,7d0c"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a405 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a405
new file mode 100755
index 0000000..3208b3b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a405
@@ -0,0 +1,4 @@
+# D-Link DWM-167 A1
+TargetVendor=0x2001
+TargetProduct=0x7d0d
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a406 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a406
new file mode 100755
index 0000000..4148807
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a406
@@ -0,0 +1,4 @@
+# D-Link DWM-221
+TargetVendor=0x2001
+TargetProduct=0x7e19
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a407 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a407
new file mode 100755
index 0000000..6522888
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a407
@@ -0,0 +1,4 @@
+# D-Link DWM-157 C1
+TargetVendor=0x2001
+TargetProduct=0x7d0e
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a40a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a40a
new file mode 100755
index 0000000..3db2e55
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a40a
@@ -0,0 +1,4 @@
+# D-Link DWM-156 A8 (Myanmar)
+TargetVendor=0x2001
+TargetProduct=0x7d10
+MessageContent="555342431234567800000000000003f0010100000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a40d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a40d
new file mode 100755
index 0000000..4f12646
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a40d
@@ -0,0 +1,4 @@
+# D-Link DWR-910
+TargetVendor=0x2001
+TargetProduct=0x7e38
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a706 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a706
new file mode 100755
index 0000000..1b4ee3e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a706
@@ -0,0 +1,4 @@
+# D-Link DWM-156 A7
+TargetVendor=0x2001
+TargetProduct=0x7d01
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a707 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a707
new file mode 100755
index 0000000..6362dad
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a707
@@ -0,0 +1,4 @@
+# D-Link DWM-157 B1
+TargetVendor=0x2001
+TargetProduct=0x7d02
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a708 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a708
new file mode 100755
index 0000000..15c8323
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a708
@@ -0,0 +1,4 @@
+# D-Link DWM-158 D1
+TargetVendor=0x2001
+TargetProduct=0x7d03
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a805 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a805
new file mode 100755
index 0000000..97e0c7b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a805
@@ -0,0 +1,4 @@
+# D-Link DWR-510
+TargetVendor=0x2001
+TargetProduct=0x7e12
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a80b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a80b
new file mode 100755
index 0000000..fbbb6c8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a80b
@@ -0,0 +1,5 @@
+# D-Link DWM-156 (Variant)
+TargetVendor=0x2001
+TargetProduct=0x7d00
+MessageContent="555342431234567800000000000003f0010100000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2015_0001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2015_0001
new file mode 100755
index 0000000..02a559f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2015_0001
@@ -0,0 +1,3 @@
+# Venus VT-18
+TargetClass=0xff
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/201e_1023 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/201e_1023
new file mode 100755
index 0000000..98fe5a4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/201e_1023
@@ -0,0 +1,6 @@
+# Haier CE682 (EVDO)
+TargetVendor=0x201e
+TargetProduct=0x1022
+MessageContent="55534243123456780000000000000600000000000000000000000000000000"
+MessageContent2="5553424312345679c000000080000671030000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/201e_2009 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/201e_2009
new file mode 100755
index 0000000..84fefe1
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/201e_2009
@@ -0,0 +1,3 @@
+# Haier CE 100 
+TargetClass=0xff
+StandardEject=1 
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_0002 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_0002
new file mode 100755
index 0000000..f67f7a2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_0002
@@ -0,0 +1,4 @@
+# Mediatek MT6229, Micromax MMX 377G, Olicard 300
+TargetVendor=0x2020
+TargetProductList="2000,4000,4010"
+MessageContent="555342430820298900000000000003f0010100000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_f00e b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_f00e
new file mode 100755
index 0000000..ec38550
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_f00e
@@ -0,0 +1,5 @@
+# SpeedUp SU-8000 and others
+TargetVendor=0x2020
+TargetProductList="1005,1008"
+StandardEject=1
+WaitBefore=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_f00f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_f00f
new file mode 100755
index 0000000..64e60f0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_f00f
@@ -0,0 +1,5 @@
+# SpeedUp SU-8000U
+TargetVendor=0x2020
+TargetProduct=0x1005
+StandardEject=1
+WaitBefore=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2077_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2077_1000
new file mode 100755
index 0000000..8bac36b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2077_1000
@@ -0,0 +1,4 @@
+# Changhong CH690, D-Link DWM-163 + DWM-168
+TargetVendor=0x2077
+TargetProductList="7001,7010,7011"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2077_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2077_f000
new file mode 100755
index 0000000..e65c97b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2077_f000
@@ -0,0 +1,5 @@
+# Telenet 3G dongle (T&W WU160), Netgear AC327U and others
+TargetVendor=0x2077
+TargetProductList="9000,9062,a000,a003"
+StandardEject=1
+MessageContent="55534243123456700000000000000616aa0000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20a6_f00a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20a6_f00a
new file mode 100755
index 0000000..9e20b7e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20a6_f00a
@@ -0,0 +1,4 @@
+# BM WM78
+TargetVendor=0x20a6
+TargetProduct=0x1000
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20a6_f00e b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20a6_f00e
new file mode 100755
index 0000000..dd6aefa
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20a6_f00e
@@ -0,0 +1,4 @@
+# Intex 3.5G
+TargetVendor=0x20a6
+TargetProduct=0x1105
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20b9_1682 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20b9_1682
new file mode 100755
index 0000000..a65c1ea
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20b9_1682
@@ -0,0 +1,3 @@
+# Tlaytech TEU800
+TargetClass=0xff
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/21f5_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/21f5_1000
new file mode 100755
index 0000000..ebb13da
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/21f5_1000
@@ -0,0 +1,4 @@
+# StrongRising (China Telcom), Air FlexiNet
+TargetVendor=0x21f5
+TargetProduct=0x2008
+MessageContent="5553424312345678c000000080000671010000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/21f5_3010 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/21f5_3010
new file mode 100755
index 0000000..ef2c097
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/21f5_3010
@@ -0,0 +1,4 @@
+# StrongRising STD808
+TargetVendor=0x21f5
+TargetProduct=0x1101
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2262_0001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2262_0001
new file mode 100755
index 0000000..4339910
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2262_0001
@@ -0,0 +1,4 @@
+# Viettel VT100
+TargetVendor=0x2262
+TargetProduct=0x0002
+MessageContent="5553424340799288C000000080010A16000000C00000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22de_6801 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22de_6801
new file mode 100755
index 0000000..a610b60
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22de_6801
@@ -0,0 +1,3 @@
+# WeTelecom WM-D200
+TargetClass=0xff
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22de_6803 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22de_6803
new file mode 100755
index 0000000..55b59c5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22de_6803
@@ -0,0 +1,4 @@
+# WeTelecom WM-D300
+TargetVendor=0x22de
+TargetProduct=0x6801
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22f4_0021 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22f4_0021
new file mode 100755
index 0000000..7980f66
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22f4_0021
@@ -0,0 +1,3 @@
+# Tata Photon+, Olive VME102
+TargetClass=0xff
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0001
new file mode 100755
index 0000000..5008f5c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0001
@@ -0,0 +1,2 @@
+# Linktop LW272/LW273 (BSNL Teracom)
+Configuration=3
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0003 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0003
new file mode 100755
index 0000000..5008f5c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0003
@@ -0,0 +1,2 @@
+# Linktop LW272/LW273 (BSNL Teracom)
+Configuration=3
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0007 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0007
new file mode 100755
index 0000000..63996da
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0007
@@ -0,0 +1,2 @@
+# Visiontek 82GH 3G
+Configuration=3
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000b
new file mode 100755
index 0000000..e8dd4bb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000b
@@ -0,0 +1,2 @@
+# Zoom 3G
+Configuration=3
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000c
new file mode 100755
index 0000000..e8dd4bb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000c
@@ -0,0 +1,2 @@
+# Zoom 3G
+Configuration=3
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000d
new file mode 100755
index 0000000..66ec4cc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000d
@@ -0,0 +1,2 @@
+# Intex Speed 3G v7.2
+Configuration=3
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0101 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0101
new file mode 100755
index 0000000..721e5c4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0101
@@ -0,0 +1,2 @@
+# Linktop LW272/LW273
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0103 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0103
new file mode 100755
index 0000000..e543736
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0103
@@ -0,0 +1,2 @@
+# Teracom LW272
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2357_0200 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2357_0200
new file mode 100755
index 0000000..6251747
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2357_0200
@@ -0,0 +1,4 @@
+# TP-Link MA180
+TargetVendor=0x2357
+TargetProduct=0x0201
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2357_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2357_f000
new file mode 100755
index 0000000..aba6b49
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2357_f000
@@ -0,0 +1,4 @@
+# TP-Link MA260
+TargetVendor=0x2357
+TargetProduct=0x9000
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/23a2_1010 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/23a2_1010
new file mode 100755
index 0000000..95cee31
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/23a2_1010
@@ -0,0 +1,4 @@
+# Titan 3.5G
+TargetVendor=0x23a2
+TargetProduct=0x1234
+MessageContent="555342431234567800000000000006161f6d62706b00000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_a000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_a000
new file mode 100755
index 0000000..6981490
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_a000
@@ -0,0 +1,4 @@
+# Unknown devices
+TargetVendor=0x257a
+TargetProductList="1601,161f,162f,261f,262f,361f,362f"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_b000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_b000
new file mode 100755
index 0000000..6981490
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_b000
@@ -0,0 +1,4 @@
+# Unknown devices
+TargetVendor=0x257a
+TargetProductList="1601,161f,162f,261f,262f,361f,362f"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_c000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_c000
new file mode 100755
index 0000000..6981490
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_c000
@@ -0,0 +1,4 @@
+# Unknown devices
+TargetVendor=0x257a
+TargetProductList="1601,161f,162f,261f,262f,361f,362f"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_d000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_d000
new file mode 100755
index 0000000..6981490
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_d000
@@ -0,0 +1,4 @@
+# Unknown devices
+TargetVendor=0x257a
+TargetProductList="1601,161f,162f,261f,262f,361f,362f"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/6000_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/6000_1000
new file mode 100755
index 0000000..e9d346f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/6000_1000
@@ -0,0 +1,4 @@
+# BlueLink BL-EV08C
+TargetVendor=0x05c6
+TargetProduct=0x6000
+MessageContent="5553424312345678c000000080000671010000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/8888_6500 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/8888_6500
new file mode 100755
index 0000000..85b2776
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/8888_6500
@@ -0,0 +1,4 @@
+# Exiss Mobile E-190 series (made by C-motech)
+TargetVendor=0x16d8
+TargetProduct=0x6533
+MessageContent="5553424398e2c4812400000080000bff524445564348473d43440000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/ed09_1021 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/ed09_1021
new file mode 100755
index 0000000..d23a846
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/ed09_1021
@@ -0,0 +1,4 @@
+# Aiko 81D, fw with wrong vendor ID
+TargetVendor=0xed09
+TargetProduct=0x1010
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.h b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.h
new file mode 100755
index 0000000..f40796f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.h
@@ -0,0 +1,116 @@
+/*
+  This file is part of usb_modeswitch, a mode switching tool for controlling
+  the mode of 'multi-state' USB devices
+
+  Version 2.4.0, 2016/06/12
+  Copyright (C) 2007 - 2016  Josua Dietze
+
+  Config file parsing stuff borrowed from Guillaume Dargaud
+  (http://www.gdargaud.net/Hack/SourceCode.html)
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details:
+
+  http://www.gnu.org/licenses/gpl.txt
+
+*/
+
+#include <stdlib.h>
+#include <libusb.h>
+
+void readConfigFile(const char *configFilename);
+void printConfig();
+int switchSendMessage();
+int switchConfiguration();
+int switchAltSetting();
+void switchHuaweiMode();
+
+void switchSierraMode();
+void switchGCTMode();
+void switchKobilMode();
+void switchQisdaMode();
+void switchQuantaMode();
+void switchSequansMode();
+void switchActionMode();
+void switchBlackberryMode();
+void switchPantechMode();
+void switchCiscoMode();
+int switchSonyMode();
+int detachDriver();
+int checkSuccess();
+int sendMessage(char* message, int count);
+int write_bulk(int endpoint, unsigned char *message, int length);
+int read_bulk(int endpoint, unsigned char *buffer, int length);
+void release_usb_device(int dummy);
+struct libusb_device* search_devices( int *numFound, int vendor, char* productList,
+		int targetClass, int configuration, int mode);
+int find_first_bulk_endpoint(int direction);
+int get_current_config_value();
+int get_interface_class();
+char* ReadParseParam(const char* FileName, char *VariableName);
+int hex2num(char c);
+int hex2byte(const char *hex);
+int hexstr2bin(const char *hex, unsigned char *buffer, int len);
+void printVersion();
+void printHelp();
+void close_all();
+void abortExit();
+int readArguments(int argc, char **argv);
+void deviceDescription();
+void resetUSB();
+void release_usb_device(int dummy);
+int findMBIMConfig(int vendor, int product, int mode);
+
+
+// Boolean
+#define  and     &&
+#define  or      ||
+#define  not     !
+
+// Bitwise
+#define  bitand  &
+#define  bitor   |
+#define  compl   ~
+#define  xor     ^
+
+// Equals
+#define  and_eq  &=
+#define  not_eq  !=
+#define  or_eq   |=
+#define  xor_eq  ^=
+
+extern char* ReadParseParam(const char* FileName, char *VariableName);
+
+extern char *TempPP;
+
+#define ParseParamString(ParamFileName, Str) \
+	if ((TempPP=ReadParseParam((ParamFileName), #Str))!=NULL) \
+		strcpy(Str, TempPP); else Str[0]='\0'
+		
+#define ParseParamInt(ParamFileName, Int) \
+	if ((TempPP=ReadParseParam((ParamFileName), #Int))!=NULL) \
+		Int=atoi(TempPP)
+
+#define ParseParamHex(ParamFileName, Int) \
+	if ((TempPP=ReadParseParam((ParamFileName), #Int))!=NULL) \
+		Int=strtol(TempPP, NULL, 16)
+
+#define ParseParamFloat(ParamFileName, Flt) \
+	if ((TempPP=ReadParseParam((ParamFileName), #Flt))!=NULL) \
+		Flt=atof(TempPP)
+
+#define ParseParamBool(ParamFileName, B) \
+	if ((TempPP=ReadParseParam((ParamFileName), #B))!=NULL) \
+		B=(toupper(TempPP[0])=='Y' || toupper(TempPP[0])=='T'|| TempPP[0]=='1'); else B=0
+
+#define ParseParamBoolMap(ParamFileName, B, M, Const) \
+	if ((TempPP=ReadParseParam((ParamFileName), #B))!=NULL) \
+		if (toupper(TempPP[0])=='Y' || toupper(TempPP[0])=='T'|| TempPP[0]=='1') \
+			M=M+Const
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.sh b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.sh
new file mode 100755
index 0000000..b126ec3
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+# part of usb_modeswitch 2.4.0
+device_in()
+{
+	if [ ! -e /var/lib/usb_modeswitch/$1 ]; then
+		return 0
+	fi
+	while read line
+	do
+		if [ $(expr "$line" : "$2:$3") != 0 ]; then
+			return 1
+		fi
+	done </var/lib/usb_modeswitch/$1
+	if [ $(expr "$line" : "$2:$3") != 0 ]; then
+		return 1
+	fi
+	return 0
+}
+
+if [ $(expr "$1" : "--.*") ]; then
+	p_id=$4
+	if [ -z $p_id ]; then
+		prod=$5
+		if [ -z $prod ]; then
+			prod=$3
+		fi
+		prod=${prod%/*}
+		v_id=0x${prod%/*}
+		p_id=0x${prod#*/}
+		if [ "$v_id" = "0x" ]; then
+			v_id="0"
+			p_id="0"
+		fi
+		v_id="$(printf %04x $(($v_id)))"
+		p_id="$(printf %04x $(($p_id)))"
+	else
+		v_id=$3
+	fi
+fi
+PATH=/sbin:/usr/sbin:$PATH
+case "$1" in
+	--driver-bind)
+		# driver binding code removed
+		exit 0
+		;;
+	--symlink-name)
+		device_in "link_list" $v_id $p_id
+		if [ "$?" = "1" ]; then
+			if [ -e "/usr/sbin/usb_modeswitch_dispatcher" ]; then
+				exec usb_modeswitch_dispatcher $1 $2 2>>/dev/null
+			fi
+		fi
+		exit 0
+		;;
+esac
+
+IFS='/' read -r p1 p2 <<EOF
+$1
+EOF
+
+PATH=/bin:/sbin:/usr/bin:/usr/sbin
+init_path=`readlink /sbin/init`
+if [ `basename $init_path` = "systemd" ]; then
+	systemctl --no-block start usb_modeswitch@$p1'_'$p2.service
+elif [ -e "/etc/init/usb-modeswitch-upstart.conf" ]; then
+	initctl emit --no-wait usb-modeswitch-upstart UMS_PARAM=$1
+else
+	# only old distros, new udev will kill all subprocesses
+	exec 1<&- 2<&- 5<&- 7<&-
+	exec usb_modeswitch_dispatcher --switch-mode $1 &
+fi
+exit 0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.tcl
new file mode 100755
index 0000000..3e590fd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch.tcl
@@ -0,0 +1,1015 @@
+#!/usr/bin/tclsh
+
+# Wrapper (tcl) for usb_modeswitch, called from
+# /lib/udev/rules.d/40-usb_modeswitch.rules
+# (part of data pack "usb-modeswitch-data") via
+# /lib/udev/usb_modeswitch
+#
+# Does ID check on newly discovered USB devices and calls
+# the mode switching program with the matching parameter
+# file from /usr/share/usb_modeswitch
+#
+# Part of usb-modeswitch-2.4.0 package
+# (C) Josua Dietze 2009-2016
+
+set arg0 [lindex $argv 0]
+if [regexp {\.tcl$} $arg0] {
+	if [file exists $arg0] {
+		set argv [lrange $argv 1 end]
+		source $arg0
+		exit
+	}
+}
+
+# Setting of these switches is done in the global config
+# file (/etc/usb_modeswitch.conf) if available
+
+set flags(logging) 1
+set flags(noswitching) 0
+set flags(stordelay) 0
+set flags(logwrite) 0
+# also settable in device config files
+set flags(nombim) 0
+
+# Execution starts at file bottom
+
+proc {Main} {argv argc} {
+
+global scsi usb config match device flags setup devdir loginit
+
+set flags(config) ""
+Log "[ParseGlobalConfig]"
+
+# The facility to add a symbolic link pointing to the
+# ttyUSB port which provides interrupt transfer, i.e.
+# the port to connect through.
+# Will check for interrupt endpoint in ttyUSB port (lowest if
+# there is more than one); if found, return "gsmmodem[n]" name
+# to udev for symlink creation
+
+# This is run once for every port of LISTED devices by
+# a udev rule
+
+if {[lindex $argv 0] == "--symlink-name"} {
+	puts -nonewline [SymLinkName [lindex $argv 1]]
+	SafeExit
+}
+
+if {[lindex $argv 0] == "--switch-systemd"} {
+	set argList [split [lindex $argv 1] _]
+	Log "\nStarted via systemd"
+} else {
+	if {[lindex $argv 0] == "--switch-upstart"} {
+		Log "\nStarted via upstart"
+	}
+	set argList [split [lindex $argv 1] /]
+}
+if [string length [lindex $argList 1]] {
+	set device [lindex $argList 1]
+} else {
+	set device "noname"
+}
+if {$flags(stordelay) > 0} {
+	SetStorageDelay $flags(stordelay)
+}
+
+Log "Raw args from udev: [lindex $argv 1]\n"
+
+if {$device == "noname"} {
+	Log "\nNo data from udev. Exit"
+	SafeExit
+}
+
+if {![regexp -- {--switch-} [lindex $argv 0]]} {
+	Log "\nNo command given. Exit"
+	SafeExit
+}
+
+set setup(dbdir) /usr/share/usb_modeswitch
+set setup(dbdir_etc) /etc/usb_modeswitch.d
+
+
+if {![file exists $setup(dbdir)] && ![file exists $setup(dbdir_etc)]} {
+	Log "\nError: no config database found in /usr/share or /etc. Exit"
+	SafeExit
+}
+set bindir /usr/sbin
+
+set devList1 {}
+set devList2 {}
+
+
+# arg 0: the bus id for the device (udev: %b), often ommitted
+# arg 1: the "kernel name" for the device (udev: %k)
+#
+# Used to determine the top directory for the device in sysfs
+
+set ifChk 0
+if {[string length [lindex $argList 0]] == 0} {
+	if {[string length [lindex $argList 1]] == 0} {
+		Log "No device number values given from udev! Exit"
+		SafeExit
+	} else {
+		if {![regexp {(.*?):} [lindex $argList 1] d dev_top]} {
+			if {![regexp {([0-9]+-[0-9]+\.?[0-9]*.*)} [lindex $argList 1] d dev_top]} {
+				Log "Could not determine device dir from udev values! Exit"
+				SafeExit
+			}
+		}
+	}
+} else {
+	set dev_top [lindex $argList 0]
+	regexp {(.*?):} $dev_top d dev_top
+}
+
+set devdir /sys/bus/usb/devices/$dev_top
+if {![file isdirectory $devdir]} {
+	Log "Top device directory not found ($devdir)! Exit"
+	SafeExit
+}
+Log "Use top device dir $devdir"
+
+set iface 0
+Log "Check class of first interface ..."
+set config(class) [IfClass 0 $devdir]
+if {$config(class) < 0} {
+	Log " No access to interface 0. Exit"
+	SafeExit
+}
+Log " Interface 0 class is $config(class)."
+
+set ifdir [file tail [IfDir $iface $devdir]]
+regexp {:([0-9]+\.[0-9]+)$} $ifdir d iface
+
+set flags(logwrite) 1
+
+# Mapping of the short string identifiers (in the config
+# file names) to the long name used here
+#
+# If we need them it's a snap to add new attributes here!
+
+set match(sVe) scsi(vendor)
+set match(sMo) scsi(model)
+set match(sRe) scsi(rev)
+set match(uMa) usb(manufacturer)
+set match(uPr) usb(product)
+set match(uSe) usb(serial)
+
+
+# Now reading the USB attributes
+if {![ReadUSBAttrs $devdir]} {
+	Log "USB attributes not found in sysfs tree. Exit"
+	SafeExit
+}
+set config(vendor) $usb(idVendor)
+set config(product) $usb(idProduct)
+
+
+if $flags(logging) {
+	Log "\n----------------\nUSB values from sysfs:"
+	foreach attr {manufacturer product serial} {
+		Log "  $attr\t$usb($attr)"
+	}
+	Log "----------------"
+}
+
+if $flags(noswitching) {
+	SysLog "usb_modeswitch: switching disabled, no action for $usb(idVendor):$usb(idProduct)"
+	Log "\nSwitching globally disabled. Exit"
+	SafeExit
+}
+
+if {$usb(bNumConfigurations) == "1"} {
+	set configParam "-u -1"
+	Log "bNumConfigurations is 1 - don't check for active configuration"
+} else {
+	set configParam ""
+}
+
+# Check (and switch) for operating system if Huawei device present
+
+set flags(os) "linux"
+if {$usb(idVendor) == "12d1" && [regexp -nocase {android} [exec cat /proc/version]]} {
+	set flags(os) "android"
+}
+if {$flags(os) == "android"} {
+	set configList [ConfigGet conflist $usb(idVendor):#android]
+} else {
+	set configList [ConfigGet conflist $usb(idVendor):$usb(idProduct)]
+}
+
+if {[llength $configList] == 0} {
+	Log "Aargh! Config file missing for $usb(idVendor):$usb(idProduct)! Exit"
+	SafeExit
+}
+Log "ConfigList: $configList"
+
+# Check if there is more than one config file for this USB ID,
+# which would make an attribute test necessary. If so, check if
+# SCSI values are needed
+
+set scsiNeeded 0
+if {[llength $configList] > 1} {
+	if [regexp {:s} $configList] {
+		set scsiNeeded 1
+	}
+}
+if $scsiNeeded {
+	if [ReadSCSIAttrs $devdir:$iface] {
+		Log "----------------\nSCSI values from sysfs:"
+		foreach attr {vendor model rev} {
+			Log " $attr\t$scsi($attr)"
+		}
+		Log "----------------"
+	} else {
+		Log "Could not get SCSI attributes, exclude devices with SCSI match"
+	}
+} else {
+	Log "SCSI attributes not needed, move on"
+}
+
+# General wait - some devices need this
+after 500
+
+# Now check for a matching config file. Matching is done
+# by MatchDevice
+
+set report {}
+foreach mconfig $configList {
+
+	# skipping installer leftovers like "*.rpmnew"
+	if [regexp {\.(dpkg|rpm)} $mconfig] {continue}
+
+	Log "Check config: $mconfig"
+	if [MatchDevice $mconfig] {
+		Log "! matched. Read config data"
+#		set flags(config) $mconfig
+		if [string length $usb(busnum)] {
+			set busParam "-b [string trimleft $usb(busnum) 0]"
+			set devParam "-g [string trimleft $usb(devnum) 0]"
+		} else {
+			set busParam ""
+			set devParam ""
+		}
+		set flags(config) [ConfigGet conffile $mconfig]
+		ParseDeviceConfig $flags(config)
+		if [regexp -nocase {/[0-9a-f]+:#} $flags(config)] {
+			Log "Note: Using generic manufacturer configuration for \"$flags(os)\""
+		}
+		if $flags(nombim) {
+			set config(NoMBIMCheck) 1
+		}
+		if {$config(WaitBefore) != ""} {
+			Log "Delay time of $config(WaitBefore) seconds"
+			append config(WaitBefore) "000"
+			after $config(WaitBefore)
+			Log " wait is over, start mode switch"
+		}
+		if {$config(NoMBIMCheck)==0 && $usb(bNumConfigurations) > 1} {
+			Log "Device may have an MBIM configuration, check driver ..."
+			if [CheckMBIM] {
+				Log " driver for MBIM devices is available"
+				Log "Find MBIM configuration number ..."
+				if [catch {set cfgno [exec /usr/sbin/usb_modeswitch -j -Q $busParam $devParam -v $usb(idVendor) -p $usb(idProduct)]} err] {
+					Log "Error when trying to find MBIM configuration, switch to legacy modem mode"
+				} else {
+					set cfgno [string trim $cfgno]
+					if {$cfgno > 0} {
+						set config(Configuration) $cfgno
+						set flags(config) "Configuration=$cfgno"
+					} else {
+						Log " No MBIM configuration found, switch to legacy modem mode"
+					}
+				}
+			} else {
+				Log " no MBIM driver found, switch to legacy modem mode"
+			}
+		}
+		if [PantechAutoSwitch] {
+			Log "Waiting for Pantech auto-modeswitch"
+			set report "ok:busdev"
+			break
+		}
+		if {$config(Configuration) == 0} {
+			Log "Config file contains dummy method, do nothing. Exit"
+			SafeExit
+		}
+		UnbindDriver $devdir $ifdir
+		# Now we are actually switching
+		if $flags(logging) {
+			Log "Command to be run:\nusb_modeswitch -W -D $configParam $busParam $devParam -v $usb(idVendor) -p $usb(idProduct) -f \$flags(config)"
+			set report [exec /usr/sbin/usb_modeswitch -W -D $configParam $busParam $devParam -v $usb(idVendor) -p $usb(idProduct) -f "$flags(config)" 2>@1]
+			Log "\nVerbose debug output of usb_modeswitch and libusb follows"
+			Log "(Note that some USB errors are to be expected in the process)"
+			Log "--------------------------------"
+			Log $report
+			Log "--------------------------------"
+			Log "(end of usb_modeswitch output)\n"
+		} else {
+			set report [exec /usr/sbin/usb_modeswitch -Q -D $configParam $busParam $devParam -v $usb(idVendor) -p $usb(idProduct) -f "$flags(config)" 2>@1]
+		}
+		break
+	} else {
+		Log "* no match, don't use this config"
+	}
+}
+
+# Switching is complete; success checking was either
+# done by usb_modeswitch and logged via syslog OR bus/dev
+# parameter were used; then we do check for success HERE
+
+if {$config(Configuration) != ""} {
+	set ifdir [regsub {(\d):\d+\.0} $ifdir "\\1:$config(Configuration).0"]
+}
+
+if [regexp {ok:busdev} $report] {
+	if [CheckSuccess $devdir] {
+		Log "Mode switching was successful, found $usb(idVendor):$usb(idProduct) ($usb(manufacturer): $usb(product))"
+		SysLog "usb_modeswitch: switched to $usb(idVendor):$usb(idProduct) on [format %03d $usb(busnum)]/[format %03d $usb(devnum)]"
+	} else {
+		Log "\nTarget config not matching - current values are"
+		LogAttributes
+		Log "\nMode switching may have failed. Exit"
+		SafeExit
+	}
+} else {
+	if {![file isdirectory $devdir]} {
+		Log "Device directory in sysfs is gone! Something went wrong, abort"
+		SafeExit
+	}
+	if {![regexp {ok:} $report]} {
+		Log "\nCore program reported switching failure. Exit"
+		SafeExit
+	}
+	# Give the device another second if it's not fully back yet
+	if {![file exists $devdir/idProduct]} {
+		after 1000
+	}
+	ReadUSBAttrs $devdir $ifdir
+}
+
+# driver binding removed !!
+
+if {[string length "$usb(idVendor)$usb(idProduct)"] < 8} {
+	if {![regexp {ok:(\w{4}):(\w{4})} $report d usb(idVendor) usb(idProduct)]} {
+		Log "No target vendor/product ID found or given, can't continue. Abort"
+		SafeExit
+	}
+}
+# wait for drivers to bind
+after 500
+if {[llength [glob -nocomplain $devdir/$ifdir/ttyUSB*]] > 0} {
+	Log "Serial USB driver bound to interface 0\n will try to guess and symlink modem port on next connect"
+	AddToList link_list $usb(idVendor):$usb(idProduct)
+}
+
+# In newer kernels there is a switch to avoid the use of a device
+# reset (e.g. from usb-storage) which would possibly switch back
+# a mode-switching device to initial mode
+if [regexp {ok:} $report] {
+	Log "Check for AVOID_RESET_QUIRK kernel attribute"
+	if [file exists $devdir/avoid_reset_quirk] {
+		if [catch {exec echo "1" >$devdir/avoid_reset_quirk 2>/dev/null} err] {
+			Log " Error setting the attribute: $err"
+		} else {
+			Log " AVOID_RESET_QUIRK activated"
+		}
+	} else {
+		Log " not present in this kernel"
+	}
+}
+
+Log "\nAll done, exit\n"
+SafeExit
+
+}
+# end of proc {Main}
+
+
+proc {ReadSCSIAttrs} {topdir} {
+
+global scsi
+set counter 0
+set sysdir $topdir
+Log "Check storage tree in sysfs ..."
+while {$counter < 20} {
+	Log " loop $counter/20"
+	if {![file isdirectory $sysdir]} {
+		# Device is gone. Unplugged? Switched by kernel?
+		Log " sysfs device tree is gone; abort SCSI value check"
+		return 0
+	}
+	# Searching the storage/SCSI tree; might take a while
+	if {[set dirList [glob -nocomplain $topdir/host*]] != ""} {
+		set sysdir [lindex $dirList 0]
+		if {[set dirList [glob -nocomplain $sysdir/target*]] != ""} {
+			set sysdir [lindex $dirList 0]
+			regexp {.*target(.*)} $sysdir d subdir
+			if {[set dirList [glob -nocomplain $sysdir/$subdir*]] != ""} {
+				set sysdir [lindex $dirList 0]
+				if [file exists $sysdir/vendor] {
+					Log " Storage tree is ready"
+					break
+				}
+			}
+		}
+	}
+	after 500
+	incr counter
+}
+if {$counter == 20} {
+	Log "SCSI tree not found; you may want to check if this path/file exists:"
+	Log "$sysdir/vendor\n"
+	return 0
+}
+
+Log "Read SCSI values ..."
+foreach attr {vendor model rev} {
+	if [file exists $sysdir/$attr] {
+		set rc [open $sysdir/$attr r]
+		set scsi($attr) [read -nonewline $rc]
+		close $rc
+	} else {
+		set scsi($attr) ""
+		Log "Warning: SCSI attribute \"$attr\" not found."
+	}
+}
+return 1
+
+}
+# end of proc {ReadSCSIAttrs}
+
+
+proc {ReadUSBAttrs} {dir args} {
+
+global usb
+
+set attrList {idVendor idProduct bConfigurationValue manufacturer product serial devnum busnum bNumConfigurations}
+set mandatoryList {idVendor idProduct bNumConfigurations}
+set result 1
+if {$args != ""} {
+	lappend attrList "$args/bInterfaceClass"
+	lappend mandatoryList "$args/bInterfaceClass"
+}
+foreach attr $attrList {
+	if [file exists $dir/$attr] {
+		set rc [open $dir/$attr r]
+		set usb($attr) [string trim [read -nonewline $rc]]
+		close $rc
+	} else {
+		set usb($attr) ""
+		if {[lsearch $mandatoryList $attr] > -1} {
+			set result 0
+		}
+		if {$attr == "serial"} {continue}
+		Log "   Warning: USB attribute \"$attr\" not found"
+	}
+}
+return $result
+
+}
+# end of proc {ReadUSBAttrs}
+
+
+proc {MatchDevice} {config} {
+
+global scsi usb match
+
+set devinfo [file tail $config]
+set infoList [split $devinfo :]
+set stringList [lrange $infoList 2 end]
+if {[llength $stringList] == 0} {return 1}
+
+foreach teststring $stringList {
+	if {$teststring == "?"} {return 0}
+	set tokenList [split $teststring =]
+	set id [lindex $tokenList 0]
+	set matchstring [lindex $tokenList 1]
+	set blankstring ""
+	regsub -all {_} $matchstring { } blankstring
+	Log "match $match($id)"
+	Log "  string1 (exact):  $matchstring"
+	Log "  string2 (blanks): $blankstring"
+	Log " device string: [set $match($id)]"
+	if {!([string match *$matchstring* [set $match($id)]] || [string match *$blankstring* [set $match($id)]])} {
+		return 0
+	}
+}
+return 1
+
+}
+# end of proc {MatchDevice}
+
+
+proc {ParseGlobalConfig} {} {
+
+global flags
+set configFile ""
+set places [list /etc/usb_modeswitch.conf /etc/sysconfig/usb_modeswitch /etc/default/usb_modeswitch]
+foreach cfg $places {
+	if [file exists $cfg] {
+		set configFile $cfg
+		break
+	}
+}
+if {$configFile == ""} {return}
+
+set rc [open $configFile r]
+while {![eof $rc]} {
+	gets $rc line
+	if [regexp {^#} [string trim $line]] {continue}
+	if [regexp {DisableMBIMGlobal\s*=\s*([^\s]+)} $line d val] {
+		if [regexp -nocase {1|yes|true} $val] {
+			set flags(nombim) 1
+		} else {
+			set flags(nombim) 0
+		}
+	}
+	if [regexp {DisableSwitching\s*=\s*([^\s]+)} $line d val] {
+		if [regexp -nocase {1|yes|true} $val] {
+			set flags(noswitching) 1
+		}
+	}
+	if [regexp {EnableLogging\s*=\s*([^\s]+)} $line d val] {
+		if [regexp -nocase {1|yes|true} $val] {
+			set flags(logging) 1
+		} else {
+			set flags(logging) 0
+		}
+	}
+	if [regexp {SetStorageDelay\s*=\s*([^\s]+)} $line d val] {
+		if [regexp {\d+} $val] {
+			set flags(stordelay) $val
+		}
+	}
+
+}
+return "Use global config file: $configFile"
+
+}
+# end of proc {ParseGlobalConfig}
+
+
+proc ParseDeviceConfig {cfg} {
+
+global config
+set config(WaitBefore) ""
+set config(TargetVendor) ""
+set config(TargetProduct) ""
+set config(TargetClass) ""
+set config(Configuration) ""
+set config(NoMBIMCheck) 0
+set config(PantechMode) 0
+set config(CheckSuccess) 20
+
+foreach pname [lsort [array names config]] {
+	if [regexp -line "^\[^# \]*?$pname.*?= *(0x(\\w+)|\"(\[0-9a-fA-F,\]+)\"|(\[0-9\]+)) *\$" $cfg d config($pname)] {
+#		Log "config: $pname set to $config($pname)"
+	}
+}
+
+set config(WaitBefore) [string trimleft $config(WaitBefore) 0]
+
+}
+# end of proc {ParseDeviceConfig}
+
+
+proc ConfigGet {command config} {
+
+global setup usb flags
+
+switch $command {
+
+	conflist {
+		# Unpackaged configs first; sorting is essential for priority
+		set configList [lsort -decreasing [glob -nocomplain $setup(dbdir_etc)/$config*]]
+		set configList [concat $configList [lsort -decreasing [glob -nocomplain $setup(dbdir)/$config*]]]
+		eval lappend configList [glob -nocomplain $setup(dbdir)/$usb(idVendor):#$flags(os)]
+		if [file exists $setup(dbdir)/configPack.tar.gz] {
+			Log "Found packed config collection $setup(dbdir)/configPack.tar.gz"
+			if [catch {set packedList [exec tar -tzf $setup(dbdir)/configPack.tar.gz 2>/dev/null]} err] {
+				Log "Error: problem opening config package; tar returned\n $err"
+				return {}
+			}
+			set packedList [split $packedList \n]
+			set packedConfigList [lsort -decreasing [lsearch -glob -all -inline $packedList $config*]]
+			lappend packedConfigList [lsearch -inline $packedList $usb(idVendor):#$flags(os)]
+			# Now add packaged configs with a mark, again sorted for priority
+			foreach packedConfig $packedConfigList {
+				lappend configList "pack/$packedConfig"
+			}
+		}
+		return $configList
+	}
+	conffile {
+		if [regexp {^pack/} $config] {
+			set config [regsub {pack/} $config {}]
+			Log "Extract config $config from collection $setup(dbdir)/configPack.tar.gz"
+			set configContent [exec tar -xzOf $setup(dbdir)/configPack.tar.gz $config 2>/dev/null]
+		} else {
+			if [regexp [list $setup(dbdir_etc)] $config] {
+				Log "Use config file from override folder $setup(dbdir_etc)"
+				SysLog "usb_modeswitch: use overriding config file $config; make sure this is intended"
+				SysLog "usb_modeswitch: please report any new or corrected settings; otherwise, check for outdated files"
+			}
+			set rc [open $config r]
+			set configContent [read $rc]
+			close $rc
+		}
+		return $configContent
+	}
+}
+
+}
+# end of proc {ConfigGet}
+
+proc {Log} {msg} {
+
+global flags device loginit
+
+if {$flags(logging) == 0} {return}
+
+if $flags(logwrite) {
+	if [string length $loginit] {
+		exec echo "\nUSB_ModeSwitch log from [clock format [clock seconds]]" >/var/log/usb_modeswitch_$device
+		exec echo "$loginit" >>/var/log/usb_modeswitch_$device
+		set loginit ""
+	}
+	exec echo $msg >>/var/log/usb_modeswitch_$device
+} else {
+	append loginit "\n$msg"
+}
+
+}
+# end of proc {Log}
+
+
+# Writing the log file and exit
+proc {SafeExit} {} {
+
+global flags
+set flags(logwrite) 1
+Log ""
+exit
+
+}
+# end of proc {SafeExit}
+
+
+proc {SymLinkName} {path} {
+global device flags
+
+proc {hasInterrupt} {ifDir} {
+	if {[llength [glob -nocomplain $ifDir/ttyUSB*]] == 0} {
+		Log "  no ttyUSB interface - skip endpoint check"
+		return 0
+	}
+	foreach epDir [glob -nocomplain $ifDir/ep_*] {
+		set e [file tail $epDir]
+		Log "  check $e ..."
+		if [file exists $epDir/type] {
+			set rc [open $epDir/type r]
+			set type [read $rc]
+			close $rc
+			if [regexp {Interrupt} $type] {
+				Log "  $e has interrupt transfer type"
+				return 1
+			}
+		}
+	}
+	return 0
+}
+
+set loginit "usb_modeswitch called with --symlink-name\n parameter: $path\n"
+
+# In case the device path is returned as /class/tty/ttyUSB,
+# get the USB device path from linked tree "device"
+set linkpath /sys$path/device
+if [file exists $linkpath] {
+	if {[file type $linkpath] == "link"} {
+		set rawpath [file readlink $linkpath]
+		set trimpath [regsub -all {\.\./} $rawpath {}]
+ 		if [file isdirectory /sys/$trimpath] {
+			append loginit "\n Use path $path\n"
+			set path /$trimpath
+		}
+	}
+}
+if {![regexp {([0-9]+-[0-9]+[\.0-9]*:[^/]*).*(ttyUSB[0-9]+)} $path d myDev myPort]} {
+	if $flags(logging) {
+		set device [clock clicks]
+		set flags(logwrite) 1
+		Log "$loginit\nThis is not a ttyUSB port. Abort"
+	}
+	return ""
+}
+
+set device ttyUSB_$myDev
+set flags(logwrite) 1
+Log "$loginit\nMy name is $myPort\n"
+
+if {![regexp {(.*?[0-9]+)\.([0-9]+)/ttyUSB} /sys$path d ifRoot ifNum]} {
+	Log "Could not find interface in path\n $path. Abort"
+	return ""
+}
+
+set ifDir $ifRoot.$ifNum
+
+Log "Check my endpoints ...\n in $ifDir"
+if [hasInterrupt $ifDir] {
+	Log "\n--> I am an interrupt port"
+	set rightPort 1
+} else {
+	Log "\n--> I am not an interrupt port\n"
+	set rightPort 0
+}
+
+# There are devices with more than one interrupt interface.
+# Assume that the lowest of these is usable. Check all
+# possible lower interfaces
+
+if { $rightPort && ($ifNum > 0) } {
+	Log "\nLook for lower ports with interrupt endpoints"
+	for {set i 0} {$i < $ifNum} {incr i} {
+		set ifDir $ifRoot.$i
+		Log " in ifDir $ifDir ..."
+		if [hasInterrupt $ifDir] {
+			Log "\n--> found an interrupt interface below me\n"
+			set rightPort 0
+			break
+		}
+	}
+}
+if {$rightPort == 0} {
+	Log "Return empty name and exit"
+	return ""
+}
+
+Log "\n--> No interrupt interface below me\n"
+
+cd /dev
+set idx 2
+set symlinkName "gsmmodem"
+while {$idx < 256} {
+	if {![file exists $symlinkName]} {
+		set placeholder [open /dev/$symlinkName w]
+		close $placeholder
+		break
+	}
+	set symlinkName gsmmodem$idx
+	incr idx
+}
+if {$idx == 256} {return ""}
+
+Log "Return symlink name \"$symlinkName\" and exit"
+return $symlinkName
+
+}
+# end of proc {SymLinkName}
+
+
+# Add USB ID to list of devices needing later treatment
+proc {AddToList} {name id} {
+
+set listfile /var/lib/usb_modeswitch/$name
+if [file exists $listfile] {
+	set rc [open $listfile r]
+	set buffer [read $rc]
+	close $rc
+	if [string match *$id* $buffer] {
+		return
+	}
+	set idList [split [string trim $buffer] \n]
+}
+lappend idList $id
+set buffer [join $idList "\n"]
+if [catch {set lc [open $listfile w]}] {return}
+puts $lc $buffer
+close $lc
+
+}
+# end of proc {AddToList}
+
+
+proc {CheckSuccess} {devdir} {
+
+global config usb flags
+
+# For Cisco AM10, target device not on same port
+if {$usb(idVendor) == "1307" && $usb(idProduct) == "1169"} {
+	set devdir [string range $devdir 0 end-1]2
+}
+set ifdir [file tail [IfDir 0 $devdir]]
+if {[string length $config(TargetClass)] || [string length $config(Configuration)]} {
+	set config(TargetVendor) $usb(idVendor)
+	set config(TargetProduct) $usb(idProduct)
+}
+Log "Check success of mode switch for max. $config(CheckSuccess) seconds ..."
+
+set expected 1
+for {set i 1} {$i <= $config(CheckSuccess)} {incr i} {
+	after 1000
+	if {![file isdirectory $devdir]} {
+		Log " Wait for device file system ($i sec.) ..."
+		continue
+	} else {
+		Log " Read attributes ..."
+	}
+	set ifdir [IfDir 0 $devdir]
+	if {$ifdir == ""} {continue}
+	set ifdir [file tail $ifdir]
+	if {![ReadUSBAttrs $devdir $ifdir]} {
+		Log " Essential attributes are missing, continue wait ..."
+		continue
+	}
+	if [string length $config(Configuration)] {
+		if {$usb(bConfigurationValue) != $config(Configuration)} {continue}
+	}
+	if [string length $config(TargetClass)] {
+		if {![regexp $usb($ifdir/bInterfaceClass) $config(TargetClass)]} {
+			if {$config(class) != $usb($ifdir/bInterfaceClass} {
+				set expected 0
+			} else {continue}
+		}
+	}
+	if {![regexp $usb(idVendor) $config(TargetVendor)]} {
+		if {![regexp $usb(idVendor) $config(vendor)]} {
+			set expected 0
+		} else {continue}
+	}
+	if {![regexp $usb(idProduct) $config(TargetProduct)]} {
+		if {![regexp $usb(idProduct) $config(product)]} {
+			set expected 0
+		} else {continue}
+	}
+	# Arriving here means that device attributes have changed
+	if $expected {
+		Log " All attributes matched"
+	} else {
+		if [regexp -nocase {/[0-9a-f]+:#} $flags(config)] {
+			Log " idProduct has changed after generic mode-switch, assume success"
+		} else {
+			Log " Attributes are different but target values are unexpected:"
+			LogAttributes
+		}
+	}
+	break
+}
+if {$i > 20} {return 0} else {return 1}
+
+}
+# end of proc {CheckSuccess}
+
+
+proc {IfDir} {iface devdir} {
+
+set allfiles [glob -nocomplain $devdir/*]
+set files [glob -nocomplain $devdir/*.$iface]
+if {[llength $files] == 0} {
+	return ""
+}
+set ifdir [lindex $files 0]
+if {![file isdirectory $ifdir]} {
+	return ""
+}
+return $ifdir
+
+}
+# end of proc {IfDir}
+
+proc {IfClass} {iface devdir} {
+
+set ifdir [IfDir $iface $devdir]
+
+if {![file exists $ifdir/bInterfaceClass]} {
+	return -1
+}
+set rc [open $ifdir/bInterfaceClass r]
+set c [read $rc]
+close $rc
+return [string trim $c]
+
+}
+# end of proc {IfClass}
+
+
+proc {SysLog} {msg} {
+
+global flags
+if {![info exists flags(logger)]} {
+	set flags(logger) ""
+	foreach fn {/bin/logger /usr/bin/logger} {
+		if [file exists $fn] {
+			set flags(logger) $fn
+		}
+	}
+	Log "Logger is $flags(logger)"
+}
+if {$flags(logger) == ""} {
+	Log "Can't add system message, no syslog helper found"
+	return
+}
+catch {exec $flags(logger) -p syslog.notice "$msg" 2>/dev/null}
+
+}
+# end of proc {SysLog}
+
+proc {SetStorageDelay} {secs} {
+
+Log "Adjust delay for USB storage devices ..."
+set attrib /sys/module/usb_storage/parameters/delay_use
+if {![file exists $attrib]} {
+	Log "Error: could not find delay_use attribute"
+	return
+}
+if [catch {set ch [open $attrib r+]} err] {
+	Log "Error: could not access delay_use attribute: $err"
+	return
+}
+if {[read $ch] < $secs} {
+	seek $ch 0 start
+	puts -nonewline $ch $secs
+	Log " Delay set to $secs seconds\n"
+} else {
+	Log " Current value is higher than $secs. Leave it alone\n"
+}
+close $ch
+
+}
+# end of proc {SetStorageDelay}
+
+proc {CheckMBIM} {} {
+
+set kversion [exec uname -r]
+if [llength [glob -nocomplain /lib/modules/$kversion/kernel/drivers/net/usb/cdc_mbim*]] {return 1}
+if [file exists /sys/bus/usb/drivers/cdc_mbim] {return 1}
+return 0
+
+}
+
+proc {CheckQMI} {} {
+
+set kversion [exec uname -r]
+if [llength [glob -nocomplain /lib/modules/$kversion/kernel/drivers/net/usb/qmi_wwan*]] {return 1}
+if [file exists /sys/bus/usb/drivers/cdc_mbim] {return 1}
+return 0
+
+}
+
+proc {PantechAutoSwitch} {} {
+
+global config flags
+if {$config(PantechMode) == 3} {return 1}
+if {$config(PantechMode) == 1} {
+	if {"$config(vendor):$config(product)" == "10a9:6080"} {
+		set flags(config) [regsub {PantechMode *= *1} $flags(config) "PantechMode=2"]
+		Log " PantechMode changed to 2"
+		return 0
+	} elseif [CheckQMI] {
+		set flags(config) [regsub {PantechMode *= *1} $flags(config) "PantechMode=4"]
+		Log " PantechMode changed to 4"
+		return 0
+	} else {
+		return 1
+	}
+} else {return 0}
+
+}
+
+proc UnbindDriver {devdir ifdir} {
+
+set att $devdir/$ifdir/driver/unbind
+if [file exists $att] {
+	Log "Unbinding driver"
+	exec echo -n "$ifdir" > $att
+}
+
+}
+
+proc {LogAttributes} {} {
+
+global flags usb
+if $flags(logging) {
+	set attrList {idVendor idProduct bConfigurationValue manufacturer product serial}
+	foreach attr [lsort [array names usb]] {
+		Log "    [format %-26s $attr:] $usb($attr)"
+	}
+}
+
+}
+
+proc {HasFF} {devdir} {
+
+set i 0
+while {[set dir [IfDir $i $devdir]] != ""} {
+	set c [exec cat $dir/bInterfaceClass]
+	if {$c == "ff"} {return 1}
+	incr i
+}
+return 0
+
+}
+
+
+# The actual entry point
+Main $argv $argc
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/Android.mk b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/Android.mk
new file mode 100755
index 0000000..5dacae0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+INCLUDES = $(LOCAL_PATH)
+INCLUDES += external/libusb/libusb
+
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE := usb_modeswitch
+LOCAL_SRC_FILES := usb_modeswitch.c
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES :=$(INCLUDES)
+LOCAL_SHARED_LIBRARIES := libusb
+
+LOCAL_CFLAGS += -Wno-self-assign -Wno-sometimes-uninitialized
+LOCAL_CFLAGS += -Wno-error=deprecated-declarations -Wno-deprecated-declarations
+
+$(shell mkdir -p $(PRODUCT_OUT)/vendor/etc)
+$(shell cp -R $(LOCAL_PATH)/usb_modeswitch.d $(PRODUCT_OUT)/vendor/etc)
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/COPYING b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/COPYING
new file mode 100755
index 0000000..d60c31a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/ChangeLog b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/ChangeLog
new file mode 100755
index 0000000..42ee92a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/ChangeLog
@@ -0,0 +1,288 @@
+
+History of USB_ModeSwitch
+=========================
+
+Version 2.4.0, 2016/06/12
+    ATTENTION: All ad-hoc driver binding code (using new_id driver attribute)
+    removed - was a potential source of side effects and should now be
+    obsoleted by good kernel support for modems; Added "dummy" setting for
+    config files, to conditionally refrain from handling a device (see this
+    topic: www.draisberghof.de/usb_modeswitch/bb/viewtopic.php?f=4&t=2458 );
+    extended StandardEject sequence to include LUN 1, required for some D-Link
+    devices; add device class 239 ("miscellaneous") to sanity check (thanks to
+    Daniel Drake for reporting); udev shell script - removed driver binding,
+    removed almost all waiting and forking, improved check for systemd (thanks
+    to Daniel Drake for problem analysis and solution, see this topic/patch:
+    www.draisberghof.de/usb_modeswitch/bb/viewtopic.php?p=16777#p16777 ,
+    gist.github.com/dsd/9f83c4830ab78ce94078aedb2cf16a8f )
+Version 2.3.0, 2016/01/12
+    ATTENTION: -I flag is now history and being ignored - determining SCSI
+    attributes is really an 'outside task'; -n flag (NeedResponse) is being
+    ignored, CSW response will now always be read; introduction of parameter
+    "OptionMode", wrapping the standard bulk message for all newer Huawei
+    devices; fixed missing variable initialization in dispatcher script which
+    could lead to crash (thanks, Dmitry Kunilov!); fixed bug which prevented
+    early logging; fixed success report for Cisco AM10; some source code
+    formatting and clean-up
+Version 2.2.6, 2015/11/01
+    Renamed function abort(), avoiding possible conflicts in static builds
+    with libjim (thanks, Gustavo Zacharias); removed storage class check of
+    interface 0 from dispatcher, enabling new multi-config devices in data
+    package 20151101
+Version 2.2.5, 2015/07/16
+    Fixed bug in configuration check, possibly leading to segfault (thanks,
+    Leonid Lisovskiy); fixed Pantech commandline parameter evaluation (was
+    not working at all); added driver unbind step via sysfs in wrapper,
+    getting rid of the USB subsystem complaint "interface 0 claimed by
+    usb-storage while 'usb_modeswitch' <does this and that>"
+Version 2.2.4, 2015/07/14
+    Fixed buggy check of USB configuration selection (possibly leading
+    to segfault), tested with Alcatel X602D; removed call to 'libusb_strerror'
+    from libusb initialization - not available in earlier libusb1 versions
+Version 2.2.3, 2015/06/29
+    Fixed problem arising with systemd version 221 (220 untested), which
+    affects starting the usb_modeswitch systemd unit from the sh script
+    (reported by Archlinux users)
+Version 2.2.2, 2015/06/27
+    Added catch for libusb init error (thanks, Henrik Gustafsson); removed
+    global function result variable; added catch for USB configuration
+    read error (both thanks to "otila"); fixed wrapper script where port
+    search for symlinking modem port was broken ("/dev/gsmmodem"); changed
+    PantechMode parameter to represent different targets; added global
+    config option to disable MBIM checking and setting alltogether (request
+    from "kai"); changed udev sh script so that systemd processing takes
+    precedence over upstart; changed systemd template unit parameter to
+    avoid escaping problems
+Version 2.2.1, 2015/01/15
+    Fixed unreliable switching function for Cisco AM10
+Version 2.2.0, 2014/05/29
+    Introduction of parameter "HuaweiNewMode", wrapping the standard bulk
+    message for all newer Huawei devices; support for generic fall-back
+    config files, combined with OS switch (per vendor ID), implementation
+    to use a specific switching command on Android for all Huawei devices
+    (see README of data package for details); this change was suggested
+    by Huawei
+Version 2.1.1, 2014/03/27
+    Code cleanup, better use of libusb1; this also fixes problems with
+    determination of the active USB configuration (Samsung, Option modems);
+    "Interface" parameter was not working as expected, fixed (see also:
+    https://bugs.launchpad.net/bugs/1261923 ); fixed bogus interface release
+    in "inquire" function, again a report by "Sonya@zte"
+Version 2.1.0, 2014/01/28
+    ATTENTION: -I flag meaning reversed, default is to skip SCSI inquiry;
+    introduction of StandardEject, replacing many MessageContents with the
+    same function, reducing size of device config files, and always including
+    the 'Allow Medium Removal' before ejecting (thanks to Lars Melin for
+    the idea); fix in "bulk_read", removing bogus CSW request (report from
+    "Sonya@zte")
+Version 2.0.1, 2013/09/03
+    Fixed stupid string size bug which could lead to memory corruption
+    (thanks to Leonid Myravjev)
+Version 2.0.0, 2013/09/01
+    Switched to libusb1.0, with much help from folks of the wl500g project
+    (http://wl500g.googlecode.com): Vladislav Grishenko, Leonid Lisovskiy,
+    Roman Samarev, Andrey Tikhomirov;
+    major code and debug output cleanup; man page corrections and additions
+    (thanks to Thomas Haller);
+    experimental systemd and upstart integration, if present
+    (Explanation: newer udev versions kill all subprocesses, detached or
+    not. The suggested way to handle longer running processes like the
+    usb_modeswitch_dispatcher is to add simple services or tasks and start
+    these by sending signals from the udev rule)
+    !! Attention, system integrators: a crude install facility is included
+    in the Makefile to check if "upstart" or "systemd" is active and to
+    install the matching service file; you may want to adapt it better to
+    your respective system, possibly adding dependencies/targets to the
+    services. Note that the udev starter script usb_modeswitch.sh also
+    checks for the existence of the service/unit files
+Version 1.2.7, 2013/08/07
+    Two new dedicated control message functions to support Pantech LTE
+    (thanks to Adam Goode) and Blackberry Q10/Z10 (thanks to Daniel Mende)
+Version 1.2.6, 2013/06/02
+    Several changes to streamline compiling as part of larger projects
+    (thanks to Nicolas Carrier), mostly in Makefile; fix compiler warnings
+    appearing in certain build environments (N. Carrier); new Quanta
+    procedure (thanks to Andrey Tikhomirov) for Quanta 1K3 LTE; fix for
+    error with cascaded hubs in dispatcher script (hint from N. Carrier)
+Version 1.2.5, 2012/11/09
+    Initial support for MBIM devices, use with data package >= 20121109;
+    checking for these is the automatic default, new parameter NoMBIMCheck
+    prevents the check per device in case of problems; new global option
+    to set "delay_use" of usb-storage (as low values may prevent
+    mode-switching); fix for handling multi-configuration devices (thanks
+    to Bjørn Mork for advice)
+Version 1.2.4, 2012/08/12
+    Additional interface checks to prevent sending UFI commands to non-
+    storage interfaces (prompted by more ambiguous device IDs popping up);
+    change in SierraMode for handling newer devices which caused an error
+    abort before; Makefile fix for parallelized make runs
+Version 1.2.3, 2012/01/28
+    Fixed two bugs both causing the embedded-jimsh install variant of the
+    dispatcher crash (the "pure-script" install variant was NOT affected);
+    fixed some "regexp" incompatibilities with Debian's libjim
+Version 1.2.2, 2012/01/19
+    Fixed bad bug preventing mode switch for devices using TargetClass;
+    improved logging in case of negative success check
+Version 1.2.1, 2011/12/26
+    Fixed possible ambiguities when multiple identical modems are plugged
+    synchronously; this is achieved by adding -b and -g parameter (busnum
+    and devnum) for proper id'ing; some resulting workflow changes and
+    shortcuts in "system integration" mode (use sysfs/wrapper for success
+    control, reduce informative checks); improved hub usage robustness;
+    future data packages can be ridded of redundancies (default ID, success
+    check parameters), resulting in smaller files;
+    fixed bad bug which may prevent switching completely when logging is
+    not activated; fixed possible overflow in dispatcher C code (thanks to
+    Gilles Espinasse)
+Version 1.2.0, 2011/10/23
+    Added QisdaMode for Qisda H21 (thanks to Chi-Hang Long for the code);
+    dispatcher can now be installed with an embedded interpreter, so that
+    Tcl is no longer required; added command line options for binary program
+    to accept configuration data via stdin or as a long string parameter -
+    this fixes the bug with non-writable temporary file during boot;
+    reversed skipping of pre-switching delay, which has caused problems;
+    fixed potential buffer overflow (thanks to Rafael Silva for the find);
+    get first interface right even on some broken devices (thanks to
+    Alexander Gordeev for the patch); increased post-switch delay before
+    driver binding to avoid possible conflict with usb-storage
+Version 1.1.9, 2011/08/05
+    Added CiscoMode for Valet device; additional checking for CDC ACM device
+    to prevent erroneous driver loading after switching; no more post-switch
+    check for access to initial device if target parameters are given
+Version 1.1.8, 2011/06/19
+    Cleaned up switchSendMessage(); added workaround for quirky devices not
+    reporting configuration setting; added non-CSW response for arbitrary
+    bulk transfers; added SequansMode and MobileActionMode; check for active
+    configuration will be skipped if bNumConfigurations is 1 (most cases)
+Version 1.1.7, 2011/02/27
+    Attention: paths for runtime files and database have changed! Old places
+    will be found but are deprecated; /usr/share/usb_modeswitch for database,
+    /var/lib/usb_modeswitch for "remembered" IDs;
+    fix for configuration setting race (thanks to Amit Mendapara); discovered
+    incompatibility between Tcl versions <= 8.3 and >=8.4, so 8.4 is the
+    minimum prerequisite now;
+    first availability of an alternative source pack which includes "jimsh",
+    a fast Tcl mini shell, intended for resource-constrained systems
+Version 1.1.6, 2010/12/22
+    Moved warm-boot driver binding to sh wrapper, was unreliable in 1.1.5;
+    sh wrapper overhaul, made compatible with Ubuntu's "dash" shell, tclsh
+    calls reduced further; initial device checking includes current
+    bConfigurationValue now, should work with config setting for multiple
+    devices; made tcl script conform to limitations of "jimsh", the minimal
+    tcl shell (hint from Barry Kauler); fixes for "usbserial" fallback
+    (driver binding for old systems); in the C program, changed parameter
+    "MessageDelay" (hitherto unused) to "ReleaseDelay", to be used in one
+    device configuration (delay interface release after bulk message sending)
+Version 1.1.5, 2010/11/28
+    Added special control message for Kobil devices (patch from Filip Aben);
+    try to get active configuration for interface class checking (there are
+    some new devices 'switching' via configuration selection);
+    fixed "0000" target product ID - again; new bash and tcl wrapper logic:
+    the convenience functions for driver binding and symlinking will now
+    start the tcl shell ONLY for known devices; changed and appended logging
+    capabilities of said convenience functions; add loading of "usbserial"
+    as a fallback for older systems to support new devices;
+    add workaround for bug in libusb1 which affects device search during
+    success check
+Version 1.1.4, 2010/08/17
+    The package should work at boot time now (cold and warm);
+    product IDs of "0000" do exist but were not accepted, fixed (thanks to
+    Sakis Dimopoulos); response endpoint is now always detected (led to
+    possible error report when resetting all endpoints in version 1.1.3);
+    wrapper script can now work with a packed collection of config files as
+    well as with the plain folder of files; use with the "install-packed"
+    make target of the data package (for use on systems with resource
+    constraints); wrapper fix for the symlink feature: handling of multiple
+    interrupt ports was incomplete; wrapper does not longer use a temporary
+    file for the symlink feature (security considerations, Marco d'Itri)
+Version 1.1.3, 2010/06/21
+    Added delay option to separate multiple message transfers by millisecs;
+    fixed (possibly dangerous) sloppy string handling (thanks to Christophe
+    Fergeau); added "clear_halt" for response endpoint; small additions in
+    Makefile (install with -D); changes in option handling (NO MORE DEFAULT
+    CONFIG FILE!) and help text; symlink feature in wrapper can now cope
+    with devices providing more than one interrupt port; wrapper now ignores
+    package manager leftovers in config folder; replaced bash-specific syntax
+    in wrapper; changed ZTE skipping (if existing rules are found) to warning
+Version 1.1.2, 2010/04/18
+    Added support for two additional bulk messages; wrapper handles special
+    ZTE case; generalized driver loading, new parameter "DriverModule" and
+    "DriverIDPath"; new wrapper facility to add symlink pointing to interrupt
+    port (used in rule file from data pack >= 20100418)
+Version 1.1.1, 2010/03/17
+    Attention: old usb_modeswitch.conf renamed to usb_modeswitch.setup!
+    Add separate config file for wrapper (global settings for switching and
+    logging); add config file option to disable driver loading; handling of
+    kernel attribute AVOID_RESET_QUIRK added; bug fixed in SonyMode (reported
+    by "no-0n3"); bug fixed in SuccessCheck logic; minor flow alignments and
+    fixes; new devices
+Version 1.1.0, 2010/01/24
+    Attention: wrapper script location changed, uninstall old versions!
+    Major fixes in the wrapper script (stabilizing and time-saving);
+    back to unified installation, defaults to "integrated" approach;
+    new -D parameter to enable "integrated" behaviour; bugs fixed in
+    success check; man file included (borrowed from the Debian package);
+    C code and binary works with the compat library from libusb-1.0;
+    some new devices
+Version 1.0.7, 2010/01/06
+    Bug fixed for Sony mode, thanks to Marco Chiaranda; fix for parameter
+    substitution in newer udev versions, fix for bad bug in wrapper script
+    practically disabling automatic mode
+Version 1.0.6, 2009/12/21
+    New "GCT Mode", fixes for device quirks (NXP Dragonfly), fix for multiple
+    Huawei devices, cleanups, loads of new devices in config file and database,
+    minor tcl script changes
+Version 1.0.5, 2009/08/26
+    More changes and fixes regarding success check; "--version" option;
+    config "database" updated
+Version 1.0.4, 2009/08/23
+    Success check bugs (and others) fixed
+Version 1.0.3, 2009/08/20
+    Success check improved; experimental system integration (fully automated),
+    optional; new parameter "TargetProductList" needed for this; other
+    necessary small adaptations; more devices
+Version 1.0.2, 2009/06/10
+    Output bugs fixed
+Version 1.0.1, 2009/06/08
+    Added output of descriptor strings for further identification
+Version 1.0.0, 2009/06/01
+    Attention: possible incompatibilities for command line control!
+    On/off flags don't require arguments anymore (-H, -S, -O, -d, -R,
+    -n, new: -I), meaning "-R 0" does a reset like "-R 1" or "-R";
+    long option names changed to standard format (e.g. --HuaweiMode to
+    --huawei-mode); added device inquiry, for future help with device
+    identification; catch error -19 as possible success; send and response
+    endpoints now autoselected (consequently NeedResponse is back);
+    new devices
+Version 0.9.7, 2009/04/15
+    Updated SonyMode, MD 400 now stable; automatic default endpoint
+    detection from Andrew Bird
+Version 0.9.7beta, 2009/03/15
+    Major code clean up, optional success control (both suggested
+    by Daniel Cooper), new devices
+Version 0.9.6, 2009/01/08
+    Special modes added for Sierra and Sony Ericsson, new devices
+Version 0.9.5, 2008/10/27
+    New options for USB tuning (jokedst), lots of new devices, clean up
+Version 0.9.4, 2008/06/09
+    Compat fix for libusb on FreeBSD quirks, more devices
+Version 0.9.4beta2, 2008/03/19
+    Successful udev device release fix
+Version 0.9.4beta, 2008/03/16
+    Multiple device support
+Version 0.9.3, 2008/03/09
+    More devices, no changes from beta version
+Version 0.9.3beta, 2007/12/30
+    New TargetClass parameter for recent Option firmware (Paul Hardwick), more
+    devices
+Version 0.9.2, 2007/11/02
+    New Huawei mode (code from Miroslav Bobovsky, added by Denis Sutter), more
+    devices
+Version 0.9.1beta, 2007/09/04 (jokedst)
+    Added command line parsing, cleaned up config stuff, doc updates
+Version 0.9beta, 2007/08/15
+    Name change from "icon_switch", parameter file and generalizing
+Version 0.2, 2006/09/25
+    Code cleaning, more messages
+Version 0.1, 2006/09/24
+    (as "icon_switch") Just very basic functionality ...
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/Makefile b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/Makefile
new file mode 100755
index 0000000..47ed794
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/Makefile
@@ -0,0 +1,105 @@
+PROG        = usb_modeswitch
+VERS        = 2.4.0
+CC          ?= gcc
+CFLAGS      += -Wall
+LIBS        = `pkg-config --libs --cflags libusb-1.0`
+RM          = /bin/rm -f
+OBJS        = usb_modeswitch.c
+PREFIX      = $(DESTDIR)/usr
+ETCDIR      = $(DESTDIR)/etc
+SYSDIR      = $(ETCDIR)/systemd/system
+UPSDIR      = $(ETCDIR)/init
+UDEVDIR     = $(DESTDIR)/lib/udev
+SBINDIR     = $(PREFIX)/sbin
+MANDIR      = $(PREFIX)/share/man/man1
+VPATH       = jimtcl
+HOST_TCL   := $(shell cd jim && ./autosetup/find-tclsh)
+ifeq (,$(findstring jimsh0,$(HOST_TCL)))
+TCL        ?= $(HOST_TCL)
+else
+TCL        ?= /usr/bin/tclsh
+endif
+JIM_CONFIGURE_OPTS = --disable-lineedit \
+	--with-out-jim-ext="stdlib posix load signal syslog" --prefix=/usr
+
+.PHONY: clean install install-common uninstall \
+	script shared static \
+	dispatcher-script dispatcher-shared dispatcher-static \
+	install-script install-shared install-static
+
+all: script
+
+script: $(PROG) dispatcher-script
+
+shared: $(PROG) dispatcher-shared
+
+static: $(PROG) dispatcher-static
+
+$(PROG): $(OBJS) usb_modeswitch.h
+	$(CC) -o $(PROG) $(OBJS) $(CFLAGS) $(LIBS) $(LDFLAGS)
+
+jim/libjim.so:
+	cd jim && CFLAGS="$(CFLAGS)" CC="$(CC)" ./configure $(JIM_CONFIGURE_OPTS) --shared
+	$(MAKE) -C jim lib
+
+jim/libjim.a:
+	cd jim && CFLAGS="$(CFLAGS)" CC="$(CC)" ./configure $(JIM_CONFIGURE_OPTS)
+	$(MAKE) -C jim lib
+
+dispatcher-script: usb_modeswitch.tcl
+	sed 's_!/usr/bin/tclsh_!'"$(TCL)"'_' < usb_modeswitch.tcl > usb_modeswitch_dispatcher
+
+dispatcher-shared: jim/libjim.so dispatcher.c usb_modeswitch.string
+	$(CC) dispatcher.c $(LDFLAGS) -Ljim -ljim -Ijim -o usb_modeswitch_dispatcher $(CFLAGS)
+
+dispatcher-static: jim/libjim.a dispatcher.c usb_modeswitch.string
+	$(CC) dispatcher.c $(LDFLAGS) jim/libjim.a -Ijim -o usb_modeswitch_dispatcher $(CFLAGS)
+
+usb_modeswitch.string: usb_modeswitch.tcl
+	$(HOST_TCL) make_string.tcl usb_modeswitch.tcl > $@
+
+clean:
+	$(RM) usb_modeswitch
+	$(RM) usb_modeswitch_dispatcher
+	$(RM) usb_modeswitch.string
+	$(RM) jim/autosetup/jimsh0
+	$(RM) jim/autosetup/jimsh0.c
+
+distclean: clean
+	-$(MAKE) -C jim distclean
+
+ums-clean:
+	$(RM) usb_modeswitch
+	$(RM) usb_modeswitch_dispatcher
+	$(RM) usb_modeswitch.string
+
+# If the systemd folder is present, install the service for starting the dispatcher
+# If not, use the dispatcher directly from the udev rule as in previous versions
+
+install-common: $(PROG) usb_modeswitch_dispatcher
+	install -D --mode=755 usb_modeswitch $(SBINDIR)/usb_modeswitch
+	install -D --mode=755 usb_modeswitch.sh $(UDEVDIR)/usb_modeswitch
+	install -D --mode=644 usb_modeswitch.conf $(ETCDIR)/usb_modeswitch.conf
+	install -D --mode=644 usb_modeswitch.1 $(MANDIR)/usb_modeswitch.1
+	install -D --mode=644 usb_modeswitch_dispatcher.1 $(MANDIR)/usb_modeswitch_dispatcher.1
+	install -D --mode=755 usb_modeswitch_dispatcher $(SBINDIR)/usb_modeswitch_dispatcher
+	install -d $(DESTDIR)/var/lib/usb_modeswitch
+	test -d $(UPSDIR) -a -e /sbin/initctl && install --mode=644 usb-modeswitch-upstart.conf $(UPSDIR) || test 1
+	test -d $(SYSDIR) -a \( -e /usr/bin/systemctl -o -e /bin/systemctl \) && install --mode=644 usb_modeswitch@.service $(SYSDIR) || test 1
+
+install: install-script
+
+install-script: dispatcher-script install-common
+
+install-shared: dispatcher-shared install-common
+
+install-static: dispatcher-static install-common
+
+uninstall:
+	$(RM) $(SBINDIR)/usb_modeswitch
+	$(RM) $(SBINDIR)/usb_modeswitch_dispatcher
+	$(RM) $(UDEVDIR)/usb_modeswitch
+	$(RM) $(ETCDIR)/usb_modeswitch.conf
+	$(RM) $(MANDIR)/usb_modeswitch.1
+	$(RM) -R $(DESTDIR)/var/lib/usb_modeswitch
+	$(RM) $(SYSDIR)/usb_modeswitch@.service
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/README b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/README
new file mode 100755
index 0000000..da6fb351
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/README
@@ -0,0 +1,271 @@
+README for USB_ModeSwitch
+
+For up-to-date and more detailed information (plus a friendly forum) visit
+http://www.draisberghof.de/usb_modeswitch
+
+
+What it is
+==========
+
+USB_ModeSwitch is - hardly surprising -  a mode switching tool for controlling
+USB devices with multiple "modes". Now, what does THAT mean?
+
+More and more USB devices have their MS Windows drivers onboard; when plugged
+in for the first time they act like a flash storage and offer their driver
+installation from there.
+After installation (and on every consecutive plugging) the driver switches the
+mode internally by sending a certain command sequence; the storage device
+vanishes (in most cases) and a different device - like a USB modem - shows up.
+To the host, this is like unplugging one device and then plugging annother.
+
+At first this feature appeared on devices with cell phone chipsets, presumably
+because some of them were already able to change the mode of their USB port
+from storage to communication - so why not make use of this in a modem stick?
+Modem maker "Option" calls that feature "ZeroCD (TM)" since it eliminates the
+need for shipping a separate driver carrier.
+
+In the beginning, nothing of this was documented in any form and there was
+hardly any Linux/Unix support available.
+On the good side, most of the known devices are working out of the box in all
+modes with available Linux modules like "usb-storage" or serial USB drivers.
+That leaves only the problem of the mode-switching from storage to whatever
+the thing is supposed to do.
+
+Fortunately there are things like human smartness, USB sniffing programs and
+LibUSB. The obvious way is to eavesdrop on the communication of the MS Windows
+driver, to isolate the command or action that does the switching, and then re-
+play the same sequence in a non-Windows system.
+
+In theory, this task could also be handled on the kernel driver level, but a
+userspace program is much more flexible and can easily be disabled if access
+to the initial mode of those devices should be desired. There has been a
+principle decision by kernel developers to keep mode-switching outside of the
+kernel.
+
+So USB_ModeSwitch has evolved to make this process easy to handle by taking the
+relevant parameters from configuration files and handling all initialization
+and communication business, with essential help from "libusb".
+
+In Linux and friends it is intended to work automatically - via udev events
+and rules - and doing the mode switch without any user interaction.
+However, the core C program should be as portable als libusb itself; it does not
+rely on specific Linux features.
+It can also be run as an interactive command line tool, particularly useful when
+trying to tinker with hitherto unknown devices.
+
+We have already collected a wide range of information on how to mode-switch all
+sorts of devices. If you run into a new one that is unknown yet, don't despair:
+we can find out what you need to do!
+
+
+How to install
+==============
+
+If you only need the core C program, just run "make". All further steps de-
+scribed below are referring to a common, fairly current Linux system where
+USB_ModeSwitch is expected to do its work automatically.
+
+!! You need the usb-modeswitch-data package from the same source as this !!
+
+If you have an earlier version installed, de-installation is recommended ("make
+uninstall") but not mandatory. The wrapper script location changed in 1.1.0;
+old files might be orphaned but will not do any harm.
+
+The main prerequisite for installing from source is the development package for
+"libusb". It may be called "libusb-dev" or similar in your distribution. From
+usb_modeswitch 2.0.0 on, it should have an "1.x" in the name to reflect the change
+to libusb-1. There are also variants around called "libusbx" if libusb-1 is not
+available on your distribution.
+
+To install the tool set, unpack and run the install command (see below) in the
+newly created directory.
+
+From version 1.2.0, there are three flavours of installing. The only difference
+between those is the way the dispatcher is installed, but this affects the
+dependencies as well:
+
+1. If you have the "Tcl" scripting language available on your system (packages
+   "tcl" or "jimsh"), use the light-weight installation:
+
+   # make install
+
+2. If you are size-constrained and have the Jimsh library on your system
+   (package "libjim-dev"), you can have the Tcl interpreter embedded with the
+   dispatcher, using its shared lib:
+
+   # make install-shared
+
+3. If you are size-constrained and definitely don't need a Tcl interpreter
+   for anything else, choose the statically embedded flavour. This will have
+   no further dependency as it uses the included interpreter code, which is
+   configured for small size:
+
+   # make install-static
+
+Note that the "static"/"shared" targets are NOT referring to the usb_modeswitch
+program, only to the dispatcher!
+Any one of these commands will install a small posix shell script, the
+dispatcher (wrapper) as script or as binary, a global config file, the core
+program and a man page.
+
+Install the data package as well and you are set.
+
+NOTE: installing over (possibly outdated) Linux distribution packages of this
+program and the data collection should not be a problem.
+
+
+How to use
+==========
+
+If your device is known, you should be able to just plug it and use it. If
+it doesn't work - we will find out why.
+
+For manual use just run "usb_modeswitch" (as root). Work with the command
+line interface or with a setup file. You can use any file and give its path
+with the "-c" parameter.
+The file named "device_reference.txt" that you can find on the home site of
+this package is a device and configuration reference containing most known
+devices; you can use it as a "database" to create your own configuration file.
+It's heavily commented and should tell you what to do. It also contains a
+thorough explanation of all the parameters.
+
+Run "usb_modeswitch -h" to list the command line parameters.
+See also the provided man page.
+
+Important note: Manual use is mainly intended for testing and analyzing!!
+The program puts no limits on what you can send to your USB device, so I
+assume it is possible to screw it up profoundly.
+
+Once your new device is switching fine you can add it to the data files to
+make the process automatic.
+
+For this to work, add a rule entry to the rules file to let udev run
+usb_modeswitch as soon as the default IDs are found (when the device is
+plugged). If you look into the rules file you will see immediately how
+your new entry should look like.
+The location is:
+/lib/udev/rules.d/40-usb_modeswitch.rules
+
+Then add your new config file to the folder
+"/etc/usb_modeswitch.d" (only for custom config files!).
+And don't forget to report your success !!
+
+Again, remember that the rules file and the default device config folder
+(/usr/share/usb_modeswitch) are installed by the usb_modeswitch data package.
+
+
+##########
+Important: libusb programs - like this tool - want to be run with administrative
+privileges (as root or with sudo)!
+##########
+
+
+
+Known working hardware, Troubleshooting
+=======================================
+
+Please go to the homepage (see link at the top). Read carefully.
+For support questions use ONLY public posts in the forum.
+
+
+
+Contribute
+==========
+
+USB_ModeSwitch comes quite handy for experimenting with your own hardware if
+not supported yet. You could try this approach:
+
+Note the device's vendor and product ID from /proc/bus/usb/devices (or from the
+output of lsusb); the assigned driver is usually "usb-storage". Then try spying
+on the USB communication to the device with the same ID inside MS Windoze. I
+recommend this tool:
+"SniffUSB" (http://benoit.papillault.free.fr/usbsnoop/index.php.en).
+
+PLEASE post any improvements, new device information and/or bug reports to the
+forum (see above) or send it to the author (see below)!
+
+
+Whodunit
+========
+
+Copyright 2007 - 2015 Josua Dietze (for non-support notifications write a personal
+message through the forum to "Josh"; everything else only in a forum thread)
+
+ !!! NO SUPPORT QUESTIONS VIA E-MAIL, use the forum !!!
+
+Major contributions:
+
+Command line parsing and other essential contributions:
+ Joakim Wennergren
+
+TargetClass parameter implementation to support new Option devices/firmware:
+ Paul Hardwick (http://www.pharscape.org)
+
+Created with initial help from:
+ "usbsnoop2libusb.pl" by Timo Lindfors
+ (http://iki.fi/lindi/usb/usbsnoop2libusb.pl)
+
+Config file parsing code borrowed from:
+ Guillaume Dargaud (http://www.gdargaud.net/Hack/SourceCode.html)
+
+Hexstr2bin function borrowed from:
+ Jouni Malinen (http://hostap.epitest.fi/wpa_supplicant, from "common.c")
+
+Indispensable help with device research and compilation:
+ Lars Melin
+
+Code, fixes and ideas contributed by:
+ Aki Makkonen
+ Denis Sutter
+ Lucas Benedicic
+ Roman Laube
+ Luigi Iotti
+ Vincent Teoh
+ Tommy Cheng
+ Daniel Cooper
+ Andrew Bird
+ Yaroslav Levandovskiy
+ Sakis Dimopoulos
+ Steven Fernandez
+ Christophe Fergeau
+ Nils Radtke
+ Filip Aben
+ Amit Mendapara
+ Roman S. Samarev
+ Chi-Hang Long
+ Andrey Tikhomirov
+ Daniel Mende
+ Nicholas Carrier
+ Adam Goode
+ Leonid Lisovskiy
+ Vladislav Grishenko
+ Daniel Drake
+
+Device information contributors are named in the "device_reference.txt" file.
+
+JimTcl is currently maintained by Steve Bennett; see README in subfolder
+ for details. It is released under a FreeBSD-style license.
+ Visit http://jim.tcl.tk/
+
+
+
+Legal
+=====
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details:
+
+http://www.gnu.org/licenses/gpl.txt
+
+Or find it as the file COPYING in this folder.
+
+
+
+
+Last revised: 2016-06-12, Josua Dietze
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/dispatcher.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/dispatcher.c
new file mode 100755
index 0000000..c38ae31
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/dispatcher.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2011-2016 Josua Dietze, usb_modeswitch version 2.3.0
+ * Contains code under
+ * Copyright (c) 2010 Wojciech A. Koszek <wkoszek@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <jim.h>
+
+/* RAW is defined to the complete Tcl code in that file: */
+#include "usb_modeswitch.string"
+
+#define MAX_ARGSIZE 1024
+
+int main(int argc, char **argv)
+{
+	int i, retval;
+	char arg[MAX_ARGSIZE];
+	char arglist[MAX_ARGSIZE]; 
+
+	Jim_Interp *interp;
+
+	interp = NULL;
+	arglist[0] = '\0';
+
+	for (i=1; i<argc; i++) {
+		if (strlen(argv[i]) > MAX_ARGSIZE-4) {
+			printf("Argument #%d extends maximum size, skip it\n", i);
+			continue;
+		}
+		if ( (strlen(arglist) + strlen(argv[i])) > MAX_ARGSIZE-4) {
+			printf("Argument #%d would extend maximum list size, skip it\n", i);
+			continue;
+		}
+		sprintf(arg,"{%s} ",argv[i]);
+		strncat(arglist,arg,MAX_ARGSIZE-1);
+	}
+
+	char code[sizeof(RAW) + sizeof(arglist) + 28];
+	sprintf(code, "set argv {%s}\nset argc %d\n", arglist, argc-1);
+	strncat(code, RAW, sizeof(RAW));
+
+	/* Create Jim instance */
+	interp = Jim_CreateInterp();
+	assert(interp != NULL && "Could not create interpreter!");
+
+	/* Register base commands, actually implementing Tcl */
+	Jim_RegisterCoreCommands(interp);
+
+	/* Initialize any static extensions */
+	Jim_InitStaticExtensions(interp);
+
+	/* Evaluate the script that's now in "code" */
+	retval = Jim_Eval(interp, code);
+	if (retval < 0)
+		printf("Evaluation returned error %d\n", retval);
+
+	/* Free the interpreter */
+	Jim_FreeInterp(interp);
+	return (EXIT_SUCCESS);
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/AUTHORS b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/AUTHORS
new file mode 100755
index 0000000..73413a5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/AUTHORS
@@ -0,0 +1,41 @@
+Salvatore Sanfilippo <antirez@invece.org>
+
+with the help (patches, bug reports, ideas, extensions) of:
+
+Pat Thoyts
+Clemens Hintze
+
+See also the ChangeLog and README files for other credits.
+
+DESIGN CREDITS:
+
+some of the idea inside Jim are the fruit of long discussions
+inside the Tclers chat room. The feedback of the Tcl
+comunity in general, and of the members of the Tcl Core Team, was
+very important to avoid mistakes: I used the great experience of
+this people as a test for some of the ideas I put into Jim.
+Bad ideas tend to be demolished in no time by good engineers.
+
+Also the following ideas are due to the following authors:
+
+- Jim locals were originally proposed by Miguel Sofer, I (SS) added
+  the feature that make they similar to lexical scoped closures
+  using capturing of the local variables value if no explicit
+  intialization is provided.
+
+- The [lmap] command is my (SS) design, but I incorporated inside the
+  command an interesting idea of Donal K. Fellows that proposed that
+  the [continue] command may be used to skip the accumulation of the
+  current-iteartion result, providing in one command the power of
+  [map] and [filter] together.
+
+ 
+ChangeLog committers to be identified. Tentative list:  
+ 
+antirez - Salvatore Sanfilippo <antirez@gmail.com>
+patthoyts - Pat Thoyts <patthoyts@users.sf.net> 
+oharboe - �yvind Harboe - soyvind.harboe@zylin.com
+Andrew Lunn <andrew@lunn.ch> 
+Duane Ellis <openocd@duaneellis.com>
+Uwe Klein <uklein@klein-messgeraete.de>
+Clemens Hintze ml-jim@qiao.in-berlin.de aka chi
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/LICENSE b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/LICENSE
new file mode 100755
index 0000000..d5b9ecb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/LICENSE
@@ -0,0 +1,45 @@
+Unless explicitly stated, all files within Jim repository are released
+under following license:
+
+/* Jim - A small embeddable Tcl interpreter
+ *
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
+ * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net> 
+ * Copyright 2008 oharboe - �yvind Harboe - oyvind.harboe@zylin.com
+ * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
+ * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
+ * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
+ * Copyright 2008 Steve Bennett <steveb@workware.net.au>
+ * Copyright 2009 Nico Coesel <ncoesel@dealogic.nl>
+ * Copyright 2009 Zachary T Welch zw@superlucidity.net
+ * Copyright 2009 David Brownell
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ */
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/Makefile.in b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/Makefile.in
new file mode 100755
index 0000000..0191c83
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/Makefile.in
@@ -0,0 +1,198 @@
+# Tools
+CC ?= @CCACHE@ @CC@
+CXX = @CCACHE@ @CXX@
+RANLIB = @RANLIB@
+AR = @AR@
+STRIP = @STRIP@
+
+# Configuration
+
+SH_CFLAGS ?= @SH_CFLAGS@
+SH_LDFLAGS ?= @SH_LDFLAGS@
+SHOBJ_CFLAGS ?= @SHOBJ_CFLAGS@
+SHOBJ_LDFLAGS ?= @SHOBJ_LDFLAGS@
+CFLAGS = @CFLAGS@
+CXXFLAGS = @CXXFLAGS@
+LDFLAGS = @LDFLAGS@
+LDLIBS += @LDLIBS@
+exec_prefix ?= @exec_prefix@
+prefix ?= @prefix@
+
+CC += -D_GNU_SOURCE -Wall $(OPTIM) -I.
+CXX += -D_GNU_SOURCE -Wall $(OPTIM) -I.
+@if srcdir != .
+CFLAGS += -I@srcdir@
+CXXFLAGS += -I@srcdir@
+VPATH := @srcdir@
+@endif
+
+@if JIM_STATICLIB
+LIBJIM := libjim.a
+@else
+LIBJIM := libjim.so
+SH_LIBJIM := $(LIBJIM)
+CC += $(SH_CFLAGS)
+CXX += $(SH_CFLAGS)
+DEF_LD_PATH := @LD_LIBRARY_PATH@=`pwd` 
+@endif
+
+@if HAVE_CXX_EXTENSIONS
+JIMSH_CC := $(CXX) $(CXXFLAGS)
+@else
+JIMSH_CC := $(CC) $(CFLAGS)
+@endif
+
+OBJS := _load-static-exts.o jim-subcmd.o jim-interactive.o jim-format.o jim.o utf8.o jimregexp.o \
+    @EXTRA_OBJS@ @C_EXT_OBJS@ @TCL_EXT_OBJS@
+
+JIMSH := jimsh@EXEEXT@
+
+all: $(JIMSH) @C_EXT_SHOBJS@
+
+# Create C extensions from pure Tcl extensions
+.SUFFIXES: .tcl
+.tcl.o:
+	@tclsh@ @srcdir@/make-c-ext.tcl $< >_$*.c || ( rm _$*.c; exit 1)
+	$(CC) $(CFLAGS) -c -o $@ _$*.c || ( rm _$*.c; exit 1)
+	@rm -f _$*.c
+
+docs: Tcl.html
+
+$(JIMSH): $(LIBJIM) jimsh.o initjimsh.o
+	$(JIMSH_CC) @SH_LINKFLAGS@ $(LDFLAGS) -o $@ jimsh.o initjimsh.o $(LIBJIM) $(LDLIBS)
+
+@if JIM_INSTALL
+install: all docs @TCL_EXTS@ install-exec
+	mkdir -p $(DESTDIR)$(prefix)/lib/jim
+	cp $(LIBJIM) $(DESTDIR)$(prefix)/lib
+	cp @srcdir@/README.extensions @C_EXT_SHOBJS@ @TCL_EXTS@ $(DESTDIR)$(prefix)/lib/jim
+	mkdir -p $(DESTDIR)$(prefix)/include
+	cp @srcdir@/jim.h @srcdir@/jim-eventloop.h @srcdir@/jim-nvp.h @srcdir@/jim-signal.h \
+		@srcdir@/jim-subcmd.h @srcdir@/jim-win32compat.h $(DESTDIR)$(prefix)/include
+	cp jim-config.h $(DESTDIR)$(prefix)/include
+	mkdir -p $(DESTDIR)$(prefix)/doc/jim
+	cp Tcl.html $(DESTDIR)$(prefix)/doc/jim
+
+install-exec: all
+	mkdir -p $(DESTDIR)$(prefix)/bin
+	cp $(JIMSH) $(DESTDIR)$(prefix)/bin
+
+uninstall:
+	rm -f $(DESTDIR)$(prefix)/bin/$(JIMSH)
+	rm -f $(DESTDIR)$(prefix)/lib/$(LIBJIM)
+	for i in README.extensions @C_EXT_SHOBJS@ @TCL_EXTS@; do rm -f $(DESTDIR)$(prefix)/lib/jim/$$i; done
+	rm -f $(DESTDIR)$(prefix)/include/jim*.h
+	rm -f $(DESTDIR)$(prefix)/doc/jim/Tcl.html
+@else
+install install-exec uninstall:
+@endif
+
+test: $(JIMSH)
+	$(DEF_LD_PATH) $(MAKE) -C @srcdir@/tests jimsh=`pwd`/jimsh
+
+$(OBJS): Makefile
+
+@if JIM_UTF8
+# Generate the unicode case mapping
+utf8.o: _unicode_mapping.c
+
+_unicode_mapping.c: @srcdir@/UnicodeData.txt @srcdir@/parse-unidata.tcl
+	@tclsh@ @srcdir@/parse-unidata.tcl @srcdir@/UnicodeData.txt >$@ || ( rm $@; exit 1)
+@endif
+
+_load-static-exts.c: @srcdir@/make-load-static-exts.tcl Makefile
+	@tclsh@ @srcdir@/make-load-static-exts.tcl @STATIC_EXTS@ >$@ || ( rm $@; exit 1)
+
+@if JIM_STATICLIB
+$(LIBJIM): $(OBJS)
+	$(AR) cr $@ $(OBJS)
+	$(RANLIB) $@
+@else
+$(LIBJIM): $(OBJS)
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SH_LDFLAGS) -o $@ $(OBJS) $(LDLIBS)
+@endif
+
+# Note that $> $^ is for compatibility with both GNU make and BSD make
+readdir.so: jim-readdir.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-readdir.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-readdir.o $(SH_LIBJIM) 
+
+array.so: jim-array.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-array.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-array.o $(SH_LIBJIM) 
+
+clock.so: jim-clock.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-clock.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-clock.o $(SH_LIBJIM) 
+
+file.so: jim-file.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-file.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-file.o $(SH_LIBJIM) 
+
+posix.so: jim-posix.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-posix.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-posix.o $(SH_LIBJIM) 
+
+regexp.so: jim-regexp.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-regexp.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-regexp.o $(SH_LIBJIM) 
+
+syslog.so: jim-syslog.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-syslog.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-syslog.o $(SH_LIBJIM) 
+
+readline.so: jim-readline.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-readline.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-readline.o $(SH_LIBJIM) @LDLIBS_readline@
+
+pack.so: jim-pack.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-pack.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-pack.o $(SH_LIBJIM) @LDLIBS_pack@
+
+sqlite.so: jim-sqlite.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-sqlite.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-sqlite.o $(SH_LIBJIM) @LDLIBS_sqlite@
+
+sqlite3.so: jim-sqlite3.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-sqlite3.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-sqlite3.o $(SH_LIBJIM) @LDLIBS_sqlite3@
+
+win32.so: jim-win32.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-win32.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-win32.o $(SH_LIBJIM) @LDLIBS_win32@
+
+mk.so: jim-mk.cpp
+	$(CXX) $(CXXFLAGS) $(SHOBJ_CFLAGS) -c -o jim-mk.o $> $^
+	$(CXX) $(CXXFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-mk.o $(SH_LIBJIM) @LDLIBS_mk@
+
+sdl.so: jim-sdl.c
+	$(CC) $(CFLAGS) $(SHOBJ_CFLAGS) -c -o jim-sdl.o $> $^
+	$(CC) $(CFLAGS) $(LDFLAGS) $(SHOBJ_LDFLAGS) -o $@ jim-sdl.o $(SH_LIBJIM) @LDLIBS_sdl@
+
+Tcl.html: jim_tcl.txt
+	@tclsh@ @srcdir@/make-index $> $^ | asciidoc -o $@ -d manpage - || cp @srcdir@/Tcl_shipped.html Tcl.html
+
+clean:
+	rm -f *.o *.so lib*.a $(JIMSH) Tcl.html _*.c
+
+distclean: clean
+	rm -f jimautoconf.h jim-config.h Makefile config.log autosetup/jimsh0.c autosetup/jimsh0@EXEEXT@
+
+ship: Tcl.html
+	cp $< Tcl_shipped.html
+
+# automake compatibility. do nothing for all these targets
+EMPTY_AUTOMAKE_TARGETS := dvi pdf ps info html tags ctags mostlyclean maintainer-clean check installcheck installdirs \
+ install-pdf install-ps install-info install-html -install-dvi uninstall install-data
+.PHONY: $(EMPTY_AUTOMAKE_TARGETS)
+$(EMPTY_AUTOMAKE_TARGETS):
+
+# automake compatibility - install sources from the current dir to $(distdir)
+distdir_full := $(shell cd $(distdir); pwd)
+distdir:
+	cd "@srcdir@"; git ls-files | cpio -pdmu $(distdir_full)
+
+reconfig:
+	CC='@CC@' @AUTOREMAKE@
+
+lib: $(LIBJIM)
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/README b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/README
new file mode 100755
index 0000000..8acacc4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/README
@@ -0,0 +1,235 @@
+The Jim Interpreter
+
+A small-footprint implementation of the Tcl programming language.
+
+--------------------------------------------------------------------------------
+WHAT IS JIM?
+--------------------------------------------------------------------------------
+
+Jim is a small footprint implementation of the Tcl programming language
+written from scratch. Currently Jim Tcl is very feature complete with
+an extensive test suite (see the tests directory).
+There are some Tcl commands and features which are not implemented
+(and likely never will be), including namespaces, traces and Tk. However
+Jim Tcl offers a number of both Tcl8.5 and Tcl8.6 features ({*}, dict, lassign,
+tailcall and optional UTF-8 support) and some unique features.
+These unique features include [lambda] with garbage collection, a general GC/references
+system, arrays as syntax sugar for [dict]tionaries, object-based I/O and more.
+
+Other common features of the Tcl programming language are present, like
+the "everything is a string" behaviour, implemented internally as
+dual ported objects to ensure that the execution time does not reflect
+the semantic of the language :)
+
+--------------------------------------------------------------------------------
+WHEN JIM CAN BE USEFUL?
+--------------------------------------------------------------------------------
+
+1) If you are writing an application, and want to make it scriptable, with
+Jim you have a way to do it that does not require to link your application
+with a big system. You can include the Jim source directly in your project
+and use the Jim API to write the glue code that makes your application
+scriptable in Jim, with the following advantages:
+
+- Jim is not the next "little language", but it's a Tcl implementation.
+  You can reuse your knowledge if you already Tcl skills, or enjoy
+  the availability of documentation, books, web resources, ...
+  (for example check my online Tcl book at http://www.invece.org/tclwise)
+
+- Jim is simple, 14k lines of core code. If you want to adapt it you can hack
+  the source code to meet the needs of your application. It makes you
+  able to have scripting for default, and avoid external dependences.
+
+  Having scripting support *inside*, and in a way that a given version
+  of your program always gets shipped a given version of Jim, you can
+  write part of your application in Jim itself. Like it happens for
+  Emacs/Elisp, or Gimp/Scheme, both this applications have the interpreter
+  inside.
+
+- Jim is Tcl, and Tcl looks like a configuration file if you want. So
+  if you use Jim you have also a flexible syntax for your config file.
+  This is a valid Tcl script:
+
+     set MyFeature on
+     ifssl {
+       set SslPort 45000
+       use compression
+     }
+
+  It looks like a configuration file, but if you implement the [ifssl]
+  and [use] commands, it's a valid Tcl script.
+
+- Tcl scales with the user. Not all know it, but Tcl is so powerful that
+  you can reprogram the language in itself. Jim support this features
+  of the Tcl programming language. You can write new control structures,
+  use the flexible data types it offers (Lists are a central data structure,
+  with Dictionaries that are also lists). Still Tcl is simpler for the
+  casual programmer, especially if compared to other languages offering
+  small footprint implementations (like Scheme and FORTH).
+
+- Because of the Tcl semantic (pass by value, everything is a command
+  since there are no reserved words), there is a nice API to glue
+  your application with Jim. See under the Jim Tcl manual for more detail.
+
+- Jim is supported. If you need commercial software, contact the original author
+  at 'antirez@gmail.com' or the current maintainer at 'steveb@workware.net.au'.
+
+2) The other "field" where Jim can be useful is obviously embedded systems.
+
+3) We are working to make Jim as feature-complete as possible, thanks to
+   dynamically loaded extensions it may stay as little as it is today
+   but able to do interesting things for you. So it's not excluded that
+   in the future Jim will be an option as general purpose language.
+   But don't mind, for this there is already the mainstream Tcl
+   implementation ;).
+
+--------------------------------------------------------------------------------
+HOW BIG IS IT?
+--------------------------------------------------------------------------------
+
+Jim with the default extensions configured and compiled with -Os is about 130k.
+Without any extensions, it is about 85k.
+
+--------------------------------------------------------------------------------
+HOW FAST IS IT?
+--------------------------------------------------------------------------------
+
+Jim is in most code faster than Tcl7.6p2 (latest 7.x version),
+and slower than Tcl 8.4.x. You can expect pretty decent performance
+for such a little interpreter.
+
+If you want a more precise measure, there is 'bench.tcl' inside this
+distribution that will run both under Jim and Tcl, so just execute
+it with both the interpreters and see what you get :)
+
+--------------------------------------------------------------------------------
+HOW TO COMPILE
+--------------------------------------------------------------------------------
+
+Jim was tested under Linux, FreeBSD, MacosX, eCos, QNX, Windows XP (mingw, MVC).
+
+To compile jim itself try:
+
+  ./configure
+  make
+
+--------------------------------------------------------------------------------
+EXTENSIONS
+--------------------------------------------------------------------------------
+
+Many optional extensions are included. Some are C extensions and others are pure Tcl.
+Form more information, try:
+
+  ./configure --help
+
+--------------------------------------------------------------------------------
+HOW TO EMBED JIM INTO APPLICATIONS
+--------------------------------------------------------------------------------
+
+See the "examples.api" directory
+
+--------------------------------------------------------------------------------
+HOW TO WRITE EXTENSIONS FOR JIM
+--------------------------------------------------------------------------------
+
+See the extensions shipped with Jim, jim-readline.c, jim-clock.c, glob.tcl and oo.tcl
+
+--------------------------------------------------------------------------------
+COPYRIGHT and LICENSE
+--------------------------------------------------------------------------------
+
+Unless explicitly stated, all files within Jim repository are released
+under following license:
+
+/* Jim - A small embeddable Tcl interpreter
+ *
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
+ * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net> 
+ * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
+ * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
+ * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
+ * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
+ * Copyright 2008 Steve Bennett <steveb@workware.net.au>
+ * Copyright 2009 Nico Coesel <ncoesel@dealogic.nl>
+ * Copyright 2009 Zachary T Welch zw@superlucidity.net
+ * Copyright 2009 David Brownell
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ */
+--------------------------------------------------------------------------------
+HISTORY
+--------------------------------------------------------------------------------
+
+"first Jim goal: to vent my need to hack on Tcl."
+
+And actually this is exactly why I started Jim, in the first days
+of Jenuary 2005. After a month of hacking Jim was able to run
+simple scripts, now, after two months it started to be clear to
+me that it was not just the next toy to throw away but something
+that may evolve into a real interpreter. In the same time
+Pat Thoyts and Clemens Hintze started to contribute code, so that
+the development of new core commands was faster, and also more
+people hacking on the same code had as result fixes in the API,
+C macros, and so on.
+
+Currently we are at the point that the core interpreter is almost finished
+and it is entering the Beta stage. There is to add some other core command,
+to do a code review to ensure quality of all the parts and to write
+documentation.
+
+We already started to work on extensions like OOP, event loop,
+I/O, networking, regexp. Some extensions are already ready for
+prime time, like the Sqlite extension and the ANSI I/O.
+
+------------------------------------------------------------------------------
+Thanks to...
+------------------------------------------------------------------------------
+
+- First of all, thanks to every guy that are listed in the AUTHORS file,
+  that directly helped with code and ideas. Also check the ChangeLog
+  file for additional credits about patches or bug reports.
+- Elisa Manara that helped me to select this ill conceived name for
+  an interpreter.
+- Many people on the Tclers Chat that helped me to explore issues
+  about the use and the implementation of the Tcl programming language.
+- David Welton for the tech info sharing and our chats about
+  programming languages design and the ability of software to "scale down".
+- Martin S. Weber for the great help with Solaris issues, debugging of
+  problems with [load] on this arch, 64bit tests.
+- The authors of "valgrind", for this wonderful tool, that helped me a
+  lot to fix bugs in minutes instead of hours.
+
+
+----
+Enjoy!
+Salvatore Sanfilippo
+10 Mar 2005
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/README.usb_modeswitch b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/README.usb_modeswitch
new file mode 100755
index 0000000..7f3ae41
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/README.usb_modeswitch
@@ -0,0 +1,6 @@
+The content of this folder is customized for shipping with usb_modeswitch;
+for the original source see:
+
+http://repo.or.cz/w/jimtcl.git
+
+This is version 0.72 of jimtcl
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/auto.def b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/auto.def
new file mode 100755
index 0000000..2cdb85c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/auto.def
@@ -0,0 +1,436 @@
+# vim:se syn=tcl:
+#
+
+# Note: modules which support options *must* be included before 'options'
+use cc cc-shared
+
+options {
+    utf8            => "include support for utf8-encoded strings"
+    lineedit=1      => "disable line editing"
+    references=1    => "disable support for references"
+    math            => "include support for math functions"
+    ipv6            => "include ipv6 support in the aio extension"
+    maintainer      => {enable the [debug] command and JimPanic}
+    full            => "Enable some optional features: ipv6, math, utf8, binary, oo, tree"
+    with-jim-shared shared => "build a shared library instead of a static library"
+    jim-regexp      => "use the built-in (Tcl-compatible) regexp, even if POSIX regex is available"
+    with-jim-ext: {with-ext:"ext1 ext2 ..."} => {
+        Specify additional jim extensions to include.
+        These are enabled by default:
+
+        aio       - ANSI I/O, including open and socket
+        eventloop - after, vwait, update
+        array     - Tcl-compatible array command
+        clock     - Tcl-compatible clock command
+        exec      - Tcl-compatible exec command
+        file      - Tcl-compatible file command
+        glob      - Tcl-compatible glob command
+        readdir   - Required for glob
+        package   - Package management with the package command
+        load      - Load binary extensions at runtime with load or package
+        posix     - Posix APIs including os.fork, os.wait, pid
+        regexp    - Tcl-compatible regexp, regsub commands
+        signal    - Signal handling
+        stdlib    - Built-in commands including lassign, lambda, alias
+        syslog    - System logging with syslog
+        tclcompat - Tcl compatible read, gets, puts, parray, case, ...
+
+        These are disabled by default:
+
+        nvp       - Name-value pairs C-only API
+        oo        - Jim OO extension
+        tree      - OO tree structure, similar to tcllib ::struct::tree
+        binary    - Tcl-compatible 'binary' command
+        readline  - Interface to libreadline
+        rlprompt  - Tcl wrapper around the readline extension
+        mk        - Interface to Metakit
+        sqlite    - Interface to sqlite
+        sqlite3   - Interface to sqlite3
+        win32     - Interface to win32
+    }
+    with-out-jim-ext: {without-ext:"default|ext1 ext2 ..."} => {
+        Specify jim extensions to exclude.
+        If 'default' is given, the default extensions will not be added.
+    }
+    with-jim-extmod: {with-mod:"ext1 ext2 ..."} => {
+        Specify jim extensions to build as separate modules (either C or Tcl).
+        Note that not all extensions can be built as loadable modules.
+    }
+    # To help out openocd with automake
+    install-jim=1
+}
+
+cc-check-types "long long"
+
+cc-check-includes sys/socket.h netinet/in.h arpa/inet.h netdb.h
+cc-check-includes sys/un.h dlfcn.h unistd.h crt_externs.h
+
+define LDLIBS ""
+
+# Haiku needs -lnetwork, Solaris needs -lnsl
+if {[cc-check-function-in-lib inet_ntop {nsl network}]} {
+    # This does nothing if no libs are needed
+    cc-with [list -libs [get-define lib_inet_ntop]]
+    define-append LDLIBS [get-define lib_inet_ntop]
+}
+# Solaris needs -lsocket, Windows needs -lwsock32
+if {[cc-check-function-in-lib socket socket]} {
+    define-append LDLIBS [get-define lib_socket]
+}
+
+cc-check-functions ualarm lstat fork vfork system select
+cc-check-functions backtrace geteuid mkstemp realpath strptime gettimeofday
+cc-check-functions regcomp waitpid sigaction sys_signame sys_siglist
+cc-check-functions syslog opendir readlink sleep usleep pipe getaddrinfo utimes
+if {[cc-check-functions sysinfo]} {
+    cc-with {-includes sys/sysinfo.h} {
+        cc-check-members "struct sysinfo.uptime"
+    }
+}
+
+define TCL_LIBRARY [get-define prefix]/lib/jim
+
+lassign [split [get-define host] -] host_cpu host_vendor host_os
+# Scrub revision from the host_os
+regsub -all {[0-9.]} $host_os {} host_os
+
+switch -glob -- $host_os {
+    mingw* {
+        # We provide our own implementation of dlopen for mingw32
+        define-feature dlopen-compat
+        define-feature winconsole
+        define TCL_PLATFORM_OS $host_os
+        define TCL_PLATFORM_PLATFORM windows
+        define TCL_PLATFORM_PATH_SEPARATOR {;}
+    }
+    default {
+        # Note that cygwin is considered a unix platform
+        define TCL_PLATFORM_OS $host_os
+        define TCL_PLATFORM_PLATFORM unix
+        define TCL_PLATFORM_PATH_SEPARATOR :
+    }
+}
+
+# Find some tools
+cc-check-tools ar ranlib strip
+define tclsh [info nameofexecutable]
+
+if {![cc-check-functions _NSGetEnviron]} {
+    msg-checking "Checking environ declared in unistd.h..."
+    if {[cctest -cflags -D_GNU_SOURCE -includes unistd.h -code {char **ep = environ;}]} {
+        define NO_ENVIRON_EXTERN
+        msg-result "yes"
+    } else {
+        msg-result "no"
+    }
+}
+
+# Windows has a mkdir with no permission arg
+cc-check-includes sys/types.h sys/stat.h
+msg-checking "Checking for mkdir with one arg..."
+if {[cctest -includes {sys/types.h sys/stat.h} -code {mkdir("/dummy");}]} {
+    define HAVE_MKDIR_ONE_ARG
+    msg-result yes
+} else {
+    msg-result no
+}
+
+# autosetup can't handle C++ libraries
+proc check-metakit {} {
+    set found 0
+    cc-with {-lang c++} {
+        msg-checking "Checking for Metakit..."
+        if {[cctest -includes mk4.h -libs -lmk4 -code {c4_Storage dummy();}]} {
+            msg-result ok
+            define lib_mk -lmk4
+            incr found
+        } else {
+            msg-result "not found"
+        }
+    }
+    return $found
+}
+
+set extra_objs {}
+set jimregexp 0
+
+if {[opt-bool utf8 full]} {
+    msg-result "Enabling UTF-8"
+    define JIM_UTF8
+    incr jimregexp
+} else {
+    define JIM_UTF8 0
+}
+if {[opt-bool maintainer]} {
+    msg-result "Enabling maintainer settings"
+    define JIM_MAINTAINER
+}
+if {[opt-bool math full]} {
+    msg-result "Enabling math functions"
+    define JIM_MATH_FUNCTIONS
+    cc-check-function-in-lib sin m
+    define-append LDLIBS [get-define lib_sin]
+}
+if {[opt-bool ipv6 full]} {
+    msg-result "Enabling IPv6"
+    define JIM_IPV6
+}
+if {[opt-bool lineedit full]} {
+    if {([cc-check-includes termios.h] && [cc-check-functions isatty]) || [have-feature winconsole]} {
+        msg-result "Enabling line editing"
+        define USE_LINENOISE
+        lappend extra_objs linenoise.o
+    }
+}
+if {[opt-bool references]} {
+    msg-result "Enabling references"
+    define JIM_REFERENCES
+}
+if {[opt-bool shared with-jim-shared]} {
+    msg-result "Building shared library"
+} else {
+    msg-result "Building static library"
+    define JIM_STATICLIB
+}
+define JIM_INSTALL [opt-bool install-jim]
+
+# Note: Extension handling is mapped directly from the configure.ac
+# implementation
+
+set without [join [opt-val {without-ext with-out-jim-ext}]]
+set withext [join [opt-val {with-ext with-jim-ext}]]
+set withmod [join [opt-val {with-mod with-jim-extmod}]]
+
+# Tcl extensions
+set ext_tcl "stdlib glob tclcompat tree rlprompt oo binary"
+# Native extensions
+set ext_c "load package readdir array clock exec file posix regexp signal aio eventloop pack syslog nvp readline mk sqlite sqlite3 win32 sdl"
+
+# C++ extensions
+set ext_cxx "mk"
+
+# Tcl extensions which can be modules
+set ext_tcl_mod "glob tree rlprompt oo binary"
+# Native extensions which can be modules
+set ext_c_mod "readdir array clock file posix regexp syslog readline pack mk sqlite sqlite3 win32 sdl"
+
+# All extensions
+set ext_all [concat $ext_c $ext_tcl]
+
+# Default static extensions
+set ext_default "stdlib load package readdir glob array clock exec file posix regexp signal tclcompat aio eventloop syslog"
+
+if {[opt-bool full]} {
+    lappend ext_default tree binary
+}
+
+if {$without eq "default"} {
+    set ext_default stdlib
+    set without {}
+}
+
+# Check valid extension names
+foreach i [concat $withext $without $withmod] {
+    if {$i ni $ext_all} {
+        user-error "Unknown extension: $i"
+    }
+}
+
+# needs_xxx="expression" means that the expr must eval to 1 to select the extension
+# dep_xxx="yyy zzz" means that if xxx is selected, so is yyy and zzz
+set dep(glob) readdir
+set dep(rlprompt) readline
+set dep(tree) oo
+set dep(binary) pack
+
+set needs(exec) {expr {([have-feature vfork] && [have-feature waitpid]) || [have-feature system]}}
+set needs(load) {expr {[cc-check-function-in-lib dlopen dl] || [have-feature dlopen-compat]}}
+set libdep(load) lib_dlopen
+set needs(posix) {have-feature waitpid}
+set needs(readdir) {have-feature opendir}
+set needs(readline) {cc-check-function-in-lib readline readline}
+set libdep(readline) lib_readline
+set needs(signal) {expr {[have-feature sigaction] && [have-feature vfork]}}
+set needs(mk) {check-metakit}
+set libdep(mk) lib_mk
+set needs(sqlite) {cc-check-function-in-lib sqlite_open sqlite}
+set libdep(sqlite) lib_sqlite_open
+set needs(sqlite3) {cc-check-function-in-lib sqlite3_open sqlite3}
+set libdep(sqlite3) lib_sqlite3_open
+set needs(syslog) {have-feature syslog}
+set needs(win32) {have-feature windows}
+set needs(sdl) {expr {[cc-check-function-in-lib SDL_SetVideoMode SDL] && [cc-check-function-in-lib rectangleRGBA SDL_gfx]}}
+set libdep(sdl) {lib_SDL_SetVideoMode lib_rectangleRGBA}
+
+# First handle dependencies. If an extension is enabled, also enable its dependency
+foreach i [concat $ext_default $withext] {
+    if {$i in $without} {
+        continue
+    }
+    if {[info exists dep($i)]} {
+        lappend withext {*}$dep($i)
+    }
+}
+
+foreach i $withmod {
+    if {[info exists dep($i)]} {
+        # Theoretically, a mod could depend upon something which must be static
+        # If already configured static, don't make it a module
+        foreach d $dep($i) {
+            if {$d ni $withext} {
+                lappend withmod $d
+            }
+        }
+    }
+}
+
+# Now that we know what the platform supports:
+
+# For all known extensions:
+# - If it is disabled, remove it
+# - Otherwise, check to see if it's pre-requisites are met
+# -   If yes, add it if it is enabled or is a default
+# -   If no, error if it is enabled, or do nothing otherwise
+# - Modules may be either C or Tcl
+
+set extmodtcl {}
+set extmod {}
+set ext {}
+
+foreach i [lsort $ext_all] {
+    # First discard the extension if disabled or not enabled
+    if {$i in $without} {
+        msg-result "Extension $i...disabled"
+        continue
+    }
+    if {$i ni [concat $withext $withmod $ext_default]} {
+        msg-result "Extension $i...not enabled"
+        continue
+    }
+
+    # Check dependencies
+    set met 1
+    if {[info exists needs($i)]} {
+        set met [eval $needs($i)]
+    }
+
+    define LDLIBS_$i ""
+
+    msg-checking "Extension $i..."
+
+    # Selected as a module?
+    if {$i in $withmod} {
+        if {$i in $ext_tcl_mod} {
+            # Easy, a Tcl module
+            msg-result "tcl"
+            lappend extmodtcl $i
+            continue
+        }
+        if {$i ni $ext_c_mod} {
+            user-error "not a module"
+        }
+        if {!$met} {
+            user-error "dependencies not met"
+        }
+        msg-result "module"
+        lappend extmod $i
+        if {[info exists libdep($i)]} {
+            foreach j $libdep($i) {
+                define-append LDLIBS_$i [get-define $j ""]
+            }
+        }
+        continue
+    }
+
+    # Selected as a static extension?
+    if {$i in $withext} {
+        if {!$met} {
+            user-error "dependencies not met"
+        }
+        msg-result "enabled"
+    } elseif {$i in $ext_default} {
+        if {!$met} {
+            msg-result "disabled (dependencies)"
+            continue
+        }
+        msg-result "enabled (default)"
+    } else {
+        continue
+    }
+
+    lappend ext $i
+    if {[info exists libdep($i)]} {
+        foreach j $libdep($i) {
+            define-append LDLIBS [get-define $j ""]
+        }
+    }
+}
+
+if {[have-feature windows]} {
+    lappend extra_objs jim-win32compat.o
+
+    if {$extmod ne "" && [get-define JIM_LIBTYPE] eq "static"} {
+        user-error "cygwin/mingw require --shared for dynamic modules"
+    }
+}
+
+if {"regexp" in "$ext $extmod"} {
+    # No regcomp means we need to use the built-in version
+    if {![have-feature regcomp]} {
+        incr jimregexp
+    }
+}
+
+if {$jimregexp || [opt-bool jim-regexp]} {
+    msg-result "Using built-in regexp"
+    define JIM_REGEXP
+
+    # If the built-in regexp overrides the system regcomp, etc.
+    # jim must be built shared so that the correct symbols are found
+    if {"regexp" in $extmod && [get-define JIM_LIBTYPE] eq "static" && [have-feature regcomp]} {
+        user-error "Must use --shared with regexp module and built-in regexp"
+    }
+}
+if {"load" ni $ext} {
+    # If we don't have load, no need to support shared objects
+    define SH_LINKFLAGS ""
+}
+
+msg-result "Jim static extensions: [lsort $ext]"
+if {$extmodtcl ne ""} {
+    msg-result "Jim Tcl extensions: [lsort $extmodtcl]"
+}
+if {$extmod ne ""} {
+    msg-result "Jim dynamic extensions: [lsort $extmod]"
+}
+
+# Separate out the static extensions into C and Tcl
+set ext_static_c {}
+set ext_static_tcl {}
+foreach e $ext {
+    define jim_ext_$e
+    if {$e in $ext_tcl} {
+        lappend ext_static_tcl $e
+    } else {
+        lappend ext_static_c $e
+    }
+}
+
+# If there are any static C++ extensions, jimsh must be linked using
+# the C++ compiler
+foreach e $ext_static_c {
+    if {$e in $ext_cxx} {
+        define HAVE_CXX_EXTENSIONS
+    }
+}
+
+define STATIC_EXTS [concat $ext_static_c $ext_static_tcl]
+define C_EXT_OBJS [prefix jim- [suffix .o $ext_static_c]]
+define TCL_EXT_OBJS [suffix .o $ext_static_tcl]
+define C_EXT_SHOBJS [suffix .so $extmod]
+define TCL_EXTS [suffix .tcl $extmodtcl]
+define EXTRA_OBJS $extra_objs
+
+make-config-header jim-config.h -auto {HAVE_LONG_LONG* JIM_UTF8} -none *
+make-config-header jimautoconf.h -auto {jim_ext_* TCL_PLATFORM_* TCL_LIBRARY USE_* JIM_*}
+make-template Makefile.in
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/LICENSE b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/LICENSE
new file mode 100755
index 0000000..4fe636c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/LICENSE
@@ -0,0 +1,35 @@
+Unless explicitly stated, all files which form part of autosetup
+are released under the following license:
+
+---------------------------------------------------------------------
+autosetup - A build environment "autoconfigurator"
+
+Copyright (c) 2010-2011, WorkWare Systems <http://workware.net.au/>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following
+   disclaimer in the documentation and/or other materials
+   provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE WORKWARE SYSTEMS ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WORKWARE
+SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation
+are those of the authors and should not be interpreted as representing
+official policies, either expressed or implied, of WorkWare Systems.
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/README.autosetup b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/README.autosetup
new file mode 100755
index 0000000..c7f69a8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/README.autosetup
@@ -0,0 +1 @@
+This is autosetup v0.6.3. See http://msteveb.github.com/autosetup/
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/autosetup b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/autosetup
new file mode 100755
index 0000000..b1134c8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/autosetup
@@ -0,0 +1,1820 @@
+#!/bin/sh
+# Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+# vim:se syntax=tcl:
+# \
+dir=`dirname "$0"`; exec "`$dir/find-tclsh`" "$0" "$@"
+
+set autosetup(version) 0.6.3
+
+# Can be set to 1 to debug early-init problems
+set autosetup(debug) 0
+
+##################################################################
+#
+# Main flow of control, option handling
+#
+proc main {argv} {
+	global autosetup define
+
+	# There are 3 potential directories involved:
+	# 1. The directory containing autosetup (this script)
+	# 2. The directory containing auto.def
+	# 3. The current directory
+
+	# From this we need to determine:
+	# a. The path to this script (and related support files)
+	# b. The path to auto.def
+	# c. The build directory, where output files are created
+
+	# This is also complicated by the fact that autosetup may
+	# have been run via the configure wrapper ([getenv WRAPPER] is set)
+
+	# Here are the rules.
+	# a. This script is $::argv0
+	#    => dir, prog, exe, libdir
+	# b. auto.def is in the directory containing the configure wrapper,
+	#    otherwise it is in the current directory.
+	#    => srcdir, autodef
+	# c. The build directory is the current directory
+	#    => builddir, [pwd]
+
+	# 'misc' is needed before we can do anything, so set a temporary libdir
+	# in case this is the development version
+	set autosetup(libdir) [file dirname $::argv0]/lib
+	use misc
+
+	# (a)
+	set autosetup(dir) [realdir [file dirname [realpath $::argv0]]]
+	set autosetup(prog) [file join $autosetup(dir) [file tail $::argv0]]
+	set autosetup(exe) [getenv WRAPPER $autosetup(prog)]
+	if {$autosetup(installed)} {
+		set autosetup(libdir) $autosetup(dir)
+	} else {
+		set autosetup(libdir) [file join $autosetup(dir) lib]
+	}
+	autosetup_add_dep $autosetup(prog)
+
+	# (b)
+	if {[getenv WRAPPER ""] eq ""} {
+		# Invoked directly
+		set autosetup(srcdir) [pwd]
+	} else {
+		# Invoked via the configure wrapper
+		set autosetup(srcdir) [file dirname $autosetup(exe)]
+	}
+	set autosetup(autodef) [relative-path $autosetup(srcdir)/auto.def]
+
+	# (c)
+	set autosetup(builddir) [pwd]
+
+	set autosetup(argv) $argv
+	set autosetup(cmdline) {}
+	set autosetup(options) {}
+	set autosetup(optionhelp) {}
+	set autosetup(showhelp) 0
+
+	# Parse options
+	use getopt
+
+	array set ::useropts [getopt argv]
+
+	#"=Core Options:"
+	options-add {
+		help:=local  => "display help and options. Optionally specify a module name, such as --help=system"
+		version      => "display the version of autosetup"
+		ref:=text manual:=text
+		reference:=text => "display the autosetup command reference. 'text', 'wiki', 'asciidoc' or 'markdown'"
+		debug        => "display debugging output as autosetup runs"
+		install:=.   => "install autosetup to the current or given directory (in the 'autosetup/' subdirectory)"
+		force init   => "create an initial 'configure' script if none exists"
+		# Undocumented options
+		option-checking=1
+		nopager
+		quiet
+		timing
+		conf:
+	}
+
+	#parray ::useropts
+	if {[opt-bool version]} {
+		puts $autosetup(version)
+		exit 0
+	}
+
+	# autosetup --conf=alternate-auto.def
+	if {[opt-val conf] ne ""} {
+		set autosetup(autodef) [opt-val conf]
+	}
+
+	# Debugging output (set this early)
+	incr autosetup(debug) [opt-bool debug]
+	incr autosetup(force) [opt-bool force]
+	incr autosetup(msg-quiet) [opt-bool quiet]
+	incr autosetup(msg-timing) [opt-bool timing]
+
+	# If the local module exists, source it now to allow for
+	# project-local customisations
+	if {[file exists $autosetup(libdir)/local.tcl]} {
+		use local
+	}
+
+	if {[opt-val help] ne ""} {
+		incr autosetup(showhelp)
+		use help
+		autosetup_help [opt-val help]
+	}
+
+	if {[opt-val {manual ref reference}] ne ""} {
+		use help
+		autosetup_reference [opt-val {manual ref reference}]
+	}
+
+	if {[opt-bool init]} {
+		use init
+		autosetup_init
+	}
+
+	if {[opt-val install] ne ""} {
+		use install
+		autosetup_install [opt-val install]
+	}
+
+	if {![file exists $autosetup(autodef)]} {
+		# Check for invalid option first
+		options {}
+		user-error "No auto.def found in $autosetup(srcdir)"
+	}
+
+	# Parse extra arguments into autosetup(cmdline)
+	foreach arg $argv {
+		if {[regexp {([^=]*)=(.*)} $arg -> n v]} {
+			dict set autosetup(cmdline) $n $v
+			define $n $v
+		} else {
+			user-error "Unexpected parameter: $arg"
+		}
+	}
+
+	autosetup_add_dep $autosetup(autodef)
+
+	set cmd [file-normalize $autosetup(exe)]
+	foreach arg $autosetup(argv) {
+		append cmd " [quote-if-needed $arg]"
+	}
+	define AUTOREMAKE $cmd
+
+	# Log how we were invoked
+	configlog "Invoked as: [getenv WRAPPER $::argv0] [quote-argv $autosetup(argv)]"
+
+	source $autosetup(autodef)
+
+	# Could warn here if options {} was not specified
+
+	show-notices
+
+	if {$autosetup(debug)} {
+		parray define
+	}
+
+	exit 0
+}
+
+# @opt-bool option ...
+#
+# Check each of the named, boolean options and return 1 if any of them have
+# been set by the user.
+#
+proc opt-bool {args} {
+	option-check-names {*}$args
+	opt_bool ::useropts {*}$args
+}
+
+# @opt-val option-list ?default=""?
+#
+# Returns a list containing all the values given for the non-boolean options in 'option-list'.
+# There will be one entry in the list for each option given by the user, including if the
+# same option was used multiple times.
+# If only a single value is required, use something like:
+#
+## lindex [opt-val $names] end
+#
+# If no options were set, $default is returned (exactly, not as a list).
+#
+proc opt-val {names {default ""}} {
+	option-check-names {*}$names
+	join [opt_val ::useropts $names $default]
+}
+
+proc option-check-names {args} {
+	foreach o $args {
+		if {$o ni $::autosetup(options)} {
+			autosetup-error "Request for undeclared option --$o"
+		}
+	}
+}
+
+# Parse the option definition in $opts and update
+# ::useropts() and ::autosetup(optionhelp) appropriately
+#
+proc options-add {opts {header ""}} {
+	global useropts autosetup
+
+	# First weed out comment lines
+	set realopts {}
+	foreach line [split $opts \n] {
+		if {![string match "#*" [string trimleft $line]]} {
+			append realopts $line \n
+		}
+	}
+	set opts $realopts
+
+	for {set i 0} {$i < [llength $opts]} {incr i} {
+		set opt [lindex $opts $i]
+		if {[string match =* $opt]} {
+			# This is a special heading
+			lappend autosetup(optionhelp) $opt ""
+			set header {}
+			continue
+		}
+
+		#puts "i=$i, opt=$opt"
+		regexp {^([^:=]*)(:)?(=)?(.*)$} $opt -> name colon equal value
+		if {$name in $autosetup(options)} {
+			autosetup-error "Option $name already specified"
+		}
+
+		#puts "$opt => $name $colon $equal $value"
+
+		# Find the corresponding value in the user options
+		# and set the default if necessary
+		if {[string match "-*" $opt]} {
+			# This is a documentation-only option, like "-C <dir>"
+			set opthelp $opt
+		} elseif {$colon eq ""} {
+			# Boolean option
+			lappend autosetup(options) $name
+
+			if {![info exists useropts($name)]} {
+				set useropts($name) $value
+			}
+			if {$value eq "1"} {
+				set opthelp "--disable-$name"
+			} else {
+				set opthelp "--$name"
+			}
+		} else {
+			# String option.
+			lappend autosetup(options) $name
+
+			if {$equal eq "="} {
+				if {[info exists useropts($name)]} {
+					# If the user specified the option with no value, the value will be "1"
+					# Replace with the default
+					if {$useropts($name) eq "1"} {
+						set useropts($name) $value
+					}
+				}
+				set opthelp "--$name?=$value?"
+			} else {
+				set opthelp "--$name=$value"
+			}
+		}
+
+		# Now create the help for this option if appropriate
+		if {[lindex $opts $i+1] eq "=>"} {
+			set desc [lindex $opts $i+2]
+			#string match \n* $desc
+			if {$header ne ""} {
+				lappend autosetup(optionhelp) $header ""
+				set header ""
+			}
+			# A multi-line description
+			lappend autosetup(optionhelp) $opthelp $desc
+			incr i 2
+		}
+	}
+}
+
+# @module-options optionlist
+#
+# Like 'options', but used within a module.
+proc module-options {opts} {
+	set header ""
+	if {$::autosetup(showhelp) > 1 && [llength $opts]} {
+		set header "Module Options:"
+	}
+	options-add $opts $header
+
+	if {$::autosetup(showhelp)} {
+		# Ensure that the module isn't executed on --help
+		# We are running under eval or source, so use break
+		# to prevent further execution
+		#return -code break -level 2
+		return -code break
+	}
+}
+
+proc max {a b} {
+	expr {$a > $b ? $a : $b}
+}
+
+proc options-wrap-desc {text length firstprefix nextprefix initial} {
+	set len $initial
+	set space $firstprefix
+	foreach word [split $text] {
+		set word [string trim $word]
+		if {$word == ""} {
+			continue
+		}
+		if {$len && [string length $space$word] + $len >= $length} {
+			puts ""
+			set len 0
+			set space $nextprefix
+		}
+		incr len [string length $space$word]
+		puts -nonewline $space$word
+		set space " "
+	}
+	if {$len} {
+		puts ""
+	}
+}
+
+proc options-show {} {
+	# Determine the max option width
+	set max 0
+	foreach {opt desc} $::autosetup(optionhelp) {
+		if {[string match =* $opt] || [string match \n* $desc]} {
+			continue
+		}
+		set max [max $max [string length $opt]]
+	}
+	set indent [string repeat " " [expr $max+4]]
+	set cols [getenv COLUMNS 80]
+	catch {
+		lassign [exec stty size] rows cols
+	}
+	incr cols -1
+	# Now output
+	foreach {opt desc} $::autosetup(optionhelp) {
+		if {[string match =* $opt]} {
+			puts [string range $opt 1 end]
+			continue
+		}
+		puts -nonewline "  [format %-${max}s $opt]"
+		if {[string match \n* $desc]} {
+			puts $desc
+		} else {
+			options-wrap-desc [string trim $desc] $cols "  " $indent [expr $max + 2]
+		}
+	}
+}
+
+# @options options-spec
+#
+# Specifies configuration-time options which may be selected by the user
+# and checked with opt-val and opt-bool. The format of options-spec follows.
+#
+# A boolean option is of the form:
+#
+## name[=0|1]  => "Description of this boolean option"
+#
+# The default is name=0, meaning that the option is disabled by default.
+# If name=1 is used to make the option enabled by default, the description should reflect
+# that with text like "Disable support for ...".
+#
+# An argument option (one which takes a parameter) is of the form:
+#
+## name:[=]value  => "Description of this option"
+#
+# If the name:value form is used, the value must be provided with the option (as --name=myvalue).
+# If the name:=value form is used, the value is optional and the given value is used as the default
+# if is not provided.
+#
+# Undocumented options are also supported by omitting the "=> description.
+# These options are not displayed with --help and can be useful for internal options or as aliases.
+#
+# For example, --disable-lfs is an alias for --disable=largefile:
+#
+## lfs=1 largefile=1 => "Disable large file support"
+#
+proc options {optlist} {
+	# Allow options as a list or args
+	options-add $optlist "Local Options:"
+
+	if {$::autosetup(showhelp)} {
+		options-show
+		exit 0
+	}
+
+	# Check for invalid options
+	if {[opt-bool option-checking]} {
+		foreach o [array names ::useropts] {
+			if {$o ni $::autosetup(options)} {
+				user-error "Unknown option --$o"
+			}
+		}
+	}
+}
+
+proc config_guess {} {
+	if {[file-isexec $::autosetup(dir)/config.guess]} {
+		exec-with-stderr sh $::autosetup(dir)/config.guess
+	} else {
+		configlog "No config.guess, so using uname"
+		string tolower [exec uname -p]-unknown-[exec uname -s][exec uname -r]
+	}
+}
+
+proc config_sub {alias} {
+	if {[file-isexec $::autosetup(dir)/config.sub]} {
+		exec-with-stderr sh $::autosetup(dir)/config.sub $alias
+	} else {
+		return $alias
+	}
+}
+
+# @define name ?value=1?
+#
+# Defines the named variable to the given value.
+# These (name, value) pairs represent the results of the configuration check
+# and are available to be checked, modified and substituted.
+#
+proc define {name {value 1}} {
+	set ::define($name) $value
+	#dputs "$name <= $value"
+}
+
+# @define-append name value ...
+#
+# Appends the given value(s) to the given 'defined' variable.
+# If the variable is not defined or empty, it is set to $value.
+# Otherwise the value is appended, separated by a space.
+# Any extra values are similarly appended.
+# If any value is already contained in the variable (as a substring) it is omitted.
+#
+proc define-append {name args} {
+	if {[get-define $name ""] ne ""} {
+		# Make a token attempt to avoid duplicates
+		foreach arg $args {
+			if {[string first $arg $::define($name)] == -1} {
+				append ::define($name) " " $arg
+			}
+		}
+	} else {
+		set ::define($name) [join $args]
+	}
+	#dputs "$name += [join $args] => $::define($name)"
+}
+
+# @get-define name ?default=0?
+#
+# Returns the current value of the 'defined' variable, or $default
+# if not set.
+#
+proc get-define {name {default 0}} {
+	if {[info exists ::define($name)]} {
+		#dputs "$name => $::define($name)"
+		return $::define($name)
+	}
+	#dputs "$name => $default"
+	return $default
+}
+
+# @is-defined name
+#
+# Returns 1 if the given variable is defined.
+#
+proc is-defined {name} {
+	info exists ::define($name)
+}
+
+# @all-defines
+#
+# Returns a dictionary (name value list) of all defined variables.
+#
+# This is suitable for use with 'dict', 'array set' or 'foreach'
+# and allows for arbitrary processing of the defined variables.
+#
+proc all-defines {} {
+	array get ::define
+}
+
+
+# @get-env name default
+#
+# If $name was specified on the command line, return it.
+# If $name was set in the environment, return it.
+# Otherwise return $default.
+#
+proc get-env {name default} {
+	if {[dict exists $::autosetup(cmdline) $name]} {
+		return [dict get $::autosetup(cmdline) $name]
+	}
+	getenv $name $default
+}
+
+# @env-is-set name
+#
+# Returns 1 if the $name was specified on the command line or in the environment.
+# Note that an empty environment variable is not considered to be set.
+#
+proc env-is-set {name} {
+	if {[dict exists $::autosetup(cmdline) $name]} {
+		return 1
+	}
+	if {[getenv $name ""] ne ""} {
+		return 1
+	}
+	return 0
+}
+
+# @readfile filename ?default=""?
+#
+# Return the contents of the file, without the trailing newline.
+# If the doesn't exist or can't be read, returns $default.
+#
+proc readfile {filename {default_value ""}} {
+	set result $default_value
+	catch {
+		set f [open $filename]
+		set result [read -nonewline $f]
+		close $f
+	}
+	return $result
+}
+
+# @writefile filename value
+#
+# Creates the given file containing $value.
+# Does not add an extra newline.
+#
+proc writefile {filename value} {
+	set f [open $filename w]
+	puts -nonewline $f $value
+	close $f
+}
+
+proc quote-if-needed {str} {
+	if {[string match {*[\" ]*} $str]} {
+		return \"[string map [list \" \\" \\ \\\\] $str]\"
+	}
+	return $str
+}
+
+proc quote-argv {argv} {
+	set args {}
+	foreach arg $argv {
+		lappend args [quote-if-needed $arg]
+	}
+	join $args
+}
+
+# @suffix suf list
+#
+# Takes a list and returns a new list with $suf appended
+# to each element
+#
+## suffix .c {a b c} => {a.c b.c c.c}
+#
+proc suffix {suf list} {
+	set result {}
+	foreach p $list {
+		lappend result $p$suf
+	}
+	return $result
+}
+
+# @prefix pre list
+#
+# Takes a list and returns a new list with $pre prepended
+# to each element
+#
+## prefix jim- {a.c b.c} => {jim-a.c jim-b.c}
+#
+proc prefix {pre list} {
+	set result {}
+	foreach p $list {
+		lappend result $pre$p
+	}
+	return $result
+}
+
+# @find-executable name
+#
+# Searches the path for an executable with the given name.
+# Note that the name may include some parameters, e.g. "cc -mbig-endian",
+# in which case the parameters are ignored.
+# Returns 1 if found, or 0 if not.
+#
+proc find-executable {name} {
+	# Ignore any parameters
+	set name [lindex $name 0]
+	if {$name eq ""} {
+		# The empty string is never a valid executable
+		return 0
+	}
+	foreach p [split-path] {
+		dputs "Looking for $name in $p"
+		set exec [file join $p $name]
+		if {[file-isexec $exec]} {
+			dputs "Found $name -> $exec"
+			return 1
+		}
+	}
+	return 0
+}
+
+# @find-an-executable ?-required? name ...
+#
+# Given a list of possible executable names,
+# searches for one of these on the path.
+#
+# Returns the name found, or "" if none found.
+# If the first parameter is '-required', an error is generated
+# if no executable is found.
+#
+proc find-an-executable {args} {
+	set required 0
+	if {[lindex $args 0] eq "-required"} {
+		set args [lrange $args 1 end]
+		incr required
+	}
+	foreach name $args {
+		if {[find-executable $name]} {
+			return $name
+		}
+	}
+	if {$required} {
+		if {[llength $args] == 1} {
+			user-error "failed to find: [join $args]"
+		} else {
+			user-error "failed to find one of: [join $args]"
+		}
+	}
+	return ""
+}
+
+# @configlog msg
+#
+# Writes the given message to the configuration log, config.log
+#
+proc configlog {msg} {
+	if {![info exists ::autosetup(logfh)]} {
+		set ::autosetup(logfh) [open config.log w]
+	}
+	puts $::autosetup(logfh) $msg
+}
+
+# @msg-checking msg
+#
+# Writes the message with no newline to stdout.
+#
+proc msg-checking {msg} {
+	if {$::autosetup(msg-quiet) == 0} {
+		maybe-show-timestamp
+		puts -nonewline $msg
+		set ::autosetup(msg-checking) 1
+	}
+}
+
+# @msg-result msg
+#
+# Writes the message to stdout.
+#
+proc msg-result {msg} {
+	if {$::autosetup(msg-quiet) == 0} {
+		maybe-show-timestamp
+		puts $msg
+		set ::autosetup(msg-checking) 0
+		show-notices
+	}
+}
+
+# @msg-quiet command ...
+#
+# msg-quiet evaluates it's arguments as a command with output
+# from msg-checking and msg-result suppressed.
+#
+# This is useful if a check needs to run a subcheck which isn't
+# of interest to the user.
+proc msg-quiet {args} {
+	incr ::autosetup(msg-quiet)
+	set rc [uplevel 1 $args]
+	incr ::autosetup(msg-quiet) -1
+	return $rc
+}
+
+# Will be overridden by 'use misc'
+proc error-stacktrace {msg} {
+	return $msg
+}
+
+proc error-location {msg} {
+	return $msg
+}
+
+##################################################################
+#
+# Debugging output
+#
+proc dputs {msg} {
+	if {$::autosetup(debug)} {
+		puts $msg
+	}
+}
+
+##################################################################
+#
+# User and system warnings and errors
+#
+# Usage errors such as wrong command line options
+
+# @user-error msg
+#
+# Indicate incorrect usage to the user, including if required components
+# or features are not found.
+# autosetup exits with a non-zero return code.
+#
+proc user-error {msg} {
+	show-notices
+	puts stderr "Error: $msg"
+	puts stderr "Try: '[file tail $::autosetup(exe)] --help' for options"
+	exit 1
+}
+
+# @user-notice msg
+#
+# Output the given message to stderr.
+#
+proc user-notice {msg} {
+	lappend ::autosetup(notices) $msg
+}
+
+# Incorrect usage in the auto.def file. Identify the location.
+proc autosetup-error {msg} {
+	show-notices
+	puts stderr [error-location $msg]
+	exit 1
+}
+
+proc show-notices {} {
+	if {$::autosetup(msg-checking)} {
+		puts ""
+		set ::autosetup(msg-checking) 0
+	}
+	flush stdout
+	if {[info exists ::autosetup(notices)]} {
+		puts stderr [join $::autosetup(notices) \n]
+		unset ::autosetup(notices)
+	}
+}
+
+proc maybe-show-timestamp {} {
+	if {$::autosetup(msg-timing) && $::autosetup(msg-checking) == 0} {
+		puts -nonewline [format {[%6.2f] } [expr {([clock millis] - $::autosetup(start)) % 10000 / 1000.0}]]
+	}
+}
+
+proc autosetup_version {} {
+	return "autosetup v$::autosetup(version)"
+}
+
+##################################################################
+#
+# Directory/path handling
+#
+
+proc realdir {dir} {
+	set oldpwd [pwd]
+	cd $dir
+	set pwd [pwd]
+	cd $oldpwd
+	return $pwd
+}
+
+# Follow symlinks until we get to something which is not a symlink
+proc realpath {path} {
+	while {1} {
+		if {[catch {
+			set path [file link $path]
+		}]} {
+			# Not a link
+			break
+		}
+	}
+	return $path
+}
+
+# Convert absolute path, $path into a path relative
+# to the given directory (or the current dir, if not given).
+#
+proc relative-path {path {pwd {}}} {
+	set diff 0
+	set same 0
+	set newf {}
+	set prefix {}
+	set path [file-normalize $path]
+	if {$pwd eq ""} {
+		set pwd [pwd]
+	} else {
+		set pwd [file-normalize $pwd]
+	}
+
+	if {$path eq $pwd} {
+		return .
+	}
+
+	# Try to make the filename relative to the current dir
+	foreach p [split $pwd /] f [split $path /] {
+		if {$p ne $f} {
+			incr diff
+		} elseif {!$diff} {
+			incr same
+		}
+		if {$diff} {
+			if {$p ne ""} {
+				# Add .. for sibling or parent dir
+				lappend prefix ..
+			}
+			if {$f ne ""} {
+				lappend newf $f
+			}
+		}
+	}
+	if {$same == 1 || [llength $prefix] > 3} {
+		return $path
+	}
+
+	file join [join $prefix /] [join $newf /]
+}
+
+# Add filename as a dependency to rerun autosetup
+# The name will be normalised (converted to a full path)
+#
+proc autosetup_add_dep {filename} {
+	lappend ::autosetup(deps) [file-normalize $filename]
+}
+
+##################################################################
+#
+# Library module support
+#
+
+# @use module ...
+#
+# Load the given library modules.
+# e.g. use cc cc-shared
+#
+proc use {args} {
+	foreach m $args {
+		if {[info exists ::libmodule($m)]} {
+			continue
+		}
+		set ::libmodule($m) 1
+		if {[info exists ::modsource($m)]} {
+			uplevel #0 eval $::modsource($m)
+		} else {
+			set source $::autosetup(libdir)/${m}.tcl
+			if {[file exists $source]} {
+				uplevel #0 [list source $source]
+				autosetup_add_dep $source
+			} else {
+				puts "Looking for $source"
+				autosetup-error "use: No such module: $m"
+			}
+		}
+	}
+}
+
+# Initial settings
+set autosetup(exe) $::argv0
+set autosetup(istcl) 1
+set autosetup(start) [clock millis]
+set autosetup(installed) 0
+set autosetup(msg-checking) 0
+set autosetup(msg-quiet) 0
+
+# Embedded modules are inserted below here
+set autosetup(installed) 1
+# ----- module asciidoc-formatting -----
+
+set modsource(asciidoc-formatting) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+# asciidoc format
+
+use formatting
+
+proc para {text} {
+    regsub -all "\[ \t\n\]+" [string trim $text] " "
+}
+proc title {text} {
+    underline [para $text] =
+    nl
+}
+proc p {text} {
+    puts [para $text]
+    nl
+}
+proc code {text} {
+    foreach line [parse_code_block $text] {
+        puts "    $line"
+    }
+    nl
+}
+proc codelines {lines} {
+    foreach line $lines {
+        puts "    $line"
+    }
+    nl
+}
+proc nl {} {
+    puts ""
+}
+proc underline {text char} {
+    regexp "^(\[ \t\]*)(.*)" $text -> indent words
+    puts $text
+    puts $indent[string repeat $char [string length $words]]
+}
+proc section {text} {
+    underline "[para $text]" -
+    nl
+}
+proc subsection {text} {
+    underline "$text" ~
+    nl
+}
+proc bullet {text} {
+    puts "* [para $text]"
+}
+proc indent {text} {
+    puts " :: "
+    puts [para $text]
+}
+proc defn {first args} {
+    set sep ""
+    if {$first ne ""} {
+        puts "${first}::"
+    } else {
+        puts " :: "
+    }
+    set defn [string trim [join $args \n]]
+    regsub -all "\n\n" $defn "\n ::\n" defn
+    puts $defn
+}
+}
+
+# ----- module formatting -----
+
+set modsource(formatting) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides common text formatting
+
+# This is designed for documenation which looks like:
+# code {...}
+# or
+# code {
+#    ...
+#    ...
+# }
+# In the second case, we need to work out the indenting
+# and strip it from all lines but preserve the remaining indenting.
+# Note that all lines need to be indented with the same initial
+# spaces/tabs.
+#
+# Returns a list of lines with the indenting removed.
+#
+proc parse_code_block {text} {
+    # If the text begins with newline, take the following text,
+    # otherwise just return the original
+    if {![regexp "^\n(.*)" $text -> text]} {
+        return [list [string trim $text]]
+    }
+
+    # And trip spaces off the end
+    set text [string trimright $text]
+
+    set min 100
+    # Examine each line to determine the minimum indent
+    foreach line [split $text \n] {
+        if {$line eq ""} {
+            # Ignore empty lines for the indent calculation
+            continue
+        }
+        regexp "^(\[ \t\]*)" $line -> indent
+        set len [string length $indent]
+        if {$len < $min} {
+            set min $len
+        }
+    }
+
+    # Now make a list of lines with this indent removed
+    set lines {}
+    foreach line [split $text \n] {
+        lappend lines [string range $line $min end]
+    }
+
+    # Return the result
+    return $lines
+}
+}
+
+# ----- module getopt -----
+
+set modsource(getopt) {
+# Copyright (c) 2006 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Simple getopt module
+
+# Parse everything out of the argv list which looks like an option
+# Knows about --enable-thing and --disable-thing as alternatives for --thing=0 or --thing=1
+# Everything which doesn't look like an option, or is after --, is left unchanged
+proc getopt {argvname} {
+	upvar $argvname argv
+	set nargv {}
+
+	for {set i 0} {$i < [llength $argv]} {incr i} {
+		set arg [lindex $argv $i]
+
+		#dputs arg=$arg
+
+		if {$arg eq "--"} {
+			# End of options
+			incr i
+			lappend nargv {*}[lrange $argv $i end]
+			break
+		}
+
+		if {[regexp {^--([^=][^=]+)=(.*)$} $arg -> name value]} {
+			lappend opts($name) $value
+		} elseif {[regexp {^--(enable-|disable-)?([^=]*)$} $arg -> prefix name]} {
+			if {$prefix eq "disable-"} {
+				set value 0
+			} else {
+				set value 1
+			}
+			lappend opts($name) $value
+		} else {
+			lappend nargv $arg
+		}
+	}
+
+	#puts "getopt: argv=[join $argv] => [join $nargv]"
+	#parray opts
+
+	set argv $nargv
+
+	return [array get opts]
+}
+
+proc opt_val {optarrayname options {default {}}} {
+	upvar $optarrayname opts
+
+	set result {}
+
+	foreach o $options {
+		if {[info exists opts($o)]} {
+			lappend result {*}$opts($o)
+		}
+	}
+	if {[llength $result] == 0} {
+		return $default
+	}
+	return $result
+}
+
+proc opt_bool {optarrayname args} {
+	upvar $optarrayname opts
+
+	# Support the args being passed as a list
+	if {[llength $args] == 1} {
+		set args [lindex $args 0]
+	}
+
+	foreach o $args {
+		if {[info exists opts($o)]} {
+			if {"1" in $opts($o) || "yes" in $opts($o)} {
+				return 1
+			}
+		}
+	}
+	return 0
+}
+}
+
+# ----- module help -----
+
+set modsource(help) {
+# Copyright (c) 2010 WorkWare Systems http://workware.net.au/
+# All rights reserved
+
+# Module which provides usage, help and the command reference
+
+proc autosetup_help {what} {
+    use_pager
+
+    puts "Usage: [file tail $::autosetup(exe)] \[options\] \[settings\]\n"
+    puts "This is [autosetup_version], a build environment \"autoconfigurator\""
+    puts "See the documentation online at http://msteveb.github.com/autosetup/\n"
+
+    if {$what eq "local"} {
+        if {[file exists $::autosetup(autodef)]} {
+            # This relies on auto.def having a call to 'options'
+            # which will display options and quit
+            source $::autosetup(autodef)
+        } else {
+            options-show
+        }
+    } else {
+        incr ::autosetup(showhelp)
+        if {[catch {use $what}]} {
+            user-error "Unknown module: $what"
+        } else {
+            options-show
+        }
+    }
+    exit 0
+}
+
+# If not already paged and stdout is a tty, pipe the output through the pager
+# This is done by reinvoking autosetup with --nopager added
+proc use_pager {} {
+    if {![opt-bool nopager] && [getenv PAGER ""] ne "" && ![string match "not a tty" [exec tty]]} {
+        catch {
+            exec [info nameofexecutable] $::argv0 --nopager {*}$::argv | [getenv PAGER] >@stdout <@stdin 2>/dev/null
+        }
+        exit 0
+    }
+}
+
+# Outputs the autosetup references in one of several formats
+proc autosetup_reference {{type text}} {
+
+    use_pager
+
+    switch -glob -- $type {
+        wiki {use wiki-formatting}
+        ascii* {use asciidoc-formatting}
+        md - markdown {use markdown-formatting}
+        default {use text-formatting}
+    }
+
+    title "[autosetup_version] -- Command Reference"
+
+    section {Introduction}
+
+    p {
+        See http://msteveb.github.com/autosetup/ for the online documentation for 'autosetup'
+    }
+
+    p {
+        'autosetup' provides a number of built-in commands which
+        are documented below. These may be used from 'auto.def' to test
+        for features, define variables, create files from templates and
+        other similar actions.
+    }
+
+    automf_command_reference
+
+    exit 0
+}
+
+proc autosetup_output_block {type lines} {
+    if {[llength $lines]} {
+        switch $type {
+            code {
+                codelines $lines
+            }
+            p {
+                p [join $lines]
+            }
+            list {
+                foreach line $lines {
+                    bullet $line
+                }
+                nl
+            }
+        }
+    }
+}
+
+# Generate a command reference from inline documentation
+proc automf_command_reference {} {
+    lappend files $::autosetup(prog)
+    lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/*.tcl]]
+
+    section "Core Commands"
+    set type p
+    set lines {}
+    set cmd {}
+
+    foreach file $files {
+        set f [open $file]
+        while {![eof $f]} {
+            set line [gets $f]
+
+            # Find lines starting with "# @*" and continuing through the remaining comment lines
+            if {![regexp {^# @(.*)} $line -> cmd]} {
+                continue
+            }
+
+            # Synopsis or command?
+            if {$cmd eq "synopsis:"} {
+                section "Module: [file rootname [file tail $file]]"
+            } else {
+                subsection $cmd
+            }
+
+            set lines {}
+            set type p
+
+            # Now the description
+            while {![eof $f]} {
+                set line [gets $f]
+
+                if {![regexp {^#(#)? ?(.*)} $line -> hash cmd]} {
+                    break
+                }
+                if {$hash eq "#"} {
+                    set t code
+                } elseif {[regexp {^- (.*)} $cmd -> cmd]} {
+                    set t list
+                } else {
+                    set t p
+                }
+
+                #puts "hash=$hash, oldhash=$oldhash, lines=[llength $lines], cmd=$cmd"
+
+                if {$t ne $type || $cmd eq ""} {
+                    # Finish the current block
+                    autosetup_output_block $type $lines
+                    set lines {}
+                    set type $t
+                }
+                if {$cmd ne ""} {
+                    lappend lines $cmd
+                }
+            }
+
+            autosetup_output_block $type $lines
+        }
+        close $f
+    }
+}
+}
+
+# ----- module init -----
+
+set modsource(init) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module to help create auto.def and configure
+
+proc autosetup_init {} {
+	set create_configure 1
+	if {[file exists configure]} {
+		if {!$::autosetup(force)} {
+			# Could this be an autosetup configure?
+			if {![string match "*\nWRAPPER=*" [readfile configure]]} {
+				puts "I see configure, but not created by autosetup, so I won't overwrite it."
+				puts "Use autosetup --init --force to overwrite."
+				set create_configure 0
+			}
+		} else {
+			puts "I will overwrite the existing configure because you used --force."
+		}
+	} else {
+		puts "I don't see configure, so I will create it."
+	}
+	if {$create_configure} {
+		if {!$::autosetup(installed)} {
+			user-notice "Warning: Initialising from the development version of autosetup"
+
+			writefile configure "#!/bin/sh\nWRAPPER=\"\$0\" exec $::autosetup(dir)/autosetup \"\$@\"\n"
+		} else {
+			writefile configure \
+{#!/bin/sh
+dir="`dirname "$0"`/autosetup"
+WRAPPER="$0" exec "`$dir/find-tclsh`" "$dir/autosetup" "$@"
+}
+		}
+		catch {exec chmod 755 configure}
+	}
+	if {![file exists auto.def]} {
+		puts "I don't see auto.def, so I will create a default one."
+		writefile auto.def {# Initial auto.def created by 'autosetup --init'
+
+use cc
+
+# Add any user options here
+options {
+}
+
+make-config-header config.h
+make-template Makefile.in
+}
+	}
+	if {![file exists Makefile.in]} {
+		puts "Note: I don't see Makefile.in. You will probably need to create one."
+	}
+
+	exit 0
+}
+}
+
+# ----- module install -----
+
+set modsource(install) {
+# Copyright (c) 2006-2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which can install autosetup
+
+proc autosetup_install {dir} {
+	if {[catch {
+		cd $dir
+		file mkdir autosetup
+
+		set f [open autosetup/autosetup w]
+
+		set publicmodules {}
+
+		# First the main script, but only up until "CUT HERE"
+		set in [open $::autosetup(dir)/autosetup]
+		while {[gets $in buf] >= 0} {
+			if {$buf ne "##-- CUT HERE --##"} {
+				puts $f $buf
+				continue
+			}
+
+			# Insert the static modules here
+			# i.e. those which don't contain @synopsis:
+			puts $f "set autosetup(installed) 1"
+			foreach file [lsort [glob $::autosetup(libdir)/*.tcl]] {
+				set buf [readfile $file]
+				if {[string match "*\n# @synopsis:*" $buf]} {
+					lappend publicmodules $file
+					continue
+				}
+				set modname [file rootname [file tail $file]]
+				puts $f "# ----- module $modname -----"
+				puts $f "\nset modsource($modname) \{"
+				puts $f $buf
+				puts $f "\}\n"
+			}
+		}
+		close $in
+		close $f
+		exec chmod 755 autosetup/autosetup
+
+		# Install public modules
+		foreach file $publicmodules {
+			autosetup_install_file $file autosetup
+		}
+
+		# Install support files
+		foreach file {config.guess config.sub jimsh0.c find-tclsh test-tclsh LICENSE} {
+			autosetup_install_file $::autosetup(dir)/$file autosetup
+		}
+		exec chmod 755 autosetup/config.sub autosetup/config.guess autosetup/find-tclsh
+
+		writefile autosetup/README.autosetup \
+			"This is [autosetup_version]. See http://msteveb.github.com/autosetup/\n"
+
+	} error]} {
+		user-error "Failed to install autosetup: $error"
+	}
+	puts "Installed [autosetup_version] to autosetup/"
+	catch {exec [info nameofexecutable] autosetup/autosetup --init >@stdout 2>@stderr}
+
+	exit 0
+}
+
+# Append the contents of $file to filehandle $f
+proc autosetup_install_append {f file} {
+	set in [open $file]
+	puts $f [read $in]
+	close $in
+}
+
+proc autosetup_install_file {file dir} {
+	if {![file exists $file]} {
+		error "Missing installation file '$file'"
+	}
+	writefile [file join $dir [file tail $file]] [readfile $file]\n
+}
+
+if {$::autosetup(installed)} {
+	user-error "autosetup can only be installed from development source, not from installed copy"
+}
+}
+
+# ----- module markdown-formatting -----
+
+set modsource(markdown-formatting) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+# markdown format (kramdown syntax)
+
+use formatting
+
+proc para {text} {
+    regsub -all "\[ \t\n\]+" [string trim $text] " " text
+    regsub -all {([^a-zA-Z])'([^']*)'} $text {\1**`\2`**} text
+    regsub -all {^'([^']*)'} $text {**`\1`**} text
+    regsub -all {(http[^ \t\n]*)} $text {[\1](\1)} text
+    return $text
+}
+proc title {text} {
+    underline [para $text] =
+    nl
+}
+proc p {text} {
+    puts [para $text]
+    nl
+}
+proc codelines {lines} {
+    puts "~~~~~~~~~~~~"
+    foreach line $lines {
+        puts $line
+    }
+    puts "~~~~~~~~~~~~"
+    nl
+}
+proc code {text} {
+    puts "~~~~~~~~~~~~"
+    foreach line [parse_code_block $text] {
+        puts $line
+    }
+    puts "~~~~~~~~~~~~"
+    nl
+}
+proc nl {} {
+    puts ""
+}
+proc underline {text char} {
+    regexp "^(\[ \t\]*)(.*)" $text -> indent words
+    puts $text
+    puts $indent[string repeat $char [string length $words]]
+}
+proc section {text} {
+    underline "[para $text]" -
+    nl
+}
+proc subsection {text} {
+    puts "### `$text`"
+    nl
+}
+proc bullet {text} {
+    puts "* [para $text]"
+}
+proc defn {first args} {
+    puts "^"
+    set defn [string trim [join $args \n]]
+    if {$first ne ""} {
+        puts "**${first}**"
+        puts -nonewline ": "
+        regsub -all "\n\n" $defn "\n: " defn
+    }
+    puts "$defn"
+}
+}
+
+# ----- module misc -----
+
+set modsource(misc) {
+# Copyright (c) 2007-2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module containing misc procs useful to modules
+# Largely for platform compatibility
+
+set autosetup(istcl) [info exists ::tcl_library]
+set autosetup(iswin) [string equal windows $tcl_platform(platform)]
+
+if {$autosetup(iswin)} {
+	# mingw/windows separates $PATH with semicolons
+	# and doesn't have an executable bit
+	proc split-path {} {
+		split [getenv PATH .] {;}
+	}
+	proc file-isexec {exec} {
+		# Basic test for windows. We ignore .bat
+		if {[file isfile $exec] || [file isfile $exec.exe]} {
+			return 1
+		}
+		return 0
+	}
+} else {
+	# unix separates $PATH with colons and has and executable bit
+	proc split-path {} {
+		split [getenv PATH .] :
+	}
+	proc file-isexec {exec} {
+		file executable $exec
+	}
+}
+
+# Assume that exec can return stdout and stderr
+proc exec-with-stderr {args} {
+	exec {*}$args 2>@1
+}
+
+if {$autosetup(istcl)} {
+	# Tcl doesn't have the env command
+	proc getenv {name args} {
+		if {[info exists ::env($name)]} {
+			return $::env($name)
+		}
+		if {[llength $args]} {
+			return [lindex $args 0]
+		}
+		return -code error "environment variable \"$name\" does not exist"
+	}
+} elseif {$autosetup(iswin)} {
+	# On Windows, backslash convert all environment variables
+	# (Assume that Tcl does this for us)
+	proc getenv {name args} {
+		string map {\\ /} [env $name {*}$args]
+	}
+} else {
+	# Jim on unix is simple
+	alias getenv env
+}
+
+# In case 'file normalize' doesn't exist
+#
+proc file-normalize {path} {
+	if {[catch {file normalize $path} result]} {
+		if {$path eq ""} {
+			return ""
+		}
+		set oldpwd [pwd]
+		if {[file isdir $path]} {
+			cd $path
+			set result [pwd]
+		} else {
+			cd [file dirname $path]
+			set result [file join [pwd] [file tail $path]]
+		}
+		cd $oldpwd
+	}
+	return $result
+}
+
+# If everything is working properly, the only errors which occur
+# should be generated in user code (e.g. auto.def).
+# By default, we only want to show the error location in user code.
+# We use [info frame] to achieve this, but it works differently on Tcl and Jim.
+#
+# This is designed to be called for incorrect usage in auto.def, via autosetup-error
+#
+proc error-location {msg} {
+	if {$::autosetup(debug)} {
+		return -code error $msg
+	}
+	# Search back through the stack trace for the first error in a .def file
+	for {set i 1} {$i < [info level]} {incr i} {
+		if {$::autosetup(istcl)} {
+			array set info [info frame -$i]
+		} else {
+			lassign [info frame -$i] info(caller) info(file) info(line)
+		}
+		if {[string match *.def $info(file)]} {
+			return "[relative-path $info(file)]:$info(line): Error: $msg"
+		}
+		#puts "Skipping $info(file):$info(line)"
+	}
+	return $msg
+}
+
+# Similar to error-location, but called when user code generates an error
+# In this case we want to show the stack trace in user code, but not in autosetup code
+# (unless --debug is enabled)
+#
+proc error-stacktrace {msg} {
+	if {$::autosetup(istcl)} {
+		if {[regexp {file "([^ ]*)" line ([0-9]*)} $::errorInfo dummy file line]} {
+			return "[relative-path $file]:$line $msg\n$::errorInfo"
+		}
+		return $::errorInfo
+	} else {
+		# Prepend a live stacktrace to the error stacktrace, omitting the current level
+		set stacktrace [concat [info stacktrace] [lrange [stacktrace] 3 end]]
+
+		if {!$::autosetup(debug)} {
+			# Omit any levels from autosetup or with no file
+			set newstacktrace {}
+			foreach {p f l} $stacktrace {
+				if {[string match "*autosetup" $f] || $f eq ""} {
+					#puts "Skipping $p $f:$l"
+					continue
+				}
+				lappend newstacktrace $p $f $l
+			}
+			set stacktrace $newstacktrace
+		}
+
+		# Convert filenames to relative paths
+		set newstacktrace {}
+		foreach {p f l} $stacktrace {
+			lappend newstacktrace $p [relative-path $f] $l
+		}
+		lassign $newstacktrace p f l
+		if {$f ne ""} {
+			set prefix "$f:$l: "
+		} else {
+			set prefix ""
+		}
+
+		return "${prefix}Error: $msg\n[stackdump $newstacktrace]"
+	}
+}
+}
+
+# ----- module text-formatting -----
+
+set modsource(text-formatting) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+
+use formatting
+
+proc wordwrap {text length {firstprefix ""} {nextprefix ""}} {
+    set len 0
+    set space $firstprefix
+    foreach word [split $text] {
+        set word [string trim $word]
+        if {$word == ""} {
+            continue
+        }
+        if {$len && [string length $space$word] + $len >= $length} {
+            puts ""
+            set len 0
+            set space $nextprefix
+        }
+        incr len [string length $space$word]
+
+        # Use man-page conventions for highlighting 'quoted' and *quoted*
+        # single words.
+        # Use x^Hx for *bold* and _^Hx for 'underline'.
+        #
+        # less and more will both understand this.
+        # Pipe through 'col -b' to remove them.
+        if {[regexp {^'(.*)'([^a-zA-Z0-9_]*)$} $word -> bareword dot]} {
+            regsub -all . $bareword "_\b&" word
+            append word $dot
+        } elseif {[regexp {^[*](.*)[*]([^a-zA-Z0-9_]*)$} $word -> bareword dot]} {
+            regsub -all . $bareword "&\b&" word
+            append word $dot
+        }
+        puts -nonewline $space$word
+        set space " "
+    }
+    if {$len} {
+        puts ""
+    }
+}
+proc title {text} {
+    underline [string trim $text] =
+    nl
+}
+proc p {text} {
+    wordwrap $text 80
+    nl
+}
+proc codelines {lines} {
+    foreach line $lines {
+        puts "    $line"
+    }
+    nl
+}
+proc nl {} {
+    puts ""
+}
+proc underline {text char} {
+    regexp "^(\[ \t\]*)(.*)" $text -> indent words
+    puts $text
+    puts $indent[string repeat $char [string length $words]]
+}
+proc section {text} {
+    underline "[string trim $text]" -
+    nl
+}
+proc subsection {text} {
+    underline "$text" ~
+    nl
+}
+proc bullet {text} {
+    wordwrap $text 76 "  * " "    "
+}
+proc indent {text} {
+    wordwrap $text 76 "    " "    "
+}
+proc defn {first args} {
+    if {$first ne ""} {
+        underline "    $first" ~
+    }
+    foreach p $args {
+        if {$p ne ""} {
+            indent $p
+        }
+    }
+}
+}
+
+# ----- module wiki-formatting -----
+
+set modsource(wiki-formatting) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+# wiki.tcl.tk format output
+
+use formatting
+
+proc joinlines {text} {
+    set lines {}
+    foreach l [split [string trim $text] \n] {
+        lappend lines [string trim $l]
+    }
+    join $lines
+}
+proc p {text} {
+    puts [joinlines $text]
+    puts ""
+}
+proc title {text} {
+    puts "*** [joinlines $text] ***"
+    puts ""
+}
+proc codelines {lines} {
+    puts "======"
+    foreach line $lines {
+        puts "    $line"
+    }
+    puts "======"
+}
+proc code {text} {
+    puts "======"
+    foreach line [parse_code_block $text] {
+        puts "    $line"
+    }
+    puts "======"
+}
+proc nl {} {
+}
+proc section {text} {
+    puts "'''$text'''"
+    puts ""
+}
+proc subsection {text} {
+    puts "''$text''"
+    puts ""
+}
+proc bullet {text} {
+    puts "   * [joinlines $text]"
+}
+proc indent {text} {
+    puts "    :    [joinlines $text]"
+}
+proc defn {first args} {
+    if {$first ne ""} {
+        indent '''$first'''
+    }
+
+    foreach p $args {
+        p $p
+    }
+}
+}
+
+
+##################################################################
+#
+# Entry/Exit
+#
+if {$autosetup(debug)} {
+	main $argv
+}
+if {[catch {main $argv} msg] == 1} {
+	show-notices
+	puts stderr [error-stacktrace $msg]
+	if {!$autosetup(debug) && !$autosetup(istcl)} {
+		puts stderr "Try: '[file tail $autosetup(exe)] --debug' for a full stack trace"
+	}
+	exit 1
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/cc-lib.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/cc-lib.tcl
new file mode 100755
index 0000000..e8e5e86
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/cc-lib.tcl
@@ -0,0 +1,77 @@
+# Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# Provides a library of common tests on top of the 'cc' module.
+
+use cc
+
+module-options {}
+
+# @cc-check-lfs
+#
+# The equivalent of the AC_SYS_LARGEFILE macro
+# 
+# defines 'HAVE_LFS' if LFS is available,
+# and defines '_FILE_OFFSET_BITS=64' if necessary
+#
+# Returns 1 if 'LFS' is available or 0 otherwise
+#
+proc cc-check-lfs {} {
+	cc-check-includes sys/types.h
+	msg-checking "Checking if -D_FILE_OFFSET_BITS=64 is needed..."
+	set lfs 1
+	if {[msg-quiet cc-with {-includes sys/types.h} {cc-check-sizeof off_t}] == 8} {
+		msg-result no
+	} elseif {[msg-quiet cc-with {-includes sys/types.h -cflags -D_FILE_OFFSET_BITS=64} {cc-check-sizeof off_t}] == 8} {
+		define _FILE_OFFSET_BITS 64
+		msg-result yes
+	} else {
+		set lfs 0
+		msg-result none
+	}
+	define-feature lfs $lfs
+	return $lfs
+}
+
+# @cc-check-endian
+#
+# The equivalent of the AC_C_BIGENDIAN macro
+# 
+# defines 'HAVE_BIG_ENDIAN' if endian is known to be big,
+# or 'HAVE_LITTLE_ENDIAN' if endian is known to be little.
+#
+# Returns 1 if determined, or 0 if not.
+#
+proc cc-check-endian {} {
+	cc-check-includes sys/types.h sys/param.h
+	set rc 0
+	msg-checking "Checking endian..."
+	cc-with {-includes {sys/types.h sys/param.h}} {
+		if {[cctest -code {
+			#if !defined(BIG_ENDIAN) || !defined(BYTE_ORDER)
+				#error unknown
+			#elif BYTE_ORDER != BIG_ENDIAN
+				#error little
+			#endif
+		}]} {
+			define-feature big-endian
+			msg-result "big"
+			set rc 1
+		} elseif {[cctest -code {
+			#if !defined(LITTLE_ENDIAN) || !defined(BYTE_ORDER)
+				#error unknown
+			#elif BYTE_ORDER != LITTLE_ENDIAN
+				#error big
+			#endif
+		}]} {
+			define-feature little-endian
+			msg-result "little"
+			set rc 1
+		} else {
+			msg-result "unknown"
+		}
+	}
+	return $rc
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/cc-shared.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/cc-shared.tcl
new file mode 100755
index 0000000..1e77440
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/cc-shared.tcl
@@ -0,0 +1,63 @@
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# The 'cc-shared' module provides support for shared libraries and shared objects.
+# It defines the following variables:
+#
+## SH_CFLAGS         Flags to use compiling sources destined for a shared library
+## SH_LDFLAGS        Flags to use linking a shared library
+## SHOBJ_CFLAGS      Flags to use compiling sources destined for a shared object
+## SHOBJ_LDFLAGS     Flags to use linking a shared object
+## SH_LINKFLAGS      Flags to use linking an executable which will load shared objects
+## LD_LIBRARY_PATH   Environment variable which specifies path to shared libraries
+
+module-options {}
+
+foreach i {SH_LINKFLAGS SH_CFLAGS SH_LDFLAGS SHOBJ_CFLAGS SHOBJ_LDFLAGS} {
+	define $i ""
+}
+
+define LD_LIBRARY_PATH LD_LIBRARY_PATH
+
+switch -glob -- [get-define host] {
+	*-*-darwin* {
+		define SH_CFLAGS -dynamic
+		define SH_LDFLAGS "-dynamiclib"
+		define SHOBJ_CFLAGS "-dynamic -fno-common"
+		define SHOBJ_LDFLAGS "-bundle -undefined dynamic_lookup"
+		define LD_LIBRARY_PATH DYLD_LIBRARY_PATH
+	}
+	*-*-ming* {
+		define SH_LDFLAGS -shared
+		define SHOBJ_LDFLAGS -shared
+	}
+	*-*-cygwin {
+		define SH_LDFLAGS -shared
+		define SHOBJ_LDFLAGS -shared
+	}
+	*-*-solaris* {
+		# XXX: These haven't been fully tested. 
+		#define SH_LINKFLAGS -Wl,-export-dynamic
+		define SH_CFLAGS -Kpic
+		define SHOBJ_CFLAGS -Kpic
+		define SHOBJ_LDFLAGS "-G"
+	}
+	*-*-hpux {
+		# XXX: These haven't been tested
+		define SH_LINKFLAGS -Wl,+s
+		define SH_CFLAGS +z
+		define SHOBJ_CFLAGS "+O3 +z"
+		define SHOBJ_LDFLAGS -b
+		define LD_LIBRARY_PATH SHLIB_PATH
+	}
+	* {
+		# Generic Unix settings
+		define SH_LINKFLAGS -rdynamic
+		define SH_CFLAGS -fpic
+		define SH_LDFLAGS -shared
+		define SHOBJ_CFLAGS -fpic
+		define SHOBJ_LDFLAGS "-shared"
+	}
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/cc.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/cc.tcl
new file mode 100755
index 0000000..707e69c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/cc.tcl
@@ -0,0 +1,660 @@
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# The 'cc' module supports checking various 'features' of the C or C++
+# compiler/linker environment. Common commands are cc-check-includes,
+# cc-check-types, cc-check-functions, cc-with, make-autoconf-h and make-template.
+#
+# The following environment variables are used if set:
+#
+## CC       - C compiler
+## CXX      - C++ compiler
+## CCACHE   - Set to "none" to disable automatic use of ccache
+## CFLAGS   - Additional C compiler flags
+## CXXFLAGS - Additional C++ compiler flags
+## LDFLAGS  - Additional compiler flags during linking
+## LIBS     - Additional libraries to use (for all tests)
+## CROSS    - Tool prefix for cross compilation
+#
+# The following variables are defined from the corresponding
+# environment variables if set.
+#
+## CPPFLAGS
+## LINKFLAGS
+## CC_FOR_BUILD
+## LD
+
+use system
+
+module-options {}
+
+# Note that the return code is not meaningful
+proc cc-check-something {name code} {
+	uplevel 1 $code
+}
+
+# Checks for the existence of the given function by linking
+#
+proc cctest_function {function} {
+	cctest -link 1 -declare "extern void $function\(void);" -code "$function\();"
+}
+
+# Checks for the existence of the given type by compiling
+proc cctest_type {type} {
+	cctest -code "$type _x;"
+}
+
+# Checks for the existence of the given type/structure member.
+# e.g. "struct stat.st_mtime"
+proc cctest_member {struct_member} {
+	lassign [split $struct_member .] struct member
+	cctest -code "static $struct _s; return sizeof(_s.$member);"
+}
+
+# Checks for the existence of the given define by compiling
+#
+proc cctest_define {name} {
+	cctest -code "#ifndef $name\n#error not defined\n#endif"
+}
+
+# Checks for the existence of the given name either as
+# a macro (#define) or an rvalue (such as an enum)
+#
+proc cctest_decl {name} {
+	cctest -code "#ifndef $name\n(void)$name;\n#endif"
+}
+
+# @cc-check-sizeof type ...
+#
+# Checks the size of the given types (between 1 and 32, inclusive).
+# Defines a variable with the size determined, or "unknown" otherwise.
+# e.g. for type 'long long', defines SIZEOF_LONG_LONG.
+# Returns the size of the last type.
+#
+proc cc-check-sizeof {args} {
+	foreach type $args {
+		msg-checking "Checking for sizeof $type..."
+		set size unknown
+		# Try the most common sizes first
+		foreach i {4 8 1 2 16 32} {
+			if {[cctest -code "static int _x\[sizeof($type) == $i ? 1 : -1\] = { 1 };"]} {
+				set size $i
+				break
+			}
+		}
+		msg-result $size
+		set define [feature-define-name $type SIZEOF_]
+		define $define $size
+	}
+	# Return the last result
+	get-define $define
+}
+
+# Checks for each feature in $list by using the given script.
+#
+# When the script is evaluated, $each is set to the feature
+# being checked, and $extra is set to any additional cctest args.
+#
+# Returns 1 if all features were found, or 0 otherwise.
+proc cc-check-some-feature {list script} {
+	set ret 1
+	foreach each $list {
+		if {![check-feature $each $script]} {
+			set ret 0
+		}
+	}
+	return $ret
+}
+
+# @cc-check-includes includes ...
+#
+# Checks that the given include files can be used
+proc cc-check-includes {args} {
+	cc-check-some-feature $args {
+		cctest -includes $each
+	}
+}
+
+# @cc-check-types type ...
+#
+# Checks that the types exist.
+proc cc-check-types {args} {
+	cc-check-some-feature $args {
+		cctest_type $each
+	}
+}
+
+# @cc-check-defines define ...
+#
+# Checks that the given preprocessor symbol is defined
+proc cc-check-defines {args} {
+	cc-check-some-feature $args {
+		cctest_define $each
+	}
+}
+
+# @cc-check-decls name ...
+#
+# Checks that each given name is either a preprocessor symbol or rvalue
+# such as an enum. Note that the define used for a decl is HAVE_DECL_xxx
+# rather than HAVE_xxx
+proc cc-check-decls {args} {
+	set ret 1
+	foreach name $args {
+		msg-checking "Checking for $name..."
+		set r [cctest_decl $name]
+		define-feature "decl $name" $r
+		if {$r} {
+			msg-result "ok"
+		} else {
+			msg-result "not found"
+			set ret 0
+		}
+	}
+	return $ret
+}
+
+# @cc-check-functions function ...
+#
+# Checks that the given functions exist (can be linked)
+proc cc-check-functions {args} {
+	cc-check-some-feature $args {
+		cctest_function $each
+	}
+}
+
+# @cc-check-members type.member ...
+#
+# Checks that the given type/structure members exist.
+# A structure member is of the form "struct stat.st_mtime"
+proc cc-check-members {args} {
+	cc-check-some-feature $args {
+		cctest_member $each
+	}
+}
+
+# @cc-check-function-in-lib function libs ?otherlibs?
+#
+# Checks that the given given function can be found in one of the libs.
+#
+# First checks for no library required, then checks each of the libraries
+# in turn.
+#
+# If the function is found, the feature is defined and lib_$function is defined
+# to -l$lib where the function was found, or "" if no library required.
+# In addition, -l$lib is added to the LIBS define.
+#
+# If additional libraries may be needed for linking, they should be specified
+# as $extralibs as "-lotherlib1 -lotherlib2".
+# These libraries are not automatically added to LIBS.
+#
+# Returns 1 if found or 0 if not.
+# 
+proc cc-check-function-in-lib {function libs {otherlibs {}}} {
+	msg-checking "Checking libs for $function..."
+	set found 0
+	cc-with [list -libs $otherlibs] {
+		if {[cctest_function $function]} {
+			msg-result "none needed"
+			define lib_$function ""
+			incr found
+		} else {
+			foreach lib $libs {
+				cc-with [list -libs -l$lib] {
+					if {[cctest_function $function]} {
+						msg-result -l$lib
+						define lib_$function -l$lib
+						define-append LIBS -l$lib
+						incr found
+						break
+					}
+				}
+			}
+		}
+	}
+	if {$found} {
+		define [feature-define-name $function]
+	} else {
+		msg-result "no"
+	}
+	return $found
+}
+
+# @cc-check-tools tool ...
+#
+# Checks for existence of the given compiler tools, taking
+# into account any cross compilation prefix.
+#
+# For example, when checking for "ar", first AR is checked on the command
+# line and then in the environment. If not found, "${host}-ar" or
+# simply "ar" is assumed depending upon whether cross compiling.
+# The path is searched for this executable, and if found AR is defined
+# to the executable name.
+#
+# It is an error if the executable is not found.
+#
+proc cc-check-tools {args} {
+	foreach tool $args {
+		set TOOL [string toupper $tool]
+		set exe [get-env $TOOL [get-define cross]$tool]
+		if {![find-executable $exe]} {
+			user-error "Failed to find $exe"
+		}
+		define $TOOL $exe
+	}
+}
+
+# @cc-check-progs prog ...
+#
+# Checks for existence of the given executables on the path.
+#
+# For example, when checking for "grep", the path is searched for
+# the executable, 'grep', and if found GREP is defined as "grep".
+#
+# It the executable is not found, the variable is defined as false.
+# Returns 1 if all programs were found, or 0 otherwise.
+#
+proc cc-check-progs {args} {
+	set failed 0
+	foreach prog $args {
+		set PROG [string toupper $prog]
+		msg-checking "Checking for $prog..."
+		if {![find-executable $prog]} {
+			msg-result no
+			define $PROG false
+			incr failed
+		} else {
+			msg-result ok
+			define $PROG $prog
+		}
+	}
+	expr {!$failed}
+}
+
+# Adds the given settings to $::autosetup(ccsettings) and
+# returns the old settings.
+#
+proc cc-add-settings {settings} {
+	if {[llength $settings] % 2} {
+		autosetup-error "settings list is missing a value: $settings"
+	}
+
+	set prev [cc-get-settings]
+	# workaround a bug in some versions of jimsh by forcing
+	# conversion of $prev to a list
+	llength $prev
+
+	array set new $prev
+
+	foreach {name value} $settings {
+		switch -exact -- $name {
+			-cflags - -includes {
+				# These are given as lists
+				lappend new($name) {*}$value
+			}
+			-declare {
+				lappend new($name) $value
+			}
+			-libs {
+				# Note that new libraries are added before previous libraries
+				set new($name) [list {*}$value {*}$new($name)]
+			}
+			-link - -lang {
+				set new($name) $value
+			}
+			-source - -sourcefile - -code {
+				# XXX: These probably are only valid directly from cctest
+				set new($name) $value
+			}
+			default {
+				autosetup-error "unknown cctest setting: $name"
+			}
+		}
+	}
+
+	cc-store-settings [array get new]
+
+	return $prev
+}
+
+proc cc-store-settings {new} {
+	set ::autosetup(ccsettings) $new
+}
+
+proc cc-get-settings {} {
+	return $::autosetup(ccsettings)
+}
+
+# Similar to cc-add-settings, but each given setting
+# simply replaces the existing value.
+#
+# Returns the previous settings
+proc cc-update-settings {args} {
+	set prev [cc-get-settings]
+	cc-store-settings [dict merge $prev $args]
+	return $prev
+}
+
+# @cc-with settings ?{ script }?
+#
+# Sets the given 'cctest' settings and then runs the tests in 'script'.
+# Note that settings such as -lang replace the current setting, while
+# those such as -includes are appended to the existing setting.
+#
+# If no script is given, the settings become the default for the remainder
+# of the auto.def file.
+#
+## cc-with {-lang c++} {
+##   # This will check with the C++ compiler
+##   cc-check-types bool
+##   cc-with {-includes signal.h} {
+##     # This will check with the C++ compiler, signal.h and any existing includes.
+##     ...
+##   }
+##   # back to just the C++ compiler
+## }
+#
+# The -libs setting is special in that newer values are added *before* earlier ones.
+#
+## cc-with {-libs {-lc -lm}} {
+##   cc-with {-libs -ldl} {
+##     cctest -libs -lsocket ...
+##     # libs will be in this order: -lsocket -ldl -lc -lm
+##   }
+## }
+proc cc-with {settings args} {
+	if {[llength $args] == 0} {
+		cc-add-settings $settings
+	} elseif {[llength $args] > 1} {
+		autosetup-error "usage: cc-with settings ?script?"
+	} else {
+		set save [cc-add-settings $settings]
+		set rc [catch {uplevel 1 [lindex $args 0]} result info]
+		cc-store-settings $save
+		if {$rc != 0} {
+			return $result -code [dict get $info -code]
+		}
+		return $result
+	}
+}
+
+# @cctest ?settings?
+# 
+# Low level C compiler checker. Compiles and or links a small C program
+# according to the arguments and returns 1 if OK, or 0 if not.
+#
+# Supported settings are:
+#
+## -cflags cflags      A list of flags to pass to the compiler
+## -includes list      A list of includes, e.g. {stdlib.h stdio.h}
+## -declare code       Code to declare before main()
+## -link 1             Don't just compile, link too
+## -lang c|c++         Use the C (default) or C++ compiler
+## -libs liblist       List of libraries to link, e.g. {-ldl -lm}
+## -code code          Code to compile in the body of main()
+## -source code        Compile a complete program. Ignore -includes, -declare and -code
+## -sourcefile file    Shorthand for -source [readfile [get-define srcdir]/$file]
+#
+# Unless -source or -sourcefile is specified, the C program looks like:
+#
+## #include <firstinclude>   /* same for remaining includes in the list */
+##
+## declare-code              /* any code in -declare, verbatim */
+##
+## int main(void) {
+##   code                    /* any code in -code, verbatim */
+##   return 0;
+## }
+#
+# Any failures are recorded in 'config.log'
+#
+proc cctest {args} {
+	set src conftest__.c
+	set tmp conftest__
+
+	# Easiest way to merge in the settings
+	cc-with $args {
+		array set opts [cc-get-settings]
+	}
+
+	if {[info exists opts(-sourcefile)]} {
+		set opts(-source) [readfile [get-define srcdir]/$opts(-sourcefile) "#error can't find $opts(-sourcefile)"]
+	}
+	if {[info exists opts(-source)]} {
+		set lines $opts(-source)
+	} else {
+		foreach i $opts(-includes) {
+			if {$opts(-code) ne "" && ![feature-checked $i]} {
+				# Compiling real code with an unchecked header file
+				# Quickly (and silently) check for it now
+
+				# Remove all -includes from settings before checking
+				set saveopts [cc-update-settings -includes {}]
+				msg-quiet cc-check-includes $i
+				cc-store-settings $saveopts
+			}
+			if {$opts(-code) eq "" || [have-feature $i]} {
+				lappend source "#include <$i>"
+			}
+		}
+		lappend source {*}$opts(-declare)
+		lappend source "int main(void) {"
+		lappend source $opts(-code)
+		lappend source "return 0;"
+		lappend source "}"
+
+		set lines [join $source \n]
+	}
+
+	# Build the command line
+	set cmdline {}
+	lappend cmdline {*}[get-define CCACHE]
+	switch -exact -- $opts(-lang) {
+		c++ {
+			lappend cmdline {*}[get-define CXX] {*}[get-define CXXFLAGS]
+		}
+		c {
+			lappend cmdline {*}[get-define CC] {*}[get-define CFLAGS]
+		}
+		default {
+			autosetup-error "cctest called with unknown language: $opts(-lang)"
+		}
+	}
+
+	if {!$opts(-link)} {
+		set tmp conftest__.o
+		lappend cmdline -c
+	}
+	lappend cmdline {*}$opts(-cflags)
+
+	switch -glob -- [get-define host] {
+		*-*-darwin* {
+			# Don't generate .dSYM directories
+			lappend cmdline -gstabs
+		}
+	}
+	lappend cmdline $src -o $tmp {*}$opts(-libs)
+
+	# At this point we have the complete command line and the
+	# complete source to be compiled. Get the result from cache if
+	# we can
+	if {[info exists ::cc_cache($cmdline,$lines)]} {
+		msg-checking "(cached) "
+		set ok $::cc_cache($cmdline,$lines)
+		if {$::autosetup(debug)} {
+			configlog "From cache (ok=$ok): [join $cmdline]"
+			configlog "============"
+			configlog $lines
+			configlog "============"
+		}
+		return $ok
+	}
+
+	writefile $src $lines\n
+
+	set ok 1
+	if {[catch {exec-with-stderr {*}$cmdline} result errinfo]} {
+		configlog "Failed: [join $cmdline]"
+		configlog $result
+		configlog "============"
+		configlog "The failed code was:"
+		configlog $lines
+		configlog "============"
+		set ok 0
+	} elseif {$::autosetup(debug)} {
+		configlog "Compiled OK: [join $cmdline]"
+		configlog "============"
+		configlog $lines
+		configlog "============"
+	}
+	file delete $src
+	file delete $tmp
+
+	# cache it
+	set ::cc_cache($cmdline,$lines) $ok
+
+	return $ok
+}
+
+# @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*?
+#
+# Deprecated - see make-config-header
+proc make-autoconf-h {file {autopatterns {HAVE_*}} {barepatterns {SIZEOF_* HAVE_DECL_*}}} {
+	user-notice "*** make-autoconf-h is deprecated -- use make-config-header instead"
+	make-config-header $file -auto $autopatterns -bare $barepatterns
+}
+
+# @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ...
+#
+# Examines all defined variables which match the given patterns
+# and writes an include file, $file, which defines each of these.
+# Variables which match '-auto' are output as follows:
+# - defines which have the value "0" are ignored.
+# - defines which have integer values are defined as the integer value.
+# - any other value is defined as a string, e.g. "value"
+# Variables which match '-bare' are defined as-is.
+# Variables which match '-str' are defined as a string, e.g. "value"
+# Variables which match '-none' are omitted.
+#
+# Note that order is important. The first pattern which matches is selected
+# Default behaviour is:
+#
+#  -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
+#
+# If the file would be unchanged, it is not written.
+proc make-config-header {file args} {
+	set guard _[string toupper [regsub -all {[^a-zA-Z0-9]} [file tail $file] _]]
+	file mkdir [file dirname $file]
+	set lines {}
+	lappend lines "#ifndef $guard"
+	lappend lines "#define $guard"
+
+	# Add some defaults
+	lappend args -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_*
+
+	foreach n [lsort [dict keys [all-defines]]] {
+		set value [get-define $n]
+		set type [calc-define-output-type $n $args]
+		switch -exact -- $type {
+			-bare {
+				# Just output the value unchanged
+			}
+			-none {
+				continue
+			}
+			-str {
+				set value \"$value\"
+			}
+			-auto {
+				# Automatically determine the type
+				if {$value eq "0"} {
+					lappend lines "/* #undef $n */"
+					continue
+				}
+				if {![string is integer -strict $value]} {
+					set value \"$value\"
+				}
+			}
+			"" {
+				continue
+			}
+			default {
+				autosetup-error "Unknown type in make-config-header: $type"
+			}
+		}
+		lappend lines "#define $n $value"
+	}
+	lappend lines "#endif"
+	set buf [join $lines \n]
+	write-if-changed $file $buf {
+		msg-result "Created $file"
+	}
+}
+
+proc calc-define-output-type {name spec} {
+	foreach {type patterns} $spec {
+		foreach pattern $patterns {
+			if {[string match $pattern $name]} {
+				return $type
+			}
+		}
+	}
+	return ""
+}
+
+# Initialise some values from the environment or commandline or default settings
+foreach i {LDFLAGS LIBS CPPFLAGS LINKFLAGS {CFLAGS "-g -O2"}} {
+	lassign $i var default
+	define $var [get-env $var $default]
+}
+
+if {[env-is-set CC]} {
+	# Set by the user, so don't try anything else
+	set try [list [get-env CC ""]]
+} else {
+	# Try some reasonable options
+	set try [list [get-define cross]cc [get-define cross]gcc]
+}
+define CC [find-an-executable {*}$try]
+if {[get-define CC] eq ""} {
+	user-error "Could not find a C compiler. Tried: [join $try ", "]"
+}
+
+define CPP [get-env CPP "[get-define CC] -E"]
+
+# XXX: Could avoid looking for a C++ compiler until requested
+# Note that if CXX isn't found, we just set it to "false". It might not be needed.
+if {[env-is-set CXX]} {
+	define CXX [find-an-executable -required [get-env CXX ""]]
+} else {
+	define CXX [find-an-executable [get-define cross]c++ [get-define cross]g++ false]
+}
+
+# CXXFLAGS default to CFLAGS if not specified
+define CXXFLAGS [get-env CXXFLAGS [get-define CFLAGS]]
+
+cc-check-tools ld
+
+# May need a CC_FOR_BUILD, so look for one
+define CC_FOR_BUILD [find-an-executable [get-env CC_FOR_BUILD ""] cc gcc false]
+
+if {[get-define CC] eq ""} {
+	user-error "Could not find a C compiler. Tried: [join $try ", "]"
+}
+
+define CCACHE [find-an-executable [get-env CCACHE ccache]]
+
+# Initial cctest settings
+cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {}}
+
+msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]"
+if {[get-define CXX] ne "false"} {
+	msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]"
+}
+msg-result "Build C compiler...[get-define CC_FOR_BUILD]"
+
+if {![cc-check-includes stdlib.h]} {
+	user-error "Compiler does not work. See config.log"
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/config.guess b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/config.guess
new file mode 100755
index 0000000..4c8f032
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/config.guess
@@ -0,0 +1,1508 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+#   Free Software Foundation, Inc.
+
+timestamp='2010-09-24'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner.  Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
+Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' HUP INT TERM
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" HUP INT PIPE TERM ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep -q __ELF__
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+	        os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+	        UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+        echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm:riscos:*:*|arm:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+	echo i386-pc-auroraux${UNAME_RELEASE}
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	eval $set_cc_for_build
+	SUN_ARCH="i386"
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH="x86_64"
+	    fi
+	fi
+	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+ 	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[4567])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+              	{
+              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+              	case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+              	    switch (bits)
+              		{
+              		case 64: puts ("hppa2.0w"); break;
+              		case 32: puts ("hppa2.0n"); break;
+              		default: puts ("hppa2.0"); break;
+              		} break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+              	    puts ("hppa2.0"); break;
+              #endif
+              	default: puts ("hppa1.0"); break;
+              	}
+                  exit (0);
+              }
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep -q __LP64__
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit ;;
+    5000:UNIX_System_V:4.*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	case ${UNAME_MACHINE} in
+	    pc98)
+		echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:windows32*:*)
+    	# uname -m includes "-pc" on this system.
+    	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:*)
+    	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    authenticamd | genuineintel | EM64T)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    8664:Windows_NT:*)
+	echo x86_64-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+	objdump --private-headers /bin/sh | grep -q ld.so.1
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-gnu
+	else
+	    echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    cris:Linux:*:*)
+	echo cris-axis-linux-gnu
+	exit ;;
+    crisv32:Linux:*:*)
+	echo crisv32-axis-linux-gnu
+	exit ;;
+    frv:Linux:*:*)
+    	echo frv-unknown-linux-gnu
+	exit ;;
+    i*86:Linux:*:*)
+	LIBC=gnu
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#ifdef __dietlibc__
+	LIBC=dietlibc
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+	echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef ${UNAME_MACHINE}
+	#undef ${UNAME_MACHINE}el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=${UNAME_MACHINE}el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=${UNAME_MACHINE}
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    or32:Linux:*:*)
+	echo or32-unknown-linux-gnu
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-gnu
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit ;;
+    sh64*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    tile*:Linux:*:*)
+	echo ${UNAME_MACHINE}-tilera-linux-gnu
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-gnu
+	exit ;;
+    x86_64:Linux:*:*)
+	echo x86_64-unknown-linux-gnu
+	exit ;;
+    xtensa*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+    	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configury will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+        exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes@openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf@swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+	        echo mips-nec-sysv${UNAME_RELEASE}
+	else
+	        echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+        exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	case $UNAME_PROCESSOR in
+	    i386)
+		eval $set_cc_for_build
+		if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+		  if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		      (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		      grep IS_64BIT_ARCH >/dev/null
+		  then
+		      UNAME_PROCESSOR="x86_64"
+		  fi
+		fi ;;
+	    unknown) UNAME_PROCESSOR=powerpc ;;
+	esac
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NEO-?:NONSTOP_KERNEL:*:*)
+	echo neo-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSE-?:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+    	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+	  ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    c34*)
+	echo c34-convex-bsd
+	exit ;;
+    c38*)
+	echo c38-convex-bsd
+	exit ;;
+    c4*)
+	echo c4-convex-bsd
+	exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/config.sub b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/config.sub
new file mode 100755
index 0000000..320e303
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/config.sub
@@ -0,0 +1,1739 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+#   Free Software Foundation, Inc.
+
+timestamp='2010-09-11'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted GNU ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
+Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+  linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+  knetbsd*-gnu* | netbsd*-gnu* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray | -microblaze)
+		os=
+		basic_machine=$1
+		;;
+        -bluegene*)
+	        os=-cnk
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+ 	-chorusrdb)
+ 		os=-chorusrdb
+		basic_machine=$1
+ 		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+	| bfin \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| lm32 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | mcore | mep | metag \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64octeon | mips64octeonel \
+	| mips64orion | mips64orionel \
+	| mips64r5900 | mips64r5900el \
+	| mips64vr | mips64vrel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| moxie \
+	| mt \
+	| msp430 \
+	| nds32 | nds32le | nds32be \
+	| nios | nios2 \
+	| ns16k | ns32k \
+	| or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| rx \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu | strongarm \
+	| tahoe | thumb | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+	| ubicom32 \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+	| z8k | z80)
+		basic_machine=$basic_machine-unknown
+		;;
+	c54x)
+		basic_machine=tic54x-unknown
+		;;
+	c55x)
+		basic_machine=tic55x-unknown
+		;;
+	c6x)
+		basic_machine=tic6x-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12 | picochip)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* \
+	| clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| lm32-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64octeon-* | mips64octeonel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64r5900-* | mips64r5900el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nds32-* | nds32le-* | nds32be-* \
+	| nios-* | nios2-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* | rx-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tile-* | tilegx-* \
+	| tron-* \
+	| ubicom32-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-* | z80-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+    	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aros)
+		basic_machine=i386-pc
+		os=-aros
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	bluegene*)
+		basic_machine=powerpc-ibm
+		os=-cnk
+		;;
+	c54x-*)
+		basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c55x-*)
+		basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c6x-*)
+		basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+        cegcc)
+		basic_machine=arm-unknown
+		os=-cegcc
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dicos)
+		basic_machine=i686-pc
+		os=-dicos
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+        microblaze)
+		basic_machine=microblaze-xilinx
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+        neo-tandem)
+		basic_machine=neo-tandem
+		;;
+        nse-tandem)
+		basic_machine=nse-tandem
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+		;;
+	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+        # This must be matched before tile*.
+        tilegx*)
+		basic_machine=tilegx-unknown
+		os=-linux-gnu
+		;;
+	tile*)
+		basic_machine=tile-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	z80-*-coff)
+		basic_machine=z80-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+        -auroraux)
+	        os=-auroraux
+		;;
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+	      | -sym* | -kopensolaris* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* | -aros* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -openbsd* | -solidbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* | -cegcc* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -linux-android* \
+	      | -linux-newlib* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+        -os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+        -tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-dicos*)
+		os=-dicos
+		;;
+        -nacl*)
+	        ;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+        score-*)
+		os=-elf
+		;;
+        spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+        c4x-* | tic4x-*)
+        	os=-coff
+		;;
+	tic54x-*)
+		os=-coff
+		;;
+	tic55x-*)
+		os=-coff
+		;;
+	tic6x-*)
+		os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+        mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+    	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-cnk*|-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/find-tclsh b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/find-tclsh
new file mode 100755
index 0000000..7ef152a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/find-tclsh
@@ -0,0 +1,17 @@
+#!/bin/sh
+# Looks for a suitable tclsh or jimsh in the PATH
+# If not found, builds a bootstrap jimsh from source
+d=`dirname "$0"`
+{ "$d/jimsh0" "$d/test-tclsh"; } 2>/dev/null && exit 0
+PATH="$PATH:$d"
+for tclsh in jimsh tclsh tclsh8.5 tclsh8.6; do
+	{ $tclsh "$d/test-tclsh"; } 2>/dev/null && exit 0
+done
+echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
+./make-bootstrap-jim > $d/jimsh0.c
+for cc in ${CC_FOR_BUILD:-cc} gcc; do
+	{ $cc -o "$d/jimsh0" "$d/jimsh0.c"; } 2>/dev/null || continue
+	"$d/jimsh0" "$d/test-tclsh" && exit 0
+done
+echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
+echo false
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/system.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/system.tcl
new file mode 100755
index 0000000..f05d05b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/system.tcl
@@ -0,0 +1,268 @@
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# This module supports common system interrogation and options
+# such as --host, --build, --prefix, and setting srcdir, builddir, and EXEXT.
+#
+# It also support the 'feature' naming convention, where searching
+# for a feature such as sys/type.h defines HAVE_SYS_TYPES_H
+#
+module-options {
+	host:host-alias =>		{a complete or partial cpu-vendor-opsys for the system where
+							the application will run (defaults to the same value as --build)}
+	build:build-alias =>	{a complete or partial cpu-vendor-opsys for the system
+							where the application will be built (defaults to the
+							result of running config.guess)}
+	prefix:dir =>			{the target directory for the build (defaults to /usr/local)}
+
+	# These (hidden) options are supported for autoconf/automake compatibility
+	exec-prefix:
+	bindir:
+	sbindir:
+	includedir:
+	mandir:
+	infodir:
+	libexecdir:
+	datadir:
+	libdir:
+	sysconfdir:
+	sharedstatedir:
+	localstatedir:
+	maintainer-mode=0
+	dependency-tracking=0
+}
+
+# Returns 1 if exists, or 0 if  not
+#
+proc check-feature {name code} {
+	msg-checking "Checking for $name..."
+	set r [uplevel 1 $code]
+	define-feature $name $r
+	if {$r} {
+		msg-result "ok"
+	} else {
+		msg-result "not found"
+	}
+	return $r
+}
+
+# @have-feature name ?default=0?
+#
+# Returns the value of the feature if defined, or $default if not.
+# See 'feature-define-name' for how the feature name
+# is translated into the define name.
+#
+proc have-feature {name {default 0}} {
+	get-define [feature-define-name $name] $default
+}
+
+# @define-feature name ?value=1?
+#
+# Sets the feature 'define' to the given value.
+# See 'feature-define-name' for how the feature name
+# is translated into the define name.
+#
+proc define-feature {name {value 1}} {
+	define [feature-define-name $name] $value
+}
+
+# @feature-checked name
+#
+# Returns 1 if the feature has been checked, whether true or not
+#
+proc feature-checked {name} {
+	is-defined [feature-define-name $name]
+}
+
+# @feature-define-name name ?prefix=HAVE_?
+#
+# Converts a name to the corresponding define,
+# e.g. sys/stat.h becomes HAVE_SYS_STAT_H.
+#
+# Converts * to P and all non-alphanumeric to underscore.
+#
+proc feature-define-name {name {prefix HAVE_}} {
+	string toupper $prefix[regsub -all {[^a-zA-Z0-9]} [regsub -all {[*]} $name p] _]
+}
+
+# If $file doesn't exist, or it's contents are different than $buf,
+# the file is written and $script is executed.
+# Otherwise a "file is unchanged" message is displayed.
+proc write-if-changed {file buf {script {}}} {
+	set old [readfile $file ""]
+	if {$old eq $buf && [file exists $file]} {
+		msg-result "$file is unchanged"
+	} else {
+		writefile $file $buf\n
+		uplevel 1 $script
+	}
+}
+
+# @make-template template ?outfile?
+#
+# Reads the input file <srcdir>/$template and writes the output file $outfile.
+# If $outfile is blank/omitted, $template should end with ".in" which
+# is removed to create the output file name.
+#
+# Each pattern of the form @define@ is replaced the the corresponding
+# define, if it exists, or left unchanged if not.
+# 
+# The special value @srcdir@ is subsituted with the relative
+# path to the source directory from the directory where the output
+# file is created. Use @top_srcdir@ for the absolute path.
+#
+# Conditional sections may be specified as follows:
+## @if name == value
+## lines
+## @else
+## lines
+## @endif
+#
+# Where 'name' is a defined variable name and @else is optional.
+# If the expression does not match, all lines through '@endif' are ignored.
+#
+# The alternative forms may also be used:
+## @if name
+## @if name != value
+#
+# Where the first form is true if the variable is defined, but not empty or 0
+#
+# Currently these expressions can't be nested.
+#
+proc make-template {template {out {}}} {
+	set infile [file join $::autosetup(srcdir) $template]
+
+	if {![file exists $infile]} {
+		user-error "Template $template is missing"
+	}
+
+	# Define this as late as possible
+	define AUTODEPS $::autosetup(deps)
+
+	if {$out eq ""} {
+		if {[file ext $template] ne ".in"} {
+			autosetup-error "make_template $template has no target file and can't guess"
+		}
+		set out [file rootname $template]
+	}
+
+	set outdir [file dirname $out]
+
+	# Make sure the directory exists
+	file mkdir $outdir
+
+	# Set up srcdir to be relative to the target dir
+	define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir]
+
+	set mapping {}
+	foreach {n v} [array get ::define] {
+		lappend mapping @$n@ $v
+	}
+	set result {}
+	foreach line [split [readfile $infile] \n] {
+		if {[info exists cond]} {
+			set l [string trimright $line]
+			if {$l eq "@endif"} {
+				unset cond
+				continue
+			}
+			if {$l eq "@else"} {
+				set cond [expr {!$cond}]
+				continue
+			}
+			if {$cond} {
+				lappend result $line
+			}
+			continue
+		}
+		if {[regexp {^@if\s+(\w+)(.*)} $line -> name expression]} {
+			lassign $expression equal value
+			set varval [get-define $name ""]
+			if {$equal eq ""} {
+				set cond [expr {$varval ni {"" 0}}]
+			} else {
+				set cond [expr {$varval eq $value}]
+				if {$equal ne "=="} {
+					set cond [expr {!$cond}]
+				}
+			}
+			continue
+		}
+		lappend result $line
+	}
+	writefile $out [string map $mapping [join $result \n]]\n
+
+	msg-result "Created [relative-path $out] from [relative-path $template]"
+}
+
+# build/host tuples and cross-compilation prefix
+set build [opt-val build]
+define build_alias $build
+if {$build eq ""} {
+	define build [config_guess]
+} else {
+	define build [config_sub $build]
+}
+
+set host [opt-val host]
+define host_alias $host
+if {$host eq ""} {
+	define host [get-define build]
+	set cross ""
+} else {
+	define host [config_sub $host]
+	set cross $host-
+}
+define cross [get-env CROSS $cross]
+
+set prefix [opt-val prefix /usr/local]
+
+# These are for compatibility with autoconf
+define target [get-define host]
+define prefix $prefix
+define builddir $autosetup(builddir)
+define srcdir $autosetup(srcdir)
+# Allow this to come from the environment
+define top_srcdir [get-env top_srcdir [get-define srcdir]]
+
+# autoconf supports all of these
+set exec_prefix [opt-val exec-prefix $prefix]
+define exec_prefix $exec_prefix
+foreach {name defpath} {
+	bindir /bin
+	sbindir /sbin
+	libexecdir /libexec
+	libdir /lib
+} {
+	define $name [opt-val $name $exec_prefix$defpath]
+}
+foreach {name defpath} {
+	datadir /share
+	sysconfdir /etc
+	sharedstatedir /com
+	localstatedir /var
+	infodir /share/info
+	mandir /share/man
+	includedir /include
+} {
+	define $name [opt-val $name $prefix$defpath]
+}
+
+define SHELL [get-env SHELL [find-an-executable sh bash ksh]]
+
+# Windows vs. non-Windows
+switch -glob -- [get-define host] {
+	*-*-ming* - *-*-cygwin {
+		define-feature windows
+		define EXEEXT .exe
+	}
+	default {
+		define EXEEXT ""
+	}
+}
+
+# Display
+msg-result "Host System...[get-define host]"
+msg-result "Build System...[get-define build]"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/test-tclsh b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/test-tclsh
new file mode 100755
index 0000000..75126d2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/autosetup/test-tclsh
@@ -0,0 +1,20 @@
+# A small Tcl script to verify that the chosen
+# interpreter works. Sometimes we might e.g. pick up
+# an interpreter for a different arch.
+# Outputs the full path to the interpreter
+
+if {[catch {info version} version] == 0} {
+	# This is Jim Tcl
+	if {$version >= 0.72} {
+		# Ensure that regexp works
+		regexp (a.*?) a
+		puts [info nameofexecutable]
+		exit 0
+	}
+} elseif {[catch {info tclversion} version] == 0} {
+	if {$version >= 8.5 && ![string match 8.5a* [info patchlevel]]} {
+		puts [info nameofexecutable]
+		exit 0
+	}
+}
+exit 1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/bootstrap.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/bootstrap.tcl
new file mode 100755
index 0000000..e7adf4b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/bootstrap.tcl
@@ -0,0 +1,3 @@
+# No need for package support in the bootstrap jimsh, but
+# Tcl extensions call package require
+proc package {args} {}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/configure b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/configure
new file mode 100755
index 0000000..1c5586f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/configure
@@ -0,0 +1,3 @@
+#!/bin/sh
+dir="`dirname "$0"`/autosetup"
+WRAPPER="$0" exec "`$dir/find-tclsh`" "$dir/autosetup" "$@"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/configure.ac b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/configure.ac
new file mode 100755
index 0000000..b70b5d8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/configure.ac
@@ -0,0 +1 @@
+# Dummy configure.ac to make automake happy
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/andrew.txt b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/andrew.txt
new file mode 100755
index 0000000..8dbfcfc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/andrew.txt
@@ -0,0 +1,65 @@
+Delivered-To: oyvindharboe@gmail.com
+Received: by 10.100.7.20 with SMTP id 20cs86142ang;
+        Wed, 16 Jul 2008 00:45:59 -0700 (PDT)
+Received: by 10.142.238.12 with SMTP id l12mr5009290wfh.204.1216194359186;
+        Wed, 16 Jul 2008 00:45:59 -0700 (PDT)
+Return-Path: <andrew@lunn.ch>
+Received: from cpanel5.proisp.no (cpanel5.proisp.no [209.85.100.29])
+        by mx.google.com with ESMTP id 31si6762736wff.16.2008.07.16.00.45.57;
+        Wed, 16 Jul 2008 00:45:59 -0700 (PDT)
+Received-SPF: fail (google.com: domain of andrew@lunn.ch does not designate 209.85.100.29 as permitted sender) client-ip=209.85.100.29;
+Authentication-Results: mx.google.com; spf=hardfail (google.com: domain of andrew@lunn.ch does not designate 209.85.100.29 as permitted sender) smtp.mail=andrew@lunn.ch
+Received: from londo.lunn.ch ([80.238.139.98]:48839 ident=mail)
+	by cpanel5.proisp.no with esmtp (Exim 4.69)
+	(envelope-from <andrew@lunn.ch>)
+	id 1KJ1ht-00085G-Ng
+	for oyvind.harboe@zylin.com; Wed, 16 Jul 2008 09:45:52 +0200
+Received: from lunn by londo.lunn.ch with local (Exim 3.36 #1 (Debian))
+	id 1KJ1hq-0005ss-00; Wed, 16 Jul 2008 09:45:46 +0200
+Date: Wed, 16 Jul 2008 09:45:46 +0200
+From: Andrew Lunn <andrew@lunn.ch>
+To: ?yvind Harboe <oyvind.harboe@zylin.com>
+Cc: jim-devel@lists.berlios.de, antirez@gmail.com, patthoyts@users.sf.net,
+	andrew@lunn.ch, openocd@duaneellis.com, uklein@klein-messgeraete.de,
+	ml-jim@qiao.in-berlin.de
+Subject: Re: Change Jim Tcl license
+Message-ID: <20080716074546.GC24771@lunn.ch>
+References: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+In-Reply-To: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+User-Agent: Mutt/1.5.18 (2008-05-17)
+X-Spam-Status: No, score=-2.6
+X-Spam-Score: -25
+X-Spam-Bar: --
+X-Spam-Flag: NO
+X-AntiAbuse: This header was added to track abuse, please include it with any abuse report
+X-AntiAbuse: Primary Hostname - cpanel5.proisp.no
+X-AntiAbuse: Original Domain - zylin.com
+X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12]
+X-AntiAbuse: Sender Address Domain - lunn.ch
+X-Source: 
+X-Source-Args: 
+X-Source-Dir: 
+
+On Wed, Jul 16, 2008 at 09:34:14AM +0200, ?yvind Harboe wrote:
+> Hi all,
+> 
+> I'm currently the maintainer of Jim Tcl trying as best as I can
+> to fill Salvatore's shoes.
+> 
+> Short story:
+> 
+> If you have contributed to Jim Tcl, please reply to this email
+> that you agree that we can switch Jim Tcl to a FreeBSD license.
+
+I've no problems with this, but my contributions are very minimal.
+
+Do you want this written down, in blood, to keep the lawyers happy?
+
+At a minimum i think everybody's agreement needs to be posted to a
+public email list which is publicly archived etc so there is a
+record of the agreement...
+
+       Andrew
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/clemens.txt b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/clemens.txt
new file mode 100755
index 0000000..806f7ed
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/clemens.txt
@@ -0,0 +1,87 @@
+                                                                                                                                                                                                                                                               
+Delivered-To: oyvindharboe@gmail.com
+Received: by 10.100.7.20 with SMTP id 20cs114742ang;
+        Wed, 16 Jul 2008 08:58:18 -0700 (PDT)
+Received: by 10.114.137.2 with SMTP id k2mr325372wad.95.1216223896673;
+        Wed, 16 Jul 2008 08:58:16 -0700 (PDT)
+Return-Path: <ml-jim@qiao.in-berlin.de>
+Received: from cpanel5.proisp.no (cpanel5.proisp.no [209.85.100.29])
+        by mx.google.com with ESMTP id m28si10145125waf.16.2008.07.16.08.58.15;
+        Wed, 16 Jul 2008 08:58:16 -0700 (PDT)
+Received-SPF: neutral (google.com: 209.85.100.29 is neither permitted nor denied by best guess record for domain of ml-jim@qiao.in-berlin.de) client-ip=209.85.100.29;
+Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.100.29 is neither permitted nor denied by best guess record for domain of ml-jim@qiao.in-berlin.de) smtp.mail=ml-jim@qiao.in-berlin.de
+Received: from gnu.in-berlin.de ([192.109.42.4]:58401)
+	by cpanel5.proisp.no with esmtps (TLSv1:AES256-SHA:256)
+	(Exim 4.69)
+	(envelope-from <ml-jim@qiao.in-berlin.de>)
+	id 1KJ9OG-0006Hf-8y
+	for oyvind.harboe@zylin.com; Wed, 16 Jul 2008 17:58:07 +0200
+X-Envelope-From: ml-jim@qiao.in-berlin.de
+X-Envelope-To: <oyvind.harboe@zylin.com>
+Received: from qiao.in-berlin.de (qiao.in-berlin.de [217.197.85.72])
+	by gnu.in-berlin.de (8.13.8/8.13.8/Debian-2) with ESMTP id m6GFvxio009504
+	for <oyvind.harboe@zylin.com>; Wed, 16 Jul 2008 17:58:02 +0200
+Received: from [192.168.0.10] ([::ffff:192.168.0.10])
+  by qiao.in-berlin.de with esmtp; Wed, 16 Jul 2008 18:00:04 +0200
+  id 0001D68D.487E1B04.000042E7
+In-Reply-To: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+References: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+Mime-Version: 1.0 (Apple Message framework v753.1)
+Content-Type: text/plain; charset=ISO-8859-1; delsp=yes; format=flowed
+Message-Id: <E112D7A6-89D1-40C8-913C-7DAF7303E7EC@qiao.in-berlin.de>
+Cc: jim-devel@lists.berlios.de, antirez@gmail.com, patthoyts@users.sf.net,
+        andrew@lunn.ch, openocd@duaneellis.com, uklein@klein-messgeraete.de
+Content-Transfer-Encoding: quoted-printable
+From: Clemens Hintze <ml-jim@qiao.in-berlin.de>
+Subject: Re: Change Jim Tcl license
+Date: Wed, 16 Jul 2008 17:58:14 +0200
+To: "=?ISO-8859-1?Q?\"=D8yvind_Harboe\"?=" <oyvind.harboe@zylin.com>
+X-Mailer: Apple Mail (2.753.1)
+X-Spam-Score:  (0.101) BAYES_50,RDNS_NONE
+X-Scanned-By: MIMEDefang_at_IN-Berlin_e.V. on 192.109.42.4
+X-Spam-Status: No, score=-2.6
+X-Spam-Score: -25
+X-Spam-Bar: --
+X-Spam-Flag: NO
+X-AntiAbuse: This header was added to track abuse, please include it with any abuse report
+X-AntiAbuse: Primary Hostname - cpanel5.proisp.no
+X-AntiAbuse: Original Domain - zylin.com
+X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12]
+X-AntiAbuse: Sender Address Domain - qiao.in-berlin.de
+X-Source: 
+X-Source-Args: 
+X-Source-Dir: 
+
+
+Am 16.07.2008 um 09:34 schrieb =D8yvind Harboe:
+
+> Hi all,
+
+Hi =D8yvind,
+
+(...)
+
+> If you have contributed to Jim Tcl, please reply to this email
+> that you agree that we can switch Jim Tcl to a FreeBSD license.
+>
+> Once I have a record of all contributors agreeing to switch
+> to a FreeBSD license, I'll update CVS.
+
+No problem with me: I agree to permit my contributions to the Jim =20
+project to be
+re-licensed under a BSD compatible license.
+
+(...)
+
+> Please let me know if any of the emails below are wrong(chi is
+> missing) or the list is not complete.
+
+After consultation with the voices in my head, I can ensure you, =20
+'chi' is also agreeing with the re-licensing, because its me too ;-)
+
+Thank you very much to revive Jim! :-)
+
+Best regards,
+Clemens Hintze.
+
+(...)=
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/duane.txt b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/duane.txt
new file mode 100755
index 0000000..56f962c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/duane.txt
@@ -0,0 +1,65 @@
+Delivered-To: oyvindharboe@gmail.com
+Received: by 10.100.7.20 with SMTP id 20cs93801ang;
+        Wed, 16 Jul 2008 03:40:02 -0700 (PDT)
+Received: by 10.142.148.10 with SMTP id v10mr5070849wfd.317.1216204801306;
+        Wed, 16 Jul 2008 03:40:01 -0700 (PDT)
+Return-Path: <openocd@duaneellis.com>
+Received: from cpanel5.proisp.no (cpanel5.proisp.no [209.85.100.29])
+        by mx.google.com with ESMTP id 27si9313433wff.3.2008.07.16.03.40.00;
+        Wed, 16 Jul 2008 03:40:01 -0700 (PDT)
+Received-SPF: neutral (google.com: 209.85.100.29 is neither permitted nor denied by best guess record for domain of openocd@duaneellis.com) client-ip=209.85.100.29;
+Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.100.29 is neither permitted nor denied by best guess record for domain of openocd@duaneellis.com) smtp.mail=openocd@duaneellis.com
+Received: from smtpout10-04.prod.mesa1.secureserver.net ([64.202.165.238]:48803 helo=smtpout10.prod.mesa1.secureserver.net)
+	by cpanel5.proisp.no with smtp (Exim 4.69)
+	(envelope-from <openocd@duaneellis.com>)
+	id 1KJ4QL-0005cq-GB
+	for oyvind.harboe@zylin.com; Wed, 16 Jul 2008 12:39:54 +0200
+Received: (qmail 2305 invoked from network); 16 Jul 2008 10:39:56 -0000
+Received: from unknown (68.37.53.103)
+  by smtpout10-04.prod.mesa1.secureserver.net (64.202.165.238) with ESMTP; 16 Jul 2008 10:39:55 -0000
+Message-ID: <487DCFEC.4010104@duaneellis.com>
+Date: Wed, 16 Jul 2008 06:39:40 -0400
+From: Duane Ellis <openocd@duaneellis.com>
+Reply-To: openocd@duaneellis.com
+User-Agent: Thunderbird 2.0.0.14 (Windows/20080421)
+MIME-Version: 1.0
+To: =?ISO-8859-1?Q?=D8yvind_Harboe?= <oyvind.harboe@zylin.com>
+CC: jim-devel@lists.berlios.de, antirez@gmail.com, 
+ patthoyts@users.sf.net, andrew@lunn.ch, uklein@klein-messgeraete.de, 
+ ml-jim@qiao.in-berlin.de
+Subject: Re: Change Jim Tcl license
+References: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+In-Reply-To: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 8bit
+X-Spam-Status: No, score=-2.6
+X-Spam-Score: -25
+X-Spam-Bar: --
+X-Spam-Flag: NO
+X-AntiAbuse: This header was added to track abuse, please include it with any abuse report
+X-AntiAbuse: Primary Hostname - cpanel5.proisp.no
+X-AntiAbuse: Original Domain - zylin.com
+X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12]
+X-AntiAbuse: Sender Address Domain - duaneellis.com
+X-Source: 
+X-Source-Args: 
+X-Source-Dir: 
+
+Oyvind Harboe wrote:
+> Short story:
+>
+> If you have contributed to Jim Tcl, please reply to this email
+> that you agree that we can switch Jim Tcl to a FreeBSD license.
+>
+> Once I have a record of all contributors agreeing to switch
+> to a FreeBSD license, I'll update CVS.
+>
+>   
+OK - from me
+
+    --Duane.
+
+-Duane.
+
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/oharboe.txt b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/oharboe.txt
new file mode 100755
index 0000000..af4a8e8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/oharboe.txt
@@ -0,0 +1,85 @@
+                                                                                                                                                                                                                                                            
+Received: by 10.100.7.20 with HTTP; Wed, 16 Jul 2008 10:12:05 -0700 (PDT)
+Message-ID: <c09652430807161012m178c5fbesef9a3f831e4d1dac@mail.gmail.com>
+Date: Wed, 16 Jul 2008 19:12:05 +0200
+From: "=?ISO-8859-1?Q?=D8yvind_Harboe?=" <oyvind.harboe@zylin.com>
+Sender: oyvindharboe@gmail.com
+To: jim-devel@lists.berlios.de
+Subject: Re: Change Jim Tcl license
+In-Reply-To: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=ISO-8859-1
+Content-Transfer-Encoding: quoted-printable
+Content-Disposition: inline
+References: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+Delivered-To: oyvindharboe@gmail.com
+X-Google-Sender-Auth: fc18e85532eee8f2
+
+For the record:
+
+I would like my contributions  to Jim Tcl to be under a FreeBSD license too=
+.
+
+On Wed, Jul 16, 2008 at 9:34 AM, =D8yvind Harboe <oyvind.harboe@zylin.com> =
+wrote:
+> Hi all,
+>
+> I'm currently the maintainer of Jim Tcl trying as best as I can
+> to fill Salvatore's shoes.
+>
+> Short story:
+>
+> If you have contributed to Jim Tcl, please reply to this email
+> that you agree that we can switch Jim Tcl to a FreeBSD license.
+>
+> Once I have a record of all contributors agreeing to switch
+> to a FreeBSD license, I'll update CVS.
+>
+> Long story:
+>
+> The current Jim Tcl license has a problem with GPL. If you
+> link GPL code and Jim Tcl, the result is no license at all.
+>
+> This prevents Jim Tcl from being used in GPL projects.
+>
+> Lately Jim Tcl has been used with OpenOCD, a GPL project,
+> and the license issue must be resolved one way or another.
+>
+> Upon conferring with Jonathan Larmour <jifl@ecoscentric.com>, who
+> has kindly helped out with his knowledge on the topic, I have
+> concluded that the best way to rectify this is to change the
+> Jim Tcl license to a FreeBSD license. See OpenOCD mailing
+> list for a discussion on this if you want details.
+>
+> http://www.fsf.org/licensing/licenses/index_html#FreeBSD
+>
+> As far as I can determine, below is the complete list of contributors.
+>
+>
+> antirez - Salvatore Sanfilippo <antirez@gmail.com>
+> patthoyts - ?? Pat Thoyts <patthoyts@users.sf.net>
+> oharboe - =D8yvind Harboe - soyvind.harboe@zylin.com
+> chi - ??
+> Andrew Lunn <andrew@lunn.ch>
+> Duane Ellis <openocd@duaneellis.com>
+> Uwe Klein <uklein@klein-messgeraete.de>
+> Clemens Hintze ml-jim@qiao.in-berlin.de
+>
+> Please let me know if any of the emails below are wrong(chi is
+> missing) or the list is not complete.
+>
+>
+> --
+> =D8yvind Harboe
+> http://www.zylin.com/zy1000.html
+> ARM7 ARM9 XScale Cortex
+> JTAG debugger and flash programmer
+>
+
+
+
+--=20
+=D8yvind Harboe
+http://www.zylin.com/zy1000.html
+ARM7 ARM9 XScale Cortex
+JTAG debugger and flash programmer
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/pat.txt b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/pat.txt
new file mode 100755
index 0000000..988a599
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/pat.txt
@@ -0,0 +1,84 @@
+                                                                                                                                                                                                                                                             
+Delivered-To: oyvindharboe@gmail.com
+Received: by 10.100.7.20 with SMTP id 20cs108097ang;
+        Wed, 16 Jul 2008 07:49:02 -0700 (PDT)
+Received: by 10.142.232.20 with SMTP id e20mr80874wfh.138.1216219741865;
+        Wed, 16 Jul 2008 07:49:01 -0700 (PDT)
+Return-Path: <patthoyts@users.sourceforge.net>
+Received: from cpanel5.proisp.no (cpanel5.proisp.no [209.85.100.29])
+        by mx.google.com with ESMTP id 30si10551683wff.18.2008.07.16.07.49.01;
+        Wed, 16 Jul 2008 07:49:01 -0700 (PDT)
+Received-SPF: neutral (google.com: 209.85.100.29 is neither permitted nor denied by best guess record for domain of patthoyts@users.sourceforge.net) client-ip=209.85.100.29;
+Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.100.29 is neither permitted nor denied by best guess record for domain of patthoyts@users.sourceforge.net) smtp.mail=patthoyts@users.sourceforge.net
+Received: from smtp-out4.blueyonder.co.uk ([195.188.213.7]:38596)
+	by cpanel5.proisp.no with esmtp (Exim 4.69)
+	(envelope-from <patthoyts@users.sourceforge.net>)
+	id 1KJ8JH-0000Vd-OT
+	for oyvind.harboe@zylin.com; Wed, 16 Jul 2008 16:48:52 +0200
+Received: from [172.23.170.141] (helo=anti-virus02-08)
+	by smtp-out4.blueyonder.co.uk with smtp (Exim 4.52)
+	id 1KJ8JO-0007r0-Cy; Wed, 16 Jul 2008 15:48:58 +0100
+Received: from [77.102.249.21] (helo=badger.patthoyts.tk)
+	by asmtp-out4.blueyonder.co.uk with esmtp (Exim 4.52)
+	id 1KJ8J6-0000gY-VY; Wed, 16 Jul 2008 15:48:41 +0100
+Received: by badger.patthoyts.tk (Postfix, from userid 1000)
+	id 810535184F; Wed, 16 Jul 2008 15:48:40 +0100 (BST)
+Sender: pat@badger.patthoyts.tk
+To: =?iso-8859-1?q?=D8yvind_Harboe?= <oyvind.harboe@zylin.com>
+Cc: jim-devel@lists.berlios.de
+Subject: Re: Change Jim Tcl license
+References: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+X-Face:  .`d#euqz@6H{";Ysmx2IVe_7M3vA+2w1X[QLk?ZO&QRauXQL{*L'$3getx}9+zK.-KWDx3.
+ qrlR)76MFb`6bgoGvLpLtcQKB=X~;*<JKLtwLBM(IA'?rVjs1*tq\VHn?WMNsB,3XXWF@5.)4SRFa+
+ '?a?.s#@hl7CiTo'F"O!fvbL0
+X-Url: http://www.patthoyts.tk/
+From: Pat Thoyts <patthoyts@users.sourceforge.net>
+Date: 16 Jul 2008 15:48:39 +0100
+In-Reply-To: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+Message-ID: <87fxq97um0.fsf@badger.patthoyts.tk>
+Lines: 27
+User-Agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.3
+MIME-Version: 1.0
+Content-Type: text/plain; charset=iso-8859-1
+Content-Transfer-Encoding: quoted-printable
+X-Spam-Status: No, score=-2.6
+X-Spam-Score: -25
+X-Spam-Bar: --
+X-Spam-Flag: NO
+X-AntiAbuse: This header was added to track abuse, please include it with any abuse report
+X-AntiAbuse: Primary Hostname - cpanel5.proisp.no
+X-AntiAbuse: Original Domain - zylin.com
+X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12]
+X-AntiAbuse: Sender Address Domain - users.sourceforge.net
+X-Source: 
+X-Source-Args: 
+X-Source-Dir: 
+
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+"=D8yvind Harboe" <oyvind.harboe@zylin.com> writes:
+
+>If you have contributed to Jim Tcl, please reply to this email
+>that you agree that we can switch Jim Tcl to a FreeBSD license.
+>
+>Once I have a record of all contributors agreeing to switch
+>to a FreeBSD license, I'll update CVS.
+
+I hereby agree to permit my contributions to the Jim project to be
+re-licensed under a BSD compatible license.
+
+- --=20
+Pat Thoyts                            http://www.patthoyts.tk/
+PGP fingerprint 2C 6E 98 07 2C 59 C8 97  10 CE 11 E6 04 E0 B9 DD
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.8 (SunOS)
+Comment: Processed by Mailcrypt 3.5.8 <http://mailcrypt.sourceforge.net/>
+
+iQCVAwUBSH4KO2B90JXwhOSJAQKtqQP9ERwSXpbP69l4JSrunG29Rhu2F3r83zu3
+GAKpFu4HwkVnIStLQ4o3tsqG9uKrVDbRMa187eSwHmlXXIMwDlkCKNsDFxvdLDZz
+kbTYDibspYSw6CjwOUSTXifK9P7ho4Q7PtsRnJ8T1IMlGJlwg39Rxd+mpEO/if3q
+ExIwM1aBbAs=3D
+=3Du8si
+-----END PGP SIGNATURE-----
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/salvatore.txt b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/salvatore.txt
new file mode 100755
index 0000000..5bbf973
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/salvatore.txt
@@ -0,0 +1,88 @@
+                                                                                                                                                                                                                                                             
+Delivered-To: oyvindharboe@gmail.com
+Received: by 10.100.7.20 with SMTP id 20cs113143ang;
+        Wed, 16 Jul 2008 08:41:11 -0700 (PDT)
+Received: by 10.142.140.15 with SMTP id n15mr127048wfd.84.1216222870242;
+        Wed, 16 Jul 2008 08:41:10 -0700 (PDT)
+Return-Path: <antirez@gmail.com>
+Received: from cpanel5.proisp.no (cpanel5.proisp.no [209.85.100.29])
+        by mx.google.com with ESMTP id 29si7397124wfg.0.2008.07.16.08.41.08;
+        Wed, 16 Jul 2008 08:41:10 -0700 (PDT)
+Received-SPF: neutral (google.com: 209.85.100.29 is neither permitted nor denied by domain of antirez@gmail.com) client-ip=209.85.100.29;
+Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.100.29 is neither permitted nor denied by domain of antirez@gmail.com) smtp.mail=antirez@gmail.com; dkim=pass (test mode) header.i=@gmail.com
+Received: from fg-out-1718.google.com ([72.14.220.155]:16058)
+	by cpanel5.proisp.no with esmtp (Exim 4.69)
+	(envelope-from <antirez@gmail.com>)
+	id 1KJ97g-0004yX-1W
+	for oyvind.harboe@zylin.com; Wed, 16 Jul 2008 17:40:59 +0200
+Received: by fg-out-1718.google.com with SMTP id l27so3985052fgb.19
+        for <oyvind.harboe@zylin.com>; Wed, 16 Jul 2008 08:40:59 -0700 (PDT)
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+        d=gmail.com; s=gamma;
+        h=domainkey-signature:received:received:message-id:date:from:to
+         :subject:cc:in-reply-to:mime-version:content-type
+         :content-transfer-encoding:content-disposition:references;
+        bh=/aWDZQfgMBPqomYWZ2AUKOhhGMju+bwnSBbKL8MBonA=;
+        b=i0P3OKDopn/vHfa5ZrUvBjuPBnj43GMw8FOXKjxM/IfvywJParYqBS2Vmlw8RTndFg
+         J5wwxXf5056cZu/GbKbj8xLfylFfSInVaO7OnDutA3CeX1iU35my1DU6l9W6ILkLiT1P
+         Azi3L27rFQrzau/s53VU/UVELc3WckWdu1a1k=
+DomainKey-Signature: a=rsa-sha1; c=nofws;
+        d=gmail.com; s=gamma;
+        h=message-id:date:from:to:subject:cc:in-reply-to:mime-version
+         :content-type:content-transfer-encoding:content-disposition
+         :references;
+        b=ww2MIz9svJttgS8mTRBhEX8Isveugn2hl3sMcgh0hZ1+ln8YbiysxYxZkdddewWm02
+         WXsWgSgwy7MIPAUK1tNjzgkZ2l789SdrAtBCmqmRWJJI+ESTqbHMz8cqW+QRVP/A9Dfm
+         8+AR85DHi7SOB0mdHtq9fsavZReUdaSIgy6F4=
+Received: by 10.86.80.5 with SMTP id d5mr2284433fgb.19.1216222858224;
+        Wed, 16 Jul 2008 08:40:58 -0700 (PDT)
+Received: by 10.86.50.18 with HTTP; Wed, 16 Jul 2008 08:40:58 -0700 (PDT)
+Message-ID: <c6114db60807160840n62186f46w7cdc1bbec91186ca@mail.gmail.com>
+Date: Wed, 16 Jul 2008 17:40:58 +0200
+From: "Salvatore Sanfilippo" <antirez@gmail.com>
+To: "=?ISO-8859-1?Q?=D8yvind_Harboe?=" <oyvind.harboe@zylin.com>
+Subject: Re: Change Jim Tcl license
+Cc: jim-devel@lists.berlios.de, patthoyts@users.sf.net, andrew@lunn.ch, 
+	openocd@duaneellis.com, uklein@klein-messgeraete.de, 
+	ml-jim@qiao.in-berlin.de
+In-Reply-To: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=ISO-8859-1
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline
+References: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+X-Spam-Status: No, score=-2.6
+X-Spam-Score: -25
+X-Spam-Bar: --
+X-Spam-Flag: NO
+X-AntiAbuse: This header was added to track abuse, please include it with any abuse report
+X-AntiAbuse: Primary Hostname - cpanel5.proisp.no
+X-AntiAbuse: Original Domain - zylin.com
+X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12]
+X-AntiAbuse: Sender Address Domain - gmail.com
+X-Source: 
+X-Source-Args: 
+X-Source-Dir: 
+
+I agree to permit my contributions to the Jim project to be
+re-licensed under a BSD compatible license.
+
+Since I'm currently the top contributor if it's safer from
+the legal point of view I can also put a tar.gz of the current
+Jim source code with a BSD "LICENSE" file on my website.
+
+Otherwise I can sign by hand a letter and send a digitalized
+image here.
+
+Ciao,
+Salvatore
+
+-- 
+Salvatore 'antirez' Sanfilippo
+http://antirez.com
+
+Organizations which design systems are constrained to produce designs
+which are copies of the communication structures of these
+organizations.
+
+Conway's Law
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/uwe.txt b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/uwe.txt
new file mode 100755
index 0000000..035ca32
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/freebsd/uwe.txt
@@ -0,0 +1,73 @@
+Delivered-To: oyvindharboe@gmail.com
+Received: by 10.100.7.20 with SMTP id 20cs89014ang;
+        Wed, 16 Jul 2008 01:58:32 -0700 (PDT)
+Received: by 10.142.125.9 with SMTP id x9mr5028534wfc.123.1216198711465;
+        Wed, 16 Jul 2008 01:58:31 -0700 (PDT)
+Return-Path: <wiederling@googlemail.com>
+Received: from cpanel5.proisp.no (cpanel5.proisp.no [209.85.100.29])
+        by mx.google.com with ESMTP id 30si6756166wfa.10.2008.07.16.01.58.29;
+        Wed, 16 Jul 2008 01:58:31 -0700 (PDT)
+Received-SPF: neutral (google.com: 209.85.100.29 is neither permitted nor denied by domain of wiederling@googlemail.com) client-ip=209.85.100.29;
+Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.100.29 is neither permitted nor denied by domain of wiederling@googlemail.com) smtp.mail=wiederling@googlemail.com; dkim=pass (test mode) header.i=@googlemail.com
+Received: from wr-out-0506.google.com ([64.233.184.233]:51225)
+	by cpanel5.proisp.no with esmtp (Exim 4.69)
+	(envelope-from <wiederling@googlemail.com>)
+	id 1KJ2q7-00057b-IR
+	for oyvind.harboe@zylin.com; Wed, 16 Jul 2008 10:58:24 +0200
+Received: by wr-out-0506.google.com with SMTP id c8so2209154wra.27
+        for <oyvind.harboe@zylin.com>; Wed, 16 Jul 2008 01:58:25 -0700 (PDT)
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+        d=googlemail.com; s=gamma;
+        h=domainkey-signature:received:received:message-id:date:from:to
+         :subject:cc:in-reply-to:mime-version:content-type
+         :content-transfer-encoding:content-disposition:references;
+        bh=VxcH0g2H5iLUo27gqJiqrlY4uVbN1NFE4skyMKqysPM=;
+        b=JPK53r6LQ6GqBCG1kfVYyTPuPuVhlBrbzQ8oSBwpwuwwB7t3CSv+c75jRjb/n3y8mi
+         gN1r6noZucK9ZpRZiHxYZpHVhYFcWbZ+ZXM75H2qIFfl4YDzfgg/Ub7CzoR2LskuBsRk
+         DMH2LnyAYf+Om2YAKJdkoMnGbPMDMFSrNHeIc=
+DomainKey-Signature: a=rsa-sha1; c=nofws;
+        d=googlemail.com; s=gamma;
+        h=message-id:date:from:to:subject:cc:in-reply-to:mime-version
+         :content-type:content-transfer-encoding:content-disposition
+         :references;
+        b=VAGlxpb1YGbex/eaS0tQgWvH/lWHzgD5R/rxjshVSwZJOStwqMA1F5jNQgybQFIn1F
+         zWoiAV81uWMzBEGYab7SGsStWLxovcBSgi9NL+XqwAkhBdrWjgFPvpBHn5PvgOOXEhGH
+         EGhjrY8qp2LSxhFcW3/DvgObhBBKtY1J+qzvA=
+Received: by 10.90.115.17 with SMTP id n17mr1231758agc.90.1216198705850;
+        Wed, 16 Jul 2008 01:58:25 -0700 (PDT)
+Received: by 10.90.105.18 with HTTP; Wed, 16 Jul 2008 01:58:25 -0700 (PDT)
+Message-ID: <1af31b6f0807160158o295303adh43abdd34fbe8ec99@mail.gmail.com>
+Date: Wed, 16 Jul 2008 10:58:25 +0200
+From: "Uwe Klein" <wiederling@googlemail.com>
+To: "=?ISO-8859-1?Q?=D8yvind_Harboe?=" <oyvind.harboe@zylin.com>
+Subject: Re: [Jim-devel] Change Jim Tcl license
+Cc: jim-devel@lists.berlios.de, patthoyts@users.sf.net, andrew@lunn.ch, 
+	uklein@klein-messgeraete.de, antirez@gmail.com, 
+	openocd@duaneellis.com, ml-jim@qiao.in-berlin.de
+In-Reply-To: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=ISO-8859-1
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline
+References: <c09652430807160034pd4a5b0q18f69a219827e111@mail.gmail.com>
+X-Spam-Status: No, score=-2.6
+X-Spam-Score: -25
+X-Spam-Bar: --
+X-Spam-Flag: NO
+X-AntiAbuse: This header was added to track abuse, please include it with any abuse report
+X-AntiAbuse: Primary Hostname - cpanel5.proisp.no
+X-AntiAbuse: Original Domain - zylin.com
+X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12]
+X-AntiAbuse: Sender Address Domain - googlemail.com
+X-Source: 
+X-Source-Args: 
+X-Source-Dir: 
+
+>  If you have contributed to Jim Tcl, please reply to this email
+>  that you agree that we can switch Jim Tcl to a FreeBSD license.
+
+For Uwe Klein <uklein@klein-messgeraete.de>
+
+This is OK with me.
+
+uwe
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/glob.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/glob.tcl
new file mode 100755
index 0000000..cd94d8d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/glob.tcl
@@ -0,0 +1,129 @@
+# Implements a Tcl-compatible glob command based on readdir
+#
+# (c) 2008 Steve Bennett <steveb@workware.net.au>
+#
+# See LICENCE in this directory for licensing.
+
+package require readdir
+
+# Implements the Tcl glob command
+#
+# Usage: glob ?-nocomplain? pattern ...
+#
+# Patterns use 'string match' (glob) pattern matching for each
+# directory level, plus support for braced alternations.
+#
+# e.g. glob "te[a-e]*/*.{c,tcl}"
+#
+# Note: files starting with . will only be returned if matching component
+#       of the pattern starts with .
+proc glob {args} {
+
+	# If $dir is a directory, return a list of all entries
+	# it contains which match $pattern
+	#
+	local proc glob.readdir_pattern {dir pattern} {
+		set result {}
+
+		# readdir doesn't return . or .., so simulate it here
+		if {$pattern in {. ..}} {
+			return $pattern
+		}
+
+		# If the pattern isn't actually a pattern...
+		if {[string match {*[*?]*} $pattern]} {
+			# Use -nocomplain here to return nothing if $dir is not a directory
+			set files [readdir -nocomplain $dir]
+		} elseif {[file isdir $dir] && [file exists $dir/$pattern]} {
+			set files [list $pattern]
+		} else {
+			set files ""
+		}
+
+		foreach name $files {
+			if {[string match $pattern $name]} {
+				# Only include entries starting with . if the pattern starts with .
+				if {[string index $name 0] eq "." && [string index $pattern 0] ne "."} {
+					continue
+				}
+				lappend result $name
+			}
+		}
+
+		return $result
+	}
+
+	# If the pattern contains a braced expression, return a list of
+	# patterns with the braces expanded. {c,b}* => c* b*
+	# Otherwise just return the pattern
+	# Note: Only supports one braced expression. i.e. not {a,b}*{c,d}*
+	proc glob.expandbraces {pattern} {
+		# Avoid regexp for dependency reasons.
+		# XXX: Doesn't handle backslashed braces
+		if {[set fb [string first "\{" $pattern]] < 0} {
+			return $pattern
+		}
+		if {[set nb [string first "\}" $pattern $fb]] < 0} {
+			return $pattern
+		}
+		set before [string range $pattern 0 $fb-1]
+		set braced [string range $pattern $fb+1 $nb-1]
+		set after [string range $pattern $nb+1 end]
+
+		lmap part [split $braced ,] {
+			set pat $before$part$after
+		}
+	}
+
+	# Core glob implementation. Returns a list of files/directories matching the pattern
+	proc glob.glob {pattern} {
+		set dir [file dirname $pattern]
+		if {$dir eq $pattern} {
+			# At the top level
+			return [list $dir]
+		}
+
+		# Recursively expand the parent directory
+		set dirlist [glob.glob $dir]
+		set pattern [file tail $pattern]
+
+		# Now collect the fiels/directories
+		set result {}
+		foreach dir $dirlist {
+			set globdir $dir
+			if {[string match "*/" $dir]} {
+				set sep ""
+			} elseif {$dir eq "."} {
+				set globdir ""
+				set sep ""
+			} else {
+				set sep /
+			}
+			foreach pat [glob.expandbraces $pattern] {
+				foreach name [glob.readdir_pattern $dir $pat] {
+					lappend result $globdir$sep$name
+				}
+			}
+		}
+		return $result
+	}
+
+	# Start of main glob
+	set nocomplain 0
+
+	if {[lindex $args 0] eq "-nocomplain"} {
+		set nocomplain 1
+		set args [lrange $args 1 end]
+	}
+
+	set result {}
+	foreach pattern $args {
+		lappend result {*}[glob.glob $pattern]
+	}
+
+	if {$nocomplain == 0 && [llength $result] == 0} {
+		return -code error "no files matched glob patterns"
+	}
+
+	return $result
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/initjimsh.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/initjimsh.tcl
new file mode 100755
index 0000000..a764f3a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/initjimsh.tcl
@@ -0,0 +1,27 @@
+# This pseudo-package is loaded from jimsh to add additional
+# paths to $auto_path and to source ~/.jimrc
+
+proc _jimsh_init {} {
+	rename _jimsh_init {}
+
+	# Add to the standard auto_path
+	lappend p {*}[split [env JIMLIB {}] $::tcl_platform(pathSeparator)]
+	lappend p {*}$::auto_path
+	lappend p [file dirname [info nameofexecutable]]
+	set ::auto_path $p
+
+	if {$::tcl_interactive && [env HOME {}] ne ""} {
+		foreach src {.jimrc jimrc.tcl} {
+			if {[file exists [env HOME]/$src]} {
+				uplevel #0 source [env HOME]/$src
+				break
+			}
+		}
+	}
+}
+
+if {$tcl_platform(platform) eq "windows"} {
+	set jim_argv0 [string map {\\ /} $jim_argv0]
+}
+
+_jimsh_init
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-aio.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-aio.c
new file mode 100755
index 0000000..710a47d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-aio.c
@@ -0,0 +1,1353 @@
+
+/* Jim - A small embeddable Tcl interpreter
+ *
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
+ * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
+ * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
+ * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
+ * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
+ * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ **/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+
+#if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#else
+#define JIM_ANSIC
+#endif
+
+#include "jim-eventloop.h"
+#include "jim-subcmd.h"
+
+#define AIO_CMD_LEN 32      /* e.g. aio.handleXXXXXX */
+#define AIO_BUF_LEN 256     /* Can keep this small and rely on stdio buffering */
+
+#define AIO_KEEPOPEN 1
+
+#if defined(JIM_IPV6)
+#define IPV6 1
+#else
+#define IPV6 0
+#ifndef PF_INET6
+#define PF_INET6 0
+#endif
+#endif
+
+#if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP)
+union sockaddr_any {
+    struct sockaddr sa;
+    struct sockaddr_in sin;
+#if IPV6
+    struct sockaddr_in6 sin6;
+#endif
+};
+
+#ifndef HAVE_INET_NTOP
+const char *inet_ntop(int af, const void *src, char *dst, int size)
+{
+    if (af != PF_INET) {
+        return NULL;
+    }
+    snprintf(dst, size, "%s", inet_ntoa(((struct sockaddr_in *)src)->sin_addr));
+    return dst;
+}
+#endif
+#endif /* JIM_BOOTSTRAP */
+
+typedef struct AioFile
+{
+    FILE *fp;
+    Jim_Obj *filename;
+    int type;
+    int OpenFlags;              /* AIO_KEEPOPEN? keep FILE* */
+    int fd;
+#ifdef O_NDELAY
+    int flags;
+#endif
+    Jim_Obj *rEvent;
+    Jim_Obj *wEvent;
+    Jim_Obj *eEvent;
+    int addr_family;
+} AioFile;
+
+static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+static int JimMakeChannel(Jim_Interp *interp, FILE *fh, int fd, Jim_Obj *filename,
+    const char *hdlfmt, int family, const char *mode);
+
+#if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP)
+static int JimParseIPv6Address(Jim_Interp *interp, const char *hostport, union sockaddr_any *sa, int *salen)
+{
+#if IPV6
+    /*
+     * An IPv6 addr/port looks like:
+     *   [::1]
+     *   [::1]:2000
+     *   [fe80::223:6cff:fe95:bdc0%en1]:2000
+     *   [::]:2000
+     *   2000
+     *
+     *   Note that the "any" address is ::, which is the same as when no address is specified.
+     */
+     char *sthost = NULL;
+     const char *stport;
+     int ret = JIM_OK;
+     struct addrinfo req;
+     struct addrinfo *ai;
+
+    stport = strrchr(hostport, ':');
+    if (!stport) {
+        /* No : so, the whole thing is the port */
+        stport = hostport;
+        hostport = "::";
+        sthost = Jim_StrDup(hostport);
+    }
+    else {
+        stport++;
+    }
+
+    if (*hostport == '[') {
+        /* This is a numeric ipv6 address */
+        char *pt = strchr(++hostport, ']');
+        if (pt) {
+            sthost = Jim_StrDupLen(hostport, pt - hostport);
+        }
+    }
+
+    if (!sthost) {
+        sthost = Jim_StrDupLen(hostport, stport - hostport - 1);
+    }
+
+    memset(&req, '\0', sizeof(req));
+    req.ai_family = PF_INET6;
+
+    if (getaddrinfo(sthost, NULL, &req, &ai)) {
+        Jim_SetResultFormatted(interp, "Not a valid address: %s", hostport);
+        ret = JIM_ERR;
+    }
+    else {
+        memcpy(&sa->sin, ai->ai_addr, ai->ai_addrlen);
+        *salen = ai->ai_addrlen;
+
+        sa->sin.sin_port = htons(atoi(stport));
+
+        freeaddrinfo(ai);
+    }
+    Jim_Free(sthost);
+
+    return ret;
+#else
+    Jim_SetResultString(interp, "ipv6 not supported", -1);
+    return JIM_ERR;
+#endif
+}
+
+static int JimParseIpAddress(Jim_Interp *interp, const char *hostport, union sockaddr_any *sa, int *salen)
+{
+    /* An IPv4 addr/port looks like:
+     *   192.168.1.5
+     *   192.168.1.5:2000
+     *   2000
+     *
+     * If the address is missing, INADDR_ANY is used.
+     * If the port is missing, 0 is used (only useful for server sockets).
+     */
+    char *sthost = NULL;
+    const char *stport;
+    int ret = JIM_OK;
+
+    stport = strrchr(hostport, ':');
+    if (!stport) {
+        /* No : so, the whole thing is the port */
+        stport = hostport;
+        sthost = Jim_StrDup("0.0.0.0");
+    }
+    else {
+        sthost = Jim_StrDupLen(hostport, stport - hostport);
+        stport++;
+    }
+
+    {
+#ifdef HAVE_GETADDRINFO
+        struct addrinfo req;
+        struct addrinfo *ai;
+        memset(&req, '\0', sizeof(req));
+        req.ai_family = PF_INET;
+
+        if (getaddrinfo(sthost, NULL, &req, &ai)) {
+            ret = JIM_ERR;
+        }
+        else {
+            memcpy(&sa->sin, ai->ai_addr, ai->ai_addrlen);
+            *salen = ai->ai_addrlen;
+            freeaddrinfo(ai);
+        }
+#else
+        struct hostent *he;
+
+        ret = JIM_ERR;
+
+        if ((he = gethostbyname(sthost)) != NULL) {
+            if (he->h_length == sizeof(sa->sin.sin_addr)) {
+                *salen = sizeof(sa->sin);
+                sa->sin.sin_family= he->h_addrtype;
+                memcpy(&sa->sin.sin_addr, he->h_addr, he->h_length); /* set address */
+                ret = JIM_OK;
+            }
+        }
+#endif
+
+        sa->sin.sin_port = htons(atoi(stport));
+    }
+    Jim_Free(sthost);
+
+    if (ret != JIM_OK) {
+        Jim_SetResultFormatted(interp, "Not a valid address: %s", hostport);
+    }
+
+    return ret;
+}
+
+#ifdef HAVE_SYS_UN_H
+static int JimParseDomainAddress(Jim_Interp *interp, const char *path, struct sockaddr_un *sa)
+{
+    sa->sun_family = PF_UNIX;
+    snprintf(sa->sun_path, sizeof(sa->sun_path), "%s", path);
+
+    return JIM_OK;
+}
+#endif
+#endif /* JIM_BOOTSTRAP */
+
+static void JimAioSetError(Jim_Interp *interp, Jim_Obj *name)
+{
+    if (name) {
+        Jim_SetResultFormatted(interp, "%#s: %s", name, strerror(errno));
+    }
+    else {
+        Jim_SetResultString(interp, strerror(errno), -1);
+    }
+}
+
+static void JimAioDelProc(Jim_Interp *interp, void *privData)
+{
+    AioFile *af = privData;
+
+    JIM_NOTUSED(interp);
+
+    Jim_DecrRefCount(interp, af->filename);
+
+    if (!(af->OpenFlags & AIO_KEEPOPEN)) {
+        fclose(af->fp);
+    }
+#ifdef jim_ext_eventloop
+    /* remove existing EventHandlers */
+    if (af->rEvent) {
+        Jim_DeleteFileHandler(interp, af->fp);
+    }
+    if (af->wEvent) {
+        Jim_DeleteFileHandler(interp, af->fp);
+    }
+    if (af->eEvent) {
+        Jim_DeleteFileHandler(interp, af->fp);
+    }
+#endif
+    Jim_Free(af);
+}
+
+static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    char buf[AIO_BUF_LEN];
+    Jim_Obj *objPtr;
+    int nonewline = 0;
+    int neededLen = -1;         /* -1 is "read as much as possible" */
+
+    if (argc && Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) {
+        nonewline = 1;
+        argv++;
+        argc--;
+    }
+    if (argc == 1) {
+        jim_wide wideValue;
+
+        if (Jim_GetWide(interp, argv[0], &wideValue) != JIM_OK)
+            return JIM_ERR;
+        if (wideValue < 0) {
+            Jim_SetResultString(interp, "invalid parameter: negative len", -1);
+            return JIM_ERR;
+        }
+        neededLen = (int)wideValue;
+    }
+    else if (argc) {
+        return -1;
+    }
+    objPtr = Jim_NewStringObj(interp, NULL, 0);
+    while (neededLen != 0) {
+        int retval;
+        int readlen;
+
+        if (neededLen == -1) {
+            readlen = AIO_BUF_LEN;
+        }
+        else {
+            readlen = (neededLen > AIO_BUF_LEN ? AIO_BUF_LEN : neededLen);
+        }
+        retval = fread(buf, 1, readlen, af->fp);
+        if (retval > 0) {
+            Jim_AppendString(interp, objPtr, buf, retval);
+            if (neededLen != -1) {
+                neededLen -= retval;
+            }
+        }
+        if (retval != readlen)
+            break;
+    }
+    /* Check for error conditions */
+    if (ferror(af->fp)) {
+        clearerr(af->fp);
+        /* eof and EAGAIN are not error conditions */
+        if (!feof(af->fp) && errno != EAGAIN) {
+            /* I/O error */
+            Jim_FreeNewObj(interp, objPtr);
+            JimAioSetError(interp, af->filename);
+            return JIM_ERR;
+        }
+    }
+    if (nonewline) {
+        int len;
+        const char *s = Jim_GetString(objPtr, &len);
+
+        if (len > 0 && s[len - 1] == '\n') {
+            objPtr->length--;
+            objPtr->bytes[objPtr->length] = '\0';
+        }
+    }
+    Jim_SetResult(interp, objPtr);
+    return JIM_OK;
+}
+
+static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    long count = 0;
+    long maxlen = LONG_MAX;
+    FILE *outfh = Jim_AioFilehandle(interp, argv[0]);
+
+    if (outfh == NULL) {
+        return JIM_ERR;
+    }
+
+    if (argc == 2) {
+        if (Jim_GetLong(interp, argv[1], &maxlen) != JIM_OK) {
+            return JIM_ERR;
+        }
+    }
+
+    while (count < maxlen) {
+        int ch = fgetc(af->fp);
+
+        if (ch == EOF || fputc(ch, outfh) == EOF) {
+            break;
+        }
+        count++;
+    }
+
+    if (ferror(af->fp)) {
+        Jim_SetResultFormatted(interp, "error while reading: %s", strerror(errno));
+        clearerr(af->fp);
+        return JIM_ERR;
+    }
+
+    if (ferror(outfh)) {
+        Jim_SetResultFormatted(interp, "error while writing: %s", strerror(errno));
+        clearerr(outfh);
+        return JIM_ERR;
+    }
+
+    Jim_SetResultInt(interp, count);
+
+    return JIM_OK;
+}
+
+static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    char buf[AIO_BUF_LEN];
+    Jim_Obj *objPtr;
+    int len;
+
+    errno = 0;
+
+    objPtr = Jim_NewStringObj(interp, NULL, 0);
+    while (1) {
+        buf[AIO_BUF_LEN - 1] = '_';
+        if (fgets(buf, AIO_BUF_LEN, af->fp) == NULL)
+            break;
+
+        if (buf[AIO_BUF_LEN - 1] == '\0' && buf[AIO_BUF_LEN - 2] != '\n') {
+            Jim_AppendString(interp, objPtr, buf, AIO_BUF_LEN - 1);
+        }
+        else {
+            len = strlen(buf);
+
+            if (len && (buf[len - 1] == '\n')) {
+                /* strip "\n" */
+                len--;
+            }
+
+            Jim_AppendString(interp, objPtr, buf, len);
+            break;
+        }
+    }
+    if (ferror(af->fp) && errno != EAGAIN && errno != EINTR) {
+        /* I/O error */
+        Jim_FreeNewObj(interp, objPtr);
+        JimAioSetError(interp, af->filename);
+        clearerr(af->fp);
+        return JIM_ERR;
+    }
+
+    if (argc) {
+        if (Jim_SetVariable(interp, argv[0], objPtr) != JIM_OK) {
+            Jim_FreeNewObj(interp, objPtr);
+            return JIM_ERR;
+        }
+
+        len = Jim_Length(objPtr);
+
+        if (len == 0 && feof(af->fp)) {
+            /* On EOF returns -1 if varName was specified */
+            len = -1;
+        }
+        Jim_SetResultInt(interp, len);
+    }
+    else {
+        Jim_SetResult(interp, objPtr);
+    }
+    return JIM_OK;
+}
+
+static int aio_cmd_puts(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    int wlen;
+    const char *wdata;
+    Jim_Obj *strObj;
+
+    if (argc == 2) {
+        if (!Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) {
+            return -1;
+        }
+        strObj = argv[1];
+    }
+    else {
+        strObj = argv[0];
+    }
+
+    wdata = Jim_GetString(strObj, &wlen);
+    if (fwrite(wdata, 1, wlen, af->fp) == (unsigned)wlen) {
+        if (argc == 2 || putc('\n', af->fp) != EOF) {
+            return JIM_OK;
+        }
+    }
+    JimAioSetError(interp, af->filename);
+    return JIM_ERR;
+}
+
+#if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP)
+static int aio_cmd_recvfrom(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    char *buf;
+    union sockaddr_any sa;
+    long len;
+    socklen_t salen = sizeof(sa);
+    int rlen;
+
+    if (Jim_GetLong(interp, argv[0], &len) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    buf = Jim_Alloc(len + 1);
+
+    rlen = recvfrom(fileno(af->fp), buf, len, 0, &sa.sa, &salen);
+    if (rlen < 0) {
+        Jim_Free(buf);
+        JimAioSetError(interp, NULL);
+        return JIM_ERR;
+    }
+    buf[rlen] = 0;
+    Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, rlen));
+
+    if (argc > 1) {
+        /* INET6_ADDRSTRLEN is 46. Add some for [] and port */
+        char addrbuf[60];
+
+#if IPV6
+        if (sa.sa.sa_family == PF_INET6) {
+            addrbuf[0] = '[';
+            /* Allow 9 for []:65535\0 */
+            inet_ntop(sa.sa.sa_family, &sa.sin6.sin6_addr, addrbuf + 1, sizeof(addrbuf) - 9);
+            snprintf(addrbuf + strlen(addrbuf), 8, "]:%d", ntohs(sa.sin.sin_port));
+        }
+        else
+#endif
+        {
+            /* Allow 7 for :65535\0 */
+            inet_ntop(sa.sa.sa_family, &sa.sin.sin_addr, addrbuf, sizeof(addrbuf) - 7);
+            snprintf(addrbuf + strlen(addrbuf), 7, ":%d", ntohs(sa.sin.sin_port));
+        }
+
+        if (Jim_SetVariable(interp, argv[1], Jim_NewStringObj(interp, addrbuf, -1)) != JIM_OK) {
+            return JIM_ERR;
+        }
+    }
+
+    return JIM_OK;
+}
+
+
+static int aio_cmd_sendto(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    int wlen;
+    int len;
+    const char *wdata;
+    union sockaddr_any sa;
+    const char *addr = Jim_String(argv[1]);
+    int salen;
+
+    if (IPV6 && af->addr_family == PF_INET6) {
+        if (JimParseIPv6Address(interp, addr, &sa, &salen) != JIM_OK) {
+            return JIM_ERR;
+        }
+    }
+    else if (JimParseIpAddress(interp, addr, &sa, &salen) != JIM_OK) {
+        return JIM_ERR;
+    }
+    wdata = Jim_GetString(argv[0], &wlen);
+
+    /* Note that we don't validate the socket type. Rely on sendto() failing if appropriate */
+    len = sendto(fileno(af->fp), wdata, wlen, 0, &sa.sa, salen);
+    if (len < 0) {
+        JimAioSetError(interp, NULL);
+        return JIM_ERR;
+    }
+    Jim_SetResultInt(interp, len);
+    return JIM_OK;
+}
+
+static int aio_cmd_accept(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    int sock;
+    union sockaddr_any sa;
+    socklen_t addrlen = sizeof(sa);
+
+    sock = accept(af->fd, &sa.sa, &addrlen);
+    if (sock < 0) {
+        JimAioSetError(interp, NULL);
+        return JIM_ERR;
+    }
+
+    /* Create the file command */
+    return JimMakeChannel(interp, NULL, sock, Jim_NewStringObj(interp, "accept", -1),
+        "aio.sockstream%ld", af->addr_family, "r+");
+}
+
+static int aio_cmd_listen(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    long backlog;
+
+    if (Jim_GetLong(interp, argv[0], &backlog) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    if (listen(af->fd, backlog)) {
+        JimAioSetError(interp, NULL);
+        return JIM_ERR;
+    }
+
+    return JIM_OK;
+}
+#endif /* JIM_BOOTSTRAP */
+
+static int aio_cmd_flush(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    if (fflush(af->fp) == EOF) {
+        JimAioSetError(interp, af->filename);
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+static int aio_cmd_eof(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    Jim_SetResultInt(interp, feof(af->fp));
+    return JIM_OK;
+}
+
+static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_DeleteCommand(interp, Jim_String(argv[0]));
+    return JIM_OK;
+}
+
+static int aio_cmd_seek(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+    int orig = SEEK_SET;
+    long offset;
+
+    if (argc == 2) {
+        if (Jim_CompareStringImmediate(interp, argv[1], "start"))
+            orig = SEEK_SET;
+        else if (Jim_CompareStringImmediate(interp, argv[1], "current"))
+            orig = SEEK_CUR;
+        else if (Jim_CompareStringImmediate(interp, argv[1], "end"))
+            orig = SEEK_END;
+        else {
+            return -1;
+        }
+    }
+    if (Jim_GetLong(interp, argv[0], &offset) != JIM_OK) {
+        return JIM_ERR;
+    }
+    if (fseek(af->fp, offset, orig) == -1) {
+        JimAioSetError(interp, af->filename);
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+static int aio_cmd_tell(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    Jim_SetResultInt(interp, ftell(af->fp));
+    return JIM_OK;
+}
+
+static int aio_cmd_filename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    Jim_SetResult(interp, af->filename);
+    return JIM_OK;
+}
+
+#ifdef O_NDELAY
+static int aio_cmd_ndelay(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    int fmode = af->flags;
+
+    if (argc) {
+        long nb;
+
+        if (Jim_GetLong(interp, argv[0], &nb) != JIM_OK) {
+            return JIM_ERR;
+        }
+        if (nb) {
+            fmode |= O_NDELAY;
+        }
+        else {
+            fmode &= ~O_NDELAY;
+        }
+        fcntl(af->fd, F_SETFL, fmode);
+        af->flags = fmode;
+    }
+    Jim_SetResultInt(interp, (fmode & O_NONBLOCK) ? 1 : 0);
+    return JIM_OK;
+}
+#endif
+
+static int aio_cmd_buffering(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    static const char * const options[] = {
+        "none",
+        "line",
+        "full",
+        NULL
+    };
+    enum
+    {
+        OPT_NONE,
+        OPT_LINE,
+        OPT_FULL,
+    };
+    int option;
+
+    if (Jim_GetEnum(interp, argv[0], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+        return JIM_ERR;
+    }
+    switch (option) {
+        case OPT_NONE:
+            setvbuf(af->fp, NULL, _IONBF, 0);
+            break;
+        case OPT_LINE:
+            setvbuf(af->fp, NULL, _IOLBF, BUFSIZ);
+            break;
+        case OPT_FULL:
+            setvbuf(af->fp, NULL, _IOFBF, BUFSIZ);
+            break;
+    }
+    return JIM_OK;
+}
+
+#ifdef jim_ext_eventloop
+static void JimAioFileEventFinalizer(Jim_Interp *interp, void *clientData)
+{
+    Jim_Obj *objPtr = clientData;
+
+    Jim_DecrRefCount(interp, objPtr);
+}
+
+static int JimAioFileEventHandler(Jim_Interp *interp, void *clientData, int mask)
+{
+    Jim_Obj *objPtr = clientData;
+
+    return Jim_EvalObjBackground(interp, objPtr);
+}
+
+static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask, Jim_Obj **scriptHandlerObj,
+    int argc, Jim_Obj * const *argv)
+{
+    int scriptlen = 0;
+
+    if (argc == 0) {
+        /* Return current script */
+        if (*scriptHandlerObj) {
+            Jim_SetResult(interp, *scriptHandlerObj);
+        }
+        return JIM_OK;
+    }
+
+    if (*scriptHandlerObj) {
+        /* Delete old handler */
+        Jim_DeleteFileHandler(interp, af->fp);
+        *scriptHandlerObj = NULL;
+    }
+
+    /* Now possibly add the new script(s) */
+    Jim_GetString(argv[0], &scriptlen);
+    if (scriptlen == 0) {
+        /* Empty script, so done */
+        return JIM_OK;
+    }
+
+    /* A new script to add */
+    Jim_IncrRefCount(argv[0]);
+    *scriptHandlerObj = argv[0];
+
+    Jim_CreateFileHandler(interp, af->fp, mask,
+        JimAioFileEventHandler, *scriptHandlerObj, JimAioFileEventFinalizer);
+
+    return JIM_OK;
+}
+
+static int aio_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    return aio_eventinfo(interp, af, JIM_EVENT_READABLE, &af->rEvent, argc, argv);
+}
+
+static int aio_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    return aio_eventinfo(interp, af, JIM_EVENT_WRITABLE, &af->wEvent, argc, argv);
+}
+
+static int aio_cmd_onexception(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    AioFile *af = Jim_CmdPrivData(interp);
+
+    return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, &af->wEvent, argc, argv);
+}
+#endif
+
+static const jim_subcmd_type aio_command_table[] = {
+    {   .cmd = "read",
+        .args = "?-nonewline? ?len?",
+        .function = aio_cmd_read,
+        .minargs = 0,
+        .maxargs = 2,
+        .description = "Read and return bytes from the stream. To eof if no len."
+    },
+    {   .cmd = "copyto",
+        .args = "handle ?size?",
+        .function = aio_cmd_copy,
+        .minargs = 1,
+        .maxargs = 2,
+        .description = "Copy up to 'size' bytes to the given filehandle, or to eof if no size."
+    },
+    {   .cmd = "gets",
+        .args = "?var?",
+        .function = aio_cmd_gets,
+        .minargs = 0,
+        .maxargs = 1,
+        .description = "Read one line and return it or store it in the var"
+    },
+    {   .cmd = "puts",
+        .args = "?-nonewline? str",
+        .function = aio_cmd_puts,
+        .minargs = 1,
+        .maxargs = 2,
+        .description = "Write the string, with newline unless -nonewline"
+    },
+#if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP)
+    {   .cmd = "recvfrom",
+        .args = "len ?addrvar?",
+        .function = aio_cmd_recvfrom,
+        .minargs = 1,
+        .maxargs = 2,
+        .description = "Receive up to 'len' bytes on the socket. Sets 'addrvar' with receive address, if set"
+    },
+    {   .cmd = "sendto",
+        .args = "str address",
+        .function = aio_cmd_sendto,
+        .minargs = 2,
+        .maxargs = 2,
+        .description = "Send 'str' to the given address (dgram only)"
+    },
+    {   .cmd = "accept",
+        .function = aio_cmd_accept,
+        .description = "Server socket only: Accept a connection and return stream"
+    },
+    {   .cmd = "listen",
+        .args = "backlog",
+        .function = aio_cmd_listen,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Set the listen backlog for server socket"
+    },
+#endif /* JIM_BOOTSTRAP */
+    {   .cmd = "flush",
+        .function = aio_cmd_flush,
+        .description = "Flush the stream"
+    },
+    {   .cmd = "eof",
+        .function = aio_cmd_eof,
+        .description = "Returns 1 if stream is at eof"
+    },
+    {   .cmd = "close",
+        .flags = JIM_MODFLAG_FULLARGV,
+        .function = aio_cmd_close,
+        .description = "Closes the stream"
+    },
+    {   .cmd = "seek",
+        .args = "offset ?start|current|end",
+        .function = aio_cmd_seek,
+        .minargs = 1,
+        .maxargs = 2,
+        .description = "Seeks in the stream (default 'current')"
+    },
+    {   .cmd = "tell",
+        .function = aio_cmd_tell,
+        .description = "Returns the current seek position"
+    },
+    {   .cmd = "filename",
+        .function = aio_cmd_filename,
+        .description = "Returns the original filename"
+    },
+#ifdef O_NDELAY
+    {   .cmd = "ndelay",
+        .args = "?0|1?",
+        .function = aio_cmd_ndelay,
+        .minargs = 0,
+        .maxargs = 1,
+        .description = "Set O_NDELAY (if arg). Returns current/new setting."
+    },
+#endif
+    {   .cmd = "buffering",
+        .args = "none|line|full",
+        .function = aio_cmd_buffering,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Sets buffering"
+    },
+#ifdef jim_ext_eventloop
+    {   .cmd = "readable",
+        .args = "?readable-script?",
+        .minargs = 0,
+        .maxargs = 1,
+        .function = aio_cmd_readable,
+        .description = "Returns script, or invoke readable-script when readable, {} to remove",
+    },
+    {   .cmd = "writable",
+        .args = "?writable-script?",
+        .minargs = 0,
+        .maxargs = 1,
+        .function = aio_cmd_writable,
+        .description = "Returns script, or invoke writable-script when writable, {} to remove",
+    },
+    {   .cmd = "onexception",
+        .args = "?exception-script?",
+        .minargs = 0,
+        .maxargs = 1,
+        .function = aio_cmd_onexception,
+        .description = "Returns script, or invoke exception-script when oob data, {} to remove",
+    },
+#endif
+    { 0 }
+};
+
+static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return Jim_CallSubCmd(interp, Jim_ParseSubCmd(interp, aio_command_table, argc, argv), argc, argv);
+}
+
+static int JimAioOpenCommand(Jim_Interp *interp, int argc,
+        Jim_Obj *const *argv)
+{
+    FILE *fp;
+    const char *hdlfmt;
+    const char *mode;
+
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "filename ?mode?");
+        return JIM_ERR;
+    }
+
+    mode = (argc == 3) ? Jim_String(argv[2]) : "r";
+    hdlfmt = Jim_String(argv[1]);
+    if (Jim_CompareStringImmediate(interp, argv[1], "stdin")) {
+        fp = stdin;
+    }
+    else if (Jim_CompareStringImmediate(interp, argv[1], "stdout")) {
+        fp = stdout;
+    }
+    else if (Jim_CompareStringImmediate(interp, argv[1], "stderr")) {
+        fp = stderr;
+    }
+    else {
+        const char *filename = Jim_String(argv[1]);
+
+
+#ifdef jim_ext_tclcompat
+        /* If the filename starts with '|', use popen instead */
+        if (*filename == '|') {
+            Jim_Obj *evalObj[3];
+
+            evalObj[0] = Jim_NewStringObj(interp, "popen", -1);
+            evalObj[1] = Jim_NewStringObj(interp, filename + 1, -1);
+            evalObj[2] = Jim_NewStringObj(interp, mode, -1);
+
+            return Jim_EvalObjVector(interp, 3, evalObj);
+        }
+#endif
+        hdlfmt = "aio.handle%ld";
+        fp = NULL;
+    }
+
+    /* Create the file command */
+    return JimMakeChannel(interp, fp, -1, argv[1], hdlfmt, 0, mode);
+}
+
+/**
+ * Creates a channel for fh/fd/filename.
+ *
+ * If fh is not NULL, uses that as the channel (and set AIO_KEEPOPEN).
+ * Otherwise, if fd is >= 0, uses that as the chanel.
+ * Otherwise opens 'filename' with mode 'mode'.
+ *
+ * hdlfmt is a sprintf format for the filehandle. Anything with %ld at the end will do.
+ * mode is used for open or fdopen.
+ *
+ * Creates the command and sets the name as the current result.
+ */
+static int JimMakeChannel(Jim_Interp *interp, FILE *fh, int fd, Jim_Obj *filename,
+    const char *hdlfmt, int family, const char *mode)
+{
+    AioFile *af;
+    char buf[AIO_CMD_LEN];
+    int OpenFlags = 0;
+
+    Jim_IncrRefCount(filename);
+
+    if (fh == NULL) {
+        if (fd < 0) {
+            fh = fopen(Jim_String(filename), mode);
+        }
+        else {
+            fh = fdopen(fd, mode);
+        }
+    }
+    else {
+        OpenFlags = AIO_KEEPOPEN;
+    }
+
+    if (fh == NULL) {
+        JimAioSetError(interp, filename);
+        close(fd);
+        Jim_DecrRefCount(interp, filename);
+        return JIM_ERR;
+    }
+
+    /* Create the file command */
+    af = Jim_Alloc(sizeof(*af));
+    memset(af, 0, sizeof(*af));
+    af->fp = fh;
+    af->fd = fileno(fh);
+    af->filename = filename;
+#ifdef FD_CLOEXEC
+    if ((OpenFlags & AIO_KEEPOPEN) == 0) {
+        fcntl(af->fd, F_SETFD, FD_CLOEXEC);
+        af->OpenFlags = OpenFlags;
+    }
+#endif
+#ifdef O_NDELAY
+    af->flags = fcntl(af->fd, F_GETFL);
+#endif
+    af->addr_family = family;
+    snprintf(buf, sizeof(buf), hdlfmt, Jim_GetId(interp));
+    Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc);
+
+    Jim_SetResultString(interp, buf, -1);
+
+    return JIM_OK;
+}
+
+#if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP)
+
+static int JimAioSockCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *hdlfmt = "aio.unknown%ld";
+    const char *socktypes[] = {
+        "unix",
+        "unix.server",
+        "dgram",
+        "dgram.server",
+        "stream",
+        "stream.server",
+        "pipe",
+        NULL
+    };
+    enum
+    {
+        SOCK_UNIX,
+        SOCK_UNIX_SERVER,
+        SOCK_DGRAM_CLIENT,
+        SOCK_DGRAM_SERVER,
+        SOCK_STREAM_CLIENT,
+        SOCK_STREAM_SERVER,
+        SOCK_STREAM_PIPE,
+        SOCK_DGRAM6_CLIENT,
+        SOCK_DGRAM6_SERVER,
+        SOCK_STREAM6_CLIENT,
+        SOCK_STREAM6_SERVER,
+    };
+    int socktype;
+    int sock;
+    const char *hostportarg = NULL;
+    int res;
+    int on = 1;
+    const char *mode = "r+";
+    int family = PF_INET;
+    Jim_Obj *argv0 = argv[0];
+    int ipv6 = 0;
+
+    if (argc > 1 && Jim_CompareStringImmediate(interp, argv[1], "-ipv6")) {
+        if (!IPV6) {
+            Jim_SetResultString(interp, "ipv6 not supported", -1);
+            return JIM_ERR;
+        }
+        ipv6 = 1;
+        family = PF_INET6;
+    }
+    argc -= ipv6;
+    argv += ipv6;
+
+    if (argc < 2) {
+      wrongargs:
+        Jim_WrongNumArgs(interp, 1, &argv0, "?-ipv6? type ?address?");
+        return JIM_ERR;
+    }
+
+    if (Jim_GetEnum(interp, argv[1], socktypes, &socktype, "socket type", JIM_ERRMSG) != JIM_OK)
+        return JIM_ERR;
+
+    Jim_SetEmptyResult(interp);
+
+    hdlfmt = "aio.sock%ld";
+
+    if (argc > 2) {
+        hostportarg = Jim_String(argv[2]);
+    }
+
+    switch (socktype) {
+        case SOCK_DGRAM_CLIENT:
+            if (argc == 2) {
+                /* No address, so an unconnected dgram socket */
+                sock = socket(family, SOCK_DGRAM, 0);
+                if (sock < 0) {
+                    JimAioSetError(interp, NULL);
+                    return JIM_ERR;
+                }
+                break;
+            }
+            /* fall through */
+        case SOCK_STREAM_CLIENT:
+            {
+                union sockaddr_any sa;
+                int salen;
+
+                if (argc != 3) {
+                    goto wrongargs;
+                }
+
+                if (ipv6) {
+                    if (JimParseIPv6Address(interp, hostportarg, &sa, &salen) != JIM_OK) {
+                        return JIM_ERR;
+                    }
+                }
+                else if (JimParseIpAddress(interp, hostportarg, &sa, &salen) != JIM_OK) {
+                    return JIM_ERR;
+                }
+                sock = socket(family, (socktype == SOCK_DGRAM_CLIENT) ? SOCK_DGRAM : SOCK_STREAM, 0);
+                if (sock < 0) {
+                    JimAioSetError(interp, NULL);
+                    return JIM_ERR;
+                }
+                res = connect(sock, &sa.sa, salen);
+                if (res) {
+                    JimAioSetError(interp, argv[2]);
+                    close(sock);
+                    return JIM_ERR;
+                }
+            }
+            break;
+
+        case SOCK_STREAM_SERVER:
+        case SOCK_DGRAM_SERVER:
+            {
+                union sockaddr_any sa;
+                int salen;
+
+                if (argc != 3) {
+                    goto wrongargs;
+                }
+
+                if (ipv6) {
+                    if (JimParseIPv6Address(interp, hostportarg, &sa, &salen) != JIM_OK) {
+                        return JIM_ERR;
+                    }
+                }
+                else if (JimParseIpAddress(interp, hostportarg, &sa, &salen) != JIM_OK) {
+                    return JIM_ERR;
+                }
+                sock = socket(family, (socktype == SOCK_DGRAM_SERVER) ? SOCK_DGRAM : SOCK_STREAM, 0);
+                if (sock < 0) {
+                    JimAioSetError(interp, NULL);
+                    return JIM_ERR;
+                }
+
+                /* Enable address reuse */
+                setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
+
+                res = bind(sock, &sa.sa, salen);
+                if (res) {
+                    JimAioSetError(interp, argv[2]);
+                    close(sock);
+                    return JIM_ERR;
+                }
+                if (socktype == SOCK_STREAM_SERVER) {
+                    res = listen(sock, 5);
+                    if (res) {
+                        JimAioSetError(interp, NULL);
+                        close(sock);
+                        return JIM_ERR;
+                    }
+                }
+                hdlfmt = "aio.socksrv%ld";
+            }
+            break;
+
+#ifdef HAVE_SYS_UN_H
+        case SOCK_UNIX:
+            {
+                struct sockaddr_un sa;
+                socklen_t len;
+
+                if (argc != 3 || ipv6) {
+                    goto wrongargs;
+                }
+
+                if (JimParseDomainAddress(interp, hostportarg, &sa) != JIM_OK) {
+                    JimAioSetError(interp, argv[2]);
+                    return JIM_ERR;
+                }
+                family = PF_UNIX;
+                sock = socket(PF_UNIX, SOCK_STREAM, 0);
+                if (sock < 0) {
+                    JimAioSetError(interp, NULL);
+                    return JIM_ERR;
+                }
+                len = strlen(sa.sun_path) + 1 + sizeof(sa.sun_family);
+                res = connect(sock, (struct sockaddr *)&sa, len);
+                if (res) {
+                    JimAioSetError(interp, argv[2]);
+                    close(sock);
+                    return JIM_ERR;
+                }
+                hdlfmt = "aio.sockunix%ld";
+                break;
+            }
+
+        case SOCK_UNIX_SERVER:
+            {
+                struct sockaddr_un sa;
+                socklen_t len;
+
+                if (argc != 3 || ipv6) {
+                    goto wrongargs;
+                }
+
+                if (JimParseDomainAddress(interp, hostportarg, &sa) != JIM_OK) {
+                    JimAioSetError(interp, argv[2]);
+                    return JIM_ERR;
+                }
+                family = PF_UNIX;
+                sock = socket(PF_UNIX, SOCK_STREAM, 0);
+                if (sock < 0) {
+                    JimAioSetError(interp, NULL);
+                    return JIM_ERR;
+                }
+                len = strlen(sa.sun_path) + 1 + sizeof(sa.sun_family);
+                res = bind(sock, (struct sockaddr *)&sa, len);
+                if (res) {
+                    JimAioSetError(interp, argv[2]);
+                    close(sock);
+                    return JIM_ERR;
+                }
+                res = listen(sock, 5);
+                if (res) {
+                    JimAioSetError(interp, NULL);
+                    close(sock);
+                    return JIM_ERR;
+                }
+                hdlfmt = "aio.sockunixsrv%ld";
+                break;
+            }
+#endif
+
+#ifdef HAVE_PIPE
+        case SOCK_STREAM_PIPE:
+            {
+                int p[2];
+
+                if (argc != 2 || ipv6) {
+                    goto wrongargs;
+                }
+
+                if (pipe(p) < 0) {
+                    JimAioSetError(interp, NULL);
+                    return JIM_ERR;
+                }
+
+                if (JimMakeChannel(interp, NULL, p[0], argv[1], "aio.pipe%ld", 0, "r") == JIM_OK) {
+                    Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
+                    Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
+
+                    if (JimMakeChannel(interp, NULL, p[1], argv[1], "aio.pipe%ld", 0, "w") == JIM_OK) {
+                        Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
+                        Jim_SetResult(interp, objPtr);
+                        return JIM_OK;
+                    }
+                }
+                /* Can only be here if fdopen() failed */
+                close(p[0]);
+                close(p[1]);
+                JimAioSetError(interp, NULL);
+                return JIM_ERR;
+            }
+            break;
+#endif
+        default:
+            Jim_SetResultString(interp, "Unsupported socket type", -1);
+            return JIM_ERR;
+    }
+
+    return JimMakeChannel(interp, NULL, sock, argv[1], hdlfmt, family, mode);
+}
+#endif /* JIM_BOOTSTRAP */
+
+FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command)
+{
+    Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG);
+
+    if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) {
+        return ((AioFile *) cmdPtr->u.native.privData)->fp;
+    }
+    Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command);
+    return NULL;
+}
+
+int Jim_aioInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "aio", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    Jim_CreateCommand(interp, "open", JimAioOpenCommand, NULL, NULL);
+#ifndef JIM_ANSIC
+    Jim_CreateCommand(interp, "socket", JimAioSockCommand, NULL, NULL);
+#endif
+
+    /* Takeover stdin, stdout and stderr */
+    Jim_EvalGlobal(interp, "open stdin; open stdout; open stderr");
+
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-array.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-array.c
new file mode 100755
index 0000000..89a86f0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-array.c
@@ -0,0 +1,274 @@
+
+/*
+ * Implements the array command for jim
+ *
+ * (c) 2008 Steve Bennett <steveb@workware.net.au>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ *
+ * Based on code originally from Tcl 6.7:
+ *
+ * Copyright 1987-1991 Regents of the University of California
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies.  The University of California
+ * makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "jim-subcmd.h"
+
+static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    /* Just a regular [info exists] */
+    Jim_SetResultInt(interp, Jim_GetVariable(interp, argv[0], 0) != 0);
+    return JIM_OK;
+}
+
+static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int i;
+    int len;
+    int all = 0;
+    Jim_Obj *resultObj;
+    Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+    Jim_Obj *dictObj;
+    Jim_Obj **dictValuesObj;
+
+    if (!objPtr) {
+        return JIM_OK;
+    }
+
+    if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
+        all = 1;
+    }
+
+    /* If it is a dictionary or list with an even number of elements, nothing else to do */
+    if (all) {
+        if (Jim_IsDict(objPtr) || (Jim_IsList(objPtr) && Jim_ListLength(interp, objPtr) % 2 == 0)) {
+            Jim_SetResult(interp, objPtr);
+            return JIM_OK;
+        }
+    }
+
+    if (Jim_DictKeysVector(interp, objPtr, NULL, 0, &dictObj, JIM_ERRMSG) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    if (Jim_DictPairs(interp, dictObj, &dictValuesObj, &len) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    if (all) {
+        /* Return the whole array */
+        Jim_SetResult(interp, dictObj);
+    }
+    else {
+        /* Only return the matching values */
+        resultObj = Jim_NewListObj(interp, NULL, 0);
+
+        for (i = 0; i < len; i += 2) {
+            if (Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) {
+                Jim_ListAppendElement(interp, resultObj, dictValuesObj[i]);
+                Jim_ListAppendElement(interp, resultObj, dictValuesObj[i + 1]);
+            }
+        }
+
+        Jim_SetResult(interp, resultObj);
+    }
+    Jim_Free(dictValuesObj);
+    return JIM_OK;
+
+}
+
+static int array_cmd_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+
+    if (!objPtr) {
+        return JIM_OK;
+    }
+
+    return Jim_DictKeys(interp, objPtr, argc == 1 ? NULL : argv[1]);
+}
+
+static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int i;
+    int len;
+    Jim_Obj *resultObj;
+    Jim_Obj *objPtr;
+    Jim_Obj *dictObj;
+    Jim_Obj **dictValuesObj;
+
+    if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
+        /* Unset the whole array */
+        Jim_UnsetVariable(interp, argv[0], JIM_NONE);
+        return JIM_OK;
+    }
+
+    objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+
+    if (Jim_DictKeysVector(interp, objPtr, NULL, 0, &dictObj, JIM_ERRMSG) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    if (Jim_DictPairs(interp, dictObj, &dictValuesObj, &len) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    /* Create a new object with the values which don't match */
+    resultObj = Jim_NewDictObj(interp, NULL, 0);
+
+    for (i = 0; i < len; i += 2) {
+        if (!Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) {
+            Jim_DictAddElement(interp, resultObj, dictValuesObj[i], dictValuesObj[i + 1]);
+        }
+    }
+    Jim_Free(dictValuesObj);
+
+    Jim_SetVariable(interp, argv[0], resultObj);
+    return JIM_OK;
+}
+
+static int array_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr;
+    int len = 0;
+
+    /* Not found means zero length */
+    objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+    if (objPtr) {
+        len = Jim_DictSize(interp, objPtr);
+        if (len < 0) {
+            return JIM_ERR;
+        }
+    }
+
+    Jim_SetResultInt(interp, len);
+
+    return JIM_OK;
+}
+
+static int array_cmd_set(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int i;
+    int len;
+    int rc = JIM_OK;
+    Jim_Obj *listObj = argv[1];
+
+    if (Jim_GetVariable(interp, argv[0], JIM_NONE) == NULL) {
+        /* Doesn't exist, so just set the list directly */
+        return Jim_SetVariable(interp, argv[0], listObj);
+    }
+
+    len = Jim_ListLength(interp, listObj);
+    if (len % 2) {
+        Jim_SetResultString(interp, "list must have an even number of elements", -1);
+        return JIM_ERR;
+    }
+    for (i = 0; i < len && rc == JIM_OK; i += 2) {
+        Jim_Obj *nameObj;
+        Jim_Obj *valueObj;
+
+        Jim_ListIndex(interp, listObj, i, &nameObj, JIM_NONE);
+        Jim_ListIndex(interp, listObj, i + 1, &valueObj, JIM_NONE);
+
+        rc = Jim_SetDictKeysVector(interp, argv[0], &nameObj, 1, valueObj, JIM_ERRMSG);
+    }
+
+    return rc;
+}
+
+static const jim_subcmd_type array_command_table[] = {
+        {       .cmd = "exists",
+                .args = "arrayName",
+                .function = array_cmd_exists,
+                .minargs = 1,
+                .maxargs = 1,
+                .description = "Does array exist?"
+        },
+        {       .cmd = "get",
+                .args = "arrayName ?pattern?",
+                .function = array_cmd_get,
+                .minargs = 1,
+                .maxargs = 2,
+                .description = "Array contents as name value list"
+        },
+        {       .cmd = "names",
+                .args = "arrayName ?pattern?",
+                .function = array_cmd_names,
+                .minargs = 1,
+                .maxargs = 2,
+                .description = "Array keys as a list"
+        },
+        {       .cmd = "set",
+                .args = "arrayName list",
+                .function = array_cmd_set,
+                .minargs = 2,
+                .maxargs = 2,
+                .description = "Set array from list"
+        },
+        {       .cmd = "size",
+                .args = "arrayName",
+                .function = array_cmd_size,
+                .minargs = 1,
+                .maxargs = 1,
+                .description = "Number of elements in array"
+        },
+        {       .cmd = "unset",
+                .args = "arrayName ?pattern?",
+                .function = array_cmd_unset,
+                .minargs = 1,
+                .maxargs = 2,
+                .description = "Unset elements of an array"
+        },
+        {       .cmd = 0,
+        }
+};
+
+int Jim_arrayInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "array", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    Jim_CreateCommand(interp, "array", Jim_SubCmdProc, (void *)array_command_table, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-clock.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-clock.c
new file mode 100755
index 0000000..51ffb51
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-clock.c
@@ -0,0 +1,159 @@
+
+/*
+ * tcl_clock.c
+ *
+ * Implements the clock command
+ */
+
+/* For strptime() */
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 500
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "jim-subcmd.h"
+
+static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    /* How big is big enough? */
+    char buf[100];
+    time_t t;
+    long seconds;
+
+    const char *format = "%a %b  %d %H:%M:%S %Z %Y";
+
+    if (argc == 2 || (argc == 3 && !Jim_CompareStringImmediate(interp, argv[1], "-format"))) {
+        return -1;
+    }
+
+    if (argc == 3) {
+        format = Jim_String(argv[2]);
+    }
+
+    if (Jim_GetLong(interp, argv[0], &seconds) != JIM_OK) {
+        return JIM_ERR;
+    }
+    t = seconds;
+
+    strftime(buf, sizeof(buf), format, localtime(&t));
+
+    Jim_SetResultString(interp, buf, -1);
+
+    return JIM_OK;
+}
+
+#ifdef HAVE_STRPTIME
+static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    char *pt;
+    struct tm tm;
+    time_t now = time(0);
+
+    if (!Jim_CompareStringImmediate(interp, argv[1], "-format")) {
+        return -1;
+    }
+
+    /* Initialise with the current date/time */
+    localtime_r(&now, &tm);
+
+    pt = strptime(Jim_String(argv[0]), Jim_String(argv[2]), &tm);
+    if (pt == 0 || *pt != 0) {
+        Jim_SetResultString(interp, "Failed to parse time according to format", -1);
+        return JIM_ERR;
+    }
+
+    /* Now convert into a time_t */
+    Jim_SetResultInt(interp, mktime(&tm));
+
+    return JIM_OK;
+}
+#endif
+
+static int clock_cmd_seconds(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_SetResultInt(interp, time(NULL));
+
+    return JIM_OK;
+}
+
+static int clock_cmd_micros(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, NULL);
+
+    Jim_SetResultInt(interp, (jim_wide) tv.tv_sec * 1000000 + tv.tv_usec);
+
+    return JIM_OK;
+}
+
+static int clock_cmd_millis(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, NULL);
+
+    Jim_SetResultInt(interp, (jim_wide) tv.tv_sec * 1000 + tv.tv_usec / 1000);
+
+    return JIM_OK;
+}
+
+static const jim_subcmd_type clock_command_table[] = {
+    {   .cmd = "seconds",
+        .function = clock_cmd_seconds,
+        .minargs = 0,
+        .maxargs = 0,
+        .description = "Returns the current time as seconds since the epoch"
+    },
+    {   .cmd = "clicks",
+        .function = clock_cmd_micros,
+        .minargs = 0,
+        .maxargs = 0,
+        .description = "Returns the current time in 'clicks'"
+    },
+    {   .cmd = "microseconds",
+        .function = clock_cmd_micros,
+        .minargs = 0,
+        .maxargs = 0,
+        .description = "Returns the current time in microseconds"
+    },
+    {   .cmd = "milliseconds",
+        .function = clock_cmd_millis,
+        .minargs = 0,
+        .maxargs = 0,
+        .description = "Returns the current time in milliseconds"
+    },
+    {   .cmd = "format",
+        .args = "seconds ?-format format?",
+        .function = clock_cmd_format,
+        .minargs = 1,
+        .maxargs = 3,
+        .description = "Format the given time"
+    },
+#ifdef HAVE_STRPTIME
+    {   .cmd = "scan",
+        .args = "str -format format",
+        .function = clock_cmd_scan,
+        .minargs = 3,
+        .maxargs = 3,
+        .description = "Determine the time according to the given format"
+    },
+#endif
+    { 0 }
+};
+
+int Jim_clockInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "clock", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    Jim_CreateCommand(interp, "clock", Jim_SubCmdProc, (void *)clock_command_table, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-config.h.in b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-config.h.in
new file mode 100755
index 0000000..2394bc5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-config.h.in
@@ -0,0 +1,2 @@
+/* Public autoconf settings */
+@DEFINE_HAVE_LONG_LONG@
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-eventloop.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-eventloop.c
new file mode 100755
index 0000000..a7efdc2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-eventloop.c
@@ -0,0 +1,760 @@
+
+/* Jim - A small embeddable Tcl interpreter
+ *
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
+ * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
+ * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
+ * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
+ * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
+ * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ **/
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "jim-eventloop.h"
+
+/* POSIX includes */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#if defined(__MINGW32__)
+#include <windows.h>
+#include <winsock.h>
+#define msleep Sleep
+#ifndef HAVE_USLEEP
+#define usleep(US) msleep((US) / 1000)
+#endif
+#else
+#include <sys/select.h>
+
+#ifndef HAVE_USLEEP
+/* XXX: Implement this in terms of select() or nanosleep() */
+#define usleep(US)
+#endif
+#define msleep(MS) sleep((MS) / 1000); usleep(((MS) % 1000) * 1000);
+#endif
+
+/* --- */
+
+/* File event structure */
+typedef struct Jim_FileEvent
+{
+    FILE *handle;
+    int mask;                   /* one of JIM_EVENT_(READABLE|WRITABLE|EXCEPTION) */
+    Jim_FileProc *fileProc;
+    Jim_EventFinalizerProc *finalizerProc;
+    void *clientData;
+    struct Jim_FileEvent *next;
+} Jim_FileEvent;
+
+/* Time event structure */
+typedef struct Jim_TimeEvent
+{
+    jim_wide id;                /* time event identifier. */
+    int mode;                   /* restart, repetitive .. UK */
+    long initialms;             /* initial relativ timer value UK */
+    long when_sec;              /* seconds */
+    long when_ms;               /* milliseconds */
+    Jim_TimeProc *timeProc;
+    Jim_EventFinalizerProc *finalizerProc;
+    void *clientData;
+    struct Jim_TimeEvent *next;
+} Jim_TimeEvent;
+
+/* Per-interp stucture containing the state of the event loop */
+typedef struct Jim_EventLoop
+{
+    jim_wide timeEventNextId;
+    Jim_FileEvent *fileEventHead;
+    Jim_TimeEvent *timeEventHead;
+    int suppress_bgerror; /* bgerror returned break, so don't call it again */
+} Jim_EventLoop;
+
+static void JimAfterTimeHandler(Jim_Interp *interp, void *clientData);
+static void JimAfterTimeEventFinalizer(Jim_Interp *interp, void *clientData);
+
+int Jim_EvalObjBackground(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
+{
+    Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop");
+    Jim_CallFrame *savedFramePtr;
+    int retval;
+
+    savedFramePtr = interp->framePtr;
+    interp->framePtr = interp->topFramePtr;
+    retval = Jim_EvalObj(interp, scriptObjPtr);
+    interp->framePtr = savedFramePtr;
+    /* Try to report the error (if any) via the bgerror proc */
+    if (retval != JIM_OK && !eventLoop->suppress_bgerror) {
+        Jim_Obj *objv[2];
+        int rc = JIM_ERR;
+
+        objv[0] = Jim_NewStringObj(interp, "bgerror", -1);
+        objv[1] = Jim_GetResult(interp);
+        Jim_IncrRefCount(objv[0]);
+        Jim_IncrRefCount(objv[1]);
+        if (Jim_GetCommand(interp, objv[0], JIM_NONE) == NULL || (rc = Jim_EvalObjVector(interp, 2, objv)) != JIM_OK) {
+            if (rc == JIM_BREAK) {
+                /* No more bgerror calls */
+                eventLoop->suppress_bgerror++;
+            }
+            else {
+                /* Report the error to stderr. */
+                Jim_MakeErrorMessage(interp);
+                fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
+                /* And reset the result */
+                Jim_SetResultString(interp, "", -1);
+            }
+        }
+        Jim_DecrRefCount(interp, objv[0]);
+        Jim_DecrRefCount(interp, objv[1]);
+    }
+    return retval;
+}
+
+
+void Jim_CreateFileHandler(Jim_Interp *interp, FILE * handle, int mask,
+    Jim_FileProc * proc, void *clientData, Jim_EventFinalizerProc * finalizerProc)
+{
+    Jim_FileEvent *fe;
+    Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop");
+
+    fe = Jim_Alloc(sizeof(*fe));
+    fe->handle = handle;
+    fe->mask = mask;
+    fe->fileProc = proc;
+    fe->finalizerProc = finalizerProc;
+    fe->clientData = clientData;
+    fe->next = eventLoop->fileEventHead;
+    eventLoop->fileEventHead = fe;
+}
+
+void Jim_DeleteFileHandler(Jim_Interp *interp, FILE * handle)
+{
+    Jim_FileEvent *fe, *prev = NULL;
+    Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop");
+
+    fe = eventLoop->fileEventHead;
+    while (fe) {
+        if (fe->handle == handle) {
+            if (prev == NULL)
+                eventLoop->fileEventHead = fe->next;
+            else
+                prev->next = fe->next;
+            if (fe->finalizerProc)
+                fe->finalizerProc(interp, fe->clientData);
+            Jim_Free(fe);
+            return;
+        }
+        prev = fe;
+        fe = fe->next;
+    }
+}
+
+static void JimGetTime(long *seconds, long *milliseconds)
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, NULL);
+    *seconds = tv.tv_sec;
+    *milliseconds = tv.tv_usec / 1000;
+}
+
+jim_wide Jim_CreateTimeHandler(Jim_Interp *interp, jim_wide milliseconds,
+    Jim_TimeProc * proc, void *clientData, Jim_EventFinalizerProc * finalizerProc)
+{
+    Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop");
+    jim_wide id = eventLoop->timeEventNextId++;
+    Jim_TimeEvent *te, *e, *prev;
+    long cur_sec, cur_ms;
+
+    JimGetTime(&cur_sec, &cur_ms);
+
+    te = Jim_Alloc(sizeof(*te));
+    te->id = id;
+    te->mode = 0;
+    te->initialms = milliseconds;
+    te->when_sec = cur_sec + milliseconds / 1000;
+    te->when_ms = cur_ms + milliseconds % 1000;
+    if (te->when_ms >= 1000) {
+        te->when_sec++;
+        te->when_ms -= 1000;
+    }
+    te->timeProc = proc;
+    te->finalizerProc = finalizerProc;
+    te->clientData = clientData;
+
+    /* Add to the appropriate place in the list */
+    if (eventLoop->timeEventHead) {
+        prev = NULL;
+        for (e = eventLoop->timeEventHead; e; e = e->next) {
+            if (te->when_sec < e->when_sec || (te->when_sec == e->when_sec && te->when_ms < e->when_ms)) {
+                break;
+            }
+            prev = e;
+        }
+        if (prev) {
+            te->next = prev->next;
+            prev->next = te;
+            return id;
+        }
+    }
+
+    te->next = eventLoop->timeEventHead;
+    eventLoop->timeEventHead = te;
+
+    return id;
+}
+
+static jim_wide JimParseAfterId(Jim_Obj *idObj)
+{
+    int len;
+    const char *tok = Jim_GetString(idObj, &len);
+    jim_wide id;
+
+    if (strncmp(tok, "after#", 6) == 0 && Jim_StringToWide(tok + 6, &id, 10) == JIM_OK) {
+        /* Got an event by id */
+        return id;
+    }
+    return -1;
+}
+
+static jim_wide JimFindAfterByScript(Jim_EventLoop *eventLoop, Jim_Obj *scriptObj)
+{
+    Jim_TimeEvent *te;
+
+    for (te = eventLoop->timeEventHead; te; te = te->next) {
+        /* Is this an 'after' event? */
+        if (te->timeProc == JimAfterTimeHandler) {
+            if (Jim_StringEqObj(scriptObj, te->clientData)) {
+                return te->id;
+            }
+        }
+    }
+    return -1;                  /* NO event with the specified ID found */
+}
+
+static Jim_TimeEvent *JimFindTimeHandlerById(Jim_EventLoop *eventLoop, jim_wide id)
+{
+    Jim_TimeEvent *te;
+
+    for (te = eventLoop->timeEventHead; te; te = te->next) {
+        if (te->id == id) {
+            return te;
+        }
+    }
+    return NULL;
+}
+
+static Jim_TimeEvent *Jim_RemoveTimeHandler(Jim_EventLoop *eventLoop, jim_wide id)
+{
+    Jim_TimeEvent *te, *prev = NULL;
+
+    for (te = eventLoop->timeEventHead; te; te = te->next) {
+        if (te->id == id) {
+            if (prev == NULL)
+                eventLoop->timeEventHead = te->next;
+            else
+                prev->next = te->next;
+            return te;
+        }
+        prev = te;
+    }
+    return NULL;
+}
+
+static void Jim_FreeTimeHandler(Jim_Interp *interp, Jim_TimeEvent *te)
+{
+    if (te->finalizerProc)
+        te->finalizerProc(interp, te->clientData);
+    Jim_Free(te);
+}
+
+jim_wide Jim_DeleteTimeHandler(Jim_Interp *interp, jim_wide id)
+{
+    Jim_TimeEvent *te;
+    Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop");
+
+    if (id >= eventLoop->timeEventNextId) {
+        return -2;              /* wrong event ID */
+    }
+
+    te = Jim_RemoveTimeHandler(eventLoop, id);
+    if (te) {
+        jim_wide remain;
+        long cur_sec, cur_ms;
+
+        JimGetTime(&cur_sec, &cur_ms);
+
+        remain = (te->when_sec - cur_sec) * 1000;
+        remain += (te->when_ms - cur_ms);
+        remain = (remain < 0) ? 0 : remain;
+
+        Jim_FreeTimeHandler(interp, te);
+        return remain;
+    }
+    return -1;                  /* NO event with the specified ID found */
+}
+
+/* --- POSIX version of Jim_ProcessEvents, for now the only available --- */
+
+/* Process every pending time event, then every pending file event
+ * (that may be registered by time event callbacks just processed).
+ * Without special flags the function sleeps until some file event
+ * fires, or when the next time event occurrs (if any).
+ *
+ * If flags is 0, the function does nothing and returns.
+ * if flags has JIM_ALL_EVENTS set, all the kind of events are processed.
+ * if flags has JIM_FILE_EVENTS set, file events are processed.
+ * if flags has JIM_TIME_EVENTS set, time events are processed.
+ * if flags has JIM_DONT_WAIT set the function returns ASAP until all
+ * the events that's possible to process without to wait are processed.
+ *
+ * The function returns the number of events processed or -1 if
+ * there are no matching handlers, or -2 on error.
+ */
+int Jim_ProcessEvents(Jim_Interp *interp, int flags)
+{
+    jim_wide sleep_ms = -1;
+    int processed = 0;
+    Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop");
+    Jim_FileEvent *fe = eventLoop->fileEventHead;
+    Jim_TimeEvent *te;
+    jim_wide maxId;
+
+    if ((flags & JIM_FILE_EVENTS) == 0 || fe == NULL) {
+        /* No file events */
+        if ((flags & JIM_TIME_EVENTS) == 0 || eventLoop->timeEventHead == NULL) {
+            /* No time events */
+            return -1;
+        }
+    }
+
+    /* Note that we want call select() even if there are no
+     * file events to process as long as we want to process time
+     * events, in order to sleep until the next time event is ready
+     * to fire. */
+
+    if (flags & JIM_DONT_WAIT) {
+        /* Wait no time */
+        sleep_ms = 0;
+    }
+    else if (flags & JIM_TIME_EVENTS) {
+        /* The nearest timer is always at the head of the list */
+        if (eventLoop->timeEventHead) {
+            Jim_TimeEvent *shortest = eventLoop->timeEventHead;
+            long now_sec, now_ms;
+
+            /* Calculate the time missing for the nearest
+             * timer to fire. */
+            JimGetTime(&now_sec, &now_ms);
+            sleep_ms = 1000 * (shortest->when_sec - now_sec) + (shortest->when_ms - now_ms);
+            if (sleep_ms < 0) {
+                sleep_ms = 1;
+            }
+        }
+        else {
+            /* Wait forever */
+            sleep_ms = -1;
+        }
+    }
+
+#ifdef HAVE_SELECT
+    if (flags & JIM_FILE_EVENTS) {
+        int retval;
+        struct timeval tv, *tvp = NULL;
+        fd_set rfds, wfds, efds;
+        int maxfd = -1;
+
+        FD_ZERO(&rfds);
+        FD_ZERO(&wfds);
+        FD_ZERO(&efds);
+
+        /* Check file events */
+        while (fe != NULL) {
+            int fd = fileno(fe->handle);
+
+            if (fe->mask & JIM_EVENT_READABLE)
+                FD_SET(fd, &rfds);
+            if (fe->mask & JIM_EVENT_WRITABLE)
+                FD_SET(fd, &wfds);
+            if (fe->mask & JIM_EVENT_EXCEPTION)
+                FD_SET(fd, &efds);
+            if (maxfd < fd)
+                maxfd = fd;
+            fe = fe->next;
+        }
+
+        if (sleep_ms >= 0) {
+            tvp = &tv;
+            tvp->tv_sec = sleep_ms / 1000;
+            tvp->tv_usec = 1000 * (sleep_ms % 1000);
+        }
+
+        retval = select(maxfd + 1, &rfds, &wfds, &efds, tvp);
+
+        if (retval < 0) {
+            if (errno == EINVAL) {
+                /* This can happen on mingw32 if a non-socket filehandle is passed */
+                Jim_SetResultString(interp, "non-waitable filehandle", -1);
+                return -2;
+            }
+            /* XXX: What about EINTR? */
+        }
+        else if (retval > 0) {
+            fe = eventLoop->fileEventHead;
+            while (fe != NULL) {
+                int fd = fileno(fe->handle);
+                int mask = 0;
+
+                if ((fe->mask & JIM_EVENT_READABLE) && FD_ISSET(fd, &rfds))
+                    mask |= JIM_EVENT_READABLE;
+                if (fe->mask & JIM_EVENT_WRITABLE && FD_ISSET(fd, &wfds))
+                    mask |= JIM_EVENT_WRITABLE;
+                if (fe->mask & JIM_EVENT_EXCEPTION && FD_ISSET(fd, &efds))
+                    mask |= JIM_EVENT_EXCEPTION;
+
+                if (mask) {
+                    if (fe->fileProc(interp, fe->clientData, mask) != JIM_OK) {
+                        /* Remove the element on handler error */
+                        Jim_DeleteFileHandler(interp, fe->handle);
+                    }
+                    processed++;
+                    /* After an event is processed our file event list
+                     * may no longer be the same, so what we do
+                     * is to clear the bit for this file descriptor and
+                     * restart again from the head. */
+                    fe = eventLoop->fileEventHead;
+                    FD_CLR(fd, &rfds);
+                    FD_CLR(fd, &wfds);
+                    FD_CLR(fd, &efds);
+                }
+                else {
+                    fe = fe->next;
+                }
+            }
+        }
+    }
+#else
+    if (sleep_ms > 0) {
+        msleep(sleep_ms);
+    }
+#endif
+
+    /* Check time events */
+    te = eventLoop->timeEventHead;
+    maxId = eventLoop->timeEventNextId - 1;
+    while (te) {
+        long now_sec, now_ms;
+        jim_wide id;
+
+        if (te->id > maxId) {
+            te = te->next;
+            continue;
+        }
+        JimGetTime(&now_sec, &now_ms);
+        if (now_sec > te->when_sec || (now_sec == te->when_sec && now_ms >= te->when_ms)) {
+            id = te->id;
+            /* Remove from the list before executing */
+            Jim_RemoveTimeHandler(eventLoop, id);
+            te->timeProc(interp, te->clientData);
+            /* After an event is processed our time event list may
+             * no longer be the same, so we restart from head.
+             * Still we make sure to don't process events registered
+             * by event handlers itself in order to don't loop forever
+             * even in case an [after 0] that continuously register
+             * itself. To do so we saved the max ID we want to handle. */
+            Jim_FreeTimeHandler(interp, te);
+
+            te = eventLoop->timeEventHead;
+            processed++;
+        }
+        else {
+            te = te->next;
+        }
+    }
+
+    return processed;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void JimELAssocDataDeleProc(Jim_Interp *interp, void *data)
+{
+    void *next;
+    Jim_FileEvent *fe;
+    Jim_TimeEvent *te;
+    Jim_EventLoop *eventLoop = data;
+
+    fe = eventLoop->fileEventHead;
+    while (fe) {
+        next = fe->next;
+        if (fe->finalizerProc)
+            fe->finalizerProc(interp, fe->clientData);
+        Jim_Free(fe);
+        fe = next;
+    }
+
+    te = eventLoop->timeEventHead;
+    while (te) {
+        next = te->next;
+        if (te->finalizerProc)
+            te->finalizerProc(interp, te->clientData);
+        Jim_Free(te);
+        te = next;
+    }
+    Jim_Free(data);
+}
+
+static int JimELVwaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_EventLoop *eventLoop = Jim_CmdPrivData(interp);
+    Jim_Obj *oldValue;
+    int rc;
+
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "name");
+        return JIM_ERR;
+    }
+
+    oldValue = Jim_GetGlobalVariable(interp, argv[1], JIM_NONE);
+    if (oldValue) {
+        Jim_IncrRefCount(oldValue);
+    }
+    else {
+        /* If a result was left, it is an error */
+        int len;
+        Jim_GetString(interp->result, &len);
+        if (len) {
+            return JIM_ERR;
+        }
+    }
+
+    eventLoop->suppress_bgerror = 0;
+
+    while ((rc = Jim_ProcessEvents(interp, JIM_ALL_EVENTS)) >= 0) {
+        Jim_Obj *currValue;
+        currValue = Jim_GetGlobalVariable(interp, argv[1], JIM_NONE);
+        /* Stop the loop if the vwait-ed variable changed value,
+         * or if was unset and now is set (or the contrary). */
+        if ((oldValue && !currValue) ||
+            (!oldValue && currValue) ||
+            (oldValue && currValue && !Jim_StringEqObj(oldValue, currValue)))
+            break;
+    }
+    if (oldValue)
+        Jim_DecrRefCount(interp, oldValue);
+
+
+    if (rc == -2) {
+        return JIM_ERR;
+    }
+
+    Jim_SetEmptyResult(interp);
+    return JIM_OK;
+}
+
+static int JimELUpdateCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_EventLoop *eventLoop = Jim_CmdPrivData(interp);
+    static const char * const options[] = {
+        "idletasks", NULL
+    };
+    enum { UPDATE_IDLE, UPDATE_NONE };
+    int option = UPDATE_NONE;
+    int flags = JIM_TIME_EVENTS;
+
+    if (argc == 1) {
+        flags = JIM_ALL_EVENTS;
+    }
+    else if (argc > 2 || Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+        Jim_WrongNumArgs(interp, 1, argv, "?idletasks?");
+        return JIM_ERR;
+    }
+
+    eventLoop->suppress_bgerror = 0;
+
+    while (Jim_ProcessEvents(interp, flags | JIM_DONT_WAIT) > 0) {
+    }
+
+    return JIM_OK;
+}
+
+static void JimAfterTimeHandler(Jim_Interp *interp, void *clientData)
+{
+    Jim_Obj *objPtr = clientData;
+
+    Jim_EvalObjBackground(interp, objPtr);
+}
+
+static void JimAfterTimeEventFinalizer(Jim_Interp *interp, void *clientData)
+{
+    Jim_Obj *objPtr = clientData;
+
+    Jim_DecrRefCount(interp, objPtr);
+}
+
+static int JimELAfterCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_EventLoop *eventLoop = Jim_CmdPrivData(interp);
+    jim_wide ms = 0, id;
+    Jim_Obj *objPtr, *idObjPtr;
+    static const char * const options[] = {
+        "cancel", "info", "idle", NULL
+    };
+    enum
+    { AFTER_CANCEL, AFTER_INFO, AFTER_IDLE, AFTER_RESTART, AFTER_EXPIRE, AFTER_CREATE };
+    int option = AFTER_CREATE;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "option ?arg ...?");
+        return JIM_ERR;
+    }
+    if (Jim_GetWide(interp, argv[1], &ms) != JIM_OK) {
+        if (Jim_GetEnum(interp, argv[1], options, &option, "argument", JIM_ERRMSG) != JIM_OK) {
+            return JIM_ERR;
+        }
+        Jim_SetEmptyResult(interp);
+    }
+    else if (argc == 2) {
+        /* Simply a sleep */
+        msleep(ms);
+        return JIM_OK;
+    }
+
+    switch (option) {
+        case AFTER_IDLE:
+            if (argc < 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "script ?script ...?");
+                return JIM_ERR;
+            }
+            /* fall through */
+        case AFTER_CREATE: {
+            Jim_Obj *scriptObj = Jim_ConcatObj(interp, argc - 2, argv + 2);
+            Jim_IncrRefCount(scriptObj);
+            id = Jim_CreateTimeHandler(interp, ms, JimAfterTimeHandler, scriptObj,
+                JimAfterTimeEventFinalizer);
+            objPtr = Jim_NewStringObj(interp, NULL, 0);
+            Jim_AppendString(interp, objPtr, "after#", -1);
+            idObjPtr = Jim_NewIntObj(interp, id);
+            Jim_IncrRefCount(idObjPtr);
+            Jim_AppendObj(interp, objPtr, idObjPtr);
+            Jim_DecrRefCount(interp, idObjPtr);
+            Jim_SetResult(interp, objPtr);
+            return JIM_OK;
+        }
+        case AFTER_CANCEL:
+            if (argc < 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "id|command");
+                return JIM_ERR;
+            }
+            else {
+                jim_wide remain = 0;
+
+                id = JimParseAfterId(argv[2]);
+                if (id < 0) {
+                    /* Not an event id, so search by script */
+                    Jim_Obj *scriptObj = Jim_ConcatObj(interp, argc - 2, argv + 2);
+                    id = JimFindAfterByScript(eventLoop, scriptObj);
+                    Jim_FreeNewObj(interp, scriptObj);
+                    if (id < 0) {
+                        /* Not found */
+                        break;
+                    }
+                }
+                remain = Jim_DeleteTimeHandler(interp, id);
+                if (remain >= 0) {
+                    Jim_SetResultInt(interp, remain);
+                }
+            }
+            break;
+
+        case AFTER_INFO:
+            if (argc == 2) {
+                Jim_TimeEvent *te = eventLoop->timeEventHead;
+                Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+                char buf[30];
+                const char *fmt = "after#%" JIM_WIDE_MODIFIER;
+
+                while (te) {
+                    snprintf(buf, sizeof(buf), fmt, te->id);
+                    Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, buf, -1));
+                    te = te->next;
+                }
+                Jim_SetResult(interp, listObj);
+            }
+            else if (argc == 3) {
+                id = JimParseAfterId(argv[2]);
+                if (id >= 0) {
+                    Jim_TimeEvent *e = JimFindTimeHandlerById(eventLoop, id);
+                    if (e && e->timeProc == JimAfterTimeHandler) {
+                        Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+                        Jim_ListAppendElement(interp, listObj, e->clientData);
+                        Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, e->initialms ? "timer" : "idle", -1));
+                        Jim_SetResult(interp, listObj);
+                        return JIM_OK;
+                    }
+                }
+                Jim_SetResultFormatted(interp, "event \"%#s\" doesn't exist", argv[2]);
+                return JIM_ERR;
+            }
+            else {
+                Jim_WrongNumArgs(interp, 2, argv, "?id?");
+                return JIM_ERR;
+            }
+            break;
+    }
+    return JIM_OK;
+}
+
+int Jim_eventloopInit(Jim_Interp *interp)
+{
+    Jim_EventLoop *eventLoop;
+
+    if (Jim_PackageProvide(interp, "eventloop", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    eventLoop = Jim_Alloc(sizeof(*eventLoop));
+    eventLoop->fileEventHead = NULL;
+    eventLoop->timeEventHead = NULL;
+    eventLoop->timeEventNextId = 1;
+    eventLoop->suppress_bgerror = 0;
+    Jim_SetAssocData(interp, "eventloop", JimELAssocDataDeleProc, eventLoop);
+
+    Jim_CreateCommand(interp, "vwait", JimELVwaitCommand, eventLoop, NULL);
+    Jim_CreateCommand(interp, "update", JimELUpdateCommand, eventLoop, NULL);
+    Jim_CreateCommand(interp, "after", JimELAfterCommand, eventLoop, NULL);
+
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-eventloop.h b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-eventloop.h
new file mode 100755
index 0000000..4da5408
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-eventloop.h
@@ -0,0 +1,87 @@
+/* Jim - A small embeddable Tcl interpreter
+ *
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
+ * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
+ * Copyright 2008 oharboe - �yvind Harboe - oyvind.harboe@zylin.com
+ * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
+ * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
+ * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ **/
+/* ------ USAGE -------
+ *
+ * In order to use this file from other extensions include it in every
+ * file where you need to call the eventloop API, also in the init
+ * function of your extension call Jim_ImportEventloopAPI(interp)
+ * after the Jim_InitExtension() call.
+ *
+ * See the UDP extension as example.
+ */
+
+
+#ifndef __JIM_EVENTLOOP_H__
+#define __JIM_EVENTLOOP_H__
+
+#include <stdio.h>
+
+typedef int Jim_FileProc(Jim_Interp *interp, void *clientData, int mask);
+typedef int Jim_SignalProc(Jim_Interp *interp, void *clientData, void *msg);
+typedef void Jim_TimeProc(Jim_Interp *interp, void *clientData);
+typedef void Jim_EventFinalizerProc(Jim_Interp *interp, void *clientData);
+
+/* File event structure */
+#define JIM_EVENT_READABLE 1
+#define JIM_EVENT_WRITABLE 2
+#define JIM_EVENT_EXCEPTION 4
+
+JIM_EXPORT void Jim_CreateFileHandler (Jim_Interp *interp,
+        FILE *handle, int mask,
+        Jim_FileProc *proc, void *clientData,
+        Jim_EventFinalizerProc *finalizerProc);
+JIM_EXPORT void Jim_DeleteFileHandler (Jim_Interp *interp,
+        FILE *handle);
+JIM_EXPORT jim_wide Jim_CreateTimeHandler (Jim_Interp *interp,
+        jim_wide milliseconds,
+        Jim_TimeProc *proc, void *clientData,
+        Jim_EventFinalizerProc *finalizerProc);
+JIM_EXPORT jim_wide Jim_DeleteTimeHandler (Jim_Interp *interp, jim_wide id);
+
+#define JIM_FILE_EVENTS 1
+#define JIM_TIME_EVENTS 2
+#define JIM_ALL_EVENTS (JIM_FILE_EVENTS|JIM_TIME_EVENTS)
+#define JIM_DONT_WAIT 4
+
+JIM_EXPORT int Jim_ProcessEvents (Jim_Interp *interp, int flags);
+JIM_EXPORT int Jim_EvalObjBackground (Jim_Interp *interp, Jim_Obj *scriptObjPtr);
+
+int Jim_eventloopInit(Jim_Interp *interp);
+
+#endif /* __JIM_EVENTLOOP_H__ */
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-exec.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-exec.c
new file mode 100755
index 0000000..9088156
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-exec.c
@@ -0,0 +1,1619 @@
+/*
+ * (c) 2008 Steve Bennett <steveb@workware.net.au>
+ *
+ * Implements the exec command for Jim
+ *
+ * Based on code originally from Tcl 6.7 by John Ousterhout.
+ * From that code:
+ *
+ * The Tcl_Fork and Tcl_WaitPids procedures are based on code
+ * contributed by Karl Lehenbauer, Mark Diekhans and Peter
+ * da Silva.
+ *
+ * Copyright 1987-1991 Regents of the University of California
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies.  The University of California
+ * makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+
+#if (!defined(HAVE_VFORK) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
+/* Poor man's implementation of exec with system()
+ * The system() call *may* do command line redirection, etc.
+ * The standard output is not available.
+ * Can't redirect filehandles.
+ */
+static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp);
+    int i, j;
+    int rc;
+
+    /* Create a quoted command line */
+    for (i = 1; i < argc; i++) {
+        int len;
+        const char *arg = Jim_GetString(argv[i], &len);
+
+        if (i > 1) {
+            Jim_AppendString(interp, cmdlineObj, " ", 1);
+        }
+        if (strpbrk(arg, "\\\" ") == NULL) {
+            /* No quoting required */
+            Jim_AppendString(interp, cmdlineObj, arg, len);
+            continue;
+        }
+
+        Jim_AppendString(interp, cmdlineObj, "\"", 1);
+        for (j = 0; j < len; j++) {
+            if (arg[j] == '\\' || arg[j] == '"') {
+                Jim_AppendString(interp, cmdlineObj, "\\", 1);
+            }
+            Jim_AppendString(interp, cmdlineObj, &arg[j], 1);
+        }
+        Jim_AppendString(interp, cmdlineObj, "\"", 1);
+    }
+    rc = system(Jim_String(cmdlineObj));
+
+    Jim_FreeNewObj(interp, cmdlineObj);
+
+    if (rc) {
+        Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
+        Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, 0));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, rc));
+        Jim_SetGlobalVariableStr(interp, "errorCode", errorCode);
+        return JIM_ERR;
+    }
+
+    return JIM_OK;
+}
+
+int Jim_execInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+    Jim_CreateCommand(interp, "exec", Jim_ExecCmd, NULL, NULL);
+    return JIM_OK;
+}
+#else
+/* Full exec implementation for unix and mingw */
+
+#include <errno.h>
+#include <signal.h>
+
+#define XXX printf("@%s:%d\n", __FILE__, __LINE__); fflush(stdout);
+
+#if defined(__MINGW32__)
+    /* XXX: Should we use this implementation for cygwin too? */
+    #include <fcntl.h>
+
+    typedef HANDLE fdtype;
+    typedef HANDLE pidtype;
+    #define JIM_BAD_FD INVALID_HANDLE_VALUE
+    #define JIM_BAD_PID INVALID_HANDLE_VALUE
+    #define JimCloseFd CloseHandle
+
+    #define WIFEXITED(STATUS) 1
+    #define WEXITSTATUS(STATUS) (STATUS)
+    #define WIFSIGNALED(STATUS) 0
+    #define WTERMSIG(STATUS) 0
+    #define WNOHANG 1
+
+    static fdtype JimFileno(FILE *fh);
+    static pidtype JimWaitPid(pidtype pid, int *status, int nohang);
+    static fdtype JimDupFd(fdtype infd);
+    static fdtype JimOpenForRead(const char *filename);
+    static FILE *JimFdOpenForRead(fdtype fd);
+    static int JimPipe(fdtype pipefd[2]);
+    static pidtype JimStartWinProcess(Jim_Interp *interp, char **argv, char *env,
+        fdtype inputId, fdtype outputId, fdtype errorId);
+    static int JimErrno(void);
+#else
+    #include "jim-signal.h"
+    #include <unistd.h>
+    #include <fcntl.h>
+    #include <sys/wait.h>
+
+    typedef int fdtype;
+    typedef int pidtype;
+    #define JimPipe pipe
+    #define JimErrno() errno
+    #define JIM_BAD_FD -1
+    #define JIM_BAD_PID -1
+    #define JimFileno fileno
+    #define JimReadFd read
+    #define JimCloseFd close
+    #define JimWaitPid waitpid
+    #define JimDupFd dup
+    #define JimFdOpenForRead(FD) fdopen((FD), "r")
+    #define JimOpenForRead(NAME) open((NAME), O_RDONLY, 0)
+#endif
+
+static const char *JimStrError(void);
+static char **JimSaveEnv(char **env);
+static void JimRestoreEnv(char **env);
+static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv,
+    pidtype **pidArrayPtr, fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr);
+static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr);
+static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, fdtype errorId);
+static fdtype JimCreateTemp(Jim_Interp *interp, const char *contents);
+static fdtype JimOpenForWrite(const char *filename, int append);
+static int JimRewindFd(fdtype fd);
+
+static void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
+{
+    Jim_SetResultFormatted(interp, "%s: %s", msg, JimStrError());
+}
+
+static const char *JimStrError(void)
+{
+    return strerror(JimErrno());
+}
+
+static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr)
+{
+    int len;
+    const char *s = Jim_GetString(objPtr, &len);
+
+    if (len > 0 && s[len - 1] == '\n') {
+        objPtr->length--;
+        objPtr->bytes[objPtr->length] = '\0';
+    }
+}
+
+/**
+ * Read from 'fd', append the data to strObj and close 'fd'.
+ * Returns JIM_OK if OK, or JIM_ERR on error.
+ */
+static int JimAppendStreamToString(Jim_Interp *interp, fdtype fd, Jim_Obj *strObj)
+{
+    char buf[256];
+    FILE *fh = JimFdOpenForRead(fd);
+    if (fh == NULL) {
+        return JIM_ERR;
+    }
+
+    while (1) {
+        int retval = fread(buf, 1, sizeof(buf), fh);
+        if (retval > 0) {
+            Jim_AppendString(interp, strObj, buf, retval);
+        }
+        if (retval != sizeof(buf)) {
+            break;
+        }
+    }
+    Jim_RemoveTrailingNewline(strObj);
+    fclose(fh);
+    return JIM_OK;
+}
+
+/*
+ * If the last character of the result is a newline, then remove
+ * the newline character (the newline would just confuse things).
+ *
+ * Note: Ideally we could do this by just reducing the length of stringrep
+ *       by 1, but there is no API for this :-(
+ */
+static void JimTrimTrailingNewline(Jim_Interp *interp)
+{
+    int len;
+    const char *p = Jim_GetString(Jim_GetResult(interp), &len);
+
+    if (len > 0 && p[len - 1] == '\n') {
+        Jim_SetResultString(interp, p, len - 1);
+    }
+}
+
+/**
+ * Builds the environment array from $::env
+ *
+ * If $::env is not set, simply returns environ.
+ *
+ * Otherwise allocates the environ array from the contents of $::env
+ *
+ * If the exec fails, memory can be freed via JimFreeEnv()
+ */
+static char **JimBuildEnv(Jim_Interp *interp)
+{
+#if defined(jim_ext_tclcompat)
+    int i;
+    int size;
+    int num;
+    int n;
+    char **envptr;
+    char *envdata;
+
+    Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, "env", JIM_NONE);
+
+    if (!objPtr) {
+        return Jim_GetEnviron();
+    }
+
+    /* We build the array as a single block consisting of the pointers followed by
+     * the strings. This has the advantage of being easy to allocate/free and being
+     * compatible with both unix and windows
+     */
+
+    /* Calculate the required size */
+    num = Jim_ListLength(interp, objPtr);
+    if (num % 2) {
+        num--;
+    }
+    size = Jim_Length(objPtr);
+    /* We need one \0 and one equal sign for each element.
+     * A list has at least one space for each element except the first.
+     * We only need one extra char for the extra null terminator.
+     */
+    size++;
+
+    envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size);
+    envdata = (char *)&envptr[num / 2 + 1];
+
+    n = 0;
+    for (i = 0; i < num; i += 2) {
+        const char *s1, *s2;
+        Jim_Obj *elemObj;
+
+        Jim_ListIndex(interp, objPtr, i, &elemObj, JIM_NONE);
+        s1 = Jim_String(elemObj);
+        Jim_ListIndex(interp, objPtr, i + 1, &elemObj, JIM_NONE);
+        s2 = Jim_String(elemObj);
+
+        envptr[n] = envdata;
+        envdata += sprintf(envdata, "%s=%s", s1, s2);
+        envdata++;
+        n++;
+    }
+    envptr[n] = NULL;
+    *envdata = 0;
+
+    return envptr;
+#else
+    return Jim_GetEnviron();
+#endif
+}
+
+/**
+ * Frees the environment allocated by JimBuildEnv()
+ *
+ * Must pass original_environ.
+ */
+static void JimFreeEnv(char **env, char **original_environ)
+{
+#ifdef jim_ext_tclcompat
+    if (env != original_environ) {
+        Jim_Free(env);
+    }
+#endif
+}
+
+/*
+ * Create error messages for unusual process exits.  An
+ * extra newline gets appended to each error message, but
+ * it gets removed below (in the same fashion that an
+ * extra newline in the command's output is removed).
+ */
+static int JimCheckWaitStatus(Jim_Interp *interp, pidtype pid, int waitStatus)
+{
+    Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
+    int rc = JIM_ERR;
+
+    if (WIFEXITED(waitStatus)) {
+        if (WEXITSTATUS(waitStatus) == 0) {
+            Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "NONE", -1));
+            rc = JIM_OK;
+        }
+        else {
+            Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
+            Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
+            Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WEXITSTATUS(waitStatus)));
+        }
+    }
+    else {
+        const char *type;
+        const char *action;
+
+        if (WIFSIGNALED(waitStatus)) {
+            type = "CHILDKILLED";
+            action = "killed";
+        }
+        else {
+            type = "CHILDSUSP";
+            action = "suspended";
+        }
+
+        Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, type, -1));
+
+#ifdef jim_ext_signal
+        Jim_SetResultFormatted(interp, "child %s by signal %s", action, Jim_SignalId(WTERMSIG(waitStatus)));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, Jim_SignalId(WTERMSIG(waitStatus)), -1));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, Jim_SignalName(WTERMSIG(waitStatus)), -1));
+#else
+        Jim_SetResultFormatted(interp, "child %s by signal %d", action, WTERMSIG(waitStatus));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WTERMSIG(waitStatus)));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WTERMSIG(waitStatus)));
+#endif
+    }
+    Jim_SetGlobalVariableStr(interp, "errorCode", errorCode);
+    return rc;
+}
+
+/*
+ * Data structures of the following type are used by JimFork and
+ * JimWaitPids to keep track of child processes.
+ */
+
+struct WaitInfo
+{
+    pidtype pid;                    /* Process id of child. */
+    int status;                 /* Status returned when child exited or suspended. */
+    int flags;                  /* Various flag bits;  see below for definitions. */
+};
+
+struct WaitInfoTable {
+    struct WaitInfo *info;
+    int size;
+    int used;
+};
+
+/*
+ * Flag bits in WaitInfo structures:
+ *
+ * WI_DETACHED -        Non-zero means no-one cares about the
+ *                      process anymore.  Ignore it until it
+ *                      exits, then forget about it.
+ */
+
+#define WI_DETACHED 2
+
+#define WAIT_TABLE_GROW_BY 4
+
+static void JimFreeWaitInfoTable(struct Jim_Interp *interp, void *privData)
+{
+    struct WaitInfoTable *table = privData;
+
+    Jim_Free(table->info);
+    Jim_Free(table);
+}
+
+static struct WaitInfoTable *JimAllocWaitInfoTable(void)
+{
+    struct WaitInfoTable *table = Jim_Alloc(sizeof(*table));
+    table->info = NULL;
+    table->size = table->used = 0;
+
+    return table;
+}
+
+/*
+ * The main [exec] command
+ */
+static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    fdtype outputId;               /* File id for output pipe.  -1
+                                 * means command overrode. */
+    fdtype errorId;                /* File id for temporary file
+                                 * containing error output. */
+    pidtype *pidPtr;
+    int numPids, result;
+
+    /*
+     * See if the command is to be run in background;  if so, create
+     * the command, detach it, and return.
+     */
+    if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) {
+        Jim_Obj *listObj;
+        int i;
+
+        argc--;
+        numPids = JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, NULL, NULL);
+        if (numPids < 0) {
+            return JIM_ERR;
+        }
+        /* The return value is a list of the pids */
+        listObj = Jim_NewListObj(interp, NULL, 0);
+        for (i = 0; i < numPids; i++) {
+            Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, (long)pidPtr[i]));
+        }
+        Jim_SetResult(interp, listObj);
+        JimDetachPids(interp, numPids, pidPtr);
+        Jim_Free(pidPtr);
+        return JIM_OK;
+    }
+
+    /*
+     * Create the command's pipeline.
+     */
+    numPids =
+        JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, &outputId, &errorId);
+
+    if (numPids < 0) {
+        return JIM_ERR;
+    }
+
+    /*
+     * Read the child's output (if any) and put it into the result.
+     */
+    Jim_SetResultString(interp, "", 0);
+
+    result = JIM_OK;
+    if (outputId != JIM_BAD_FD) {
+        result = JimAppendStreamToString(interp, outputId, Jim_GetResult(interp));
+        if (result < 0) {
+            Jim_SetResultErrno(interp, "error reading from output pipe");
+        }
+    }
+
+    if (JimCleanupChildren(interp, numPids, pidPtr, errorId) != JIM_OK) {
+        result = JIM_ERR;
+    }
+    return result;
+}
+
+static void JimReapDetachedPids(struct WaitInfoTable *table)
+{
+    struct WaitInfo *waitPtr;
+    int count;
+
+    if (!table) {
+        return;
+    }
+
+    for (waitPtr = table->info, count = table->used; count > 0; waitPtr++, count--) {
+        if (waitPtr->flags & WI_DETACHED) {
+            int status;
+            pidtype pid = JimWaitPid(waitPtr->pid, &status, WNOHANG);
+            if (pid != JIM_BAD_PID) {
+                if (waitPtr != &table->info[table->used - 1]) {
+                    *waitPtr = table->info[table->used - 1];
+                }
+                table->used--;
+            }
+        }
+    }
+}
+
+/**
+ * Does waitpid() on the given pid, and then removes the
+ * entry from the wait table.
+ *
+ * Returns the pid if OK and updates *statusPtr with the status,
+ * or JIM_BAD_PID if the pid was not in the table.
+ */
+static pidtype JimWaitForProcess(struct WaitInfoTable *table, pidtype pid, int *statusPtr)
+{
+    int i;
+
+    /* Find it in the table */
+    for (i = 0; i < table->used; i++) {
+        if (pid == table->info[i].pid) {
+            /* wait for it */
+            JimWaitPid(pid, statusPtr, 0);
+
+            /* Remove it from the table */
+            if (i != table->used - 1) {
+                table->info[i] = table->info[table->used - 1];
+            }
+            table->used--;
+            return pid;
+        }
+    }
+
+    /* Not found */
+    return JIM_BAD_PID;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * JimDetachPids --
+ *
+ *  This procedure is called to indicate that one or more child
+ *  processes have been placed in background and are no longer
+ *  cared about.  These children can be cleaned up with JimReapDetachedPids().
+ *
+ * Results:
+ *  None.
+ *
+ * Side effects:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr)
+{
+    int j;
+    struct WaitInfoTable *table = Jim_CmdPrivData(interp);
+
+    for (j = 0; j < numPids; j++) {
+        /* Find it in the table */
+        int i;
+        for (i = 0; i < table->used; i++) {
+            if (pidPtr[j] == table->info[i].pid) {
+                table->info[i].flags |= WI_DETACHED;
+                break;
+            }
+        }
+    }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * JimCreatePipeline --
+ *
+ *  Given an argc/argv array, instantiate a pipeline of processes
+ *  as described by the argv.
+ *
+ * Results:
+ *  The return value is a count of the number of new processes
+ *  created, or -1 if an error occurred while creating the pipeline.
+ *  *pidArrayPtr is filled in with the address of a dynamically
+ *  allocated array giving the ids of all of the processes.  It
+ *  is up to the caller to free this array when it isn't needed
+ *  anymore.  If inPipePtr is non-NULL, *inPipePtr is filled in
+ *  with the file id for the input pipe for the pipeline (if any):
+ *  the caller must eventually close this file.  If outPipePtr
+ *  isn't NULL, then *outPipePtr is filled in with the file id
+ *  for the output pipe from the pipeline:  the caller must close
+ *  this file.  If errFilePtr isn't NULL, then *errFilePtr is filled
+ *  with a file id that may be used to read error output after the
+ *  pipeline completes.
+ *
+ * Side effects:
+ *  Processes and pipes are created.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, pidtype **pidArrayPtr,
+    fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr)
+{
+    pidtype *pidPtr = NULL;         /* Points to malloc-ed array holding all
+                                 * the pids of child processes. */
+    int numPids = 0;            /* Actual number of processes that exist
+                                 * at *pidPtr right now. */
+    int cmdCount;               /* Count of number of distinct commands
+                                 * found in argc/argv. */
+    const char *input = NULL;   /* Describes input for pipeline, depending
+                                 * on "inputFile".  NULL means take input
+                                 * from stdin/pipe. */
+
+#define FILE_NAME   0           /* input/output: filename */
+#define FILE_APPEND 1           /* output only:  filename, append */
+#define FILE_HANDLE 2           /* input/output: filehandle */
+#define FILE_TEXT   3           /* input only:   input is actual text */
+
+    int inputFile = FILE_NAME;  /* 1 means input is name of input file.
+                                 * 2 means input is filehandle name.
+                                 * 0 means input holds actual
+                                 * text to be input to command. */
+
+    int outputFile = FILE_NAME; /* 0 means output is the name of output file.
+                                 * 1 means output is the name of output file, and append.
+                                 * 2 means output is filehandle name.
+                                 * All this is ignored if output is NULL
+                                 */
+    int errorFile = FILE_NAME;  /* 0 means error is the name of error file.
+                                 * 1 means error is the name of error file, and append.
+                                 * 2 means error is filehandle name.
+                                 * All this is ignored if error is NULL
+                                 */
+    const char *output = NULL;  /* Holds name of output file to pipe to,
+                                 * or NULL if output goes to stdout/pipe. */
+    const char *error = NULL;   /* Holds name of stderr file to pipe to,
+                                 * or NULL if stderr goes to stderr/pipe. */
+    fdtype inputId = JIM_BAD_FD;
+                                 /* Readable file id input to current command in
+                                 * pipeline (could be file or pipe).  JIM_BAD_FD
+                                 * means use stdin. */
+    fdtype outputId = JIM_BAD_FD;
+                                 /* Writable file id for output from current
+                                 * command in pipeline (could be file or pipe).
+                                 * JIM_BAD_FD means use stdout. */
+    fdtype errorId = JIM_BAD_FD;
+                                 /* Writable file id for all standard error
+                                 * output from all commands in pipeline.  JIM_BAD_FD
+                                 * means use stderr. */
+    fdtype lastOutputId = JIM_BAD_FD;
+                                 /* Write file id for output from last command
+                                 * in pipeline (could be file or pipe).
+                                 * -1 means use stdout. */
+    fdtype pipeIds[2];           /* File ids for pipe that's being created. */
+    int firstArg, lastArg;      /* Indexes of first and last arguments in
+                                 * current command. */
+    int lastBar;
+    int i;
+    pidtype pid;
+    char **save_environ;
+    struct WaitInfoTable *table = Jim_CmdPrivData(interp);
+
+    /* Holds the args which will be used to exec */
+    char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1));
+    int arg_count = 0;
+
+    JimReapDetachedPids(table);
+
+    if (inPipePtr != NULL) {
+        *inPipePtr = JIM_BAD_FD;
+    }
+    if (outPipePtr != NULL) {
+        *outPipePtr = JIM_BAD_FD;
+    }
+    if (errFilePtr != NULL) {
+        *errFilePtr = JIM_BAD_FD;
+    }
+    pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
+
+    /*
+     * First, scan through all the arguments to figure out the structure
+     * of the pipeline.  Count the number of distinct processes (it's the
+     * number of "|" arguments).  If there are "<", "<<", or ">" arguments
+     * then make note of input and output redirection and remove these
+     * arguments and the arguments that follow them.
+     */
+    cmdCount = 1;
+    lastBar = -1;
+    for (i = 0; i < argc; i++) {
+        const char *arg = Jim_String(argv[i]);
+
+        if (arg[0] == '<') {
+            inputFile = FILE_NAME;
+            input = arg + 1;
+            if (*input == '<') {
+                inputFile = FILE_TEXT;
+                input++;
+            }
+            else if (*input == '@') {
+                inputFile = FILE_HANDLE;
+                input++;
+            }
+
+            if (!*input && ++i < argc) {
+                input = Jim_String(argv[i]);
+            }
+        }
+        else if (arg[0] == '>') {
+            int dup_error = 0;
+
+            outputFile = FILE_NAME;
+
+            output = arg + 1;
+            if (*output == '>') {
+                outputFile = FILE_APPEND;
+                output++;
+            }
+            if (*output == '&') {
+                /* Redirect stderr too */
+                output++;
+                dup_error = 1;
+            }
+            if (*output == '@') {
+                outputFile = FILE_HANDLE;
+                output++;
+            }
+            if (!*output && ++i < argc) {
+                output = Jim_String(argv[i]);
+            }
+            if (dup_error) {
+                errorFile = outputFile;
+                error = output;
+            }
+        }
+        else if (arg[0] == '2' && arg[1] == '>') {
+            error = arg + 2;
+            errorFile = FILE_NAME;
+
+            if (*error == '@') {
+                errorFile = FILE_HANDLE;
+                error++;
+            }
+            else if (*error == '>') {
+                errorFile = FILE_APPEND;
+                error++;
+            }
+            if (!*error && ++i < argc) {
+                error = Jim_String(argv[i]);
+            }
+        }
+        else {
+            if (strcmp(arg, "|") == 0 || strcmp(arg, "|&") == 0) {
+                if (i == lastBar + 1 || i == argc - 1) {
+                    Jim_SetResultString(interp, "illegal use of | or |& in command", -1);
+                    goto badargs;
+                }
+                lastBar = i;
+                cmdCount++;
+            }
+            /* Either |, |& or a "normal" arg, so store it in the arg array */
+            arg_array[arg_count++] = (char *)arg;
+            continue;
+        }
+
+        if (i >= argc) {
+            Jim_SetResultFormatted(interp, "can't specify \"%s\" as last word in command", arg);
+            goto badargs;
+        }
+    }
+
+    if (arg_count == 0) {
+        Jim_SetResultString(interp, "didn't specify command to execute", -1);
+badargs:
+        Jim_Free(arg_array);
+        return -1;
+    }
+
+    /* Must do this before vfork(), so do it now */
+    save_environ = JimSaveEnv(JimBuildEnv(interp));
+
+    /*
+     * Set up the redirected input source for the pipeline, if
+     * so requested.
+     */
+    if (input != NULL) {
+        if (inputFile == FILE_TEXT) {
+            /*
+             * Immediate data in command.  Create temporary file and
+             * put data into file.
+             */
+            inputId = JimCreateTemp(interp, input);
+            if (inputId == JIM_BAD_FD) {
+                goto error;
+            }
+        }
+        else if (inputFile == FILE_HANDLE) {
+            /* Should be a file descriptor */
+            Jim_Obj *fhObj = Jim_NewStringObj(interp, input, -1);
+            FILE *fh = Jim_AioFilehandle(interp, fhObj);
+
+            Jim_FreeNewObj(interp, fhObj);
+            if (fh == NULL) {
+                goto error;
+            }
+            inputId = JimDupFd(JimFileno(fh));
+        }
+        else {
+            /*
+             * File redirection.  Just open the file.
+             */
+            inputId = JimOpenForRead(input);
+            if (inputId == JIM_BAD_FD) {
+                Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", input, JimStrError());
+                goto error;
+            }
+        }
+    }
+    else if (inPipePtr != NULL) {
+        if (JimPipe(pipeIds) != 0) {
+            Jim_SetResultErrno(interp, "couldn't create input pipe for command");
+            goto error;
+        }
+        inputId = pipeIds[0];
+        *inPipePtr = pipeIds[1];
+        pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
+    }
+
+    /*
+     * Set up the redirected output sink for the pipeline from one
+     * of two places, if requested.
+     */
+    if (output != NULL) {
+        if (outputFile == FILE_HANDLE) {
+            Jim_Obj *fhObj = Jim_NewStringObj(interp, output, -1);
+            FILE *fh = Jim_AioFilehandle(interp, fhObj);
+
+            Jim_FreeNewObj(interp, fhObj);
+            if (fh == NULL) {
+                goto error;
+            }
+            fflush(fh);
+            lastOutputId = JimDupFd(JimFileno(fh));
+        }
+        else {
+            /*
+             * Output is to go to a file.
+             */
+            lastOutputId = JimOpenForWrite(output, outputFile == FILE_APPEND);
+            if (lastOutputId == JIM_BAD_FD) {
+                Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", output, JimStrError());
+                goto error;
+            }
+        }
+    }
+    else if (outPipePtr != NULL) {
+        /*
+         * Output is to go to a pipe.
+         */
+        if (JimPipe(pipeIds) != 0) {
+            Jim_SetResultErrno(interp, "couldn't create output pipe");
+            goto error;
+        }
+        lastOutputId = pipeIds[1];
+        *outPipePtr = pipeIds[0];
+        pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
+    }
+    /* If we are redirecting stderr with 2>filename or 2>@fileId, then we ignore errFilePtr */
+    if (error != NULL) {
+        if (errorFile == FILE_HANDLE) {
+            if (strcmp(error, "1") == 0) {
+                /* Special 2>@1 */
+                if (lastOutputId != JIM_BAD_FD) {
+                    errorId = JimDupFd(lastOutputId);
+                }
+                else {
+                    /* No redirection of stdout, so just use 2>@stdout */
+                    error = "stdout";
+                }
+            }
+            if (errorId == JIM_BAD_FD) {
+                Jim_Obj *fhObj = Jim_NewStringObj(interp, error, -1);
+                FILE *fh = Jim_AioFilehandle(interp, fhObj);
+
+                Jim_FreeNewObj(interp, fhObj);
+                if (fh == NULL) {
+                    goto error;
+                }
+                fflush(fh);
+                errorId = JimDupFd(JimFileno(fh));
+            }
+        }
+        else {
+            /*
+             * Output is to go to a file.
+             */
+            errorId = JimOpenForWrite(error, errorFile == FILE_APPEND);
+            if (errorId == JIM_BAD_FD) {
+                Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", error, JimStrError());
+                goto error;
+            }
+        }
+    }
+    else if (errFilePtr != NULL) {
+        /*
+         * Set up the standard error output sink for the pipeline, if
+         * requested.  Use a temporary file which is opened, then deleted.
+         * Could potentially just use pipe, but if it filled up it could
+         * cause the pipeline to deadlock:  we'd be waiting for processes
+         * to complete before reading stderr, and processes couldn't complete
+         * because stderr was backed up.
+         */
+        errorId = JimCreateTemp(interp, NULL);
+        if (errorId == JIM_BAD_FD) {
+            goto error;
+        }
+        *errFilePtr = JimDupFd(errorId);
+    }
+
+    /*
+     * Scan through the argc array, forking off a process for each
+     * group of arguments between "|" arguments.
+     */
+
+    pidPtr = Jim_Alloc(cmdCount * sizeof(*pidPtr));
+    for (i = 0; i < numPids; i++) {
+        pidPtr[i] = JIM_BAD_PID;
+    }
+    for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg + 1) {
+        int pipe_dup_err = 0;
+        fdtype origErrorId = errorId;
+
+        for (lastArg = firstArg; lastArg < arg_count; lastArg++) {
+            if (arg_array[lastArg][0] == '|') {
+                if (arg_array[lastArg][1] == '&') {
+                    pipe_dup_err = 1;
+                }
+                break;
+            }
+        }
+        /* Replace | with NULL for execv() */
+        arg_array[lastArg] = NULL;
+        if (lastArg == arg_count) {
+            outputId = lastOutputId;
+        }
+        else {
+            if (JimPipe(pipeIds) != 0) {
+                Jim_SetResultErrno(interp, "couldn't create pipe");
+                goto error;
+            }
+            outputId = pipeIds[1];
+        }
+
+        /* Now fork the child */
+
+#ifdef __MINGW32__
+        pid = JimStartWinProcess(interp, &arg_array[firstArg], save_environ ? save_environ[0] : NULL, inputId, outputId, errorId);
+        if (pid == JIM_BAD_PID) {
+            Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]);
+            goto error;
+        }
+#else
+        /*
+         * Disable SIGPIPE signals:  if they were allowed, this process
+         * might go away unexpectedly if children misbehave.  This code
+         * can potentially interfere with other application code that
+         * expects to handle SIGPIPEs;  what's really needed is an
+         * arbiter for signals to allow them to be "shared".
+         */
+        if (table->info == NULL) {
+            (void)signal(SIGPIPE, SIG_IGN);
+        }
+
+        /* Need to do this befor vfork() */
+        if (pipe_dup_err) {
+            errorId = outputId;
+        }
+
+        /*
+         * Make a new process and enter it into the table if the fork
+         * is successful.
+         */
+        pid = vfork();
+        if (pid < 0) {
+            Jim_SetResultErrno(interp, "couldn't fork child process");
+            goto error;
+        }
+        if (pid == 0) {
+            /* Child */
+
+            if (inputId != -1) dup2(inputId, 0);
+            if (outputId != -1) dup2(outputId, 1);
+            if (errorId != -1) dup2(errorId, 2);
+
+            for (i = 3; (i <= outputId) || (i <= inputId) || (i <= errorId); i++) {
+                close(i);
+            }
+
+            execvp(arg_array[firstArg], &arg_array[firstArg]);
+
+            /* Need to prep an error message before vfork(), just in case */
+            fprintf(stderr, "couldn't exec \"%s\"", arg_array[firstArg]);
+            _exit(127);
+        }
+#endif
+
+        /* parent */
+
+        /*
+         * Enlarge the wait table if there isn't enough space for a new
+         * entry.
+         */
+        if (table->used == table->size) {
+            table->size += WAIT_TABLE_GROW_BY;
+            table->info = Jim_Realloc(table->info, table->size * sizeof(*table->info));
+        }
+
+        table->info[table->used].pid = pid;
+        table->info[table->used].flags = 0;
+        table->used++;
+
+        pidPtr[numPids] = pid;
+
+        /* Restore in case of pipe_dup_err */
+        errorId = origErrorId;
+
+        /*
+         * Close off our copies of file descriptors that were set up for
+         * this child, then set up the input for the next child.
+         */
+
+        if (inputId != JIM_BAD_FD) {
+            JimCloseFd(inputId);
+        }
+        if (outputId != JIM_BAD_FD) {
+            JimCloseFd(outputId);
+        }
+        inputId = pipeIds[0];
+        pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
+    }
+    *pidArrayPtr = pidPtr;
+
+    /*
+     * All done.  Cleanup open files lying around and then return.
+     */
+
+  cleanup:
+    if (inputId != JIM_BAD_FD) {
+        JimCloseFd(inputId);
+    }
+    if (lastOutputId != JIM_BAD_FD) {
+        JimCloseFd(lastOutputId);
+    }
+    if (errorId != JIM_BAD_FD) {
+        JimCloseFd(errorId);
+    }
+    Jim_Free(arg_array);
+
+    JimRestoreEnv(save_environ);
+
+    return numPids;
+
+    /*
+     * An error occurred.  There could have been extra files open, such
+     * as pipes between children.  Clean them all up.  Detach any child
+     * processes that have been created.
+     */
+
+  error:
+    if ((inPipePtr != NULL) && (*inPipePtr != JIM_BAD_FD)) {
+        JimCloseFd(*inPipePtr);
+        *inPipePtr = JIM_BAD_FD;
+    }
+    if ((outPipePtr != NULL) && (*outPipePtr != JIM_BAD_FD)) {
+        JimCloseFd(*outPipePtr);
+        *outPipePtr = JIM_BAD_FD;
+    }
+    if ((errFilePtr != NULL) && (*errFilePtr != JIM_BAD_FD)) {
+        JimCloseFd(*errFilePtr);
+        *errFilePtr = JIM_BAD_FD;
+    }
+    if (pipeIds[0] != JIM_BAD_FD) {
+        JimCloseFd(pipeIds[0]);
+    }
+    if (pipeIds[1] != JIM_BAD_FD) {
+        JimCloseFd(pipeIds[1]);
+    }
+    if (pidPtr != NULL) {
+        for (i = 0; i < numPids; i++) {
+            if (pidPtr[i] != JIM_BAD_PID) {
+                JimDetachPids(interp, 1, &pidPtr[i]);
+            }
+        }
+        Jim_Free(pidPtr);
+    }
+    numPids = -1;
+    goto cleanup;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * JimCleanupChildren --
+ *
+ *  This is a utility procedure used to wait for child processes
+ *  to exit, record information about abnormal exits, and then
+ *  collect any stderr output generated by them.
+ *
+ * Results:
+ *  The return value is a standard Tcl result.  If anything at
+ *  weird happened with the child processes, JIM_ERROR is returned
+ *  and a message is left in interp->result.
+ *
+ * Side effects:
+ *  If the last character of interp->result is a newline, then it
+ *  is removed.  File errorId gets closed, and pidPtr is freed
+ *  back to the storage allocator.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, fdtype errorId)
+{
+    struct WaitInfoTable *table = Jim_CmdPrivData(interp);
+    int result = JIM_OK;
+    int i;
+
+    for (i = 0; i < numPids; i++) {
+        int waitStatus = 0;
+        if (JimWaitForProcess(table, pidPtr[i], &waitStatus) != JIM_BAD_PID) {
+            if (JimCheckWaitStatus(interp, pidPtr[i], waitStatus) != JIM_OK) {
+                result = JIM_ERR;
+            }
+        }
+    }
+    Jim_Free(pidPtr);
+
+    /*
+     * Read the standard error file.  If there's anything there,
+     * then add the file's contents to the result
+     * string.
+     */
+    if (errorId != JIM_BAD_FD) {
+        JimRewindFd(errorId);
+        if (JimAppendStreamToString(interp, errorId, Jim_GetResult(interp)) != JIM_OK) {
+            result = JIM_ERR;
+        }
+    }
+
+    JimTrimTrailingNewline(interp);
+
+    return result;
+}
+
+int Jim_execInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+    Jim_CreateCommand(interp, "exec", Jim_ExecCmd, JimAllocWaitInfoTable(), JimFreeWaitInfoTable);
+    return JIM_OK;
+}
+
+#if defined(__MINGW32__)
+/* Windows-specific (mingw) implementation */
+
+static SECURITY_ATTRIBUTES *JimStdSecAttrs(void)
+{
+    static SECURITY_ATTRIBUTES secAtts;
+
+    secAtts.nLength = sizeof(SECURITY_ATTRIBUTES);
+    secAtts.lpSecurityDescriptor = NULL;
+    secAtts.bInheritHandle = TRUE;
+    return &secAtts;
+}
+
+static int JimErrno(void)
+{
+    switch (GetLastError()) {
+    case ERROR_FILE_NOT_FOUND: return ENOENT;
+    case ERROR_PATH_NOT_FOUND: return ENOENT;
+    case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
+    case ERROR_ACCESS_DENIED: return EACCES;
+    case ERROR_INVALID_HANDLE: return EBADF;
+    case ERROR_BAD_ENVIRONMENT: return E2BIG;
+    case ERROR_BAD_FORMAT: return ENOEXEC;
+    case ERROR_INVALID_ACCESS: return EACCES;
+    case ERROR_INVALID_DRIVE: return ENOENT;
+    case ERROR_CURRENT_DIRECTORY: return EACCES;
+    case ERROR_NOT_SAME_DEVICE: return EXDEV;
+    case ERROR_NO_MORE_FILES: return ENOENT;
+    case ERROR_WRITE_PROTECT: return EROFS;
+    case ERROR_BAD_UNIT: return ENXIO;
+    case ERROR_NOT_READY: return EBUSY;
+    case ERROR_BAD_COMMAND: return EIO;
+    case ERROR_CRC: return EIO;
+    case ERROR_BAD_LENGTH: return EIO;
+    case ERROR_SEEK: return EIO;
+    case ERROR_WRITE_FAULT: return EIO;
+    case ERROR_READ_FAULT: return EIO;
+    case ERROR_GEN_FAILURE: return EIO;
+    case ERROR_SHARING_VIOLATION: return EACCES;
+    case ERROR_LOCK_VIOLATION: return EACCES;
+    case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE;
+    case ERROR_HANDLE_DISK_FULL: return ENOSPC;
+    case ERROR_NOT_SUPPORTED: return ENODEV;
+    case ERROR_REM_NOT_LIST: return EBUSY;
+    case ERROR_DUP_NAME: return EEXIST;
+    case ERROR_BAD_NETPATH: return ENOENT;
+    case ERROR_NETWORK_BUSY: return EBUSY;
+    case ERROR_DEV_NOT_EXIST: return ENODEV;
+    case ERROR_TOO_MANY_CMDS: return EAGAIN;
+    case ERROR_ADAP_HDW_ERR: return EIO;
+    case ERROR_BAD_NET_RESP: return EIO;
+    case ERROR_UNEXP_NET_ERR: return EIO;
+    case ERROR_NETNAME_DELETED: return ENOENT;
+    case ERROR_NETWORK_ACCESS_DENIED: return EACCES;
+    case ERROR_BAD_DEV_TYPE: return ENODEV;
+    case ERROR_BAD_NET_NAME: return ENOENT;
+    case ERROR_TOO_MANY_NAMES: return ENFILE;
+    case ERROR_TOO_MANY_SESS: return EIO;
+    case ERROR_SHARING_PAUSED: return EAGAIN;
+    case ERROR_REDIR_PAUSED: return EAGAIN;
+    case ERROR_FILE_EXISTS: return EEXIST;
+    case ERROR_CANNOT_MAKE: return ENOSPC;
+    case ERROR_OUT_OF_STRUCTURES: return ENFILE;
+    case ERROR_ALREADY_ASSIGNED: return EEXIST;
+    case ERROR_INVALID_PASSWORD: return EPERM;
+    case ERROR_NET_WRITE_FAULT: return EIO;
+    case ERROR_NO_PROC_SLOTS: return EAGAIN;
+    case ERROR_DISK_CHANGE: return EXDEV;
+    case ERROR_BROKEN_PIPE: return EPIPE;
+    case ERROR_OPEN_FAILED: return ENOENT;
+    case ERROR_DISK_FULL: return ENOSPC;
+    case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE;
+    case ERROR_INVALID_TARGET_HANDLE: return EBADF;
+    case ERROR_INVALID_NAME: return ENOENT;
+    case ERROR_PROC_NOT_FOUND: return ESRCH;
+    case ERROR_WAIT_NO_CHILDREN: return ECHILD;
+    case ERROR_CHILD_NOT_COMPLETE: return ECHILD;
+    case ERROR_DIRECT_ACCESS_HANDLE: return EBADF;
+    case ERROR_SEEK_ON_DEVICE: return ESPIPE;
+    case ERROR_BUSY_DRIVE: return EAGAIN;
+    case ERROR_DIR_NOT_EMPTY: return EEXIST;
+    case ERROR_NOT_LOCKED: return EACCES;
+    case ERROR_BAD_PATHNAME: return ENOENT;
+    case ERROR_LOCK_FAILED: return EACCES;
+    case ERROR_ALREADY_EXISTS: return EEXIST;
+    case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG;
+    case ERROR_BAD_PIPE: return EPIPE;
+    case ERROR_PIPE_BUSY: return EAGAIN;
+    case ERROR_PIPE_NOT_CONNECTED: return EPIPE;
+    case ERROR_DIRECTORY: return ENOTDIR;
+    }
+    return EINVAL;
+}
+
+static int JimPipe(fdtype pipefd[2])
+{
+    if (CreatePipe(&pipefd[0], &pipefd[1], NULL, 0)) {
+        return 0;
+    }
+    return -1;
+}
+
+static fdtype JimDupFd(fdtype infd)
+{
+    fdtype dupfd;
+    pidtype pid = GetCurrentProcess();
+
+    if (DuplicateHandle(pid, infd, pid, &dupfd, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
+        return dupfd;
+    }
+    return JIM_BAD_FD;
+}
+
+static int JimRewindFd(fdtype fd)
+{
+    return SetFilePointer(fd, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER ? -1 : 0;
+}
+
+#if 0
+static int JimReadFd(fdtype fd, char *buffer, size_t len)
+{
+    DWORD num;
+
+    if (ReadFile(fd, buffer, len, &num, NULL)) {
+        return num;
+    }
+    if (GetLastError() == ERROR_HANDLE_EOF || GetLastError() == ERROR_BROKEN_PIPE) {
+        return 0;
+    }
+    return -1;
+}
+#endif
+
+static FILE *JimFdOpenForRead(fdtype fd)
+{
+    return _fdopen(_open_osfhandle((int)fd, _O_RDONLY | _O_TEXT), "r");
+}
+
+static fdtype JimFileno(FILE *fh)
+{
+    return (fdtype)_get_osfhandle(_fileno(fh));
+}
+
+static fdtype JimOpenForRead(const char *filename)
+{
+    return CreateFile(filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+        JimStdSecAttrs(), OPEN_EXISTING, 0, NULL);
+}
+
+static fdtype JimOpenForWrite(const char *filename, int append)
+{
+    return CreateFile(filename, append ? FILE_APPEND_DATA : GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+        JimStdSecAttrs(), append ? OPEN_ALWAYS : CREATE_ALWAYS, 0, (HANDLE) NULL);
+}
+
+static FILE *JimFdOpenForWrite(fdtype fd)
+{
+    return _fdopen(_open_osfhandle((int)fd, _O_TEXT), "w");
+}
+
+static pidtype JimWaitPid(pidtype pid, int *status, int nohang)
+{
+    DWORD ret = WaitForSingleObject(pid, nohang ? 0 : INFINITE);
+    if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) {
+        /* WAIT_TIMEOUT can only happend with WNOHANG */
+        return JIM_BAD_PID;
+    }
+    GetExitCodeProcess(pid, &ret);
+    *status = ret;
+    CloseHandle(pid);
+    return pid;
+}
+
+static HANDLE JimCreateTemp(Jim_Interp *interp, const char *contents)
+{
+    char name[MAX_PATH];
+    HANDLE handle;
+
+    if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, "JIM", 0, name)) {
+        return JIM_BAD_FD;
+    }
+
+    handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, JimStdSecAttrs(),
+            CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
+            NULL);
+
+    if (handle == INVALID_HANDLE_VALUE) {
+        goto error;
+    }
+
+    if (contents != NULL) {
+        /* Use fdopen() to get automatic text-mode translation */
+        FILE *fh = JimFdOpenForWrite(JimDupFd(handle));
+        if (fh == NULL) {
+            goto error;
+        }
+
+        if (fwrite(contents, strlen(contents), 1, fh) != 1) {
+            fclose(fh);
+            goto error;
+        }
+        fseek(fh, 0, SEEK_SET);
+        fclose(fh);
+    }
+    return handle;
+
+  error:
+    Jim_SetResultErrno(interp, "failed to create temp file");
+    CloseHandle(handle);
+    DeleteFile(name);
+    return JIM_BAD_FD;
+}
+
+static int
+JimWinFindExecutable(const char *originalName, char fullPath[MAX_PATH])
+{
+    int i;
+    static char extensions[][5] = {".exe", "", ".bat"};
+
+    for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) {
+        lstrcpyn(fullPath, originalName, MAX_PATH - 5);
+        lstrcat(fullPath, extensions[i]);
+
+        if (SearchPath(NULL, fullPath, NULL, MAX_PATH, fullPath, NULL) == 0) {
+            continue;
+        }
+        if (GetFileAttributes(fullPath) & FILE_ATTRIBUTE_DIRECTORY) {
+            continue;
+        }
+        return 0;
+    }
+
+    return -1;
+}
+
+static char **JimSaveEnv(char **env)
+{
+    return env;
+}
+
+static void JimRestoreEnv(char **env)
+{
+    JimFreeEnv(env, NULL);
+}
+
+static Jim_Obj *
+JimWinBuildCommandLine(Jim_Interp *interp, char **argv)
+{
+    char *start, *special;
+    int quote, i;
+
+    Jim_Obj *strObj = Jim_NewStringObj(interp, "", 0);
+
+    for (i = 0; argv[i]; i++) {
+        if (i > 0) {
+            Jim_AppendString(interp, strObj, " ", 1);
+        }
+
+        if (argv[i][0] == '\0') {
+            quote = 1;
+        }
+        else {
+            quote = 0;
+            for (start = argv[i]; *start != '\0'; start++) {
+                if (isspace(UCHAR(*start))) {
+                    quote = 1;
+                    break;
+                }
+            }
+        }
+        if (quote) {
+            Jim_AppendString(interp, strObj, "\"" , 1);
+        }
+
+        start = argv[i];
+        for (special = argv[i]; ; ) {
+            if ((*special == '\\') && (special[1] == '\\' ||
+                    special[1] == '"' || (quote && special[1] == '\0'))) {
+                Jim_AppendString(interp, strObj, start, special - start);
+                start = special;
+                while (1) {
+                    special++;
+                    if (*special == '"' || (quote && *special == '\0')) {
+                        /*
+                         * N backslashes followed a quote -> insert
+                         * N * 2 + 1 backslashes then a quote.
+                         */
+
+                        Jim_AppendString(interp, strObj, start, special - start);
+                        break;
+                    }
+                    if (*special != '\\') {
+                        break;
+                    }
+                }
+                Jim_AppendString(interp, strObj, start, special - start);
+                start = special;
+            }
+            if (*special == '"') {
+        if (special == start) {
+            Jim_AppendString(interp, strObj, "\"", 1);
+        }
+        else {
+            Jim_AppendString(interp, strObj, start, special - start);
+        }
+                Jim_AppendString(interp, strObj, "\\\"", 2);
+                start = special + 1;
+            }
+            if (*special == '\0') {
+                break;
+            }
+            special++;
+        }
+        Jim_AppendString(interp, strObj, start, special - start);
+        if (quote) {
+            Jim_AppendString(interp, strObj, "\"", 1);
+        }
+    }
+    return strObj;
+}
+
+static pidtype
+JimStartWinProcess(Jim_Interp *interp, char **argv, char *env, fdtype inputId, fdtype outputId, fdtype errorId)
+{
+    STARTUPINFO startInfo;
+    PROCESS_INFORMATION procInfo;
+    HANDLE hProcess, h;
+    char execPath[MAX_PATH];
+    char *originalName;
+    pidtype pid = JIM_BAD_PID;
+    Jim_Obj *cmdLineObj;
+
+    if (JimWinFindExecutable(argv[0], execPath) < 0) {
+        return JIM_BAD_PID;
+    }
+    originalName = argv[0];
+    argv[0] = execPath;
+
+    hProcess = GetCurrentProcess();
+    cmdLineObj = JimWinBuildCommandLine(interp, argv);
+
+    /*
+     * STARTF_USESTDHANDLES must be used to pass handles to child process.
+     * Using SetStdHandle() and/or dup2() only works when a console mode
+     * parent process is spawning an attached console mode child process.
+     */
+
+    ZeroMemory(&startInfo, sizeof(startInfo));
+    startInfo.cb = sizeof(startInfo);
+    startInfo.dwFlags   = STARTF_USESTDHANDLES;
+    startInfo.hStdInput	= INVALID_HANDLE_VALUE;
+    startInfo.hStdOutput= INVALID_HANDLE_VALUE;
+    startInfo.hStdError = INVALID_HANDLE_VALUE;
+
+    /*
+     * Duplicate all the handles which will be passed off as stdin, stdout
+     * and stderr of the child process. The duplicate handles are set to
+     * be inheritable, so the child process can use them.
+     */
+    if (inputId == JIM_BAD_FD) {
+        if (CreatePipe(&startInfo.hStdInput, &h, JimStdSecAttrs(), 0) != FALSE) {
+            CloseHandle(h);
+        }
+    } else {
+        DuplicateHandle(hProcess, inputId, hProcess, &startInfo.hStdInput,
+                0, TRUE, DUPLICATE_SAME_ACCESS);
+    }
+    if (startInfo.hStdInput == JIM_BAD_FD) {
+        goto end;
+    }
+
+    if (outputId == JIM_BAD_FD) {
+        startInfo.hStdOutput = CreateFile("NUL:", GENERIC_WRITE, 0,
+                JimStdSecAttrs(), OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    } else {
+        DuplicateHandle(hProcess, outputId, hProcess, &startInfo.hStdOutput,
+                0, TRUE, DUPLICATE_SAME_ACCESS);
+    }
+    if (startInfo.hStdOutput == JIM_BAD_FD) {
+        goto end;
+    }
+
+    if (errorId == JIM_BAD_FD) {
+        /*
+         * If handle was not set, errors should be sent to an infinitely
+         * deep sink.
+         */
+
+        startInfo.hStdError = CreateFile("NUL:", GENERIC_WRITE, 0,
+                JimStdSecAttrs(), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    } else {
+        DuplicateHandle(hProcess, errorId, hProcess, &startInfo.hStdError,
+                0, TRUE, DUPLICATE_SAME_ACCESS);
+    }
+    if (startInfo.hStdError == JIM_BAD_FD) {
+        goto end;
+    }
+
+    if (!CreateProcess(NULL, (char *)Jim_String(cmdLineObj), NULL, NULL, TRUE,
+            0, env, NULL, &startInfo, &procInfo)) {
+        goto end;
+    }
+
+    /*
+     * "When an application spawns a process repeatedly, a new thread
+     * instance will be created for each process but the previous
+     * instances may not be cleaned up.  This results in a significant
+     * virtual memory loss each time the process is spawned.  If there
+     * is a WaitForInputIdle() call between CreateProcess() and
+     * CloseHandle(), the problem does not occur." PSS ID Number: Q124121
+     */
+
+    WaitForInputIdle(procInfo.hProcess, 5000);
+    CloseHandle(procInfo.hThread);
+
+    pid = procInfo.hProcess;
+
+    end:
+    Jim_FreeNewObj(interp, cmdLineObj);
+    if (startInfo.hStdInput != JIM_BAD_FD) {
+        CloseHandle(startInfo.hStdInput);
+    }
+    if (startInfo.hStdOutput != JIM_BAD_FD) {
+        CloseHandle(startInfo.hStdOutput);
+    }
+    if (startInfo.hStdError != JIM_BAD_FD) {
+        CloseHandle(startInfo.hStdError);
+    }
+    return pid;
+}
+#else
+/* Unix-specific implementation */
+static int JimOpenForWrite(const char *filename, int append)
+{
+    return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666);
+}
+
+static int JimRewindFd(int fd)
+{
+    return lseek(fd, 0L, SEEK_SET);
+}
+
+static int JimCreateTemp(Jim_Interp *interp, const char *contents)
+{
+    char inName[] = "/tmp/tcl.tmp.XXXXXX";
+
+    int fd = mkstemp(inName);
+    if (fd == JIM_BAD_FD) {
+        Jim_SetResultErrno(interp, "couldn't create temp file");
+        return -1;
+    }
+    unlink(inName);
+    if (contents) {
+        int length = strlen(contents);
+        if (write(fd, contents, length) != length) {
+            Jim_SetResultErrno(interp, "couldn't write temp file");
+            close(fd);
+            return -1;
+        }
+        lseek(fd, 0L, SEEK_SET);
+    }
+    return fd;
+}
+
+static char **JimSaveEnv(char **env)
+{
+    char **saveenv = Jim_GetEnviron();
+    Jim_SetEnviron(env);
+    return saveenv;
+}
+
+static void JimRestoreEnv(char **env)
+{
+    JimFreeEnv(Jim_GetEnviron(), env);
+    Jim_SetEnviron(env);
+}
+#endif
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-file.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-file.c
new file mode 100755
index 0000000..7b48368
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-file.c
@@ -0,0 +1,929 @@
+/*
+ * Implements the file command for jim
+ *
+ * (c) 2008 Steve Bennett <steveb@workware.net.au>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ *
+ * Based on code originally from Tcl 6.7:
+ *
+ * Copyright 1987-1991 Regents of the University of California
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies.  The University of California
+ * makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "jim-subcmd.h"
+
+# ifndef MAXPATHLEN
+# define MAXPATHLEN JIM_PATH_LEN
+# endif
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * JimGetFileType --
+ *
+ *  Given a mode word, returns a string identifying the type of a
+ *  file.
+ *
+ * Results:
+ *  A static text string giving the file type from mode.
+ *
+ * Side effects:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static const char *JimGetFileType(int mode)
+{
+    if (S_ISREG(mode)) {
+        return "file";
+    }
+    else if (S_ISDIR(mode)) {
+        return "directory";
+    }
+    else if (S_ISCHR(mode)) {
+        return "characterSpecial";
+    }
+    else if (S_ISBLK(mode)) {
+        return "blockSpecial";
+    }
+    else if (S_ISFIFO(mode)) {
+        return "fifo";
+#ifdef S_ISLNK
+    }
+    else if (S_ISLNK(mode)) {
+        return "link";
+#endif
+#ifdef S_ISSOCK
+    }
+    else if (S_ISSOCK(mode)) {
+        return "socket";
+#endif
+    }
+    return "unknown";
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * StoreStatData --
+ *
+ *  This is a utility procedure that breaks out the fields of a
+ *  "stat" structure and stores them in textual form into the
+ *  elements of an associative array.
+ *
+ * Results:
+ *  Returns a standard Tcl return value.  If an error occurs then
+ *  a message is left in interp->result.
+ *
+ * Side effects:
+ *  Elements of the associative array given by "varName" are modified.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int set_array_int_value(Jim_Interp *interp, Jim_Obj *container, const char *key,
+    jim_wide value)
+{
+    Jim_Obj *nameobj = Jim_NewStringObj(interp, key, -1);
+    Jim_Obj *valobj = Jim_NewWideObj(interp, value);
+
+    if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj, JIM_ERRMSG) != JIM_OK) {
+        Jim_FreeObj(interp, nameobj);
+        Jim_FreeObj(interp, valobj);
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+static int set_array_string_value(Jim_Interp *interp, Jim_Obj *container, const char *key,
+    const char *value)
+{
+    Jim_Obj *nameobj = Jim_NewStringObj(interp, key, -1);
+    Jim_Obj *valobj = Jim_NewStringObj(interp, value, -1);
+
+    if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj, JIM_ERRMSG) != JIM_OK) {
+        Jim_FreeObj(interp, nameobj);
+        Jim_FreeObj(interp, valobj);
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+static int StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat *sb)
+{
+    if (set_array_int_value(interp, varName, "dev", sb->st_dev) != JIM_OK) {
+        Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variables isn't array", varName);
+        return JIM_ERR;
+    }
+    set_array_int_value(interp, varName, "ino", sb->st_ino);
+    set_array_int_value(interp, varName, "mode", sb->st_mode);
+    set_array_int_value(interp, varName, "nlink", sb->st_nlink);
+    set_array_int_value(interp, varName, "uid", sb->st_uid);
+    set_array_int_value(interp, varName, "gid", sb->st_gid);
+    set_array_int_value(interp, varName, "size", sb->st_size);
+    set_array_int_value(interp, varName, "atime", sb->st_atime);
+    set_array_int_value(interp, varName, "mtime", sb->st_mtime);
+    set_array_int_value(interp, varName, "ctime", sb->st_ctime);
+    set_array_string_value(interp, varName, "type", JimGetFileType((int)sb->st_mode));
+
+    /* And also return the value */
+    Jim_SetResult(interp, Jim_GetVariable(interp, varName, 0));
+
+    return JIM_OK;
+}
+
+static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *path = Jim_String(argv[0]);
+    const char *p = strrchr(path, '/');
+
+    if (!p) {
+        Jim_SetResultString(interp, ".", -1);
+    }
+    else if (p == path) {
+        Jim_SetResultString(interp, "/", -1);
+    }
+#if defined(__MINGW32__)
+    else if (p[-1] == ':') {
+        /* z:/dir => z:/ */
+        Jim_SetResultString(interp, path, p - path + 1);
+    }
+#endif
+    else {
+        Jim_SetResultString(interp, path, p - path);
+    }
+    return JIM_OK;
+}
+
+static int file_cmd_rootname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *path = Jim_String(argv[0]);
+    const char *lastSlash = strrchr(path, '/');
+    const char *p = strrchr(path, '.');
+
+    if (p == NULL || (lastSlash != NULL && lastSlash > p)) {
+        Jim_SetResult(interp, argv[0]);
+    }
+    else {
+        Jim_SetResultString(interp, path, p - path);
+    }
+    return JIM_OK;
+}
+
+static int file_cmd_extension(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *path = Jim_String(argv[0]);
+    const char *lastSlash = strrchr(path, '/');
+    const char *p = strrchr(path, '.');
+
+    if (p == NULL || (lastSlash != NULL && lastSlash >= p)) {
+        p = "";
+    }
+    Jim_SetResultString(interp, p, -1);
+    return JIM_OK;
+}
+
+static int file_cmd_tail(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *path = Jim_String(argv[0]);
+    const char *lastSlash = strrchr(path, '/');
+
+    if (lastSlash) {
+        Jim_SetResultString(interp, lastSlash + 1, -1);
+    }
+    else {
+        Jim_SetResult(interp, argv[0]);
+    }
+    return JIM_OK;
+}
+
+static int file_cmd_normalize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+#ifdef HAVE_REALPATH
+    const char *path = Jim_String(argv[0]);
+    char *newname = Jim_Alloc(MAXPATHLEN + 1);
+
+    if (realpath(path, newname)) {
+        Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, -1));
+    }
+    else {
+        Jim_Free(newname);
+        Jim_SetResult(interp, argv[0]);
+    }
+    return JIM_OK;
+#else
+    Jim_SetResultString(interp, "Not implemented", -1);
+    return JIM_ERR;
+#endif
+}
+
+static int file_cmd_join(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int i;
+    char *newname = Jim_Alloc(MAXPATHLEN + 1);
+    char *last = newname;
+
+    *newname = 0;
+
+    /* Simple implementation for now */
+    for (i = 0; i < argc; i++) {
+        int len;
+        const char *part = Jim_GetString(argv[i], &len);
+
+        if (*part == '/') {
+            /* Absolute component, so go back to the start */
+            last = newname;
+        }
+#if defined(__MINGW32__)
+        else if (strchr(part, ':')) {
+            /* Absolute compontent on mingw, so go back to the start */
+            last = newname;
+        }
+#endif
+        else if (part[0] == '.') {
+            if (part[1] == '/') {
+                part += 2;
+                len -= 2;
+            }
+            else if (part[1] == 0 && last != newname) {
+                /* Adding '.' to an existing path does nothing */
+                continue;
+            }
+        }
+
+        /* Add a slash if needed */
+        if (last != newname && last[-1] != '/') {
+            *last++ = '/';
+        }
+
+        if (len) {
+            if (last + len - newname >= MAXPATHLEN) {
+                Jim_Free(newname);
+                Jim_SetResultString(interp, "Path too long", -1);
+                return JIM_ERR;
+            }
+            memcpy(last, part, len);
+            last += len;
+        }
+
+        /* Remove a slash if needed */
+        if (last > newname + 1 && last[-1] == '/') {
+            *--last = 0;
+        }
+    }
+
+    *last = 0;
+
+    /* Probably need to handle some special cases ... */
+
+    Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, last - newname));
+
+    return JIM_OK;
+}
+
+static int file_access(Jim_Interp *interp, Jim_Obj *filename, int mode)
+{
+    const char *path = Jim_String(filename);
+    int rc = access(path, mode);
+
+    Jim_SetResultBool(interp, rc != -1);
+
+    return JIM_OK;
+}
+
+static int file_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return file_access(interp, argv[0], R_OK);
+}
+
+static int file_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return file_access(interp, argv[0], W_OK);
+}
+
+static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return file_access(interp, argv[0], X_OK);
+}
+
+static int file_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return file_access(interp, argv[0], F_OK);
+}
+
+static int file_cmd_delete(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int force = Jim_CompareStringImmediate(interp, argv[0], "-force");
+
+    if (force || Jim_CompareStringImmediate(interp, argv[0], "--")) {
+        argc++;
+        argv--;
+    }
+
+    while (argc--) {
+        const char *path = Jim_String(argv[0]);
+
+        if (unlink(path) == -1 && errno != ENOENT) {
+            if (rmdir(path) == -1) {
+                /* Maybe try using the script helper */
+                if (!force || Jim_EvalPrefix(interp, "file delete force", 1, argv) != JIM_OK) {
+                    Jim_SetResultFormatted(interp, "couldn't delete file \"%s\": %s", path,
+                        strerror(errno));
+                    return JIM_ERR;
+                }
+            }
+        }
+        argv++;
+    }
+    return JIM_OK;
+}
+
+#ifdef HAVE_MKDIR_ONE_ARG
+#define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME)
+#else
+#define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755)
+#endif
+
+/**
+ * Create directory, creating all intermediate paths if necessary.
+ *
+ * Returns 0 if OK or -1 on failure (and sets errno)
+ *
+ * Note: The path may be modified.
+ */
+static int mkdir_all(char *path)
+{
+    int ok = 1;
+
+    /* First time just try to make the dir */
+    goto first;
+
+    while (ok--) {
+        /* Must have failed the first time, so recursively make the parent and try again */
+        char *slash = strrchr(path, '/');
+
+        if (slash && slash != path) {
+            *slash = 0;
+            if (mkdir_all(path) != 0) {
+                return -1;
+            }
+            *slash = '/';
+        }
+      first:
+        if (MKDIR_DEFAULT(path) == 0) {
+            return 0;
+        }
+        if (errno == ENOENT) {
+            /* Create the parent and try again */
+            continue;
+        }
+        /* Maybe it already exists as a directory */
+        if (errno == EEXIST) {
+            struct stat sb;
+
+            if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
+                return 0;
+            }
+            /* Restore errno */
+            errno = EEXIST;
+        }
+        /* Failed */
+        break;
+    }
+    return -1;
+}
+
+static int file_cmd_mkdir(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    while (argc--) {
+        char *path = Jim_StrDup(Jim_String(argv[0]));
+        int rc = mkdir_all(path);
+
+        Jim_Free(path);
+        if (rc != 0) {
+            Jim_SetResultFormatted(interp, "can't create directory \"%#s\": %s", argv[0],
+                strerror(errno));
+            return JIM_ERR;
+        }
+        argv++;
+    }
+    return JIM_OK;
+}
+
+#ifdef HAVE_MKSTEMP
+static int file_cmd_tempfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int fd;
+    char *filename;
+    const char *template = "/tmp/tcl.tmp.XXXXXX";
+
+    if (argc >= 1) {
+        template = Jim_String(argv[0]);
+    }
+    filename = Jim_StrDup(template);
+
+    fd = mkstemp(filename);
+    if (fd < 0) {
+        Jim_SetResultString(interp, "Failed to create tempfile", -1);
+        return JIM_ERR;
+    }
+    close(fd);
+
+    Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, filename, -1));
+    return JIM_OK;
+}
+#endif
+
+static int file_cmd_rename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *source;
+    const char *dest;
+    int force = 0;
+
+    if (argc == 3) {
+        if (!Jim_CompareStringImmediate(interp, argv[0], "-force")) {
+            return -1;
+        }
+        force++;
+        argv++;
+        argc--;
+    }
+
+    source = Jim_String(argv[0]);
+    dest = Jim_String(argv[1]);
+
+    if (!force && access(dest, F_OK) == 0) {
+        Jim_SetResultFormatted(interp, "error renaming \"%#s\" to \"%#s\": target exists", argv[0],
+            argv[1]);
+        return JIM_ERR;
+    }
+
+    if (rename(source, dest) != 0) {
+        Jim_SetResultFormatted(interp, "error renaming \"%#s\" to \"%#s\": %s", argv[0], argv[1],
+            strerror(errno));
+        return JIM_ERR;
+    }
+
+    return JIM_OK;
+}
+
+static int file_stat(Jim_Interp *interp, Jim_Obj *filename, struct stat *sb)
+{
+    const char *path = Jim_String(filename);
+
+    if (stat(path, sb) == -1) {
+        Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+#ifndef HAVE_LSTAT
+#define lstat stat
+#endif
+
+static int file_lstat(Jim_Interp *interp, Jim_Obj *filename, struct stat *sb)
+{
+    const char *path = Jim_String(filename);
+
+    if (lstat(path, sb) == -1) {
+        Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+static int file_cmd_atime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+
+    if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+        return JIM_ERR;
+    }
+    Jim_SetResultInt(interp, sb.st_atime);
+    return JIM_OK;
+}
+
+static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+
+    if (argc == 2) {
+#ifdef HAVE_UTIMES
+        jim_wide newtime;
+        struct timeval times[2];
+
+        if (Jim_GetWide(interp, argv[1], &newtime) != JIM_OK) {
+            return JIM_ERR;
+        }
+
+        times[1].tv_sec = times[0].tv_sec = newtime;
+        times[1].tv_usec = times[0].tv_usec = 0;
+
+        if (utimes(Jim_String(argv[0]), times) != 0) {
+            Jim_SetResultFormatted(interp, "can't set time on \"%#s\": %s", argv[0], strerror(errno));
+            return JIM_ERR;
+        }
+#else
+        Jim_SetResultString(interp, "Not implemented", -1);
+        return JIM_ERR;
+#endif
+    }
+    if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+        return JIM_ERR;
+    }
+    Jim_SetResultInt(interp, sb.st_mtime);
+    return JIM_OK;
+}
+
+static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return Jim_EvalPrefix(interp, "file copy", argc, argv);
+}
+
+static int file_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+
+    if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+        return JIM_ERR;
+    }
+    Jim_SetResultInt(interp, sb.st_size);
+    return JIM_OK;
+}
+
+static int file_cmd_isdirectory(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+    int ret = 0;
+
+    if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+        ret = S_ISDIR(sb.st_mode);
+    }
+    Jim_SetResultInt(interp, ret);
+    return JIM_OK;
+}
+
+static int file_cmd_isfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+    int ret = 0;
+
+    if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+        ret = S_ISREG(sb.st_mode);
+    }
+    Jim_SetResultInt(interp, ret);
+    return JIM_OK;
+}
+
+#ifdef HAVE_GETEUID
+static int file_cmd_owned(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+    int ret = 0;
+
+    if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+        ret = (geteuid() == sb.st_uid);
+    }
+    Jim_SetResultInt(interp, ret);
+    return JIM_OK;
+}
+#endif
+
+#if defined(HAVE_READLINK)
+static int file_cmd_readlink(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *path = Jim_String(argv[0]);
+    char *linkValue = Jim_Alloc(MAXPATHLEN + 1);
+
+    int linkLength = readlink(path, linkValue, MAXPATHLEN);
+
+    if (linkLength == -1) {
+        Jim_Free(linkValue);
+        Jim_SetResultFormatted(interp, "couldn't readlink \"%#s\": %s", argv[0], strerror(errno));
+        return JIM_ERR;
+    }
+    linkValue[linkLength] = 0;
+    Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, linkValue, linkLength));
+    return JIM_OK;
+}
+#endif
+
+static int file_cmd_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+
+    if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
+        return JIM_ERR;
+    }
+    Jim_SetResultString(interp, JimGetFileType((int)sb.st_mode), -1);
+    return JIM_OK;
+}
+
+static int file_cmd_lstat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+
+    if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
+        return JIM_ERR;
+    }
+    return StoreStatData(interp, argv[1], &sb);
+}
+
+static int file_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    struct stat sb;
+
+    if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+        return JIM_ERR;
+    }
+    return StoreStatData(interp, argv[1], &sb);
+}
+
+static const jim_subcmd_type file_command_table[] = {
+    {   .cmd = "atime",
+        .args = "name",
+        .function = file_cmd_atime,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Last access time"
+    },
+    {   .cmd = "mtime",
+        .args = "name ?time?",
+        .function = file_cmd_mtime,
+        .minargs = 1,
+        .maxargs = 2,
+        .description = "Get or set last modification time"
+    },
+    {   .cmd = "copy",
+        .args = "?-force? source dest",
+        .function = file_cmd_copy,
+        .minargs = 2,
+        .maxargs = 3,
+        .description = "Copy source file to destination file"
+    },
+    {   .cmd = "dirname",
+        .args = "name",
+        .function = file_cmd_dirname,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Directory part of the name"
+    },
+    {   .cmd = "rootname",
+        .args = "name",
+        .function = file_cmd_rootname,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Name without any extension"
+    },
+    {   .cmd = "extension",
+        .args = "name",
+        .function = file_cmd_extension,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Last extension including the dot"
+    },
+    {   .cmd = "tail",
+        .args = "name",
+        .function = file_cmd_tail,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Last component of the name"
+    },
+    {   .cmd = "normalize",
+        .args = "name",
+        .function = file_cmd_normalize,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Normalized path of name"
+    },
+    {   .cmd = "join",
+        .args = "name ?name ...?",
+        .function = file_cmd_join,
+        .minargs = 1,
+        .maxargs = -1,
+        .description = "Join multiple path components"
+    },
+    {   .cmd = "readable",
+        .args = "name",
+        .function = file_cmd_readable,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Is file readable"
+    },
+    {   .cmd = "writable",
+        .args = "name",
+        .function = file_cmd_writable,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Is file writable"
+    },
+    {   .cmd = "executable",
+        .args = "name",
+        .function = file_cmd_executable,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Is file executable"
+    },
+    {   .cmd = "exists",
+        .args = "name",
+        .function = file_cmd_exists,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Does file exist"
+    },
+    {   .cmd = "delete",
+        .args = "?-force|--? name ...",
+        .function = file_cmd_delete,
+        .minargs = 1,
+        .maxargs = -1,
+        .description = "Deletes the files or directories (must be empty unless -force)"
+    },
+    {   .cmd = "mkdir",
+        .args = "dir ...",
+        .function = file_cmd_mkdir,
+        .minargs = 1,
+        .maxargs = -1,
+        .description = "Creates the directories"
+    },
+#ifdef HAVE_MKSTEMP
+    {   .cmd = "tempfile",
+        .args = "?template?",
+        .function = file_cmd_tempfile,
+        .minargs = 0,
+        .maxargs = 1,
+        .description = "Creates a temporary filename"
+    },
+#endif
+    {   .cmd = "rename",
+        .args = "?-force? source dest",
+        .function = file_cmd_rename,
+        .minargs = 2,
+        .maxargs = 3,
+        .description = "Renames a file"
+    },
+#if defined(HAVE_READLINK)
+    {   .cmd = "readlink",
+        .args = "name",
+        .function = file_cmd_readlink,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Value of the symbolic link"
+    },
+#endif
+    {   .cmd = "size",
+        .args = "name",
+        .function = file_cmd_size,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Size of file"
+    },
+    {   .cmd = "stat",
+        .args = "name var",
+        .function = file_cmd_stat,
+        .minargs = 2,
+        .maxargs = 2,
+        .description = "Stores results of stat in var array"
+    },
+    {   .cmd = "lstat",
+        .args = "name var",
+        .function = file_cmd_lstat,
+        .minargs = 2,
+        .maxargs = 2,
+        .description = "Stores results of lstat in var array"
+    },
+    {   .cmd = "type",
+        .args = "name",
+        .function = file_cmd_type,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Returns type of the file"
+    },
+#ifdef HAVE_GETEUID
+    {   .cmd = "owned",
+        .args = "name",
+        .function = file_cmd_owned,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Returns 1 if owned by the current owner"
+    },
+#endif
+    {   .cmd = "isdirectory",
+        .args = "name",
+        .function = file_cmd_isdirectory,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Returns 1 if name is a directory"
+    },
+    {   .cmd = "isfile",
+        .args = "name",
+        .function = file_cmd_isfile,
+        .minargs = 1,
+        .maxargs = 1,
+        .description = "Returns 1 if name is a file"
+    },
+    {
+        .cmd = 0
+    }
+};
+
+static int Jim_CdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *path;
+
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "dirname");
+        return JIM_ERR;
+    }
+
+    path = Jim_String(argv[1]);
+
+    if (chdir(path) != 0) {
+        Jim_SetResultFormatted(interp, "couldn't change working directory to \"%s\": %s", path,
+            strerror(errno));
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+static int Jim_PwdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const int cwd_len = 2048;
+    char *cwd = malloc(cwd_len);
+
+    if (getcwd(cwd, cwd_len) == NULL) {
+        Jim_SetResultString(interp, "Failed to get pwd", -1);
+        return JIM_ERR;
+    }
+#if defined(__MINGW32__)
+    {
+        /* Try to keep backlashes out of paths */
+        char *p = cwd;
+        while ((p = strchr(p, '\\')) != NULL) {
+            *p++ = '/';
+        }
+    }
+#endif
+
+    Jim_SetResultString(interp, cwd, -1);
+
+    free(cwd);
+    return JIM_OK;
+}
+
+int Jim_fileInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "file", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    Jim_CreateCommand(interp, "file", Jim_SubCmdProc, (void *)file_command_table, NULL);
+    Jim_CreateCommand(interp, "pwd", Jim_PwdCmd, NULL, NULL);
+    Jim_CreateCommand(interp, "cd", Jim_CdCmd, NULL, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-format.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-format.c
new file mode 100755
index 0000000..c9cde89
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-format.c
@@ -0,0 +1,433 @@
+/*
+ * Implements the internals of the format command for jim
+ *
+ * The FreeBSD license
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ *
+ * Based on code originally from Tcl 8.5:
+ *
+ * Copyright (c) 1995-1997 Sun Microsystems, Inc.
+ * Copyright (c) 1999 by Scriptics Corporation.
+ *
+ * See the file "tcl.license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ */
+#include <ctype.h>
+#include <string.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "utf8.h"
+
+#define JIM_UTF_MAX 3
+#define JIM_INTEGER_SPACE 24
+#define MAX_FLOAT_WIDTH 320
+
+/**
+ * Apply the printf-like format in fmtObjPtr with the given arguments.
+ *
+ * Returns a new object with zero reference count if OK, or NULL on error.
+ */
+Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv)
+{
+    const char *span, *format, *formatEnd, *msg;
+    int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0;
+    static const char * const mixedXPG =
+	    "cannot mix \"%\" and \"%n$\" conversion specifiers";
+    static const char * const badIndex[2] = {
+	"not enough arguments for all format specifiers",
+	"\"%n$\" argument index out of range"
+    };
+    int formatLen;
+    Jim_Obj *resultPtr;
+
+    /* A single buffer is used to store numeric fields (with sprintf())
+     * This buffer is allocated/reallocated as necessary
+     */
+    char *num_buffer = NULL;
+    int num_buffer_size = 0;
+
+    span = format = Jim_GetString(fmtObjPtr, &formatLen);
+    formatEnd = format + formatLen;
+    resultPtr = Jim_NewStringObj(interp, "", 0);
+
+    while (format != formatEnd) {
+	char *end;
+	int gotMinus, sawFlag;
+	int gotPrecision, useShort;
+	long width, precision;
+	int newXpg;
+	int ch;
+	int step;
+	int doubleType;
+	char pad = ' ';
+	char spec[2*JIM_INTEGER_SPACE + 12];
+	char *p;
+
+	int formatted_chars;
+	int formatted_bytes;
+	const char *formatted_buf;
+
+	step = utf8_tounicode(format, &ch);
+	format += step;
+	if (ch != '%') {
+	    numBytes += step;
+	    continue;
+	}
+	if (numBytes) {
+	    Jim_AppendString(interp, resultPtr, span, numBytes);
+	    numBytes = 0;
+	}
+
+	/*
+	 * Saw a % : process the format specifier.
+	 *
+	 * Step 0. Handle special case of escaped format marker (i.e., %%).
+	 */
+
+	step = utf8_tounicode(format, &ch);
+	if (ch == '%') {
+	    span = format;
+	    numBytes = step;
+	    format += step;
+	    continue;
+	}
+
+	/*
+	 * Step 1. XPG3 position specifier
+	 */
+
+	newXpg = 0;
+	if (isdigit(ch)) {
+	    int position = strtoul(format, &end, 10);
+	    if (*end == '$') {
+		newXpg = 1;
+		objIndex = position - 1;
+		format = end + 1;
+		step = utf8_tounicode(format, &ch);
+	    }
+	}
+	if (newXpg) {
+	    if (gotSequential) {
+		msg = mixedXPG;
+		goto errorMsg;
+	    }
+	    gotXpg = 1;
+	} else {
+	    if (gotXpg) {
+		msg = mixedXPG;
+		goto errorMsg;
+	    }
+	    gotSequential = 1;
+	}
+	if ((objIndex < 0) || (objIndex >= objc)) {
+	    msg = badIndex[gotXpg];
+	    goto errorMsg;
+	}
+
+	/*
+	 * Step 2. Set of flags. Also build up the sprintf spec.
+	 */
+	p = spec;
+	*p++ = '%';
+
+	gotMinus = 0;
+	sawFlag = 1;
+	do {
+	    switch (ch) {
+	    case '-':
+		gotMinus = 1;
+		break;
+	    case '0':
+		pad = ch;
+		break;
+	    case ' ':
+	    case '+':
+	    case '#':
+		break;
+	    default:
+		sawFlag = 0;
+		continue;
+	    }
+	    *p++ = ch;
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	} while (sawFlag);
+
+	/*
+	 * Step 3. Minimum field width.
+	 */
+
+	width = 0;
+	if (isdigit(ch)) {
+	    width = strtoul(format, &end, 10);
+	    format = end;
+	    step = utf8_tounicode(format, &ch);
+	} else if (ch == '*') {
+	    if (objIndex >= objc - 1) {
+		msg = badIndex[gotXpg];
+		goto errorMsg;
+	    }
+	    if (Jim_GetLong(interp, objv[objIndex], &width) != JIM_OK) {
+		goto error;
+	    }
+	    if (width < 0) {
+		width = -width;
+		if (!gotMinus) {
+		    *p++ = '-';
+		    gotMinus = 1;
+		}
+	    }
+	    objIndex++;
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	}
+
+	/*
+	 * Step 4. Precision.
+	 */
+
+	gotPrecision = precision = 0;
+	if (ch == '.') {
+	    gotPrecision = 1;
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	}
+	if (isdigit(ch)) {
+	    precision = strtoul(format, &end, 10);
+	    format = end;
+	    step = utf8_tounicode(format, &ch);
+	} else if (ch == '*') {
+	    if (objIndex >= objc - 1) {
+		msg = badIndex[gotXpg];
+		goto errorMsg;
+	    }
+	    if (Jim_GetLong(interp, objv[objIndex], &precision) != JIM_OK) {
+		goto error;
+	    }
+
+	    /*
+	     * TODO: Check this truncation logic.
+	     */
+
+	    if (precision < 0) {
+		precision = 0;
+	    }
+	    objIndex++;
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	}
+
+	/*
+	 * Step 5. Length modifier.
+	 */
+
+	useShort = 0;
+	if (ch == 'h') {
+	    useShort = 1;
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	} else if (ch == 'l') {
+	    /* Just for compatibility. All non-short integers are wide. */
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	    if (ch == 'l') {
+		format += step;
+		step = utf8_tounicode(format, &ch);
+	    }
+	}
+
+	format += step;
+	span = format;
+
+	/*
+	 * Step 6. The actual conversion character.
+	 */
+
+	if (ch == 'i') {
+	    ch = 'd';
+	}
+
+	doubleType = 0;
+
+	/* Each valid conversion will set:
+	 * formatted_buf   - the result to be added
+	 * formatted_chars - the length of formatted_buf in characters
+	 * formatted_bytes - the length of formatted_buf in bytes
+	 */
+	switch (ch) {
+	case '\0':
+	    msg = "format string ended in middle of field specifier";
+	    goto errorMsg;
+	case 's': {
+	    formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes);
+	    formatted_chars = Jim_Utf8Length(interp, objv[objIndex]);
+	    if (gotPrecision && (precision < formatted_chars)) {
+		/* Need to build a (null terminated) truncated string */
+		formatted_chars = precision;
+		formatted_bytes = utf8_index(formatted_buf, precision);
+	    }
+	    break;
+	}
+	case 'c': {
+	    jim_wide code;
+
+	    if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) {
+		goto error;
+	    }
+	    /* Just store the value in the 'spec' buffer */
+	    formatted_bytes = utf8_fromunicode(spec, code);
+	    formatted_buf = spec;
+	    formatted_chars = 1;
+	    break;
+	}
+
+	case 'e':
+	case 'E':
+	case 'f':
+	case 'g':
+	case 'G':
+	    doubleType = 1;
+	    /* fall through */
+	case 'd':
+	case 'u':
+	case 'o':
+	case 'x':
+	case 'X': {
+	    jim_wide w;
+	    double d;
+	    int length;
+
+	    /* Fill in the width and precision */
+	    if (width) {
+		p += sprintf(p, "%ld", width);
+	    }
+	    if (gotPrecision) {
+		p += sprintf(p, ".%ld", precision);
+	    }
+
+	    /* Now the modifier, and get the actual value here */
+	    if (doubleType) {
+		if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) {
+		    goto error;
+		}
+		length = MAX_FLOAT_WIDTH;
+	    }
+	    else {
+		if (Jim_GetWide(interp, objv[objIndex], &w) != JIM_OK) {
+		    goto error;
+		}
+		length = JIM_INTEGER_SPACE;
+		if (useShort) {
+		    *p++ = 'h';
+		    if (ch == 'd') {
+			w = (short)w;
+		    }
+		    else {
+			w = (unsigned short)w;
+		    }
+		}
+		else {
+		    *p++ = 'l';
+#ifdef HAVE_LONG_LONG
+		    if (sizeof(long long) == sizeof(jim_wide)) {
+			*p++ = 'l';
+		    }
+#endif
+		}
+	    }
+
+	    *p++ = (char) ch;
+	    *p = '\0';
+
+	    /* Adjust length for width and precision */
+	    if (width > length) {
+		length = width;
+	    }
+	    if (gotPrecision) {
+		length += precision;
+	    }
+
+	    /* Increase the size of the buffer if needed */
+	    if (num_buffer_size < length + 1) {
+		num_buffer_size = length + 1;
+		num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
+	    }
+
+	    if (doubleType) {
+		snprintf(num_buffer, length + 1, spec, d);
+	    }
+	    else {
+		formatted_bytes = snprintf(num_buffer, length + 1, spec, w);
+	    }
+	    formatted_chars = formatted_bytes = strlen(num_buffer);
+	    formatted_buf = num_buffer;
+	    break;
+	}
+
+	default: {
+	    /* Just reuse the 'spec' buffer */
+	    spec[0] = ch;
+	    spec[1] = '\0';
+	    Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec);
+	    goto error;
+	}
+	}
+
+	if (!gotMinus) {
+	    while (formatted_chars < width) {
+		Jim_AppendString(interp, resultPtr, &pad, 1);
+		formatted_chars++;
+	    }
+	}
+
+	Jim_AppendString(interp, resultPtr, formatted_buf, formatted_bytes);
+
+	while (formatted_chars < width) {
+	    Jim_AppendString(interp, resultPtr, &pad, 1);
+	    formatted_chars++;
+	}
+
+	objIndex += gotSequential;
+    }
+    if (numBytes) {
+	Jim_AppendString(interp, resultPtr, span, numBytes);
+    }
+
+    Jim_Free(num_buffer);
+    return resultPtr;
+
+  errorMsg:
+    Jim_SetResultString(interp, msg, -1);
+  error:
+    Jim_FreeNewObj(interp, resultPtr);
+    Jim_Free(num_buffer);
+    return NULL;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-interactive.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-interactive.c
new file mode 100755
index 0000000..658e8d8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-interactive.c
@@ -0,0 +1,137 @@
+#include <errno.h>
+#include <string.h>
+#include "jim.h"
+#include "jimautoconf.h"
+
+#ifdef USE_LINENOISE
+#include <unistd.h>
+#include "linenoise.h"
+#else
+
+#define MAX_LINE_LEN 512
+
+static char *linenoise(const char *prompt)
+{
+    char *line = malloc(MAX_LINE_LEN);
+
+    fputs(prompt, stdout);
+    fflush(stdout);
+
+    if (fgets(line, MAX_LINE_LEN, stdin) == NULL) {
+        free(line);
+        return NULL;
+    }
+    return line;
+}
+#endif
+
+int Jim_InteractivePrompt(Jim_Interp *interp)
+{
+    int retcode = JIM_OK;
+    char *history_file = NULL;
+#ifdef USE_LINENOISE
+    const char *home;
+
+    home = getenv("HOME");
+    if (home && isatty(STDIN_FILENO)) {
+        int history_len = strlen(home) + sizeof("/.jim_history");
+        history_file = Jim_Alloc(history_len);
+        snprintf(history_file, history_len, "%s/.jim_history", home);
+        linenoiseHistoryLoad(history_file);
+    }
+#endif
+
+    printf("Welcome to Jim version %d.%d" JIM_NL,
+        JIM_VERSION / 100, JIM_VERSION % 100);
+    Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1");
+
+    while (1) {
+        Jim_Obj *scriptObjPtr;
+        const char *result;
+        int reslen;
+        char prompt[20];
+        const char *str;
+
+        if (retcode != 0) {
+            const char *retcodestr = Jim_ReturnCode(retcode);
+
+            if (*retcodestr == '?') {
+                snprintf(prompt, sizeof(prompt) - 3, "[%d] ", retcode);
+            }
+            else {
+                snprintf(prompt, sizeof(prompt) - 3, "[%s] ", retcodestr);
+            }
+        }
+        else {
+            prompt[0] = '\0';
+        }
+        strcat(prompt, ". ");
+
+        scriptObjPtr = Jim_NewStringObj(interp, "", 0);
+        Jim_IncrRefCount(scriptObjPtr);
+        while (1) {
+            char state;
+            int len;
+            char *line;
+
+            line = linenoise(prompt);
+            if (line == NULL) {
+                if (errno == EINTR) {
+                    continue;
+                }
+                Jim_DecrRefCount(interp, scriptObjPtr);
+                goto out;
+            }
+            if (Jim_Length(scriptObjPtr) != 0) {
+                Jim_AppendString(interp, scriptObjPtr, "\n", 1);
+            }
+            Jim_AppendString(interp, scriptObjPtr, line, -1);
+            free(line);
+            str = Jim_GetString(scriptObjPtr, &len);
+            if (len == 0) {
+                continue;
+            }
+            if (Jim_ScriptIsComplete(str, len, &state))
+                break;
+
+            snprintf(prompt, sizeof(prompt), "%c> ", state);
+        }
+#ifdef USE_LINENOISE
+        if (strcmp(str, "h") == 0) {
+            /* built-in history command */
+            int i;
+            int len;
+            char **history = linenoiseHistory(&len);
+            for (i = 0; i < len; i++) {
+                printf("%4d %s\n", i + 1, history[i]);
+            }
+            Jim_DecrRefCount(interp, scriptObjPtr);
+            continue;
+        }
+
+        linenoiseHistoryAdd(Jim_String(scriptObjPtr));
+        if (history_file) {
+            linenoiseHistorySave(history_file);
+        }
+#endif
+        retcode = Jim_EvalObj(interp, scriptObjPtr);
+        Jim_DecrRefCount(interp, scriptObjPtr);
+
+
+
+        if (retcode == JIM_EXIT) {
+            Jim_Free(history_file);
+            return JIM_EXIT;
+        }
+        if (retcode == JIM_ERR) {
+            Jim_MakeErrorMessage(interp);
+        }
+        result = Jim_GetString(Jim_GetResult(interp), &reslen);
+        if (reslen) {
+            printf("%s\n", result);
+        }
+    }
+  out:
+    Jim_Free(history_file);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-load.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-load.c
new file mode 100755
index 0000000..4dc6ed2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-load.c
@@ -0,0 +1,126 @@
+#include "jim.h"
+#include "jimautoconf.h"
+#include <string.h>
+
+/* -----------------------------------------------------------------------------
+ * Dynamic libraries support (WIN32 not supported)
+ * ---------------------------------------------------------------------------*/
+
+#if defined(HAVE_DLOPEN) || defined(HAVE_DLOPEN_COMPAT)
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#ifndef RTLD_NOW
+    #define RTLD_NOW 0
+#endif
+#ifndef RTLD_LOCAL
+    #define RTLD_LOCAL 0
+#endif
+
+/**
+ * Note that Jim_LoadLibrary() requires a path to an existing file.
+ *
+ * If it is necessary to search JIM_LIBPATH, use Jim_PackageRequire() instead.
+ */
+int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName)
+{
+    void *handle = dlopen(pathName, RTLD_NOW | RTLD_LOCAL);
+    if (handle == NULL) {
+        Jim_SetResultFormatted(interp, "error loading extension \"%s\": %s", pathName,
+            dlerror());
+    }
+    else {
+        /* We use a unique init symbol depending on the extension name.
+         * This is done for compatibility between static and dynamic extensions.
+         * For extension readline.so, the init symbol is "Jim_readlineInit"
+         */
+        const char *pt;
+        const char *pkgname;
+        int pkgnamelen;
+        char initsym[40];
+        int (*onload) (Jim_Interp *);
+
+        pt = strrchr(pathName, '/');
+        if (pt) {
+            pkgname = pt + 1;
+        }
+        else {
+            pkgname = pathName;
+        }
+        pt = strchr(pkgname, '.');
+        if (pt) {
+            pkgnamelen = pt - pkgname;
+        }
+        else {
+            pkgnamelen = strlen(pkgname);
+        }
+        snprintf(initsym, sizeof(initsym), "Jim_%.*sInit", pkgnamelen, pkgname);
+
+        if ((onload = dlsym(handle, initsym)) == NULL) {
+            Jim_SetResultFormatted(interp,
+                "No %s symbol found in extension %s", initsym, pathName);
+        }
+        else if (onload(interp) != JIM_ERR) {
+            /* Add this handle to the stack of handles to be freed */
+            if (!interp->loadHandles) {
+                interp->loadHandles = Jim_Alloc(sizeof(*interp->loadHandles));
+                Jim_InitStack(interp->loadHandles);
+            }
+            Jim_StackPush(interp->loadHandles, handle);
+
+            Jim_SetEmptyResult(interp);
+
+            return JIM_OK;
+        }
+    }
+    if (handle) {
+        dlclose(handle);
+    }
+    return JIM_ERR;
+}
+
+static void JimFreeOneLoadHandle(void *handle)
+{
+    dlclose(handle);
+}
+
+void Jim_FreeLoadHandles(Jim_Interp *interp)
+{
+    if (interp->loadHandles) {
+        Jim_FreeStackElements(interp->loadHandles, JimFreeOneLoadHandle);
+        Jim_Free(interp->loadHandles);
+    }
+}
+
+#else /* JIM_DYNLIB */
+int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName)
+{
+    JIM_NOTUSED(interp);
+    JIM_NOTUSED(pathName);
+
+    Jim_SetResultString(interp, "the Jim binary has no support for [load]", -1);
+    return JIM_ERR;
+}
+
+void Jim_FreeLoadHandles(Jim_Interp *interp)
+{
+}
+#endif /* JIM_DYNLIB */
+
+/* [load] */
+static int Jim_LoadCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "libaryFile");
+        return JIM_ERR;
+    }
+    return Jim_LoadLibrary(interp, Jim_String(argv[1]));
+}
+
+int Jim_loadInit(Jim_Interp *interp)
+{
+    Jim_CreateCommand(interp, "load", Jim_LoadCoreCommand, NULL, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-nvp.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-nvp.c
new file mode 100755
index 0000000..be94f15
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-nvp.c
@@ -0,0 +1,338 @@
+#include <string.h>
+#include <jim-nvp.h>
+
+int Jim_GetNvp(Jim_Interp *interp,
+    Jim_Obj *objPtr, const Jim_Nvp * nvp_table, const Jim_Nvp ** result)
+{
+    Jim_Nvp *n;
+    int e;
+
+    e = Jim_Nvp_name2value_obj(interp, nvp_table, objPtr, &n);
+    if (e == JIM_ERR) {
+        return e;
+    }
+
+    /* Success? found? */
+    if (n->name) {
+        /* remove const */
+        *result = (Jim_Nvp *) n;
+        return JIM_OK;
+    }
+    else {
+        return JIM_ERR;
+    }
+}
+
+Jim_Nvp *Jim_Nvp_name2value_simple(const Jim_Nvp * p, const char *name)
+{
+    while (p->name) {
+        if (0 == strcmp(name, p->name)) {
+            break;
+        }
+        p++;
+    }
+    return ((Jim_Nvp *) (p));
+}
+
+Jim_Nvp *Jim_Nvp_name2value_nocase_simple(const Jim_Nvp * p, const char *name)
+{
+    while (p->name) {
+        if (0 == strcasecmp(name, p->name)) {
+            break;
+        }
+        p++;
+    }
+    return ((Jim_Nvp *) (p));
+}
+
+int Jim_Nvp_name2value_obj(Jim_Interp *interp, const Jim_Nvp * p, Jim_Obj *o, Jim_Nvp ** result)
+{
+    return Jim_Nvp_name2value(interp, p, Jim_String(o), result);
+}
+
+
+int Jim_Nvp_name2value(Jim_Interp *interp, const Jim_Nvp * _p, const char *name, Jim_Nvp ** result)
+{
+    const Jim_Nvp *p;
+
+    p = Jim_Nvp_name2value_simple(_p, name);
+
+    /* result */
+    if (result) {
+        *result = (Jim_Nvp *) (p);
+    }
+
+    /* found? */
+    if (p->name) {
+        return JIM_OK;
+    }
+    else {
+        return JIM_ERR;
+    }
+}
+
+int
+Jim_Nvp_name2value_obj_nocase(Jim_Interp *interp, const Jim_Nvp * p, Jim_Obj *o, Jim_Nvp ** puthere)
+{
+    return Jim_Nvp_name2value_nocase(interp, p, Jim_String(o), puthere);
+}
+
+int
+Jim_Nvp_name2value_nocase(Jim_Interp *interp, const Jim_Nvp * _p, const char *name,
+    Jim_Nvp ** puthere)
+{
+    const Jim_Nvp *p;
+
+    p = Jim_Nvp_name2value_nocase_simple(_p, name);
+
+    if (puthere) {
+        *puthere = (Jim_Nvp *) (p);
+    }
+    /* found */
+    if (p->name) {
+        return JIM_OK;
+    }
+    else {
+        return JIM_ERR;
+    }
+}
+
+
+int Jim_Nvp_value2name_obj(Jim_Interp *interp, const Jim_Nvp * p, Jim_Obj *o, Jim_Nvp ** result)
+{
+    int e;;
+    jim_wide w;
+
+    e = Jim_GetWide(interp, o, &w);
+    if (e != JIM_OK) {
+        return e;
+    }
+
+    return Jim_Nvp_value2name(interp, p, w, result);
+}
+
+Jim_Nvp *Jim_Nvp_value2name_simple(const Jim_Nvp * p, int value)
+{
+    while (p->name) {
+        if (value == p->value) {
+            break;
+        }
+        p++;
+    }
+    return ((Jim_Nvp *) (p));
+}
+
+
+int Jim_Nvp_value2name(Jim_Interp *interp, const Jim_Nvp * _p, int value, Jim_Nvp ** result)
+{
+    const Jim_Nvp *p;
+
+    p = Jim_Nvp_value2name_simple(_p, value);
+
+    if (result) {
+        *result = (Jim_Nvp *) (p);
+    }
+
+    if (p->name) {
+        return JIM_OK;
+    }
+    else {
+        return JIM_ERR;
+    }
+}
+
+
+int Jim_GetOpt_Setup(Jim_GetOptInfo * p, Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    memset(p, 0, sizeof(*p));
+    p->interp = interp;
+    p->argc = argc;
+    p->argv = argv;
+
+    return JIM_OK;
+}
+
+void Jim_GetOpt_Debug(Jim_GetOptInfo * p)
+{
+    int x;
+
+    fprintf(stderr, "---args---\n");
+    for (x = 0; x < p->argc; x++) {
+        fprintf(stderr, "%2d) %s\n", x, Jim_String(p->argv[x]));
+    }
+    fprintf(stderr, "-------\n");
+}
+
+
+int Jim_GetOpt_Obj(Jim_GetOptInfo * goi, Jim_Obj **puthere)
+{
+    Jim_Obj *o;
+
+    o = NULL;                   // failure
+    if (goi->argc) {
+        // success
+        o = goi->argv[0];
+        goi->argc -= 1;
+        goi->argv += 1;
+    }
+    if (puthere) {
+        *puthere = o;
+    }
+    if (o != NULL) {
+        return JIM_OK;
+    }
+    else {
+        return JIM_ERR;
+    }
+}
+
+int Jim_GetOpt_String(Jim_GetOptInfo * goi, char **puthere, int *len)
+{
+    int r;
+    Jim_Obj *o;
+    const char *cp;
+
+
+    r = Jim_GetOpt_Obj(goi, &o);
+    if (r == JIM_OK) {
+        cp = Jim_GetString(o, len);
+        if (puthere) {
+            /* remove const */
+            *puthere = (char *)(cp);
+        }
+    }
+    return r;
+}
+
+int Jim_GetOpt_Double(Jim_GetOptInfo * goi, double *puthere)
+{
+    int r;
+    Jim_Obj *o;
+    double _safe;
+
+    if (puthere == NULL) {
+        puthere = &_safe;
+    }
+
+    r = Jim_GetOpt_Obj(goi, &o);
+    if (r == JIM_OK) {
+        r = Jim_GetDouble(goi->interp, o, puthere);
+        if (r != JIM_OK) {
+            Jim_SetResultFormatted(goi->interp, "not a number: %#s", o);
+        }
+    }
+    return r;
+}
+
+int Jim_GetOpt_Wide(Jim_GetOptInfo * goi, jim_wide * puthere)
+{
+    int r;
+    Jim_Obj *o;
+    jim_wide _safe;
+
+    if (puthere == NULL) {
+        puthere = &_safe;
+    }
+
+    r = Jim_GetOpt_Obj(goi, &o);
+    if (r == JIM_OK) {
+        r = Jim_GetWide(goi->interp, o, puthere);
+    }
+    return r;
+}
+
+int Jim_GetOpt_Nvp(Jim_GetOptInfo * goi, const Jim_Nvp * nvp, Jim_Nvp ** puthere)
+{
+    Jim_Nvp *_safe;
+    Jim_Obj *o;
+    int e;
+
+    if (puthere == NULL) {
+        puthere = &_safe;
+    }
+
+    e = Jim_GetOpt_Obj(goi, &o);
+    if (e == JIM_OK) {
+        e = Jim_Nvp_name2value_obj(goi->interp, nvp, o, puthere);
+    }
+
+    return e;
+}
+
+void Jim_GetOpt_NvpUnknown(Jim_GetOptInfo * goi, const Jim_Nvp * nvptable, int hadprefix)
+{
+    if (hadprefix) {
+        Jim_SetResult_NvpUnknown(goi->interp, goi->argv[-2], goi->argv[-1], nvptable);
+    }
+    else {
+        Jim_SetResult_NvpUnknown(goi->interp, NULL, goi->argv[-1], nvptable);
+    }
+}
+
+
+int Jim_GetOpt_Enum(Jim_GetOptInfo * goi, const char *const *lookup, int *puthere)
+{
+    int _safe;
+    Jim_Obj *o;
+    int e;
+
+    if (puthere == NULL) {
+        puthere = &_safe;
+    }
+    e = Jim_GetOpt_Obj(goi, &o);
+    if (e == JIM_OK) {
+        e = Jim_GetEnum(goi->interp, o, lookup, puthere, "option", JIM_ERRMSG);
+    }
+    return e;
+}
+
+void
+Jim_SetResult_NvpUnknown(Jim_Interp *interp,
+    Jim_Obj *param_name, Jim_Obj *param_value, const Jim_Nvp * nvp)
+{
+    if (param_name) {
+        Jim_SetResultFormatted(interp, "%#s: Unknown: %#s, try one of: ", param_name, param_value);
+    }
+    else {
+        Jim_SetResultFormatted(interp, "Unknown param: %#s, try one of: ", param_value);
+    }
+    while (nvp->name) {
+        const char *a;
+        const char *b;
+
+        if ((nvp + 1)->name) {
+            a = nvp->name;
+            b = ", ";
+        }
+        else {
+            a = "or ";
+            b = nvp->name;
+        }
+        Jim_AppendStrings(interp, Jim_GetResult(interp), a, b, NULL);
+        nvp++;
+    }
+}
+
+const char *Jim_Debug_ArgvString(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    static Jim_Obj *debug_string_obj;
+
+    int x;
+
+    if (debug_string_obj) {
+        Jim_FreeObj(interp, debug_string_obj);
+    }
+
+    debug_string_obj = Jim_NewEmptyStringObj(interp);
+    for (x = 0; x < argc; x++) {
+        Jim_AppendStrings(interp, debug_string_obj, Jim_String(argv[x]), " ", NULL);
+    }
+
+    return Jim_String(debug_string_obj);
+}
+
+int Jim_nvpInit(Jim_Interp *interp)
+{
+    /* This is really a helper library, not an extension, but this is the easy way */
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-nvp.h b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-nvp.h
new file mode 100755
index 0000000..12ff889
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-nvp.h
@@ -0,0 +1,275 @@
+#ifndef JIM_NVP_H
+#define JIM_NVP_H
+
+#include <jim.h>
+
+/** Name Value Pairs, aka: NVP
+ *   -  Given a string - return the associated int.
+ *   -  Given a number - return the associated string.
+ *   .
+ *
+ * Very useful when the number is not a simple index into an array of
+ * known string, or there may be multiple strings (aliases) that mean then same
+ * thing.
+ *
+ * An NVP Table is terminated with ".name = NULL".
+ *
+ * During the 'name2value' operation, if no matching string is found
+ * the pointer to the terminal element (with p->name == NULL) is returned.
+ *
+ * Example:
+ * \code
+ *      const Jim_Nvp yn[] = {
+ *          { "yes", 1 },
+ *          { "no" , 0 },
+ *          { "yep", 1 },
+ *          { "nope", 0 },
+ *          { NULL, -1 },
+ *      };
+ *
+ *  Jim_Nvp *result
+ *  e = Jim_Nvp_name2value(interp, yn, "y", &result);
+ *         returns &yn[0];
+ *  e = Jim_Nvp_name2value(interp, yn, "n", &result);
+ *         returns &yn[1];
+ *  e = Jim_Nvp_name2value(interp, yn, "Blah", &result);
+ *         returns &yn[4];
+ * \endcode
+ *
+ * During the number2name operation, the first matching value is returned.
+ */
+typedef struct {
+	const char *name;
+	int         value;
+} Jim_Nvp;
+
+
+int Jim_GetNvp (Jim_Interp *interp,
+									Jim_Obj *objPtr,
+									const Jim_Nvp *nvp_table,
+									const Jim_Nvp **result);
+
+/* Name Value Pairs Operations */
+Jim_Nvp *Jim_Nvp_name2value_simple(const Jim_Nvp *nvp_table, const char *name);
+Jim_Nvp *Jim_Nvp_name2value_nocase_simple(const Jim_Nvp *nvp_table, const char *name);
+Jim_Nvp *Jim_Nvp_value2name_simple(const Jim_Nvp *nvp_table, int v);
+
+int Jim_Nvp_name2value(Jim_Interp *interp, const Jim_Nvp *nvp_table, const char *name, Jim_Nvp **result);
+int Jim_Nvp_name2value_nocase(Jim_Interp *interp, const Jim_Nvp *nvp_table, const char *name, Jim_Nvp **result);
+int Jim_Nvp_value2name(Jim_Interp *interp, const Jim_Nvp *nvp_table, int value, Jim_Nvp **result);
+
+int Jim_Nvp_name2value_obj(Jim_Interp *interp, const Jim_Nvp *nvp_table, Jim_Obj *name_obj, Jim_Nvp **result);
+int Jim_Nvp_name2value_obj_nocase(Jim_Interp *interp, const Jim_Nvp *nvp_table, Jim_Obj *name_obj, Jim_Nvp **result);
+int Jim_Nvp_value2name_obj(Jim_Interp *interp, const Jim_Nvp *nvp_table, Jim_Obj *value_obj, Jim_Nvp **result);
+
+/** prints a nice 'unknown' parameter error message to the 'result' */
+void Jim_SetResult_NvpUnknown(Jim_Interp *interp,
+												   Jim_Obj *param_name,
+												   Jim_Obj *param_value,
+												   const Jim_Nvp *nvp_table);
+
+
+/** Debug: convert argc/argv into a printable string for printf() debug
+ *
+ * \param interp - the interpeter
+ * \param argc   - arg count
+ * \param argv   - the objects
+ *
+ * \returns string pointer holding the text.
+ *
+ * Note, next call to this function will free the old (last) string.
+ *
+ * For example might want do this:
+ * \code
+ *     fp = fopen("some.file.log", "a");
+ *     fprintf(fp, "PARAMS are: %s\n", Jim_DebugArgvString(interp, argc, argv));
+ *     fclose(fp);
+ * \endcode
+ */
+const char *Jim_Debug_ArgvString(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
+
+/** A TCL -ish GetOpt like code.
+ *
+ * Some TCL objects have various "configuration" values.
+ * For example - in Tcl/Tk the "buttons" have many options.
+ *
+ * Usefull when dealing with command options.
+ * that may come in any order...
+ *
+ * Does not support "-foo = 123" type options.
+ * Only supports tcl type options, like "-foo 123"
+ */
+
+typedef struct jim_getopt {
+	Jim_Interp     *interp;
+	int            argc;
+	Jim_Obj        * const * argv;
+	int            isconfigure; /* non-zero if configure */
+} Jim_GetOptInfo;
+
+/** GetOpt - how to.
+ *
+ * Example (short and incomplete):
+ * \code
+ *   Jim_GetOptInfo goi;
+ *
+ *   Jim_GetOpt_Setup(&goi, interp, argc, argv);
+ *
+ *   while (goi.argc) {
+ *         e = Jim_GetOpt_Nvp(&goi, nvp_options, &n);
+ *         if (e != JIM_OK) {
+ *               Jim_GetOpt_NvpUnknown(&goi, nvp_options, 0);
+ *               return e;
+ *         }
+ *
+ *         switch (n->value) {
+ *         case ALIVE:
+ *             printf("Option ALIVE specified\n");
+ *             break;
+ *         case FIRST:
+ *             if (goi.argc < 1) {
+ *                     .. not enough args error ..
+ *             }
+ *             Jim_GetOpt_String(&goi, &cp, NULL);
+ *             printf("FIRSTNAME: %s\n", cp);
+ *         case AGE:
+ *             Jim_GetOpt_Wide(&goi, &w);
+ *             printf("AGE: %d\n", (int)(w));
+ *             break;
+ *         case POLITICS:
+ *             e = Jim_GetOpt_Nvp(&goi, nvp_politics, &n);
+ *             if (e != JIM_OK) {
+ *                 Jim_GetOpt_NvpUnknown(&goi, nvp_politics, 1);
+ *                 return e;
+ *             }
+ *         }
+ *  }
+ *
+ * \endcode
+ *
+ */
+
+/** Setup GETOPT
+ *
+ * \param goi    - get opt info to be initialized
+ * \param interp - jim interp
+ * \param argc   - argc count.
+ * \param argv   - argv (will be copied)
+ *
+ * \code
+ *     Jim_GetOptInfo  goi;
+ *
+ *     Jim_GetOptSetup(&goi, interp, argc, argv);
+ * \endcode
+ */
+
+int Jim_GetOpt_Setup(Jim_GetOptInfo *goi,
+											Jim_Interp *interp,
+											int argc,
+											Jim_Obj * const *  argv);
+
+
+/** Debug - Dump parameters to stderr
+ * \param goi - current parameters
+ */
+void Jim_GetOpt_Debug(Jim_GetOptInfo *goi);
+
+
+
+/** Remove argv[0] from the list.
+ *
+ * \param goi - get opt info
+ * \param puthere - where param is put
+ *
+ */
+int Jim_GetOpt_Obj(Jim_GetOptInfo *goi, Jim_Obj **puthere);
+
+/** Remove argv[0] as string.
+ *
+ * \param goi     - get opt info
+ * \param puthere - where param is put
+ * \param len     - return its length
+ */
+int Jim_GetOpt_String(Jim_GetOptInfo *goi, char **puthere, int *len);
+
+/** Remove argv[0] as double.
+ *
+ * \param goi     - get opt info
+ * \param puthere - where param is put.
+ *
+ */
+int Jim_GetOpt_Double(Jim_GetOptInfo *goi, double *puthere);
+
+/** Remove argv[0] as wide.
+ *
+ * \param goi     - get opt info
+ * \param puthere - where param is put.
+ */
+int Jim_GetOpt_Wide(Jim_GetOptInfo *goi, jim_wide *puthere);
+
+/** Remove argv[0] as NVP.
+ *
+ * \param goi     - get opt info
+ * \param lookup  - nvp lookup table
+ * \param puthere - where param is put.
+ *
+ */
+int Jim_GetOpt_Nvp(Jim_GetOptInfo *goi, const Jim_Nvp *lookup, Jim_Nvp **puthere);
+
+/** Create an appropriate error message for an NVP.
+ *
+ * \param goi - options info
+ * \param lookup - the NVP table that was used.
+ * \param hadprefix - 0 or 1 if the option had a prefix.
+ *
+ * This function will set the "interp->result" to a human readable
+ * error message listing the available options.
+ *
+ * This function assumes the previous option argv[-1] is the unknown string.
+ *
+ * If this option had some prefix, then pass "hadprefix = 1" else pass "hadprefix = 0"
+ *
+ * Example:
+ * \code
+ *
+ *  while (goi.argc) {
+ *     // Get the next option
+ *     e = Jim_GetOpt_Nvp(&goi, cmd_options, &n);
+ *     if (e != JIM_OK) {
+ *          // option was not recognized
+ *          // pass 'hadprefix = 0' because there is no prefix
+ *          Jim_GetOpt_NvpUnknown(&goi, cmd_options, 0);
+ *          return e;
+ *     }
+ *
+ *     switch (n->value) {
+ *     case OPT_SEX:
+ *          // handle:  --sex male | female | lots | needmore
+ *          e = Jim_GetOpt_Nvp(&goi, &nvp_sex, &n);
+ *          if (e != JIM_OK) {
+ *               Jim_GetOpt_NvpUnknown(&ogi, nvp_sex, 1);
+ *               return e;
+ *          }
+ *          printf("Code: (%d) is %s\n", n->value, n->name);
+ *          break;
+ *     case ...:
+ *          [snip]
+ *     }
+ * }
+ * \endcode
+ *
+ */
+void Jim_GetOpt_NvpUnknown(Jim_GetOptInfo *goi, const Jim_Nvp *lookup, int hadprefix);
+
+
+/** Remove argv[0] as Enum
+ *
+ * \param goi     - get opt info
+ * \param lookup  - lookup table.
+ * \param puthere - where param is put.
+ *
+ */
+int Jim_GetOpt_Enum(Jim_GetOptInfo *goi, const char * const *  lookup, int *puthere);
+
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-pack.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-pack.c
new file mode 100755
index 0000000..88bf2c1
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-pack.c
@@ -0,0 +1,380 @@
+#include <string.h>
+#include <jim.h>
+
+/* Provides the [pack] and [unpack] commands to pack and unpack
+ * a binary string to/from arbitrary width integers and strings.
+ *
+ * This may be used to implement the [binary] command.
+ */
+
+/**
+ * Big endian bit test.
+ *
+ * Considers 'bitvect' as a big endian bit stream and returns
+ * bit 'b' as zero or non-zero.
+ */
+static int JimTestBitBigEndian(const unsigned char *bitvec, int b)
+{
+    div_t pos = div(b, 8);
+    return bitvec[pos.quot] & (1 << (7 - pos.rem));
+}
+
+/**
+ * Little endian bit test.
+ *
+ * Considers 'bitvect' as a little endian bit stream and returns
+ * bit 'b' as zero or non-zero.
+ */
+static int JimTestBitLittleEndian(const unsigned char *bitvec, int b)
+{
+    div_t pos = div(b, 8);
+    return bitvec[pos.quot] & (1 << pos.rem);
+}
+
+/**
+ * Sign extends the given value, 'n' of width 'width' bits.
+ *
+ * For example, sign extending 0x80 with a width of 8, produces -128
+ */
+static jim_wide JimSignExtend(jim_wide n, int width)
+{
+    if (width == sizeof(jim_wide) * 8) {
+        /* Can't sign extend the maximum size integer */
+        return n;
+    }
+    if (n & ((jim_wide)1 << (width - 1))) {
+        /* Need to extend */
+        n -= ((jim_wide)1 << width);
+    }
+
+    return n;
+}
+
+/**
+ * Big endian integer extraction.
+ *
+ * Considers 'bitvect' as a big endian bit stream.
+ * Returns an integer of the given width (in bits)
+ * starting at the given position (in bits).
+ *
+ * The pos/width must represent bits inside bitvec,
+ * and the width be no more than the width of jim_wide.
+ */
+static jim_wide JimBitIntBigEndian(const unsigned char *bitvec, int pos, int width)
+{
+    jim_wide result = 0;
+    int i;
+
+    /* Aligned, byte extraction */
+    if (pos % 8 == 0 && width % 8 == 0) {
+        for (i = 0; i < width; i += 8) {
+            result = (result << 8) + bitvec[(pos + i) / 8];
+        }
+        return result;
+    }
+
+    /* Unaligned */
+    for (i = 0; i < width; i++) {
+        if (JimTestBitBigEndian(bitvec, pos + width - i - 1)) {
+            result |= ((jim_wide)1 << i);
+        }
+    }
+
+    return result;
+}
+
+/**
+ * Little endian integer extraction.
+ *
+ * Like JimBitIntBigEndian() but considers 'bitvect' as a little endian bit stream.
+ */
+static jim_wide JimBitIntLittleEndian(const unsigned char *bitvec, int pos, int width)
+{
+    jim_wide result = 0;
+    int i;
+
+    /* Aligned, byte extraction */
+    if (pos % 8 == 0 && width % 8 == 0) {
+        for (i = 0; i < width; i += 8) {
+            result += (jim_wide)bitvec[(pos + i) / 8] << i;
+        }
+        return result;
+    }
+
+    /* Unaligned */
+    for (i = 0; i < width; i++) {
+        if (JimTestBitLittleEndian(bitvec, pos + i)) {
+            result |= ((jim_wide)1 << i);
+        }
+    }
+
+    return result;
+}
+
+/**
+ * Big endian bit set.
+ *
+ * Considers 'bitvect' as a big endian bit stream and sets
+ * bit 'b' to 'bit'
+ */
+static void JimSetBitBigEndian(unsigned char *bitvec, int b, int bit)
+{
+    div_t pos = div(b, 8);
+    if (bit) {
+        bitvec[pos.quot] |= (1 << (7 - pos.rem));
+    }
+    else {
+        bitvec[pos.quot] &= ~(1 << (7 - pos.rem));
+    }
+}
+
+/**
+ * Little endian bit set.
+ *
+ * Considers 'bitvect' as a little endian bit stream and sets
+ * bit 'b' to 'bit'
+ */
+static void JimSetBitLittleEndian(unsigned char *bitvec, int b, int bit)
+{
+    div_t pos = div(b, 8);
+    if (bit) {
+        bitvec[pos.quot] |= (1 << pos.rem);
+    }
+    else {
+        bitvec[pos.quot] &= ~(1 << pos.rem);
+    }
+}
+
+/**
+ * Big endian integer packing.
+ *
+ * Considers 'bitvect' as a big endian bit stream.
+ * Packs integer 'value' of the given width (in bits)
+ * starting at the given position (in bits).
+ *
+ * The pos/width must represent bits inside bitvec,
+ * and the width be no more than the width of jim_wide.
+ */
+static void JimSetBitsIntBigEndian(unsigned char *bitvec, jim_wide value, int pos, int width)
+{
+    int i;
+
+    /* Common fast option */
+    if (pos % 8 == 0 && width == 8) {
+        bitvec[pos / 8] = value;
+        return;
+    }
+
+    for (i = 0; i < width; i++) {
+        int bit = !!(value & ((jim_wide)1 << i));
+        JimSetBitBigEndian(bitvec, pos + width - i - 1, bit);
+    }
+}
+
+/**
+ * Little endian version of JimSetBitsIntBigEndian()
+ */
+static void JimSetBitsIntLittleEndian(unsigned char *bitvec, jim_wide value, int pos, int width)
+{
+    int i;
+
+    /* Common fast option */
+    if (pos % 8 == 0 && width == 8) {
+        bitvec[pos / 8] = value;
+        return;
+    }
+
+    for (i = 0; i < width; i++) {
+        int bit = !!(value & ((jim_wide)1 << i));
+        JimSetBitLittleEndian(bitvec, pos + i, bit);
+    }
+}
+
+/**
+ * [unpack]
+ *
+ * Usage: unpack binvalue -intbe|-intle|-uintbe|-uintle|-str bitpos bitwidth
+ *
+ * Unpacks bits from $binvalue at bit position $bitpos and with $bitwidth.
+ * Interprets the value according to the type and returns it.
+ */
+static int Jim_UnpackCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int option;
+    static const char * const options[] = { "-intbe", "-intle", "-uintbe", "-uintle", "-str", NULL };
+    enum { OPT_INTBE, OPT_INTLE, OPT_UINTBE, OPT_UINTLE, OPT_STR, };
+    jim_wide pos;
+    jim_wide width;
+
+    if (argc != 5) {
+        Jim_WrongNumArgs(interp, 1, argv, "binvalue -intbe|-intle|-uintbe|-uintle|-str bitpos bitwidth");
+        return JIM_ERR;
+    }
+    if (Jim_GetEnum(interp, argv[2], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    if (Jim_GetWide(interp, argv[3], &pos) != JIM_OK) {
+        return JIM_ERR;
+    }
+    if (Jim_GetWide(interp, argv[4], &width) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    if (option == OPT_STR) {
+        int len;
+        const char *str = Jim_GetString(argv[1], &len);
+
+        if (width % 8 || pos % 8) {
+            Jim_SetResultString(interp, "string field is not on a byte boundary", -1);
+            return JIM_ERR;
+        }
+
+        if (pos >= 0 && width > 0 && pos < len * 8) {
+            if (pos + width > len * 8) {
+                width = len * 8 - pos;
+            }
+            Jim_SetResultString(interp, str + pos / 8, width / 8);
+        }
+        return JIM_OK;
+    }
+    else {
+        int len;
+        const unsigned char *str = (const unsigned char *)Jim_GetString(argv[1], &len);
+        jim_wide result = 0;
+
+        if (width > sizeof(jim_wide) * 8) {
+            Jim_SetResultFormatted(interp, "int field is too wide: %#s", argv[4]);
+            return JIM_ERR;
+        }
+
+        if (pos >= 0 && width > 0 && pos < len * 8) {
+            if (pos + width > len * 8) {
+                width = len * 8 - pos;
+            }
+            if (option == OPT_INTBE || option == OPT_UINTBE) {
+                result = JimBitIntBigEndian(str, pos, width);
+            }
+            else {
+                result = JimBitIntLittleEndian(str, pos, width);
+            }
+            if (option == OPT_INTBE || option == OPT_INTLE) {
+                result = JimSignExtend(result, width);
+            }
+        }
+        Jim_SetResultInt(interp, result);
+        return JIM_OK;
+    }
+}
+
+/**
+ * [pack]
+ *
+ * Usage: pack varname value -intle|-intbe|-str width ?bitoffset?
+ *
+ * Packs the binary representation of 'value' into the variable of the given name.
+ * The value is packed according to the given type, width and bitoffset.
+ * The variable is created if necessary (like [append])
+ * Ihe variable is expanded if necessary
+ */
+static int Jim_PackCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int option;
+    static const char * const options[] = { "-intle", "-intbe", "-str", NULL };
+    enum { OPT_LE, OPT_BE, OPT_STR };
+    jim_wide pos = 0;
+    jim_wide width;
+    jim_wide value;
+    Jim_Obj *stringObjPtr;
+    int len;
+    int freeobj = 0;
+
+    if (argc != 5 && argc != 6) {
+        Jim_WrongNumArgs(interp, 1, argv, "varName value -intle|-intbe|-str bitwidth ?bitoffset?");
+        return JIM_ERR;
+    }
+    if (Jim_GetEnum(interp, argv[3], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+        return JIM_ERR;
+    }
+    if (option != OPT_STR && Jim_GetWide(interp, argv[2], &value) != JIM_OK) {
+        return JIM_ERR;
+    }
+    if (Jim_GetWide(interp, argv[4], &width) != JIM_OK) {
+        return JIM_ERR;
+    }
+    if (width <= 0 || (option == OPT_STR && width % 8) || (option != OPT_STR && width > sizeof(jim_wide) * 8)) {
+        Jim_SetResultFormatted(interp, "bad bitwidth: %#s", argv[5]);
+        return JIM_ERR;
+    }
+    if (argc == 6) {
+        if (Jim_GetWide(interp, argv[5], &pos) != JIM_OK) {
+            return JIM_ERR;
+        }
+        if (pos < 0 || (option == OPT_STR && pos % 8)) {
+            Jim_SetResultFormatted(interp, "bad bitoffset: %#s", argv[5]);
+            return JIM_ERR;
+        }
+    }
+
+    stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
+    if (!stringObjPtr) {
+        /* Create the string if it doesn't exist */
+        stringObjPtr = Jim_NewEmptyStringObj(interp);
+        freeobj = 1;
+    }
+    else if (Jim_IsShared(stringObjPtr)) {
+        freeobj = 1;
+        stringObjPtr = Jim_DuplicateObj(interp, stringObjPtr);
+    }
+
+    len = Jim_Length(stringObjPtr) * 8;
+
+    /* Extend the string as necessary first */
+    while (len < pos + width) {
+        Jim_AppendString(interp, stringObjPtr, "", 1);
+        len += 8;
+    }
+
+    Jim_SetResultInt(interp, pos + width);
+
+    /* Now set the bits. Note that the the string *must* have no non-string rep
+     * since we are writing the bytes directly.
+     */
+    Jim_AppendString(interp, stringObjPtr, "", 0);
+
+    if (option == OPT_BE) {
+        JimSetBitsIntBigEndian((unsigned char *)stringObjPtr->bytes, value, pos, width);
+    }
+    else if (option == OPT_LE) {
+        JimSetBitsIntLittleEndian((unsigned char *)stringObjPtr->bytes, value, pos, width);
+    }
+    else {
+        pos /= 8;
+        width /= 8;
+
+        if (width > Jim_Length(argv[2])) {
+            width = Jim_Length(argv[2]);
+        }
+        memcpy(stringObjPtr->bytes + pos, Jim_GetString(argv[2], NULL), width);
+        /* No padding is needed since the string is already extended */
+    }
+
+    if (Jim_SetVariable(interp, argv[1], stringObjPtr) != JIM_OK) {
+        if (freeobj) {
+            Jim_FreeNewObj(interp, stringObjPtr);
+            return JIM_ERR;
+        }
+    }
+    return JIM_OK;
+}
+
+int Jim_packInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "pack", "1.0", JIM_ERRMSG)) {
+        return JIM_ERR;
+    }
+
+    Jim_CreateCommand(interp, "unpack", Jim_UnpackCmd, NULL, NULL);
+    Jim_CreateCommand(interp, "pack", Jim_PackCmd, NULL, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-package.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-package.c
new file mode 100755
index 0000000..9caec0d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-package.c
@@ -0,0 +1,259 @@
+#include <unistd.h>
+#include <string.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "jim-subcmd.h"
+
+/* -----------------------------------------------------------------------------
+ * Packages handling
+ * ---------------------------------------------------------------------------*/
+
+int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
+{
+    /* If the package was already provided returns an error. */
+    Jim_HashEntry *he = Jim_FindHashEntry(&interp->packages, name);
+
+    /* An empty result means the automatic entry. This can be replaced */
+    if (he && *(const char *)he->u.val) {
+        if (flags & JIM_ERRMSG) {
+            Jim_SetResultFormatted(interp, "package \"%s\" was already provided", name);
+        }
+        return JIM_ERR;
+    }
+    if (he) {
+        Jim_DeleteHashEntry(&interp->packages, name);
+    }
+    Jim_AddHashEntry(&interp->packages, name, (char *)ver);
+    return JIM_OK;
+}
+
+static char *JimFindPackage(Jim_Interp *interp, char **prefixes, int prefixc, const char *pkgName)
+{
+    int i;
+    char *buf = Jim_Alloc(JIM_PATH_LEN);
+
+    for (i = 0; i < prefixc; i++) {
+        if (prefixes[i] == NULL)
+            continue;
+
+        /* Loadable modules are tried first */
+#ifdef jim_ext_load
+        snprintf(buf, JIM_PATH_LEN, "%s/%s.so", prefixes[i], pkgName);
+        if (access(buf, R_OK) == 0) {
+            return buf;
+        }
+#endif
+        if (strcmp(prefixes[i], ".") == 0) {
+            snprintf(buf, JIM_PATH_LEN, "%s.tcl", pkgName);
+        }
+        else {
+            snprintf(buf, JIM_PATH_LEN, "%s/%s.tcl", prefixes[i], pkgName);
+        }
+
+        if (access(buf, R_OK) == 0) {
+            return buf;
+        }
+    }
+    Jim_Free(buf);
+    return NULL;
+}
+
+/* Search for a suitable package under every dir specified by JIM_LIBPATH,
+ * and load it if possible. If a suitable package was loaded with success
+ * JIM_OK is returned, otherwise JIM_ERR is returned. */
+static int JimLoadPackage(Jim_Interp *interp, const char *name, int flags)
+{
+    Jim_Obj *libPathObjPtr;
+    char **prefixes, *path;
+    int prefixc, i, retCode = JIM_ERR;
+
+    libPathObjPtr = Jim_GetGlobalVariableStr(interp, JIM_LIBPATH, JIM_NONE);
+    if (libPathObjPtr == NULL) {
+        prefixc = 0;
+        libPathObjPtr = NULL;
+    }
+    else {
+        Jim_IncrRefCount(libPathObjPtr);
+        prefixc = Jim_ListLength(interp, libPathObjPtr);
+    }
+
+    prefixes = Jim_Alloc(sizeof(char *) * prefixc);
+    for (i = 0; i < prefixc; i++) {
+        Jim_Obj *prefixObjPtr;
+
+        if (Jim_ListIndex(interp, libPathObjPtr, i, &prefixObjPtr, JIM_NONE) != JIM_OK) {
+            prefixes[i] = NULL;
+            continue;
+        }
+        prefixes[i] = Jim_StrDup(Jim_String(prefixObjPtr));
+    }
+
+    /* Scan every directory for the the first match */
+    path = JimFindPackage(interp, prefixes, prefixc, name);
+    if (path != NULL) {
+        char *p = strrchr(path, '.');
+
+        /* Note: Even if the file fails to load, we consider the package loaded.
+         *       This prevents issues with recursion.
+         *       Use a dummy version of "" to signify this case.
+         */
+        Jim_PackageProvide(interp, name, "", 0);
+
+        /* Try to load/source it */
+        if (p && strcmp(p, ".tcl") == 0) {
+            retCode = Jim_EvalFileGlobal(interp, path);
+        }
+#ifdef jim_ext_load
+        else {
+            retCode = Jim_LoadLibrary(interp, path);
+        }
+#endif
+        if (retCode != JIM_OK) {
+            /* Upon failure, remove the dummy entry */
+            Jim_DeleteHashEntry(&interp->packages, name);
+        }
+        Jim_Free(path);
+    }
+    for (i = 0; i < prefixc; i++)
+        Jim_Free(prefixes[i]);
+    Jim_Free(prefixes);
+    if (libPathObjPtr)
+        Jim_DecrRefCount(interp, libPathObjPtr);
+    return retCode;
+}
+
+int Jim_PackageRequire(Jim_Interp *interp, const char *name, int flags)
+{
+    Jim_HashEntry *he;
+
+    /* Start with an empty error string */
+    Jim_SetResultString(interp, "", 0);
+
+    he = Jim_FindHashEntry(&interp->packages, name);
+    if (he == NULL) {
+        /* Try to load the package. */
+        int retcode = JimLoadPackage(interp, name, flags);
+        if (retcode != JIM_OK) {
+            if (flags & JIM_ERRMSG) {
+                int len;
+
+                Jim_GetString(Jim_GetResult(interp), &len);
+                Jim_SetResultFormatted(interp, "%#s%sCan't load package %s",
+                    Jim_GetResult(interp), len ? "\n" : "", name);
+            }
+            return retcode;
+        }
+
+        /* In case the package did no 'package provide' */
+        Jim_PackageProvide(interp, name, "1.0", 0);
+
+        /* Now it must exist */
+        he = Jim_FindHashEntry(&interp->packages, name);
+    }
+
+    Jim_SetResultString(interp, he->u.val, -1);
+    return JIM_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * package provide name ?version?
+ *
+ *      This procedure is invoked to declare that a particular version
+ *      of a particular package is now present in an interpreter.  There
+ *      must not be any other version of this package already
+ *      provided in the interpreter.
+ *
+ * Results:
+ *      Returns JIM_OK and sets the package version (or 1.0 if not specified).
+ *
+ *----------------------------------------------------------------------
+ */
+static int package_cmd_provide(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *version = "1.0";
+
+    if (argc == 2) {
+        version = Jim_String(argv[1]);
+    }
+    return Jim_PackageProvide(interp, Jim_String(argv[0]), version, JIM_ERRMSG);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * package require name ?version?
+ *
+ *      This procedure is load a given package.
+ *      Note that the version is ignored.
+ *
+ * Results:
+ *      Returns JIM_OK and sets the package version.
+ *
+ *----------------------------------------------------------------------
+ */
+static int package_cmd_require(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    /* package require failing is important enough to add to the stack */
+    interp->addStackTrace++;
+
+    return Jim_PackageRequire(interp, Jim_String(argv[0]), JIM_ERRMSG);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * package list
+ *
+ *      Returns a list of known packages
+ *
+ * Results:
+ *      Returns JIM_OK and sets a list of known packages.
+ *
+ *----------------------------------------------------------------------
+ */
+static int package_cmd_list(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_HashTableIterator *htiter;
+    Jim_HashEntry *he;
+    Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+    htiter = Jim_GetHashTableIterator(&interp->packages);
+    while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+        Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, he->key, -1));
+    }
+    Jim_FreeHashTableIterator(htiter);
+
+    Jim_SetResult(interp, listObjPtr);
+
+    return JIM_OK;
+}
+
+static const jim_subcmd_type package_command_table[] = {
+    {.cmd = "provide",
+            .args = "name ?version?",
+            .function = package_cmd_provide,
+            .minargs = 1,
+            .maxargs = 2,
+        .description = "Indicates that the current script provides the given package"},
+    {.cmd = "require",
+            .args = "name ?version?",
+            .function = package_cmd_require,
+            .minargs = 1,
+            .maxargs = 2,
+        .description = "Loads the given package by looking in standard places"},
+    {.cmd = "list",
+            .function = package_cmd_list,
+            .minargs = 0,
+            .maxargs = 0,
+        .description = "Lists all known packages"},
+    {0}
+};
+
+int Jim_packageInit(Jim_Interp *interp)
+{
+    Jim_CreateCommand(interp, "package", Jim_SubCmdProc, (void *)package_command_table, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-posix.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-posix.c
new file mode 100755
index 0000000..0cf3604
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-posix.c
@@ -0,0 +1,231 @@
+
+/* Jim - POSIX extension
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ *
+ * 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
+ *
+ * A copy of the license is also included in the source distribution
+ * of Jim, as a TXT file name called LICENSE.
+ *
+ * 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 <sys/types.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+
+#ifdef HAVE_SYS_SYSINFO_H
+#include <sys/sysinfo.h>
+#endif
+
+static void Jim_PosixSetError(Jim_Interp *interp)
+{
+    Jim_SetResultString(interp, strerror(errno), -1);
+}
+
+#if defined(HAVE_FORK)
+static int Jim_PosixForkCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    pid_t pid;
+
+    JIM_NOTUSED(argv);
+
+    if (argc != 1) {
+        Jim_WrongNumArgs(interp, 1, argv, "");
+        return JIM_ERR;
+    }
+    if ((pid = fork()) == -1) {
+        Jim_PosixSetError(interp);
+        return JIM_ERR;
+    }
+    Jim_SetResultInt(interp, (jim_wide) pid);
+    return JIM_OK;
+}
+#endif
+
+/*
+ * os.wait ?-nohang? pid
+ *
+ * An interface to waitpid(2)
+ *
+ * Returns a 3 element list.
+ *
+ * If -nohang is specified, and the process is still alive, returns
+ *
+ *   {0 none 0}
+ *
+ * If the process does not exist or has already been waited for, returns:
+ *
+ *   {-1 error <error-description>}
+ *
+ * If the process exited normally, returns:
+ *
+ *   {<pid> exit <exit-status>}
+ *
+ * If the process terminated on a signal, returns:
+ *
+ *   {<pid> signal <signal-number>}
+ *
+ * Otherwise (core dump, stopped, continued, ...), returns:
+ *
+ *   {<pid> other 0}
+ */
+static int Jim_PosixWaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int nohang = 0;
+    long pid;
+    int status;
+    Jim_Obj *listObj;
+    const char *type;
+    int value;
+
+    if (argc > 1 && Jim_CompareStringImmediate(interp, argv[1], "-nohang")) {
+        nohang = 1;
+    }
+    if (argc != nohang + 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "?-nohang? pid");
+        return JIM_ERR;
+    }
+    if (Jim_GetLong(interp, argv[nohang + 1], &pid) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    pid = waitpid(pid, &status, nohang ? WNOHANG : 0);
+    listObj = Jim_NewListObj(interp, NULL, 0);
+    Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, pid));
+    if (pid < 0) {
+        type = "error";
+        value = errno;
+    }
+    else if (pid == 0) {
+        type = "none";
+        value = 0;
+    }
+    else if (WIFEXITED(status)) {
+        type = "exit";
+        value = WEXITSTATUS(status);
+    }
+    else if (WIFSIGNALED(status)) {
+        type = "signal";
+        value = WTERMSIG(status);
+    }
+    else {
+        type = "other";
+        value = 0;
+    }
+
+    Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, type, -1));
+    if (pid < 0) {
+        Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, strerror(value), -1));
+    }
+    else {
+        Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value));
+    }
+    Jim_SetResult(interp, listObj);
+    return JIM_OK;
+}
+
+static int Jim_PosixGetidsCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objv[8];
+
+    if (argc != 1) {
+        Jim_WrongNumArgs(interp, 1, argv, "");
+        return JIM_ERR;
+    }
+    objv[0] = Jim_NewStringObj(interp, "uid", -1);
+    objv[1] = Jim_NewIntObj(interp, getuid());
+    objv[2] = Jim_NewStringObj(interp, "euid", -1);
+    objv[3] = Jim_NewIntObj(interp, geteuid());
+    objv[4] = Jim_NewStringObj(interp, "gid", -1);
+    objv[5] = Jim_NewIntObj(interp, getgid());
+    objv[6] = Jim_NewStringObj(interp, "egid", -1);
+    objv[7] = Jim_NewIntObj(interp, getegid());
+    Jim_SetResult(interp, Jim_NewListObj(interp, objv, 8));
+    return JIM_OK;
+}
+
+#define JIM_HOST_NAME_MAX 1024
+static int Jim_PosixGethostnameCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    char *buf;
+    int rc = JIM_OK;
+
+    if (argc != 1) {
+        Jim_WrongNumArgs(interp, 1, argv, "");
+        return JIM_ERR;
+    }
+    buf = Jim_Alloc(JIM_HOST_NAME_MAX);
+    if (gethostname(buf, JIM_HOST_NAME_MAX) == -1) {
+        Jim_PosixSetError(interp);
+        rc = JIM_ERR;
+    }
+    else {
+        Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, -1));
+    }
+    return rc;
+}
+
+static int Jim_PosixUptimeCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+#ifdef HAVE_STRUCT_SYSINFO_UPTIME
+    struct sysinfo info;
+
+    if (argc != 1) {
+        Jim_WrongNumArgs(interp, 1, argv, "");
+        return JIM_ERR;
+    }
+
+    if (sysinfo(&info) == -1) {
+        Jim_PosixSetError(interp);
+        return JIM_ERR;
+    }
+
+    Jim_SetResultInt(interp, info.uptime);
+#else
+    Jim_SetResultInt(interp, (long)time(NULL));
+#endif
+    return JIM_OK;
+}
+
+static int Jim_PosixPidCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 1) {
+        Jim_WrongNumArgs(interp, 1, argv, "");
+        return JIM_ERR;
+    }
+
+    Jim_SetResultInt(interp, getpid());
+    return JIM_OK;
+}
+
+int Jim_posixInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "posix", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+#ifdef HAVE_FORK
+    Jim_CreateCommand(interp, "os.fork", Jim_PosixForkCommand, NULL, NULL);
+#endif
+    Jim_CreateCommand(interp, "os.wait", Jim_PosixWaitCommand, NULL, NULL);
+    Jim_CreateCommand(interp, "os.getids", Jim_PosixGetidsCommand, NULL, NULL);
+    Jim_CreateCommand(interp, "os.gethostname", Jim_PosixGethostnameCommand, NULL, NULL);
+    Jim_CreateCommand(interp, "os.uptime", Jim_PosixUptimeCommand, NULL, NULL);
+    Jim_CreateCommand(interp, "pid", Jim_PosixPidCommand, NULL, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-readdir.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-readdir.c
new file mode 100755
index 0000000..67fc956
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-readdir.c
@@ -0,0 +1,119 @@
+
+/*
+ * Tcl readdir command.
+ *
+ * (c) 2008 Steve Bennett <steveb@worware.net.au>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ *
+ * Based on original work by:
+ *-----------------------------------------------------------------------------
+ * Copyright 1991-1994 Karl Lehenbauer and Mark Diekhans.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies.  Karl Lehenbauer and
+ * Mark Diekhans make no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or
+ * implied warranty.
+ *-----------------------------------------------------------------------------
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Jim_ReaddirCmd --
+ *     Implements the rename TCL command:
+ *         readdir ?-nocomplain? dirPath
+ *
+ * Results:
+ *      Standard TCL result.
+ *-----------------------------------------------------------------------------
+ */
+int Jim_ReaddirCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *dirPath;
+    DIR *dirPtr;
+    struct dirent *entryPtr;
+    int nocomplain = 0;
+
+    if (argc == 3 && Jim_CompareStringImmediate(interp, argv[1], "-nocomplain")) {
+        nocomplain = 1;
+    }
+    if (argc != 2 && !nocomplain) {
+        Jim_WrongNumArgs(interp, 1, argv, "?-nocomplain? dirPath");
+        return JIM_ERR;
+    }
+
+    dirPath = Jim_String(argv[1 + nocomplain]);
+
+    dirPtr = opendir(dirPath);
+    if (dirPtr == NULL) {
+        if (nocomplain) {
+            return JIM_OK;
+        }
+        Jim_SetResultString(interp, strerror(errno), -1);
+        return JIM_ERR;
+    }
+    Jim_SetResultString(interp, strerror(errno), -1);
+
+    Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
+
+    while ((entryPtr = readdir(dirPtr)) != NULL) {
+        if (entryPtr->d_name[0] == '.') {
+            if (entryPtr->d_name[1] == '\0') {
+                continue;
+            }
+            if ((entryPtr->d_name[1] == '.') && (entryPtr->d_name[2] == '\0'))
+                continue;
+        }
+        Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp,
+                entryPtr->d_name, -1));
+    }
+    closedir(dirPtr);
+
+    return JIM_OK;
+}
+
+int Jim_readdirInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "readdir", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    Jim_CreateCommand(interp, "readdir", Jim_ReaddirCmd, NULL, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-readline.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-readline.c
new file mode 100755
index 0000000..3990d0c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-readline.c
@@ -0,0 +1,61 @@
+
+/* Jim - Readline bindings for Jim
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ *
+ * 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
+ *
+ * A copy of the license is also included in the source distribution
+ * of Jim, as a TXT file name called LICENSE.
+ *
+ * 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 "jim.h"
+#include "jimautoconf.h"
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+static int JimRlReadlineCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    char *line;
+
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "prompt");
+        return JIM_ERR;
+    }
+    line = readline(Jim_String(argv[1]));
+    if (!line) {
+        return JIM_EXIT;
+    }
+    Jim_SetResult(interp, Jim_NewStringObj(interp, line, -1));
+    return JIM_OK;
+}
+
+static int JimRlAddHistoryCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "string");
+        return JIM_ERR;
+    }
+    add_history(Jim_String(argv[1]));
+    return JIM_OK;
+}
+
+int Jim_readlineInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "readline", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    Jim_CreateCommand(interp, "readline.readline", JimRlReadlineCommand, NULL, NULL);
+    Jim_CreateCommand(interp, "readline.addhistory", JimRlAddHistoryCommand, NULL, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-regexp.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-regexp.c
new file mode 100755
index 0000000..2ccd996
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-regexp.c
@@ -0,0 +1,566 @@
+/*
+ * Implements the regexp and regsub commands for Jim
+ *
+ * (c) 2008 Steve Bennett <steveb@workware.net.au>
+ *
+ * Uses C library regcomp()/regexec() for the matching.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ *
+ * Based on code originally from Tcl 6.7:
+ *
+ * Copyright 1987-1991 Regents of the University of California
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies.  The University of California
+ * makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "jimregexp.h"
+
+static void FreeRegexpInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    regfree(objPtr->internalRep.regexpValue.compre);
+    Jim_Free(objPtr->internalRep.regexpValue.compre);
+}
+
+static const Jim_ObjType regexpObjType = {
+    "regexp",
+    FreeRegexpInternalRep,
+    NULL,
+    NULL,
+    JIM_TYPE_NONE
+};
+
+static regex_t *SetRegexpFromAny(Jim_Interp *interp, Jim_Obj *objPtr, unsigned flags)
+{
+    regex_t *compre;
+    const char *pattern;
+    int ret;
+
+    /* Check if the object is already an uptodate variable */
+    if (objPtr->typePtr == &regexpObjType &&
+        objPtr->internalRep.regexpValue.compre && objPtr->internalRep.regexpValue.flags == flags) {
+        /* nothing to do */
+        return objPtr->internalRep.regexpValue.compre;
+    }
+
+    /* Not a regexp or the flags do not match */
+
+    /* Get the string representation */
+    pattern = Jim_String(objPtr);
+    compre = Jim_Alloc(sizeof(regex_t));
+
+    if ((ret = regcomp(compre, pattern, REG_EXTENDED | flags)) != 0) {
+        char buf[100];
+
+        regerror(ret, compre, buf, sizeof(buf));
+        Jim_SetResultFormatted(interp, "couldn't compile regular expression pattern: %s", buf);
+        regfree(compre);
+        Jim_Free(compre);
+        return NULL;
+    }
+
+    Jim_FreeIntRep(interp, objPtr);
+
+    objPtr->typePtr = &regexpObjType;
+    objPtr->internalRep.regexpValue.flags = flags;
+    objPtr->internalRep.regexpValue.compre = compre;
+
+    return compre;
+}
+
+int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int opt_indices = 0;
+    int opt_all = 0;
+    int opt_inline = 0;
+    regex_t *regex;
+    int match, i, j;
+    int offset = 0;
+    regmatch_t *pmatch = NULL;
+    int source_len;
+    int result = JIM_OK;
+    const char *pattern;
+    const char *source_str;
+    int num_matches = 0;
+    int num_vars;
+    Jim_Obj *resultListObj = NULL;
+    int regcomp_flags = 0;
+    int eflags = 0;
+    int option;
+    enum {
+        OPT_INDICES,  OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_INLINE, OPT_START, OPT_END
+    };
+    static const char * const options[] = {
+        "-indices", "-nocase", "-line", "-all", "-inline", "-start", "--", NULL
+    };
+
+    if (argc < 3) {
+      wrongNumArgs:
+        Jim_WrongNumArgs(interp, 1, argv,
+            "?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?");
+        return JIM_ERR;
+    }
+
+    for (i = 1; i < argc; i++) {
+        const char *opt = Jim_String(argv[i]);
+
+        if (*opt != '-') {
+            break;
+        }
+        if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+            return JIM_ERR;
+        }
+        if (option == OPT_END) {
+            i++;
+            break;
+        }
+        switch (option) {
+            case OPT_INDICES:
+                opt_indices = 1;
+                break;
+
+            case OPT_NOCASE:
+                regcomp_flags |= REG_ICASE;
+                break;
+
+            case OPT_LINE:
+                regcomp_flags |= REG_NEWLINE;
+                break;
+
+            case OPT_ALL:
+                opt_all = 1;
+                break;
+
+            case OPT_INLINE:
+                opt_inline = 1;
+                break;
+
+            case OPT_START:
+                if (++i == argc) {
+                    goto wrongNumArgs;
+                }
+                if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
+                    return JIM_ERR;
+                }
+                break;
+        }
+    }
+    if (argc - i < 2) {
+        goto wrongNumArgs;
+    }
+
+    regex = SetRegexpFromAny(interp, argv[i], regcomp_flags);
+    if (!regex) {
+        return JIM_ERR;
+    }
+
+    pattern = Jim_String(argv[i]);
+    source_str = Jim_GetString(argv[i + 1], &source_len);
+
+    num_vars = argc - i - 2;
+
+    if (opt_inline) {
+        if (num_vars) {
+            Jim_SetResultString(interp, "regexp match variables not allowed when using -inline",
+                -1);
+            result = JIM_ERR;
+            goto done;
+        }
+        num_vars = regex->re_nsub + 1;
+    }
+
+    pmatch = Jim_Alloc((num_vars + 1) * sizeof(*pmatch));
+
+    /* If an offset has been specified, adjust for that now.
+     * If it points past the end of the string, point to the terminating null
+     */
+    if (offset) {
+        if (offset < 0) {
+            offset += source_len + 1;
+        }
+        if (offset > source_len) {
+            source_str += source_len;
+        }
+        else if (offset > 0) {
+            source_str += offset;
+        }
+        eflags |= REG_NOTBOL;
+    }
+
+    if (opt_inline) {
+        resultListObj = Jim_NewListObj(interp, NULL, 0);
+    }
+
+  next_match:
+    match = regexec(regex, source_str, num_vars + 1, pmatch, eflags);
+    if (match >= REG_BADPAT) {
+        char buf[100];
+
+        regerror(match, regex, buf, sizeof(buf));
+        Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
+        result = JIM_ERR;
+        goto done;
+    }
+
+    if (match == REG_NOMATCH) {
+        goto done;
+    }
+
+    num_matches++;
+
+    if (opt_all && !opt_inline) {
+        /* Just count the number of matches, so skip the substitution h */
+        goto try_next_match;
+    }
+
+    /*
+     * If additional variable names have been specified, return
+     * index information in those variables.
+     */
+
+    j = 0;
+    for (i += 2; opt_inline ? j < num_vars : i < argc; i++, j++) {
+        Jim_Obj *resultObj;
+
+        if (opt_indices) {
+            resultObj = Jim_NewListObj(interp, NULL, 0);
+        }
+        else {
+            resultObj = Jim_NewStringObj(interp, "", 0);
+        }
+
+        if (pmatch[j].rm_so == -1) {
+            if (opt_indices) {
+                Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1));
+                Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1));
+            }
+        }
+        else {
+            int len = pmatch[j].rm_eo - pmatch[j].rm_so;
+
+            if (opt_indices) {
+                Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp,
+                        offset + pmatch[j].rm_so));
+                Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp,
+                        offset + pmatch[j].rm_so + len - 1));
+            }
+            else {
+                Jim_AppendString(interp, resultObj, source_str + pmatch[j].rm_so, len);
+            }
+        }
+
+        if (opt_inline) {
+            Jim_ListAppendElement(interp, resultListObj, resultObj);
+        }
+        else {
+            /* And now set the result variable */
+            result = Jim_SetVariable(interp, argv[i], resultObj);
+
+            if (result != JIM_OK) {
+                Jim_FreeObj(interp, resultObj);
+                break;
+            }
+        }
+    }
+
+  try_next_match:
+    if (opt_all && (pattern[0] != '^' || (regcomp_flags & REG_NEWLINE)) && *source_str) {
+        if (pmatch[0].rm_eo) {
+            offset += pmatch[0].rm_eo;
+            source_str += pmatch[0].rm_eo;
+        }
+        else {
+            source_str++;
+            offset++;
+        }
+        if (*source_str) {
+            eflags = REG_NOTBOL;
+            goto next_match;
+        }
+    }
+
+  done:
+    if (result == JIM_OK) {
+        if (opt_inline) {
+            Jim_SetResult(interp, resultListObj);
+        }
+        else {
+            Jim_SetResultInt(interp, num_matches);
+        }
+    }
+
+    Jim_Free(pmatch);
+    return result;
+}
+
+#define MAX_SUB_MATCHES 50
+
+int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int regcomp_flags = 0;
+    int regexec_flags = 0;
+    int opt_all = 0;
+    int offset = 0;
+    regex_t *regex;
+    const char *p;
+    int result;
+    regmatch_t pmatch[MAX_SUB_MATCHES + 1];
+    int num_matches = 0;
+
+    int i, j, n;
+    Jim_Obj *varname;
+    Jim_Obj *resultObj;
+    const char *source_str;
+    int source_len;
+    const char *replace_str;
+    int replace_len;
+    const char *pattern;
+    int option;
+    enum {
+        OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_START, OPT_END
+    };
+    static const char * const options[] = {
+        "-nocase", "-line", "-all", "-start", "--", NULL
+    };
+
+    if (argc < 4) {
+      wrongNumArgs:
+        Jim_WrongNumArgs(interp, 1, argv,
+            "?switches? exp string subSpec ?varName?");
+        return JIM_ERR;
+    }
+
+    for (i = 1; i < argc; i++) {
+        const char *opt = Jim_String(argv[i]);
+
+        if (*opt != '-') {
+            break;
+        }
+        if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+            return JIM_ERR;
+        }
+        if (option == OPT_END) {
+            i++;
+            break;
+        }
+        switch (option) {
+            case OPT_NOCASE:
+                regcomp_flags |= REG_ICASE;
+                break;
+
+            case OPT_LINE:
+                regcomp_flags |= REG_NEWLINE;
+                break;
+
+            case OPT_ALL:
+                opt_all = 1;
+                break;
+
+            case OPT_START:
+                if (++i == argc) {
+                    goto wrongNumArgs;
+                }
+                if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
+                    return JIM_ERR;
+                }
+                break;
+        }
+    }
+    if (argc - i != 3 && argc - i != 4) {
+        goto wrongNumArgs;
+    }
+
+    regex = SetRegexpFromAny(interp, argv[i], regcomp_flags);
+    if (!regex) {
+        return JIM_ERR;
+    }
+    pattern = Jim_String(argv[i]);
+
+    source_str = Jim_GetString(argv[i + 1], &source_len);
+    replace_str = Jim_GetString(argv[i + 2], &replace_len);
+    varname = argv[i + 3];
+
+    /* Create the result string */
+    resultObj = Jim_NewStringObj(interp, "", 0);
+
+    /* If an offset has been specified, adjust for that now.
+     * If it points past the end of the string, point to the terminating null
+     */
+    if (offset) {
+        if (offset < 0) {
+            offset += source_len + 1;
+        }
+        if (offset > source_len) {
+            offset = source_len;
+        }
+        else if (offset < 0) {
+            offset = 0;
+        }
+    }
+
+    /* Copy the part before -start */
+    Jim_AppendString(interp, resultObj, source_str, offset);
+
+    /*
+     * The following loop is to handle multiple matches within the
+     * same source string;  each iteration handles one match and its
+     * corresponding substitution.  If "-all" hasn't been specified
+     * then the loop body only gets executed once.
+     */
+
+    n = source_len - offset;
+    p = source_str + offset;
+    do {
+        int match = regexec(regex, p, MAX_SUB_MATCHES, pmatch, regexec_flags);
+
+        if (match >= REG_BADPAT) {
+            char buf[100];
+
+            regerror(match, regex, buf, sizeof(buf));
+            Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
+            return JIM_ERR;
+        }
+        if (match == REG_NOMATCH) {
+            break;
+        }
+
+        num_matches++;
+
+        /*
+         * Copy the portion of the source string before the match to the
+         * result variable.
+         */
+        Jim_AppendString(interp, resultObj, p, pmatch[0].rm_so);
+
+        /*
+         * Append the subSpec (replace_str) argument to the variable, making appropriate
+         * substitutions.  This code is a bit hairy because of the backslash
+         * conventions and because the code saves up ranges of characters in
+         * subSpec to reduce the number of calls to Jim_SetVar.
+         */
+
+        for (j = 0; j < replace_len; j++) {
+            int idx;
+            int c = replace_str[j];
+
+            if (c == '&') {
+                idx = 0;
+            }
+            else if (c == '\\' && j < replace_len) {
+                c = replace_str[++j];
+                if ((c >= '0') && (c <= '9')) {
+                    idx = c - '0';
+                }
+                else if ((c == '\\') || (c == '&')) {
+                    Jim_AppendString(interp, resultObj, replace_str + j, 1);
+                    continue;
+                }
+                else {
+                    Jim_AppendString(interp, resultObj, replace_str + j - 1, 2);
+                    continue;
+                }
+            }
+            else {
+                Jim_AppendString(interp, resultObj, replace_str + j, 1);
+                continue;
+            }
+            if ((idx < MAX_SUB_MATCHES) && pmatch[idx].rm_so != -1 && pmatch[idx].rm_eo != -1) {
+                Jim_AppendString(interp, resultObj, p + pmatch[idx].rm_so,
+                    pmatch[idx].rm_eo - pmatch[idx].rm_so);
+            }
+        }
+
+        p += pmatch[0].rm_eo;
+        n -= pmatch[0].rm_eo;
+
+        /* If -all is not specified, or there is no source left, we are done */
+        if (!opt_all || n == 0) {
+            break;
+        }
+
+        /* An anchored pattern without -line must be done */
+        if ((regcomp_flags & REG_NEWLINE) == 0 && pattern[0] == '^') {
+            break;
+        }
+
+        /* If the pattern is empty, need to step forwards */
+        if (pattern[0] == '\0' && n) {
+            /* Need to copy the char we are moving over */
+            Jim_AppendString(interp, resultObj, p, 1);
+            p++;
+            n--;
+        }
+
+        regexec_flags |= REG_NOTBOL;
+    } while (n);
+
+    /*
+     * Copy the portion of the string after the last match to the
+     * result variable.
+     */
+    Jim_AppendString(interp, resultObj, p, -1);
+
+    /* And now set or return the result variable */
+    if (argc - i == 4) {
+        result = Jim_SetVariable(interp, varname, resultObj);
+
+        if (result == JIM_OK) {
+            Jim_SetResultInt(interp, num_matches);
+        }
+        else {
+            Jim_FreeObj(interp, resultObj);
+        }
+    }
+    else {
+        Jim_SetResult(interp, resultObj);
+        result = JIM_OK;
+    }
+
+    return result;
+}
+
+int Jim_regexpInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "regexp", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    Jim_CreateCommand(interp, "regexp", Jim_RegexpCmd, NULL, NULL);
+    Jim_CreateCommand(interp, "regsub", Jim_RegsubCmd, NULL, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-sdl.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-sdl.c
new file mode 100755
index 0000000..2e700eb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-sdl.c
@@ -0,0 +1,234 @@
+
+/* Jim - SDL extension
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ *
+ * 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
+ *
+ * A copy of the license is also included in the source distribution
+ * of Jim, as a TXT file name called LICENSE.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <SDL/SDL.h>
+#include <SDL/SDL_gfxPrimitives.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+
+#define AIO_CMD_LEN 128
+
+typedef struct JimSdlSurface
+{
+    SDL_Surface *screen;
+} JimSdlSurface;
+
+static void JimSdlSetError(Jim_Interp *interp)
+{
+    Jim_SetResultString(interp, SDL_GetError(), -1);
+}
+
+static void JimSdlDelProc(Jim_Interp *interp, void *privData)
+{
+    JimSdlSurface *jss = privData;
+
+    JIM_NOTUSED(interp);
+
+    SDL_FreeSurface(jss->screen);
+    Jim_Free(jss);
+}
+
+/* Calls to commands created via [sdl.surface] are implemented by this
+ * C command. */
+static int JimSdlHandlerCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    JimSdlSurface *jss = Jim_CmdPrivData(interp);
+    int option;
+    static const char * const options[] = {
+        "free", "flip", "pixel", "rectangle", "box", "line", "aaline",
+        "circle", "aacircle", "fcircle", NULL
+    };
+    enum
+    { OPT_FREE, OPT_FLIP, OPT_PIXEL, OPT_RECTANGLE, OPT_BOX, OPT_LINE,
+        OPT_AALINE, OPT_CIRCLE, OPT_AACIRCLE, OPT_FCIRCLE
+    };
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "method ?args ...?");
+        return JIM_ERR;
+    }
+    if (Jim_GetEnum(interp, argv[1], options, &option, "SDL surface method", JIM_ERRMSG) != JIM_OK)
+        return JIM_ERR;
+    if (option == OPT_PIXEL) {
+        /* PIXEL */
+        long x, y, red, green, blue, alpha = 255;
+
+        if (argc != 7 && argc != 8) {
+            Jim_WrongNumArgs(interp, 2, argv, "x y red green blue ?alpha?");
+            return JIM_ERR;
+        }
+        if (Jim_GetLong(interp, argv[2], &x) != JIM_OK ||
+            Jim_GetLong(interp, argv[3], &y) != JIM_OK ||
+            Jim_GetLong(interp, argv[4], &red) != JIM_OK ||
+            Jim_GetLong(interp, argv[5], &green) != JIM_OK ||
+            Jim_GetLong(interp, argv[6], &blue) != JIM_OK) {
+            return JIM_ERR;
+        }
+        if (argc == 8 && Jim_GetLong(interp, argv[7], &alpha) != JIM_OK)
+            return JIM_ERR;
+        pixelRGBA(jss->screen, x, y, red, green, blue, alpha);
+        return JIM_OK;
+    }
+    else if (option == OPT_RECTANGLE || option == OPT_BOX ||
+        option == OPT_LINE || option == OPT_AALINE) {
+        /* RECTANGLE, BOX, LINE, AALINE */
+        long x1, y1, x2, y2, red, green, blue, alpha = 255;
+
+        if (argc != 9 && argc != 10) {
+            Jim_WrongNumArgs(interp, 2, argv, "x y red green blue ?alpha?");
+            return JIM_ERR;
+        }
+        if (Jim_GetLong(interp, argv[2], &x1) != JIM_OK ||
+            Jim_GetLong(interp, argv[3], &y1) != JIM_OK ||
+            Jim_GetLong(interp, argv[4], &x2) != JIM_OK ||
+            Jim_GetLong(interp, argv[5], &y2) != JIM_OK ||
+            Jim_GetLong(interp, argv[6], &red) != JIM_OK ||
+            Jim_GetLong(interp, argv[7], &green) != JIM_OK ||
+            Jim_GetLong(interp, argv[8], &blue) != JIM_OK) {
+            return JIM_ERR;
+        }
+        if (argc == 10 && Jim_GetLong(interp, argv[9], &alpha) != JIM_OK)
+            return JIM_ERR;
+        switch (option) {
+            case OPT_RECTANGLE:
+                rectangleRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha);
+                break;
+            case OPT_BOX:
+                boxRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha);
+                break;
+            case OPT_LINE:
+                lineRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha);
+                break;
+            case OPT_AALINE:
+                aalineRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha);
+                break;
+        }
+        return JIM_OK;
+    }
+    else if (option == OPT_CIRCLE || option == OPT_AACIRCLE || option == OPT_FCIRCLE) {
+        /* CIRCLE, AACIRCLE, FCIRCLE */
+        long x, y, radius, red, green, blue, alpha = 255;
+
+        if (argc != 8 && argc != 9) {
+            Jim_WrongNumArgs(interp, 2, argv, "x y radius red green blue ?alpha?");
+            return JIM_ERR;
+        }
+        if (Jim_GetLong(interp, argv[2], &x) != JIM_OK ||
+            Jim_GetLong(interp, argv[3], &y) != JIM_OK ||
+            Jim_GetLong(interp, argv[4], &radius) != JIM_OK ||
+            Jim_GetLong(interp, argv[5], &red) != JIM_OK ||
+            Jim_GetLong(interp, argv[6], &green) != JIM_OK ||
+            Jim_GetLong(interp, argv[7], &blue) != JIM_OK) {
+            return JIM_ERR;
+        }
+        if (argc == 9 && Jim_GetLong(interp, argv[8], &alpha) != JIM_OK)
+            return JIM_ERR;
+        switch (option) {
+            case OPT_CIRCLE:
+                circleRGBA(jss->screen, x, y, radius, red, green, blue, alpha);
+                break;
+            case OPT_AACIRCLE:
+                aacircleRGBA(jss->screen, x, y, radius, red, green, blue, alpha);
+                break;
+            case OPT_FCIRCLE:
+                filledCircleRGBA(jss->screen, x, y, radius, red, green, blue, alpha);
+                break;
+        }
+        return JIM_OK;
+    }
+    else if (option == OPT_FREE) {
+        /* FREE */
+        if (argc != 2) {
+            Jim_WrongNumArgs(interp, 2, argv, "");
+            return JIM_ERR;
+        }
+        Jim_DeleteCommand(interp, Jim_String(argv[0]));
+        return JIM_OK;
+    }
+    else if (option == OPT_FLIP) {
+        /* FLIP */
+        if (argc != 2) {
+            Jim_WrongNumArgs(interp, 2, argv, "");
+            return JIM_ERR;
+        }
+        SDL_Flip(jss->screen);
+        return JIM_OK;
+    }
+    return JIM_OK;
+}
+
+static int JimSdlSurfaceCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    JimSdlSurface *jss;
+    char buf[AIO_CMD_LEN];
+    Jim_Obj *objPtr;
+    long screenId, xres, yres;
+    SDL_Surface *screen;
+
+    if (argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "xres yres");
+        return JIM_ERR;
+    }
+    if (Jim_GetLong(interp, argv[1], &xres) != JIM_OK ||
+        Jim_GetLong(interp, argv[2], &yres) != JIM_OK)
+        return JIM_ERR;
+
+    /* Try to create the surface */
+    screen = SDL_SetVideoMode(xres, yres, 32, SDL_SWSURFACE | SDL_ANYFORMAT);
+    if (screen == NULL) {
+        JimSdlSetError(interp);
+        return JIM_ERR;
+    }
+    /* Get the next file id */
+    if (Jim_EvalGlobal(interp, "if {[catch {incr sdl.surfaceId}]} {set sdl.surfaceId 0}") != JIM_OK)
+        return JIM_ERR;
+    objPtr = Jim_GetVariableStr(interp, "sdl.surfaceId", JIM_ERRMSG);
+    if (objPtr == NULL)
+        return JIM_ERR;
+    if (Jim_GetLong(interp, objPtr, &screenId) != JIM_OK)
+        return JIM_ERR;
+
+    /* Create the SDL screen command */
+    jss = Jim_Alloc(sizeof(*jss));
+    jss->screen = screen;
+    sprintf(buf, "sdl.surface%ld", screenId);
+    Jim_CreateCommand(interp, buf, JimSdlHandlerCommand, jss, JimSdlDelProc);
+    Jim_SetResultString(interp, buf, -1);
+    return JIM_OK;
+}
+
+int Jim_sdlInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "sdl", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+        JimSdlSetError(interp);
+        return JIM_ERR;
+    }
+    atexit(SDL_Quit);
+    Jim_CreateCommand(interp, "sdl.screen", JimSdlSurfaceCommand, NULL, NULL);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-signal.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-signal.c
new file mode 100755
index 0000000..6a2a2be
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-signal.c
@@ -0,0 +1,514 @@
+
+/*
+ * jim-signal.c
+ *
+ */
+
+#include <signal.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "jim-subcmd.h"
+#include "jim-signal.h"
+
+#define MAX_SIGNALS (sizeof(jim_wide) * 8)
+
+static jim_wide *sigloc;
+static jim_wide sigsblocked;
+static struct sigaction *sa_old;
+static int signal_handling[MAX_SIGNALS];
+
+/* Make sure to do this as a wide, not int */
+#define sig_to_bit(SIG) ((jim_wide)1 << (SIG))
+
+static void signal_handler(int sig)
+{
+    /* We just remember which signals occurred. Jim_Eval() will
+     * notice this as soon as it can and throw an error
+     */
+    *sigloc |= sig_to_bit(sig);
+}
+
+static void signal_ignorer(int sig)
+{
+    /* We just remember which signals occurred */
+    sigsblocked |= sig_to_bit(sig);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SignalId --
+ *
+ *      Return a textual identifier for a signal number.
+ *
+ * Results:
+ *      This procedure returns a machine-readable textual identifier
+ *      that corresponds to sig.  The identifier is the same as the
+ *      #define name in signal.h.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------
+ */
+#define CHECK_SIG(NAME) if (sig == NAME) return #NAME
+
+const char *Jim_SignalId(int sig)
+{
+    CHECK_SIG(SIGABRT);
+    CHECK_SIG(SIGALRM);
+    CHECK_SIG(SIGBUS);
+    CHECK_SIG(SIGCHLD);
+    CHECK_SIG(SIGCONT);
+    CHECK_SIG(SIGFPE);
+    CHECK_SIG(SIGHUP);
+    CHECK_SIG(SIGILL);
+    CHECK_SIG(SIGINT);
+#ifdef SIGIO
+    CHECK_SIG(SIGIO);
+#endif
+    CHECK_SIG(SIGKILL);
+    CHECK_SIG(SIGPIPE);
+    CHECK_SIG(SIGPROF);
+    CHECK_SIG(SIGQUIT);
+    CHECK_SIG(SIGSEGV);
+    CHECK_SIG(SIGSTOP);
+    CHECK_SIG(SIGSYS);
+    CHECK_SIG(SIGTERM);
+    CHECK_SIG(SIGTRAP);
+    CHECK_SIG(SIGTSTP);
+    CHECK_SIG(SIGTTIN);
+    CHECK_SIG(SIGTTOU);
+    CHECK_SIG(SIGURG);
+    CHECK_SIG(SIGUSR1);
+    CHECK_SIG(SIGUSR2);
+    CHECK_SIG(SIGVTALRM);
+    CHECK_SIG(SIGWINCH);
+    CHECK_SIG(SIGXCPU);
+    CHECK_SIG(SIGXFSZ);
+#ifdef SIGPWR
+    CHECK_SIG(SIGPWR);
+#endif
+#ifdef SIGCLD
+    CHECK_SIG(SIGCLD);
+#endif
+#ifdef SIGEMT
+    CHECK_SIG(SIGEMT);
+#endif
+#ifdef SIGLOST
+    CHECK_SIG(SIGLOST);
+#endif
+#ifdef SIGPOLL
+    CHECK_SIG(SIGPOLL);
+#endif
+#ifdef SIGINFO
+    CHECK_SIG(SIGINFO);
+#endif
+    return "unknown signal";
+}
+
+const char *Jim_SignalName(int sig)
+{
+#ifdef HAVE_SYS_SIGLIST
+    if (sig >= 0 && sig < NSIG) {
+        return sys_siglist[sig];
+    }
+#endif
+    return Jim_SignalId(sig);
+}
+
+/**
+ * Given the name of a signal, returns the signal value if found,
+ * or returns -1 (and sets an error) if not found.
+ * We accept -SIGINT, SIGINT, INT or any lowercase version or a number,
+ * either positive or negative.
+ */
+static int find_signal_by_name(Jim_Interp *interp, const char *name)
+{
+    int i;
+    const char *pt = name;
+
+    /* Remove optional - and SIG from the front of the name */
+    if (*pt == '-') {
+        pt++;
+    }
+    if (strncasecmp(name, "sig", 3) == 0) {
+        pt += 3;
+    }
+    if (isdigit(UCHAR(pt[0]))) {
+        i = atoi(pt);
+        if (i > 0 && i < MAX_SIGNALS) {
+            return i;
+        }
+    }
+    else {
+        for (i = 1; i < MAX_SIGNALS; i++) {
+            /* Jim_SignalId() returns names such as SIGINT, and
+             * returns "unknown signal id" if unknown, so this will work
+             */
+            if (strcasecmp(Jim_SignalId(i) + 3, pt) == 0) {
+                return i;
+            }
+        }
+    }
+    Jim_SetResultString(interp, "unknown signal ", -1);
+    Jim_AppendString(interp, Jim_GetResult(interp), name, -1);
+
+    return -1;
+}
+
+#define SIGNAL_ACTION_HANDLE 1
+#define SIGNAL_ACTION_IGNORE -1
+#define SIGNAL_ACTION_DEFAULT 0
+
+static int do_signal_cmd(Jim_Interp *interp, int action, int argc, Jim_Obj *const *argv)
+{
+    struct sigaction sa;
+    int i;
+
+    if (argc == 0) {
+        Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
+        for (i = 1; i < MAX_SIGNALS; i++) {
+            if (signal_handling[i] == action) {
+                /* Add signal name to the list  */
+                Jim_ListAppendElement(interp, Jim_GetResult(interp),
+                    Jim_NewStringObj(interp, Jim_SignalId(i), -1));
+            }
+        }
+        return JIM_OK;
+    }
+
+    /* Catch all the signals we care about */
+    if (action != SIGNAL_ACTION_DEFAULT) {
+        sa.sa_flags = 0;
+        sigemptyset(&sa.sa_mask);
+        if (action == SIGNAL_ACTION_HANDLE) {
+            sa.sa_handler = signal_handler;
+        }
+        else {
+            sa.sa_handler = signal_ignorer;
+        }
+    }
+
+    /* Iterate through the provided signals */
+    for (i = 0; i < argc; i++) {
+        int sig = find_signal_by_name(interp, Jim_String(argv[i]));
+
+        if (sig < 0) {
+            return JIM_ERR;
+        }
+        if (action != signal_handling[sig]) {
+            /* Need to change the action for this signal */
+            switch (action) {
+                case SIGNAL_ACTION_HANDLE:
+                case SIGNAL_ACTION_IGNORE:
+                    if (signal_handling[sig] == SIGNAL_ACTION_DEFAULT) {
+                        if (!sa_old) {
+                            /* Allocate the structure the first time through */
+                            sa_old = Jim_Alloc(sizeof(*sa_old) * MAX_SIGNALS);
+                        }
+                        sigaction(sig, &sa, &sa_old[sig]);
+                    }
+                    else {
+                        sigaction(sig, &sa, 0);
+                    }
+                    break;
+
+                case SIGNAL_ACTION_DEFAULT:
+                    /* Restore old handler */
+                    if (sa_old) {
+                        sigaction(sig, &sa_old[sig], 0);
+                    }
+            }
+            signal_handling[sig] = action;
+        }
+    }
+
+    return JIM_OK;
+}
+
+static int signal_cmd_handle(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return do_signal_cmd(interp, SIGNAL_ACTION_HANDLE, argc, argv);
+}
+
+static int signal_cmd_ignore(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return do_signal_cmd(interp, SIGNAL_ACTION_IGNORE, argc, argv);
+}
+
+static int signal_cmd_default(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return do_signal_cmd(interp, SIGNAL_ACTION_DEFAULT, argc, argv);
+}
+
+static int signal_set_sigmask_result(Jim_Interp *interp, jim_wide sigmask)
+{
+    int i;
+    Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
+    for (i = 0; i < MAX_SIGNALS; i++) {
+        if (sigmask & sig_to_bit(i)) {
+            Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, Jim_SignalId(i), -1));
+        }
+    }
+    Jim_SetResult(interp, listObj);
+    return JIM_OK;
+}
+
+static int signal_cmd_check(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int clear = 0;
+    jim_wide mask = 0;
+    jim_wide blocked;
+
+    if (argc > 0 && Jim_CompareStringImmediate(interp, argv[0], "-clear")) {
+        clear++;
+    }
+    if (argc > clear) {
+        int i;
+
+        /* Signals specified */
+        for (i = clear; i < argc; i++) {
+            int sig = find_signal_by_name(interp, Jim_String(argv[i]));
+
+            if (sig < 0 || sig >= MAX_SIGNALS) {
+                return -1;
+            }
+            mask |= sig_to_bit(sig);
+        }
+    }
+    else {
+        /* No signals specified, so check/clear all */
+        mask = ~mask;
+    }
+
+    if ((sigsblocked & mask) == 0) {
+        /* No matching signals, so empty result and nothing to do */
+        return JIM_OK;
+    }
+    /* Be careful we don't have a race condition where signals are cleared but not returned */
+    blocked = sigsblocked & mask;
+    if (clear) {
+        sigsblocked &= ~blocked;
+    }
+    /* Set the result */
+    signal_set_sigmask_result(interp, blocked);
+    return JIM_OK;
+}
+
+static int signal_cmd_throw(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int sig = SIGINT;
+
+    if (argc == 1) {
+        if ((sig = find_signal_by_name(interp, Jim_String(argv[0]))) < 0) {
+            return JIM_ERR;
+        }
+    }
+
+    /* If the signal is ignored (blocked) ... */
+    if (signal_handling[sig] == SIGNAL_ACTION_IGNORE) {
+        sigsblocked |= sig_to_bit(sig);
+        return JIM_OK;
+    }
+
+    /* Just set the signal */
+    interp->sigmask |= sig_to_bit(sig);
+
+    /* Set the canonical name of the signal as the result */
+    Jim_SetResultString(interp, Jim_SignalId(sig), -1);
+
+    /* And simply say we caught the signal */
+    return JIM_SIGNAL;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Jim_SignalCmd --
+ *     Implements the TCL signal command:
+ *         signal handle|ignore|default|throw ?signals ...?
+ *         signal throw signal
+ *
+ *     Specifies which signals are handled by Tcl code.
+ *     If the one of the given signals is caught, it causes a JIM_SIGNAL
+ *     exception to be thrown which can be caught by catch.
+ *
+ *     Use 'signal ignore' to ignore the signal(s)
+ *     Use 'signal default' to go back to the default behaviour
+ *     Use 'signal throw signal' to raise the given signal
+ *
+ *     If no arguments are given, returns the list of signals which are being handled
+ *
+ * Results:
+ *      Standard TCL results.
+ *
+ *-----------------------------------------------------------------------------
+ */
+static const jim_subcmd_type signal_command_table[] = {
+    {   .cmd = "handle",
+        .args = "?signals ...?",
+        .function = signal_cmd_handle,
+        .minargs = 0,
+        .maxargs = -1,
+        .description = "Lists handled signals, or adds to handled signals"
+    },
+    {   .cmd = "ignore",
+        .args = "?signals ...?",
+        .function = signal_cmd_ignore,
+        .minargs = 0,
+        .maxargs = -1,
+        .description = "Lists ignored signals, or adds to ignored signals"
+    },
+    {   .cmd = "default",
+        .args = "?signals ...?",
+        .function = signal_cmd_default,
+        .minargs = 0,
+        .maxargs = -1,
+        .description = "Lists defaulted signals, or adds to defaulted signals"
+    },
+    {   .cmd = "check",
+        .args = "?-clear? ?signals ...?",
+        .function = signal_cmd_check,
+        .minargs = 0,
+        .maxargs = -1,
+        .description = "Returns ignored signals which have occurred, and optionally clearing them"
+    },
+    {   .cmd = "throw",
+        .args = "?signal?",
+        .function = signal_cmd_throw,
+        .minargs = 0,
+        .maxargs = 1,
+        .description = "Raises the given signal (default SIGINT)"
+    },
+    { 0 }
+};
+
+static int Jim_AlarmCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int ret;
+
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "seconds");
+        return JIM_ERR;
+    }
+    else {
+#ifdef HAVE_UALARM
+        double t;
+
+        ret = Jim_GetDouble(interp, argv[1], &t);
+        if (ret == JIM_OK) {
+            if (t < 1) {
+                ualarm(t * 1e6, 0);
+            }
+            else {
+                alarm(t);
+            }
+        }
+#else
+        long t;
+
+        ret = Jim_GetLong(interp, argv[1], &t);
+        if (ret == JIM_OK) {
+            alarm(t);
+        }
+#endif
+    }
+
+    return ret;
+}
+
+static int Jim_SleepCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int ret;
+
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "seconds");
+        return JIM_ERR;
+    }
+    else {
+        double t;
+
+        ret = Jim_GetDouble(interp, argv[1], &t);
+        if (ret == JIM_OK) {
+#ifdef HAVE_USLEEP
+            if (t < 1) {
+                usleep(t * 1e6);
+            }
+            else
+#endif
+                sleep(t);
+        }
+    }
+
+    return ret;
+}
+
+static int Jim_KillCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int sig;
+    long pid;
+    Jim_Obj *pidObj;
+    const char *signame;
+
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "?SIG|-0? pid");
+        return JIM_ERR;
+    }
+
+    if (argc == 2) {
+        signame = "SIGTERM";
+        pidObj = argv[1];
+    }
+    else {
+        signame = Jim_String(argv[1]);
+        pidObj = argv[2];
+    }
+
+    /* Special 'kill -0 pid' to determine if a pid exists */
+    if (strcmp(signame, "-0") == 0 || strcmp(signame, "0") == 0) {
+        sig = 0;
+    }
+    else {
+        sig = find_signal_by_name(interp, signame);
+        if (sig < 0) {
+            return JIM_ERR;
+        }
+    }
+
+    if (Jim_GetLong(interp, pidObj, &pid) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    if (kill(pid, sig) == 0) {
+        return JIM_OK;
+    }
+
+    Jim_SetResultString(interp, "kill: Failed to deliver signal", -1);
+    return JIM_ERR;
+}
+
+int Jim_signalInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "signal", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    /* Teach the jim core how to set a result from a sigmask */
+    interp->signal_set_result = signal_set_sigmask_result;
+
+    /* Make sure we know where to store the signals which occur */
+    sigloc = &interp->sigmask;
+
+    Jim_CreateCommand(interp, "signal", Jim_SubCmdProc, (void *)signal_command_table, NULL);
+    Jim_CreateCommand(interp, "alarm", Jim_AlarmCmd, 0, 0);
+    Jim_CreateCommand(interp, "kill", Jim_KillCmd, 0, 0);
+
+    /* Sleep is slightly dubious here */
+    Jim_CreateCommand(interp, "sleep", Jim_SleepCmd, 0, 0);
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-signal.h b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-signal.h
new file mode 100755
index 0000000..92e080d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-signal.h
@@ -0,0 +1,24 @@
+#ifndef JIM_SIGNAL_H
+#define JIM_SIGNAL_H
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SignalId --
+ *
+ *      Return a textual identifier for a signal number.
+ *
+ * Results:
+ *      This procedure returns a machine-readable textual identifier
+ *      that corresponds to sig.  The identifier is the same as the
+ *      #define name in signal.h.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------
+ */
+const char *Jim_SignalId(int sig);
+const char *Jim_SignalName(int sig);
+
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-subcmd.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-subcmd.c
new file mode 100755
index 0000000..2de560a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-subcmd.c
@@ -0,0 +1,293 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "jim-subcmd.h"
+#include "jimautoconf.h"
+
+/**
+ * Implements the common 'commands' subcommand
+ */
+static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    /* Nothing to do, since the result has already been created */
+    return JIM_OK;
+}
+
+/**
+ * Do-nothing command to support -commands and -usage
+ */
+static const jim_subcmd_type dummy_subcmd = {
+    .cmd = "dummy",
+    .function = subcmd_null,
+    .flags = JIM_MODFLAG_HIDDEN,
+};
+
+static void add_commands(Jim_Interp *interp, const jim_subcmd_type * ct, const char *sep)
+{
+    const char *s = "";
+
+    for (; ct->cmd; ct++) {
+        if (!(ct->flags & JIM_MODFLAG_HIDDEN)) {
+            Jim_AppendStrings(interp, Jim_GetResult(interp), s, ct->cmd, NULL);
+            s = sep;
+        }
+    }
+}
+
+static void bad_subcmd(Jim_Interp *interp, const jim_subcmd_type * command_table, const char *type,
+    Jim_Obj *cmd, Jim_Obj *subcmd)
+{
+    Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+    Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), ", ", type,
+        " command \"", Jim_String(subcmd), "\": should be ", NULL);
+    add_commands(interp, command_table, ", ");
+}
+
+static void show_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc,
+    Jim_Obj *const *argv)
+{
+    Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+    Jim_AppendStrings(interp, Jim_GetResult(interp), "Usage: \"", Jim_String(argv[0]),
+        " command ... \", where command is one of: ", NULL);
+    add_commands(interp, command_table, ", ");
+}
+
+static void add_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *cmd)
+{
+    if (cmd) {
+        Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), " ", NULL);
+    }
+    Jim_AppendStrings(interp, Jim_GetResult(interp), ct->cmd, NULL);
+    if (ct->args && *ct->args) {
+        Jim_AppendStrings(interp, Jim_GetResult(interp), " ", ct->args, NULL);
+    }
+}
+
+static void show_full_usage(Jim_Interp *interp, const jim_subcmd_type * ct, int argc,
+    Jim_Obj *const *argv)
+{
+    Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+    for (; ct->cmd; ct++) {
+        if (!(ct->flags & JIM_MODFLAG_HIDDEN)) {
+            /* subcmd */
+            add_cmd_usage(interp, ct, argv[0]);
+            if (ct->description) {
+                Jim_AppendStrings(interp, Jim_GetResult(interp), "\n\n    ", ct->description, NULL);
+            }
+            Jim_AppendStrings(interp, Jim_GetResult(interp), "\n\n", NULL);
+        }
+    }
+}
+
+static void set_wrong_args(Jim_Interp *interp, const jim_subcmd_type * command_table, Jim_Obj *subcmd)
+{
+    Jim_SetResultString(interp, "wrong # args: must be \"", -1);
+    add_cmd_usage(interp, command_table, subcmd);
+    Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
+}
+
+const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type * command_table,
+    int argc, Jim_Obj *const *argv)
+{
+    const jim_subcmd_type *ct;
+    const jim_subcmd_type *partial = 0;
+    int cmdlen;
+    Jim_Obj *cmd;
+    const char *cmdstr;
+    const char *cmdname;
+    int help = 0;
+
+    cmdname = Jim_String(argv[0]);
+
+    if (argc < 2) {
+        Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+        Jim_AppendStrings(interp, Jim_GetResult(interp), "wrong # args: should be \"", cmdname,
+            " command ...\"\n", NULL);
+        Jim_AppendStrings(interp, Jim_GetResult(interp), "Use \"", cmdname, " -help\" or \"",
+            cmdname, " -help command\" for help", NULL);
+        return 0;
+    }
+
+    cmd = argv[1];
+
+    if (argc == 2 && Jim_CompareStringImmediate(interp, cmd, "-usage")) {
+        /* Show full usage */
+        show_full_usage(interp, command_table, argc, argv);
+        return &dummy_subcmd;
+    }
+
+    /* Check for the help command */
+    if (Jim_CompareStringImmediate(interp, cmd, "-help")) {
+        if (argc == 2) {
+            /* Usage for the command, not the subcommand */
+            show_cmd_usage(interp, command_table, argc, argv);
+            return &dummy_subcmd;
+        }
+        help = 1;
+
+        /* Skip the 'help' command */
+        cmd = argv[2];
+    }
+
+    /* Check for special builtin '-commands' command first */
+    if (Jim_CompareStringImmediate(interp, cmd, "-commands")) {
+        /* Build the result here */
+        Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+        add_commands(interp, command_table, " ");
+        return &dummy_subcmd;
+    }
+
+    cmdstr = Jim_GetString(cmd, &cmdlen);
+
+    for (ct = command_table; ct->cmd; ct++) {
+        if (Jim_CompareStringImmediate(interp, cmd, ct->cmd)) {
+            /* Found an exact match */
+            break;
+        }
+        if (strncmp(cmdstr, ct->cmd, cmdlen) == 0) {
+            if (partial) {
+                /* Ambiguous */
+                if (help) {
+                    /* Just show the top level help here */
+                    show_cmd_usage(interp, command_table, argc, argv);
+                    return &dummy_subcmd;
+                }
+                bad_subcmd(interp, command_table, "ambiguous", argv[0], argv[1 + help]);
+                return 0;
+            }
+            partial = ct;
+        }
+        continue;
+    }
+
+    /* If we had an unambiguous partial match */
+    if (partial && !ct->cmd) {
+        ct = partial;
+    }
+
+    if (!ct->cmd) {
+        /* No matching command */
+        if (help) {
+            /* Just show the top level help here */
+            show_cmd_usage(interp, command_table, argc, argv);
+            return &dummy_subcmd;
+        }
+        bad_subcmd(interp, command_table, "unknown", argv[0], argv[1 + help]);
+        return 0;
+    }
+
+    if (help) {
+        Jim_SetResultString(interp, "Usage: ", -1);
+        /* subcmd */
+        add_cmd_usage(interp, ct, argv[0]);
+        if (ct->description) {
+            Jim_AppendStrings(interp, Jim_GetResult(interp), "\n\n", ct->description, NULL);
+        }
+        return &dummy_subcmd;
+    }
+
+    /* Check the number of args */
+    if (argc - 2 < ct->minargs || (ct->maxargs >= 0 && argc - 2 > ct->maxargs)) {
+        Jim_SetResultString(interp, "wrong # args: must be \"", -1);
+        /* subcmd */
+        add_cmd_usage(interp, ct, argv[0]);
+        Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
+
+        return 0;
+    }
+
+    /* Good command */
+    return ct;
+}
+
+int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type * ct, int argc, Jim_Obj *const *argv)
+{
+    int ret = JIM_ERR;
+
+    if (ct) {
+        if (ct->flags & JIM_MODFLAG_FULLARGV) {
+            ret = ct->function(interp, argc, argv);
+        }
+        else {
+            ret = ct->function(interp, argc - 2, argv + 2);
+        }
+        if (ret < 0) {
+            set_wrong_args(interp, ct, argv[0]);
+            ret = JIM_ERR;
+        }
+    }
+    return ret;
+}
+
+int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const jim_subcmd_type *ct =
+        Jim_ParseSubCmd(interp, (const jim_subcmd_type *)Jim_CmdPrivData(interp), argc, argv);
+
+    return Jim_CallSubCmd(interp, ct, argc, argv);
+}
+
+/* The following two functions are for normal commands */
+int
+Jim_CheckCmdUsage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc,
+    Jim_Obj *const *argv)
+{
+    /* -usage or -help */
+    if (argc == 2) {
+        if (Jim_CompareStringImmediate(interp, argv[1], "-usage")
+            || Jim_CompareStringImmediate(interp, argv[1], "-help")) {
+            Jim_SetResultString(interp, "Usage: ", -1);
+            add_cmd_usage(interp, command_table, NULL);
+            if (command_table->description) {
+                Jim_AppendStrings(interp, Jim_GetResult(interp), "\n\n", command_table->description,
+                    NULL);
+            }
+            return JIM_OK;
+        }
+    }
+    if (argc >= 2 && command_table->function) {
+        /* This is actually a sub command table */
+
+        Jim_Obj *nargv[4];
+        int nargc = 0;
+        const char *subcmd = NULL;
+
+        if (Jim_CompareStringImmediate(interp, argv[1], "-subcommands")) {
+            Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+            add_commands(interp, (jim_subcmd_type *) command_table->function, " ");
+            return JIM_OK;
+        }
+
+        if (Jim_CompareStringImmediate(interp, argv[1], "-subhelp")
+            || Jim_CompareStringImmediate(interp, argv[1], "-help")) {
+            subcmd = "-help";
+        }
+        else if (Jim_CompareStringImmediate(interp, argv[1], "-subusage")) {
+            subcmd = "-usage";
+        }
+
+        if (subcmd) {
+            nargv[nargc++] = Jim_NewStringObj(interp, "$handle", -1);
+            nargv[nargc++] = Jim_NewStringObj(interp, subcmd, -1);
+            if (argc >= 3) {
+                nargv[nargc++] = argv[2];
+            }
+            Jim_ParseSubCmd(interp, (jim_subcmd_type *) command_table->function, nargc, nargv);
+            Jim_FreeNewObj(interp, nargv[0]);
+            Jim_FreeNewObj(interp, nargv[1]);
+            return 0;
+        }
+    }
+
+    /* Check the number of args */
+    if (argc - 1 < command_table->minargs || (command_table->maxargs >= 0
+            && argc - 1 > command_table->maxargs)) {
+        set_wrong_args(interp, command_table, NULL);
+        Jim_AppendStrings(interp, Jim_GetResult(interp), "\nUse \"", Jim_String(argv[0]),
+            " -help\" for help", NULL);
+        return JIM_ERR;
+    }
+
+    /* Not usage, but passed arg checking */
+    return -1;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-subcmd.h b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-subcmd.h
new file mode 100755
index 0000000..3a672eb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-subcmd.h
@@ -0,0 +1,92 @@
+/* Provides a common approach to implementing Tcl commands
+ * which implement subcommands
+ */
+#ifndef JIM_SUBCMD_H
+#define JIM_SUBCMD_H
+
+#include <jim.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define JIM_MODFLAG_HIDDEN   0x0001		/* Don't show the subcommand in usage or commands */
+#define JIM_MODFLAG_FULLARGV 0x0002		/* Subcmd proc gets called with full argv */
+
+/* Custom flags start at 0x0100 */
+
+/**
+ * Returns JIM_OK if OK, JIM_ERR (etc.) on error, break, continue, etc.
+ * Returns -1 if invalid args.
+ */
+typedef int tclmod_cmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
+typedef struct {
+	const char *cmd;				/* Name of the (sub)command */
+	const char *args;				/* Textual description of allowed args */
+	tclmod_cmd_function *function;	/* Function implementing the subcommand */
+	short minargs;					/* Minimum required arguments */
+	short maxargs;					/* Maximum allowed arguments or -1 if no limit */
+	unsigned flags;					/* JIM_MODFLAG_... plus custom flags */
+	const char *description;		/* Description of the subcommand */
+} jim_subcmd_type;
+
+/**
+ * Looks up the appropriate subcommand in the given command table and return
+ * the command function which implements the subcommand.
+ * NULL will be returned and an appropriate error will be set if the subcommand or
+ * arguments are invalid.
+ *
+ * Typical usage is:
+ *  {
+ *    const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, command_table, argc, argv);
+ *
+ *    return Jim_CallSubCmd(interp, ct, argc, argv);
+ *  }
+ *
+ */
+const jim_subcmd_type *
+Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv);
+
+/**
+ * Parses the args against the given command table and executes the subcommand if found
+ * or sets an appropriate error if the subcommand or arguments is invalid.
+ *
+ * Can be used directly with Jim_CreateCommand() where the ClientData is the command table.
+ *
+ * e.g. Jim_CreateCommand(interp, "mycmd", Jim_SubCmdProc, command_table, NULL);
+ */
+int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
+/**
+ * Invokes the given subcmd with the given args as returned
+ * by Jim_ParseSubCmd()
+ *
+ * If ct is NULL, returns JIM_ERR, leaving any message.
+ * Otherwise invokes ct->function
+ *
+ * If ct->function returns -1, sets an error message and returns JIM_ERR.
+ * Otherwise returns the result of ct->function.
+ */
+int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type *ct, int argc, Jim_Obj *const *argv);
+
+/**
+ * Standard processing for a command.
+ *
+ * This does the '-help' and '-usage' check and the number of args checks.
+ * for a top level command against a single 'jim_subcmd_type' structure.
+ *
+ * Additionally, if command_table->function is set, it should point to a sub command table
+ * and '-subhelp ?subcmd?', '-subusage' and '-subcommands' are then also recognised.
+ *
+ * Returns 0 if user requested usage, -1 on arg error, 1 if OK to process.
+ */
+int
+Jim_CheckCmdUsage(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-syslog.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-syslog.c
new file mode 100755
index 0000000..4e14910
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-syslog.c
@@ -0,0 +1,190 @@
+
+/* Syslog interface for tcl
+ * Copyright Victor Wagner <vitus@ice.ru> at
+ * http://www.ice.ru/~vitus/works/tcl.html#syslog
+ *
+ * Slightly modified by Steve Bennett <steveb@snapgear.com>
+ * Ported to Jim by Steve Bennett <steveb@workware.net.au>
+ */
+#include <syslog.h>
+#include <string.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+
+typedef struct
+{
+    int logOpened;
+    int facility;
+    int options;
+    char ident[32];
+} SyslogInfo;
+
+#ifndef LOG_AUTHPRIV
+# define LOG_AUTHPRIV LOG_AUTH
+#endif
+
+static const char * const facilities[] = {
+    [LOG_AUTHPRIV] = "authpriv",
+    [LOG_CRON] = "cron",
+    [LOG_DAEMON] = "daemon",
+    [LOG_KERN] = "kernel",
+    [LOG_LPR] = "lpr",
+    [LOG_MAIL] = "mail",
+    [LOG_NEWS] = "news",
+    [LOG_SYSLOG] = "syslog",
+    [LOG_USER] = "user",
+    [LOG_UUCP] = "uucp",
+    [LOG_LOCAL0] = "local0",
+    [LOG_LOCAL1] = "local1",
+    [LOG_LOCAL2] = "local2",
+    [LOG_LOCAL3] = "local3",
+    [LOG_LOCAL4] = "local4",
+    [LOG_LOCAL5] = "local5",
+    [LOG_LOCAL6] = "local6",
+    [LOG_LOCAL7] = "local7",
+};
+
+static const char * const priorities[] = {
+    [LOG_EMERG] = "emerg",
+    [LOG_ALERT] = "alert",
+    [LOG_CRIT] = "crit",
+    [LOG_ERR] = "error",
+    [LOG_WARNING] = "warning",
+    [LOG_NOTICE] = "notice",
+    [LOG_INFO] = "info",
+    [LOG_DEBUG] = "debug",
+};
+
+/**
+ * Deletes the syslog command.
+ */
+static void Jim_SyslogCmdDelete(Jim_Interp *interp, void *privData)
+{
+    SyslogInfo *info = (SyslogInfo *) privData;
+
+    if (info->logOpened) {
+        closelog();
+    }
+    Jim_Free(info);
+}
+
+/* Syslog_Log -
+ * implements syslog tcl command. General format: syslog ?options? level text
+ * options -facility -ident -options
+ *
+ * syslog ?-facility cron|daemon|...? ?-ident string? ?-options int? ?debug|info|...? text
+ */
+int Jim_SyslogCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int priority = LOG_INFO;
+    int i = 1;
+    SyslogInfo *info = Jim_CmdPrivData(interp);
+
+    if (argc <= 1) {
+      wrongargs:
+        Jim_WrongNumArgs(interp, 1, argv,
+            "?-facility cron|daemon|...? ?-ident string? ?-options int? ?debug|info|...? message");
+        return JIM_ERR;
+    }
+    while (i < argc - 1) {
+        if (Jim_CompareStringImmediate(interp, argv[i], "-facility")) {
+            int entry =
+                Jim_FindByName(Jim_String(argv[i + 1]), facilities,
+                sizeof(facilities) / sizeof(*facilities));
+            if (entry < 0) {
+                Jim_SetResultString(interp, "Unknown facility", -1);
+                return JIM_ERR;
+            }
+            if (info->facility != entry) {
+                info->facility = entry;
+                if (info->logOpened) {
+                    closelog();
+                    info->logOpened = 0;
+                }
+            }
+        }
+        else if (Jim_CompareStringImmediate(interp, argv[i], "-options")) {
+            long tmp;
+
+            if (Jim_GetLong(interp, argv[i + 1], &tmp) == JIM_ERR) {
+                return JIM_ERR;
+            }
+            info->options = tmp;
+            if (info->logOpened) {
+                closelog();
+                info->logOpened = 0;
+            }
+        }
+        else if (Jim_CompareStringImmediate(interp, argv[i], "-ident")) {
+            strncpy(info->ident, Jim_String(argv[i + 1]), sizeof(info->ident));
+            info->ident[sizeof(info->ident) - 1] = 0;
+            if (info->logOpened) {
+                closelog();
+                info->logOpened = 0;
+            }
+        }
+        else {
+            break;
+        }
+        i += 2;
+    }
+
+    /* There should be either 0, 1 or 2 args left */
+    if (i == argc) {
+        /* No args, but they have set some options, so OK */
+        return JIM_OK;
+    }
+
+    if (i < argc - 1) {
+        priority =
+            Jim_FindByName(Jim_String(argv[i]), priorities,
+            sizeof(priorities) / sizeof(*priorities));
+        if (priority < 0) {
+            Jim_SetResultString(interp, "Unknown priority", -1);
+            return JIM_ERR;
+        }
+        i++;
+    }
+
+    if (i != argc - 1) {
+        goto wrongargs;
+    }
+    if (!info->logOpened) {
+        if (!info->ident[0]) {
+            Jim_Obj *argv0 = Jim_GetGlobalVariableStr(interp, "argv0", JIM_NONE);
+
+            if (argv0) {
+                strncpy(info->ident, Jim_String(argv0), sizeof(info->ident));
+            }
+            else {
+                strcpy(info->ident, "Tcl script");
+            }
+            info->ident[sizeof(info->ident) - 1] = 0;
+        }
+        openlog(info->ident, info->options, info->facility);
+        info->logOpened = 1;
+    }
+    syslog(priority, "%s", Jim_String(argv[i]));
+
+    return JIM_OK;
+}
+
+int Jim_syslogInit(Jim_Interp *interp)
+{
+    SyslogInfo *info;
+
+    if (Jim_PackageProvide(interp, "syslog", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+
+    info = Jim_Alloc(sizeof(*info));
+
+    info->logOpened = 0;
+    info->options = 0;
+    info->facility = LOG_USER;
+    info->ident[0] = 0;
+
+    Jim_CreateCommand(interp, "syslog", Jim_SyslogCmd, info, Jim_SyslogCmdDelete);
+
+    return JIM_OK;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-win32compat.h b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-win32compat.h
new file mode 100755
index 0000000..89e01f5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim-win32compat.h
@@ -0,0 +1,69 @@
+#ifndef JIM_WIN32COMPAT_H
+#define JIM_WIN32COMPAT_H
+
+/* Compatibility for Windows (mingw and msvc, not cygwin */
+
+/* Note that at this point we don't yet have access to jimautoconf.h */
+#if defined(_WIN32) || defined(WIN32)
+#ifndef STRICT
+	#define STRICT
+#endif
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#define HAVE_DLOPEN
+void *dlopen(const char *path, int mode);
+int dlclose(void *handle);
+void *dlsym(void *handle, const char *symbol);
+char *dlerror(void);
+
+#ifdef _MSC_VER
+/* These are msvc vs gcc */
+
+#if _MSC_VER >= 1000
+	#pragma warning(disable:4146)
+#endif
+
+#define strcasecmp _stricmp
+
+#define jim_wide _int64
+#ifndef LLONG_MAX
+	#define LLONG_MAX    9223372036854775807I64
+#endif
+#ifndef LLONG_MIN
+	#define LLONG_MIN    (-LLONG_MAX - 1I64)
+#endif
+#define JIM_WIDE_MIN LLONG_MIN
+#define JIM_WIDE_MAX LLONG_MAX
+#define JIM_WIDE_MODIFIER "I64d"
+
+#include <io.h>
+
+#define HAVE_GETTIMEOFDAY
+struct timeval {
+	long tv_sec;
+	long tv_usec;
+};
+
+int gettimeofday(struct timeval *tv, void *unused);
+
+#define HAVE_OPENDIR
+struct dirent {
+	char *d_name;
+};
+
+typedef struct DIR {
+	long                handle; /* -1 for failed rewind */
+	struct _finddata_t  info;
+	struct dirent       result; /* d_name null iff first time */
+	char                *name;  /* null-terminated char string */
+} DIR;
+
+DIR *opendir(const char *name);
+int closedir(DIR *dir);
+struct dirent *readdir(DIR *dir);
+#endif /* _MSC_VER */
+
+#endif /* WIN32 */
+
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim.c
new file mode 100755
index 0000000..8543de4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim.c
@@ -0,0 +1,14478 @@
+
+/* Jim - A small embeddable Tcl interpreter
+ *
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
+ * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
+ * Copyright 2008,2009 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
+ * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
+ * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
+ * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
+ * Copyright 2008 Steve Bennett <steveb@workware.net.au>
+ * Copyright 2009 Nico Coesel <ncoesel@dealogic.nl>
+ * Copyright 2009 Zachary T Welch zw@superlucidity.net
+ * Copyright 2009 David Brownell
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ **/
+#define JIM_OPTIMIZATION        /* comment to avoid optimizations and reduce size */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <limits.h>
+#include <assert.h>
+#include <errno.h>
+#include <time.h>
+#include <setjmp.h>
+
+#include <unistd.h>
+#include <sys/time.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "utf8.h"
+
+#ifdef HAVE_BACKTRACE
+#include <execinfo.h>
+#endif
+#ifdef HAVE_CRT_EXTERNS_H
+#include <crt_externs.h>
+#endif
+
+/* For INFINITY, even if math functions are not enabled */
+#include <math.h>
+
+/* We may decide to switch to using $[...] after all, so leave it as an option */
+/*#define EXPRSUGAR_BRACKET*/
+
+/* For the no-autoconf case */
+#ifndef TCL_LIBRARY
+#define TCL_LIBRARY "."
+#endif
+#ifndef TCL_PLATFORM_OS
+#define TCL_PLATFORM_OS "unknown"
+#endif
+#ifndef TCL_PLATFORM_PLATFORM
+#define TCL_PLATFORM_PLATFORM "unknown"
+#endif
+#ifndef TCL_PLATFORM_PATH_SEPARATOR
+#define TCL_PLATFORM_PATH_SEPARATOR ":"
+#endif
+
+/*#define DEBUG_SHOW_SCRIPT*/
+/*#define DEBUG_SHOW_SCRIPT_TOKENS*/
+/*#define DEBUG_SHOW_SUBST*/
+/*#define DEBUG_SHOW_EXPR*/
+/*#define DEBUG_SHOW_EXPR_TOKENS*/
+/*#define JIM_DEBUG_GC*/
+#ifdef JIM_MAINTAINER
+#define JIM_DEBUG_COMMAND
+#define JIM_DEBUG_PANIC
+#endif
+
+const char *jim_tt_name(int type);
+
+#ifdef JIM_DEBUG_PANIC
+static void JimPanicDump(int panic_condition, const char *fmt, ...);
+#define JimPanic(X) JimPanicDump X
+#else
+#define JimPanic(X)
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Global variables
+ * ---------------------------------------------------------------------------*/
+
+/* A shared empty string for the objects string representation.
+ * Jim_InvalidateStringRep knows about it and doesn't try to free it. */
+static char JimEmptyStringRep[] = "";
+
+/* -----------------------------------------------------------------------------
+ * Required prototypes of not exported functions
+ * ---------------------------------------------------------------------------*/
+static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf);
+static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags);
+static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr,
+    int flags);
+static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr);
+static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
+static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
+    const char *prefix, const char *const *tablePtr, const char *name);
+static void JimDeleteLocalProcs(Jim_Interp *interp);
+static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, Jim_Obj *fileNameObj, int linenr,
+    int argc, Jim_Obj *const *argv);
+static int JimEvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv,
+    Jim_Obj *fileNameObj, int linenr);
+static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr);
+static int JimSign(jim_wide w);
+static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr);
+static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen);
+static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len);
+
+
+static const Jim_HashTableType JimVariablesHashTableType;
+
+/* Fast access to the int (wide) value of an object which is known to be of int type */
+#define JimWideValue(objPtr) (objPtr)->internalRep.wideValue
+
+#define JimObjTypeName(O) ((O)->typePtr ? (O)->typePtr->name : "none")
+
+static int utf8_tounicode_case(const char *s, int *uc, int upper)
+{
+    int l = utf8_tounicode(s, uc);
+    if (upper) {
+        *uc = utf8_upper(*uc);
+    }
+    return l;
+}
+
+/* These can be used in addition to JIM_CASESENS/JIM_NOCASE */
+#define JIM_CHARSET_SCAN 2
+#define JIM_CHARSET_GLOB 0
+
+/**
+ * pattern points to a string like "[^a-z\ub5]"
+ *
+ * The pattern may contain trailing chars, which are ignored.
+ *
+ * The pattern is matched against unicode char 'c'.
+ *
+ * If (flags & JIM_NOCASE), case is ignored when matching.
+ * If (flags & JIM_CHARSET_SCAN), the considers ^ and ] special at the start
+ * of the charset, per scan, rather than glob/string match.
+ *
+ * If the unicode char 'c' matches that set, returns a pointer to the ']' character,
+ * or the null character if the ']' is missing.
+ *
+ * Returns NULL on no match.
+ */
+static const char *JimCharsetMatch(const char *pattern, int c, int flags)
+{
+    int not = 0;
+    int pchar;
+    int match = 0;
+    int nocase = 0;
+
+    if (flags & JIM_NOCASE) {
+        nocase++;
+        c = utf8_upper(c);
+    }
+
+    if (flags & JIM_CHARSET_SCAN) {
+        if (*pattern == '^') {
+            not++;
+            pattern++;
+        }
+
+        /* Special case. If the first char is ']', it is part of the set */
+        if (*pattern == ']') {
+            goto first;
+        }
+    }
+
+    while (*pattern && *pattern != ']') {
+        /* Exact match */
+        if (pattern[0] == '\\') {
+first:
+            pattern += utf8_tounicode_case(pattern, &pchar, nocase);
+        }
+        else {
+            /* Is this a range? a-z */
+            int start;
+            int end;
+
+            pattern += utf8_tounicode_case(pattern, &start, nocase);
+            if (pattern[0] == '-' && pattern[1]) {
+                /* skip '-' */
+                pattern += utf8_tounicode(pattern, &pchar);
+                pattern += utf8_tounicode_case(pattern, &end, nocase);
+
+                /* Handle reversed range too */
+                if ((c >= start && c <= end) || (c >= end && c <= start)) {
+                    match = 1;
+                }
+                continue;
+            }
+            pchar = start;
+        }
+
+        if (pchar == c) {
+            match = 1;
+        }
+    }
+    if (not) {
+        match = !match;
+    }
+
+    return match ? pattern : NULL;
+}
+
+/* Glob-style pattern matching. */
+
+/* Note: string *must* be valid UTF-8 sequences
+ *       slen is a char length, not byte counts.
+ */
+static int GlobMatch(const char *pattern, const char *string, int nocase)
+{
+    int c;
+    int pchar;
+    while (*pattern) {
+        switch (pattern[0]) {
+            case '*':
+                while (pattern[1] == '*') {
+                    pattern++;
+                }
+                pattern++;
+                if (!pattern[0]) {
+                    return 1;   /* match */
+                }
+                while (*string) {
+                    /* Recursive call - Does the remaining pattern match anywhere? */
+                    if (GlobMatch(pattern, string, nocase))
+                        return 1;       /* match */
+                    string += utf8_tounicode(string, &c);
+                }
+                return 0;       /* no match */
+
+            case '?':
+                string += utf8_tounicode(string, &c);
+                break;
+
+            case '[': {
+                    string += utf8_tounicode(string, &c);
+                    pattern = JimCharsetMatch(pattern + 1, c, nocase ? JIM_NOCASE : 0);
+                    if (!pattern) {
+                        return 0;
+                    }
+                    if (!*pattern) {
+                        /* Ran out of pattern (no ']') */
+                        continue;
+                    }
+                    break;
+                }
+            case '\\':
+                if (pattern[1]) {
+                    pattern++;
+                }
+                /* fall through */
+            default:
+                string += utf8_tounicode_case(string, &c, nocase);
+                utf8_tounicode_case(pattern, &pchar, nocase);
+                if (pchar != c) {
+                    return 0;
+                }
+                break;
+        }
+        pattern += utf8_tounicode_case(pattern, &pchar, nocase);
+        if (!*string) {
+            while (*pattern == '*') {
+                pattern++;
+            }
+            break;
+        }
+    }
+    if (!*pattern && !*string) {
+        return 1;
+    }
+    return 0;
+}
+
+static int JimStringMatch(Jim_Interp *interp, Jim_Obj *patternObj, const char *string, int nocase)
+{
+    return GlobMatch(Jim_String(patternObj), string, nocase);
+}
+
+/**
+ * string comparison works on binary data.
+ *
+ * Note that the lengths are byte lengths, not char lengths.
+ */
+static int JimStringCompare(const char *s1, int l1, const char *s2, int l2)
+{
+    if (l1 < l2) {
+        return memcmp(s1, s2, l1) <= 0 ? -1 : 1;
+    }
+    else if (l2 < l1) {
+        return memcmp(s1, s2, l2) >= 0 ? 1 : -1;
+    }
+    else {
+        return JimSign(memcmp(s1, s2, l1));
+    }
+}
+
+/**
+ * No-case version.
+ *
+ * If maxchars is -1, compares to end of string.
+ * Otherwise compares at most 'maxchars' characters.
+ */
+static int JimStringCompareNoCase(const char *s1, const char *s2, int maxchars)
+{
+    while (*s1 && *s2 && maxchars) {
+        int c1, c2;
+        s1 += utf8_tounicode_case(s1, &c1, 1);
+        s2 += utf8_tounicode_case(s2, &c2, 1);
+        if (c1 != c2) {
+            return JimSign(c1 - c2);
+        }
+        maxchars--;
+    }
+    if (!maxchars) {
+        return 0;
+    }
+    /* One string or both terminated */
+    if (*s1) {
+        return 1;
+    }
+    if (*s2) {
+        return -1;
+    }
+    return 0;
+}
+
+/* Search 's1' inside 's2', starting to search from char 'index' of 's2'.
+ * The index of the first occurrence of s1 in s2 is returned.
+ * If s1 is not found inside s2, -1 is returned. */
+static int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int idx)
+{
+    int i;
+    int l1bytelen;
+
+    if (!l1 || !l2 || l1 > l2) {
+        return -1;
+    }
+    if (idx < 0)
+        idx = 0;
+    s2 += utf8_index(s2, idx);
+
+    l1bytelen = utf8_index(s1, l1);
+
+    for (i = idx; i <= l2 - l1; i++) {
+        int c;
+        if (memcmp(s2, s1, l1bytelen) == 0) {
+            return i;
+        }
+        s2 += utf8_tounicode(s2, &c);
+    }
+    return -1;
+}
+
+/**
+ * Note: Lengths and return value are in bytes, not chars.
+ */
+static int JimStringLast(const char *s1, int l1, const char *s2, int l2)
+{
+    const char *p;
+
+    if (!l1 || !l2 || l1 > l2)
+        return -1;
+
+    /* Now search for the needle */
+    for (p = s2 + l2 - 1; p != s2 - 1; p--) {
+        if (*p == *s1 && memcmp(s1, p, l1) == 0) {
+            return p - s2;
+        }
+    }
+    return -1;
+}
+
+#ifdef JIM_UTF8
+/**
+ * Note: Lengths and return value are in chars.
+ */
+static int JimStringLastUtf8(const char *s1, int l1, const char *s2, int l2)
+{
+    int n = JimStringLast(s1, utf8_index(s1, l1), s2, utf8_index(s2, l2));
+    if (n > 0) {
+        n = utf8_strlen(s2, n);
+    }
+    return n;
+}
+#endif
+
+int Jim_WideToString(char *buf, jim_wide wideValue)
+{
+    const char *fmt = "%" JIM_WIDE_MODIFIER;
+
+    return sprintf(buf, fmt, wideValue);
+}
+
+/**
+ * After an strtol()/strtod()-like conversion,
+ * check whether something was converted and that
+ * the only thing left is white space.
+ *
+ * Returns JIM_OK or JIM_ERR.
+ */
+static int JimCheckConversion(const char *str, const char *endptr)
+{
+    if (str[0] == '\0' || str == endptr) {
+        return JIM_ERR;
+    }
+
+    if (endptr[0] != '\0') {
+        while (*endptr) {
+            if (!isspace(UCHAR(*endptr))) {
+                return JIM_ERR;
+            }
+            endptr++;
+        }
+    }
+    return JIM_OK;
+}
+
+int Jim_StringToWide(const char *str, jim_wide * widePtr, int base)
+{
+    char *endptr;
+
+    *widePtr = strtoull(str, &endptr, base);
+
+    return JimCheckConversion(str, endptr);
+}
+
+int Jim_DoubleToString(char *buf, double doubleValue)
+{
+    int len;
+    char *buf0 = buf;
+
+    len = sprintf(buf, "%.12g", doubleValue);
+
+    /* Add a final ".0" if it's a number. But not
+     * for NaN or InF */
+    while (*buf) {
+        if (*buf == '.' || isalpha(UCHAR(*buf))) {
+            /* inf -> Inf, nan -> Nan */
+            if (*buf == 'i' || *buf == 'n') {
+                *buf = toupper(UCHAR(*buf));
+            }
+            if (*buf == 'I') {
+                /* Infinity -> Inf */
+                buf[3] = '\0';
+                len = buf - buf0 + 3;
+            }
+            return len;
+        }
+        buf++;
+    }
+
+    *buf++ = '.';
+    *buf++ = '0';
+    *buf = '\0';
+
+    return len + 2;
+}
+
+int Jim_StringToDouble(const char *str, double *doublePtr)
+{
+    char *endptr;
+
+    /* Callers can check for underflow via ERANGE */
+    errno = 0;
+
+    *doublePtr = strtod(str, &endptr);
+
+    return JimCheckConversion(str, endptr);
+}
+
+static jim_wide JimPowWide(jim_wide b, jim_wide e)
+{
+    jim_wide i, res = 1;
+
+    if ((b == 0 && e != 0) || (e < 0))
+        return 0;
+    for (i = 0; i < e; i++) {
+        res *= b;
+    }
+    return res;
+}
+
+/* -----------------------------------------------------------------------------
+ * Special functions
+ * ---------------------------------------------------------------------------*/
+#ifdef JIM_DEBUG_PANIC
+void JimPanicDump(int condition, const char *fmt, ...)
+{
+    va_list ap;
+
+    if (!condition) {
+        return;
+    }
+
+    va_start(ap, fmt);
+
+    fprintf(stderr, JIM_NL "JIM INTERPRETER PANIC: ");
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, JIM_NL JIM_NL);
+    va_end(ap);
+
+#ifdef HAVE_BACKTRACE
+    {
+        void *array[40];
+        int size, i;
+        char **strings;
+
+        size = backtrace(array, 40);
+        strings = backtrace_symbols(array, size);
+        for (i = 0; i < size; i++)
+            fprintf(stderr, "[backtrace] %s" JIM_NL, strings[i]);
+        fprintf(stderr, "[backtrace] Include the above lines and the output" JIM_NL);
+        fprintf(stderr, "[backtrace] of 'nm <executable>' in the bug report." JIM_NL);
+    }
+#endif
+
+    abort();
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Memory allocation
+ * ---------------------------------------------------------------------------*/
+
+void *Jim_Alloc(int size)
+{
+    return malloc(size);
+}
+
+void Jim_Free(void *ptr)
+{
+    free(ptr);
+}
+
+void *Jim_Realloc(void *ptr, int size)
+{
+    return realloc(ptr, size);
+}
+
+char *Jim_StrDup(const char *s)
+{
+    return strdup(s);
+}
+
+char *Jim_StrDupLen(const char *s, int l)
+{
+    char *copy = Jim_Alloc(l + 1);
+
+    memcpy(copy, s, l + 1);
+    copy[l] = 0;                /* Just to be sure, original could be substring */
+    return copy;
+}
+
+/* -----------------------------------------------------------------------------
+ * Time related functions
+ * ---------------------------------------------------------------------------*/
+
+/* Returns microseconds of CPU used since start. */
+static jim_wide JimClock(void)
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, NULL);
+    return (jim_wide) tv.tv_sec * 1000000 + tv.tv_usec;
+}
+
+/* -----------------------------------------------------------------------------
+ * Hash Tables
+ * ---------------------------------------------------------------------------*/
+
+/* -------------------------- private prototypes ---------------------------- */
+static int JimExpandHashTableIfNeeded(Jim_HashTable *ht);
+static unsigned int JimHashTableNextPower(unsigned int size);
+static int JimInsertHashEntry(Jim_HashTable *ht, const void *key);
+
+/* -------------------------- hash functions -------------------------------- */
+
+/* Thomas Wang's 32 bit Mix Function */
+unsigned int Jim_IntHashFunction(unsigned int key)
+{
+    key += ~(key << 15);
+    key ^= (key >> 10);
+    key += (key << 3);
+    key ^= (key >> 6);
+    key += ~(key << 11);
+    key ^= (key >> 16);
+    return key;
+}
+
+/* Generic hash function (we are using to multiply by 9 and add the byte
+ * as Tcl) */
+unsigned int Jim_GenHashFunction(const unsigned char *buf, int len)
+{
+    unsigned int h = 0;
+
+    while (len--)
+        h += (h << 3) + *buf++;
+    return h;
+}
+
+/* ----------------------------- API implementation ------------------------- */
+
+/* reset a hashtable already initialized with ht_init().
+ * NOTE: This function should only called by ht_destroy(). */
+static void JimResetHashTable(Jim_HashTable *ht)
+{
+    ht->table = NULL;
+    ht->size = 0;
+    ht->sizemask = 0;
+    ht->used = 0;
+    ht->collisions = 0;
+}
+
+/* Initialize the hash table */
+int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr)
+{
+    JimResetHashTable(ht);
+    ht->type = type;
+    ht->privdata = privDataPtr;
+    return JIM_OK;
+}
+
+/* Resize the table to the minimal size that contains all the elements,
+ * but with the invariant of a USER/BUCKETS ration near to <= 1 */
+int Jim_ResizeHashTable(Jim_HashTable *ht)
+{
+    int minimal = ht->used;
+
+    if (minimal < JIM_HT_INITIAL_SIZE)
+        minimal = JIM_HT_INITIAL_SIZE;
+    return Jim_ExpandHashTable(ht, minimal);
+}
+
+/* Expand or create the hashtable */
+int Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
+{
+    Jim_HashTable n;            /* the new hashtable */
+    unsigned int realsize = JimHashTableNextPower(size), i;
+
+    /* the size is invalid if it is smaller than the number of
+     * elements already inside the hashtable */
+    if (ht->used >= size)
+        return JIM_ERR;
+
+    Jim_InitHashTable(&n, ht->type, ht->privdata);
+    n.size = realsize;
+    n.sizemask = realsize - 1;
+    n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *));
+
+    /* Initialize all the pointers to NULL */
+    memset(n.table, 0, realsize * sizeof(Jim_HashEntry *));
+
+    /* Copy all the elements from the old to the new table:
+     * note that if the old hash table is empty ht->used is zero,
+     * so Jim_ExpandHashTable just creates an empty hash table. */
+    n.used = ht->used;
+    for (i = 0; ht->used > 0; i++) {
+        Jim_HashEntry *he, *nextHe;
+
+        if (ht->table[i] == NULL)
+            continue;
+
+        /* For each hash entry on this slot... */
+        he = ht->table[i];
+        while (he) {
+            unsigned int h;
+
+            nextHe = he->next;
+            /* Get the new element index */
+            h = Jim_HashKey(ht, he->key) & n.sizemask;
+            he->next = n.table[h];
+            n.table[h] = he;
+            ht->used--;
+            /* Pass to the next element */
+            he = nextHe;
+        }
+    }
+    assert(ht->used == 0);
+    Jim_Free(ht->table);
+
+    /* Remap the new hashtable in the old */
+    *ht = n;
+    return JIM_OK;
+}
+
+/* Add an element to the target hash table */
+int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val)
+{
+    int idx;
+    Jim_HashEntry *entry;
+
+    /* Get the index of the new element, or -1 if
+     * the element already exists. */
+    if ((idx = JimInsertHashEntry(ht, key)) == -1)
+        return JIM_ERR;
+
+    /* Allocates the memory and stores key */
+    entry = Jim_Alloc(sizeof(*entry));
+    entry->next = ht->table[idx];
+    ht->table[idx] = entry;
+
+    /* Set the hash entry fields. */
+    Jim_SetHashKey(ht, entry, key);
+    Jim_SetHashVal(ht, entry, val);
+    ht->used++;
+    return JIM_OK;
+}
+
+/* Add an element, discarding the old if the key already exists */
+int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val)
+{
+    Jim_HashEntry *entry;
+
+    /* Try to add the element. If the key
+     * does not exists Jim_AddHashEntry will suceed. */
+    if (Jim_AddHashEntry(ht, key, val) == JIM_OK)
+        return JIM_OK;
+    /* It already exists, get the entry */
+    entry = Jim_FindHashEntry(ht, key);
+    /* Free the old value and set the new one */
+    Jim_FreeEntryVal(ht, entry);
+    Jim_SetHashVal(ht, entry, val);
+    return JIM_OK;
+}
+
+/* Search and remove an element */
+int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key)
+{
+    unsigned int h;
+    Jim_HashEntry *he, *prevHe;
+
+    if (ht->used == 0)
+        return JIM_ERR;
+    h = Jim_HashKey(ht, key) & ht->sizemask;
+    he = ht->table[h];
+
+    prevHe = NULL;
+    while (he) {
+        if (Jim_CompareHashKeys(ht, key, he->key)) {
+            /* Unlink the element from the list */
+            if (prevHe)
+                prevHe->next = he->next;
+            else
+                ht->table[h] = he->next;
+            Jim_FreeEntryKey(ht, he);
+            Jim_FreeEntryVal(ht, he);
+            Jim_Free(he);
+            ht->used--;
+            return JIM_OK;
+        }
+        prevHe = he;
+        he = he->next;
+    }
+    return JIM_ERR;             /* not found */
+}
+
+/* Destroy an entire hash table */
+int Jim_FreeHashTable(Jim_HashTable *ht)
+{
+    unsigned int i;
+
+    /* Free all the elements */
+    for (i = 0; ht->used > 0; i++) {
+        Jim_HashEntry *he, *nextHe;
+
+        if ((he = ht->table[i]) == NULL)
+            continue;
+        while (he) {
+            nextHe = he->next;
+            Jim_FreeEntryKey(ht, he);
+            Jim_FreeEntryVal(ht, he);
+            Jim_Free(he);
+            ht->used--;
+            he = nextHe;
+        }
+    }
+    /* Free the table and the allocated cache structure */
+    Jim_Free(ht->table);
+    /* Re-initialize the table */
+    JimResetHashTable(ht);
+    return JIM_OK;              /* never fails */
+}
+
+Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key)
+{
+    Jim_HashEntry *he;
+    unsigned int h;
+
+    if (ht->used == 0)
+        return NULL;
+    h = Jim_HashKey(ht, key) & ht->sizemask;
+    he = ht->table[h];
+    while (he) {
+        if (Jim_CompareHashKeys(ht, key, he->key))
+            return he;
+        he = he->next;
+    }
+    return NULL;
+}
+
+Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht)
+{
+    Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter));
+
+    iter->ht = ht;
+    iter->index = -1;
+    iter->entry = NULL;
+    iter->nextEntry = NULL;
+    return iter;
+}
+
+Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter)
+{
+    while (1) {
+        if (iter->entry == NULL) {
+            iter->index++;
+            if (iter->index >= (signed)iter->ht->size)
+                break;
+            iter->entry = iter->ht->table[iter->index];
+        }
+        else {
+            iter->entry = iter->nextEntry;
+        }
+        if (iter->entry) {
+            /* We need to save the 'next' here, the iterator user
+             * may delete the entry we are returning. */
+            iter->nextEntry = iter->entry->next;
+            return iter->entry;
+        }
+    }
+    return NULL;
+}
+
+/* ------------------------- private functions ------------------------------ */
+
+/* Expand the hash table if needed */
+static int JimExpandHashTableIfNeeded(Jim_HashTable *ht)
+{
+    /* If the hash table is empty expand it to the intial size,
+     * if the table is "full" dobule its size. */
+    if (ht->size == 0)
+        return Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE);
+    if (ht->size == ht->used)
+        return Jim_ExpandHashTable(ht, ht->size * 2);
+    return JIM_OK;
+}
+
+/* Our hash table capability is a power of two */
+static unsigned int JimHashTableNextPower(unsigned int size)
+{
+    unsigned int i = JIM_HT_INITIAL_SIZE;
+
+    if (size >= 2147483648U)
+        return 2147483648U;
+    while (1) {
+        if (i >= size)
+            return i;
+        i *= 2;
+    }
+}
+
+/* Returns the index of a free slot that can be populated with
+ * an hash entry for the given 'key'.
+ * If the key already exists, -1 is returned. */
+static int JimInsertHashEntry(Jim_HashTable *ht, const void *key)
+{
+    unsigned int h;
+    Jim_HashEntry *he;
+
+    /* Expand the hashtable if needed */
+    if (JimExpandHashTableIfNeeded(ht) == JIM_ERR)
+        return -1;
+    /* Compute the key hash value */
+    h = Jim_HashKey(ht, key) & ht->sizemask;
+    /* Search if this slot does not already contain the given key */
+    he = ht->table[h];
+    while (he) {
+        if (Jim_CompareHashKeys(ht, key, he->key))
+            return -1;
+        he = he->next;
+    }
+    return h;
+}
+
+/* ----------------------- StringCopy Hash Table Type ------------------------*/
+
+static unsigned int JimStringCopyHTHashFunction(const void *key)
+{
+    return Jim_GenHashFunction(key, strlen(key));
+}
+
+static const void *JimStringCopyHTKeyDup(void *privdata, const void *key)
+{
+    int len = strlen(key);
+    char *copy = Jim_Alloc(len + 1);
+
+    JIM_NOTUSED(privdata);
+
+    memcpy(copy, key, len);
+    copy[len] = '\0';
+    return copy;
+}
+
+static void *JimStringKeyValCopyHTValDup(void *privdata, const void *val)
+{
+    int len = strlen(val);
+    char *copy = Jim_Alloc(len + 1);
+
+    JIM_NOTUSED(privdata);
+
+    memcpy(copy, val, len);
+    copy[len] = '\0';
+    return copy;
+}
+
+static int JimStringCopyHTKeyCompare(void *privdata, const void *key1, const void *key2)
+{
+    JIM_NOTUSED(privdata);
+
+    return strcmp(key1, key2) == 0;
+}
+
+static void JimStringCopyHTKeyDestructor(void *privdata, const void *key)
+{
+    JIM_NOTUSED(privdata);
+
+    Jim_Free((void *)key);      /* ATTENTION: const cast */
+}
+
+static void JimStringKeyValCopyHTValDestructor(void *privdata, void *val)
+{
+    JIM_NOTUSED(privdata);
+
+    Jim_Free((void *)val);      /* ATTENTION: const cast */
+}
+
+#if 0
+static Jim_HashTableType JimStringCopyHashTableType = {
+    JimStringCopyHTHashFunction,        /* hash function */
+    JimStringCopyHTKeyDup,      /* key dup */
+    NULL,                       /* val dup */
+    JimStringCopyHTKeyCompare,  /* key compare */
+    JimStringCopyHTKeyDestructor,       /* key destructor */
+    NULL                        /* val destructor */
+};
+#endif
+
+/* This is like StringCopy but does not auto-duplicate the key.
+ * It's used for intepreter's shared strings. */
+static const Jim_HashTableType JimSharedStringsHashTableType = {
+    JimStringCopyHTHashFunction,        /* hash function */
+    NULL,                       /* key dup */
+    NULL,                       /* val dup */
+    JimStringCopyHTKeyCompare,  /* key compare */
+    JimStringCopyHTKeyDestructor,       /* key destructor */
+    NULL                        /* val destructor */
+};
+
+/* This is like StringCopy but also automatically handle dynamic
+ * allocated C strings as values. */
+static const Jim_HashTableType JimStringKeyValCopyHashTableType = {
+    JimStringCopyHTHashFunction,        /* hash function */
+    JimStringCopyHTKeyDup,      /* key dup */
+    JimStringKeyValCopyHTValDup,        /* val dup */
+    JimStringCopyHTKeyCompare,  /* key compare */
+    JimStringCopyHTKeyDestructor,       /* key destructor */
+    JimStringKeyValCopyHTValDestructor, /* val destructor */
+};
+
+typedef struct AssocDataValue
+{
+    Jim_InterpDeleteProc *delProc;
+    void *data;
+} AssocDataValue;
+
+static void JimAssocDataHashTableValueDestructor(void *privdata, void *data)
+{
+    AssocDataValue *assocPtr = (AssocDataValue *) data;
+
+    if (assocPtr->delProc != NULL)
+        assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data);
+    Jim_Free(data);
+}
+
+static const Jim_HashTableType JimAssocDataHashTableType = {
+    JimStringCopyHTHashFunction,        /* hash function */
+    JimStringCopyHTKeyDup,      /* key dup */
+    NULL,                       /* val dup */
+    JimStringCopyHTKeyCompare,  /* key compare */
+    JimStringCopyHTKeyDestructor,       /* key destructor */
+    JimAssocDataHashTableValueDestructor        /* val destructor */
+};
+
+/* -----------------------------------------------------------------------------
+ * Stack - This is a simple generic stack implementation. It is used for
+ * example in the 'expr' expression compiler.
+ * ---------------------------------------------------------------------------*/
+void Jim_InitStack(Jim_Stack *stack)
+{
+    stack->len = 0;
+    stack->maxlen = 0;
+    stack->vector = NULL;
+}
+
+void Jim_FreeStack(Jim_Stack *stack)
+{
+    Jim_Free(stack->vector);
+}
+
+int Jim_StackLen(Jim_Stack *stack)
+{
+    return stack->len;
+}
+
+void Jim_StackPush(Jim_Stack *stack, void *element)
+{
+    int neededLen = stack->len + 1;
+
+    if (neededLen > stack->maxlen) {
+        stack->maxlen = neededLen < 20 ? 20 : neededLen * 2;
+        stack->vector = Jim_Realloc(stack->vector, sizeof(void *) * stack->maxlen);
+    }
+    stack->vector[stack->len] = element;
+    stack->len++;
+}
+
+void *Jim_StackPop(Jim_Stack *stack)
+{
+    if (stack->len == 0)
+        return NULL;
+    stack->len--;
+    return stack->vector[stack->len];
+}
+
+void *Jim_StackPeek(Jim_Stack *stack)
+{
+    if (stack->len == 0)
+        return NULL;
+    return stack->vector[stack->len - 1];
+}
+
+void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc) (void *ptr))
+{
+    int i;
+
+    for (i = 0; i < stack->len; i++)
+        freeFunc(stack->vector[i]);
+}
+
+/* -----------------------------------------------------------------------------
+ * Parser
+ * ---------------------------------------------------------------------------*/
+
+/* Token types */
+#define JIM_TT_NONE    0           /* No token returned */
+#define JIM_TT_STR     1          /* simple string */
+#define JIM_TT_ESC     2          /* string that needs escape chars conversion */
+#define JIM_TT_VAR     3          /* var substitution */
+#define JIM_TT_DICTSUGAR   4      /* Syntax sugar for [dict get], $foo(bar) */
+#define JIM_TT_CMD     5          /* command substitution */
+/* Note: Keep these three together for TOKEN_IS_SEP() */
+#define JIM_TT_SEP     6          /* word separator. arg is # of tokens. -ve if {*} */
+#define JIM_TT_EOL     7          /* line separator */
+#define JIM_TT_EOF     8          /* end of script */
+
+#define JIM_TT_LINE    9          /* special 'start-of-line' token. arg is # of arguments to the command. -ve if {*} */
+#define JIM_TT_WORD   10          /* special 'start-of-word' token. arg is # of tokens to combine. -ve if {*} */
+
+/* Additional token types needed for expressions */
+#define JIM_TT_SUBEXPR_START  11
+#define JIM_TT_SUBEXPR_END    12
+#define JIM_TT_SUBEXPR_COMMA  13
+#define JIM_TT_EXPR_INT       14
+#define JIM_TT_EXPR_DOUBLE    15
+
+#define JIM_TT_EXPRSUGAR      16  /* $(expression) */
+
+/* Operator token types start here */
+#define JIM_TT_EXPR_OP        20
+
+#define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
+
+/* Parser states */
+#define JIM_PS_DEF 0            /* Default state */
+#define JIM_PS_QUOTE 1          /* Inside "" */
+#define JIM_PS_DICTSUGAR 2      /* Tokenising abc(def) into 4 separate tokens */
+
+/* Parser context structure. The same context is used both to parse
+ * Tcl scripts and lists. */
+struct JimParserCtx
+{
+    const char *p;              /* Pointer to the point of the program we are parsing */
+    int len;                    /* Remaining length */
+    int linenr;                 /* Current line number */
+    const char *tstart;
+    const char *tend;           /* Returned token is at tstart-tend in 'prg'. */
+    int tline;                  /* Line number of the returned token */
+    int tt;                     /* Token type */
+    int eof;                    /* Non zero if EOF condition is true. */
+    int state;                  /* Parser state */
+    int comment;                /* Non zero if the next chars may be a comment. */
+    char missing;               /* At end of parse, ' ' if complete, '{' if braces incomplete, '"' if quotes incomplete */
+    int missingline;            /* Line number starting the missing token */
+};
+
+/**
+ * Results of missing quotes, braces, etc. from parsing.
+ */
+struct JimParseResult {
+    char missing;               /* From JimParserCtx.missing */
+    int line;                   /* From JimParserCtx.missingline */
+};
+
+static int JimParseScript(struct JimParserCtx *pc);
+static int JimParseSep(struct JimParserCtx *pc);
+static int JimParseEol(struct JimParserCtx *pc);
+static int JimParseCmd(struct JimParserCtx *pc);
+static int JimParseQuote(struct JimParserCtx *pc);
+static int JimParseVar(struct JimParserCtx *pc);
+static int JimParseBrace(struct JimParserCtx *pc);
+static int JimParseStr(struct JimParserCtx *pc);
+static int JimParseComment(struct JimParserCtx *pc);
+static void JimParseSubCmd(struct JimParserCtx *pc);
+static int JimParseSubQuote(struct JimParserCtx *pc);
+static void JimParseSubCmd(struct JimParserCtx *pc);
+static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc);
+
+/* Initialize a parser context.
+ * 'prg' is a pointer to the program text, linenr is the line
+ * number of the first line contained in the program. */
+static void JimParserInit(struct JimParserCtx *pc, const char *prg, int len, int linenr)
+{
+    pc->p = prg;
+    pc->len = len;
+    pc->tstart = NULL;
+    pc->tend = NULL;
+    pc->tline = 0;
+    pc->tt = JIM_TT_NONE;
+    pc->eof = 0;
+    pc->state = JIM_PS_DEF;
+    pc->linenr = linenr;
+    pc->comment = 1;
+    pc->missing = ' ';
+    pc->missingline = linenr;
+}
+
+static int JimParseScript(struct JimParserCtx *pc)
+{
+    while (1) {                 /* the while is used to reiterate with continue if needed */
+        if (!pc->len) {
+            pc->tstart = pc->p;
+            pc->tend = pc->p - 1;
+            pc->tline = pc->linenr;
+            pc->tt = JIM_TT_EOL;
+            pc->eof = 1;
+            return JIM_OK;
+        }
+        switch (*(pc->p)) {
+            case '\\':
+                if (*(pc->p + 1) == '\n' && pc->state == JIM_PS_DEF) {
+                    return JimParseSep(pc);
+                }
+                else {
+                    pc->comment = 0;
+                    return JimParseStr(pc);
+                }
+                break;
+            case ' ':
+            case '\t':
+            case '\r':
+                if (pc->state == JIM_PS_DEF)
+                    return JimParseSep(pc);
+                else {
+                    pc->comment = 0;
+                    return JimParseStr(pc);
+                }
+                break;
+            case '\n':
+            case ';':
+                pc->comment = 1;
+                if (pc->state == JIM_PS_DEF)
+                    return JimParseEol(pc);
+                else
+                    return JimParseStr(pc);
+                break;
+            case '[':
+                pc->comment = 0;
+                return JimParseCmd(pc);
+                break;
+            case '$':
+                pc->comment = 0;
+                if (JimParseVar(pc) == JIM_ERR) {
+                    pc->tstart = pc->tend = pc->p++;
+                    pc->len--;
+                    pc->tline = pc->linenr;
+                    pc->tt = JIM_TT_STR;
+                    return JIM_OK;
+                }
+                else
+                    return JIM_OK;
+                break;
+            case '#':
+                if (pc->comment) {
+                    JimParseComment(pc);
+                    continue;
+                }
+                else {
+                    return JimParseStr(pc);
+                }
+            default:
+                pc->comment = 0;
+                return JimParseStr(pc);
+                break;
+        }
+        return JIM_OK;
+    }
+}
+
+static int JimParseSep(struct JimParserCtx *pc)
+{
+    pc->tstart = pc->p;
+    pc->tline = pc->linenr;
+    while (*pc->p == ' ' || *pc->p == '\t' || *pc->p == '\r' ||
+        (*pc->p == '\\' && *(pc->p + 1) == '\n')) {
+        if (*pc->p == '\\') {
+            pc->p++;
+            pc->len--;
+            pc->linenr++;
+        }
+        pc->p++;
+        pc->len--;
+    }
+    pc->tend = pc->p - 1;
+    pc->tt = JIM_TT_SEP;
+    return JIM_OK;
+}
+
+static int JimParseEol(struct JimParserCtx *pc)
+{
+    pc->tstart = pc->p;
+    pc->tline = pc->linenr;
+    while (*pc->p == ' ' || *pc->p == '\n' || *pc->p == '\t' || *pc->p == '\r' || *pc->p == ';') {
+        if (*pc->p == '\n')
+            pc->linenr++;
+        pc->p++;
+        pc->len--;
+    }
+    pc->tend = pc->p - 1;
+    pc->tt = JIM_TT_EOL;
+    return JIM_OK;
+}
+
+/*
+** Here are the rules for parsing:
+** {braced expression}
+** - Count open and closing braces
+** - Backslash escapes meaning of braces
+**
+** "quoted expression"
+** - First double quote at start of word terminates the expression
+** - Backslash escapes quote and bracket
+** - [commands brackets] are counted/nested
+** - command rules apply within [brackets], not quoting rules (i.e. quotes have their own rules)
+**
+** [command expression]
+** - Count open and closing brackets
+** - Backslash escapes quote, bracket and brace
+** - [commands brackets] are counted/nested
+** - "quoted expressions" are parsed according to quoting rules
+** - {braced expressions} are parsed according to brace rules
+**
+** For everything, backslash escapes the next char, newline increments current line
+*/
+
+/**
+ * Parses a braced expression starting at pc->p.
+ *
+ * Positions the parser at the end of the braced expression,
+ * sets pc->tend and possibly pc->missing.
+ */
+static void JimParseSubBrace(struct JimParserCtx *pc)
+{
+    int level = 1;
+
+    /* Skip the brace */
+    pc->p++;
+    pc->len--;
+    while (pc->len) {
+        switch (*pc->p) {
+            case '\\':
+                if (pc->len > 1) {
+                    if (*++pc->p == '\n') {
+                        pc->linenr++;
+                    }
+                    pc->len--;
+                }
+                break;
+
+            case '{':
+                level++;
+                break;
+
+            case '}':
+                if (--level == 0) {
+                    pc->tend = pc->p - 1;
+                    pc->p++;
+                    pc->len--;
+                    return;
+                }
+                break;
+
+            case '\n':
+                pc->linenr++;
+                break;
+        }
+        pc->p++;
+        pc->len--;
+    }
+    pc->missing = '{';
+    pc->missingline = pc->tline;
+    pc->tend = pc->p - 1;
+}
+
+/**
+ * Parses a quoted expression starting at pc->p.
+ *
+ * Positions the parser at the end of the quoted expression,
+ * sets pc->tend and possibly pc->missing.
+ *
+ * Returns the type of the token of the string,
+ * either JIM_TT_ESC (if it contains values which need to be [subst]ed)
+ * or JIM_TT_STR.
+ */
+static int JimParseSubQuote(struct JimParserCtx *pc)
+{
+    int tt = JIM_TT_STR;
+    int line = pc->tline;
+
+    /* Skip the quote */
+    pc->p++;
+    pc->len--;
+    while (pc->len) {
+        switch (*pc->p) {
+            case '\\':
+                if (pc->len > 1) {
+                    if (*++pc->p == '\n') {
+                        pc->linenr++;
+                    }
+                    pc->len--;
+                    tt = JIM_TT_ESC;
+                }
+                break;
+
+            case '"':
+                pc->tend = pc->p - 1;
+                pc->p++;
+                pc->len--;
+                return tt;
+
+            case '[':
+                JimParseSubCmd(pc);
+                tt = JIM_TT_ESC;
+                continue;
+
+            case '\n':
+                pc->linenr++;
+                break;
+
+            case '$':
+                tt = JIM_TT_ESC;
+                break;
+        }
+        pc->p++;
+        pc->len--;
+    }
+    pc->missing = '"';
+    pc->missingline = line;
+    pc->tend = pc->p - 1;
+    return tt;
+}
+
+/**
+ * Parses a [command] expression starting at pc->p.
+ *
+ * Positions the parser at the end of the command expression,
+ * sets pc->tend and possibly pc->missing.
+ */
+static void JimParseSubCmd(struct JimParserCtx *pc)
+{
+    int level = 1;
+    int startofword = 1;
+    int line = pc->tline;
+
+    /* Skip the bracket */
+    pc->p++;
+    pc->len--;
+    while (pc->len) {
+        switch (*pc->p) {
+            case '\\':
+                if (pc->len > 1) {
+                    if (*++pc->p == '\n') {
+                        pc->linenr++;
+                    }
+                    pc->len--;
+                }
+                break;
+
+            case '[':
+                level++;
+                break;
+
+            case ']':
+                if (--level == 0) {
+                    pc->tend = pc->p - 1;
+                    pc->p++;
+                    pc->len--;
+                    return;
+                }
+                break;
+
+            case '"':
+                if (startofword) {
+                    JimParseSubQuote(pc);
+                    continue;
+                }
+                break;
+
+            case '{':
+                JimParseSubBrace(pc);
+                startofword = 0;
+                continue;
+
+            case '\n':
+                pc->linenr++;
+                break;
+        }
+        startofword = isspace(UCHAR(*pc->p));
+        pc->p++;
+        pc->len--;
+    }
+    pc->missing = '[';
+    pc->missingline = line;
+    pc->tend = pc->p - 1;
+}
+
+static int JimParseBrace(struct JimParserCtx *pc)
+{
+    pc->tstart = pc->p + 1;
+    pc->tline = pc->linenr;
+    pc->tt = JIM_TT_STR;
+    JimParseSubBrace(pc);
+    return JIM_OK;
+}
+
+static int JimParseCmd(struct JimParserCtx *pc)
+{
+    pc->tstart = pc->p + 1;
+    pc->tline = pc->linenr;
+    pc->tt = JIM_TT_CMD;
+    JimParseSubCmd(pc);
+    return JIM_OK;
+}
+
+static int JimParseQuote(struct JimParserCtx *pc)
+{
+    pc->tstart = pc->p + 1;
+    pc->tline = pc->linenr;
+    pc->tt = JimParseSubQuote(pc);
+    return JIM_OK;
+}
+
+static int JimParseVar(struct JimParserCtx *pc)
+{
+    /* skip the $ */
+    pc->p++;
+    pc->len--;
+
+#ifdef EXPRSUGAR_BRACKET
+    if (*pc->p == '[') {
+        /* Parse $[...] expr shorthand syntax */
+        JimParseCmd(pc);
+        pc->tt = JIM_TT_EXPRSUGAR;
+        return JIM_OK;
+    }
+#endif
+
+    pc->tstart = pc->p;
+    pc->tt = JIM_TT_VAR;
+    pc->tline = pc->linenr;
+
+    if (*pc->p == '{') {
+        pc->tstart = ++pc->p;
+        pc->len--;
+
+        while (pc->len && *pc->p != '}') {
+            if (*pc->p == '\n') {
+                pc->linenr++;
+            }
+            pc->p++;
+            pc->len--;
+        }
+        pc->tend = pc->p - 1;
+        if (pc->len) {
+            pc->p++;
+            pc->len--;
+        }
+    }
+    else {
+        while (1) {
+            /* Skip double colon, but not single colon! */
+            if (pc->p[0] == ':' && pc->p[1] == ':') {
+                pc->p += 2;
+                pc->len -= 2;
+                continue;
+            }
+            if (isalnum(UCHAR(*pc->p)) || *pc->p == '_') {
+                pc->p++;
+                pc->len--;
+                continue;
+            }
+            break;
+        }
+        /* Parse [dict get] syntax sugar. */
+        if (*pc->p == '(') {
+            int count = 1;
+            const char *paren = NULL;
+
+            pc->tt = JIM_TT_DICTSUGAR;
+
+            while (count && pc->len) {
+                pc->p++;
+                pc->len--;
+                if (*pc->p == '\\' && pc->len >= 1) {
+                    pc->p++;
+                    pc->len--;
+                }
+                else if (*pc->p == '(') {
+                    count++;
+                }
+                else if (*pc->p == ')') {
+                    paren = pc->p;
+                    count--;
+                }
+            }
+            if (count == 0) {
+                pc->p++;
+                pc->len--;
+            }
+            else if (paren) {
+                /* Did not find a matching paren. Back up */
+                paren++;
+                pc->len += (pc->p - paren);
+                pc->p = paren;
+            }
+#ifndef EXPRSUGAR_BRACKET
+            if (*pc->tstart == '(') {
+                pc->tt = JIM_TT_EXPRSUGAR;
+            }
+#endif
+        }
+        pc->tend = pc->p - 1;
+    }
+    /* Check if we parsed just the '$' character.
+     * That's not a variable so an error is returned
+     * to tell the state machine to consider this '$' just
+     * a string. */
+    if (pc->tstart == pc->p) {
+        pc->p--;
+        pc->len++;
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+static int JimParseStr(struct JimParserCtx *pc)
+{
+    int newword = (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
+        pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR);
+    if (newword && *pc->p == '{') {
+        return JimParseBrace(pc);
+    }
+    else if (newword && *pc->p == '"') {
+        pc->state = JIM_PS_QUOTE;
+        pc->p++;
+        pc->len--;
+        /* In case the end quote is missing */
+        pc->missingline = pc->tline;
+    }
+    pc->tstart = pc->p;
+    pc->tline = pc->linenr;
+    while (1) {
+        if (pc->len == 0) {
+            if (pc->state == JIM_PS_QUOTE) {
+                pc->missing = '"';
+            }
+            pc->tend = pc->p - 1;
+            pc->tt = JIM_TT_ESC;
+            return JIM_OK;
+        }
+        switch (*pc->p) {
+            case '\\':
+                if (pc->state == JIM_PS_DEF && *(pc->p + 1) == '\n') {
+                    pc->tend = pc->p - 1;
+                    pc->tt = JIM_TT_ESC;
+                    return JIM_OK;
+                }
+                if (pc->len >= 2) {
+                    if (*(pc->p + 1) == '\n') {
+                        pc->linenr++;
+                    }
+                    pc->p++;
+                    pc->len--;
+                }
+                break;
+            case '(':
+                /* If the following token is not '$' just keep going */
+                if (pc->len > 1 && pc->p[1] != '$') {
+                    break;
+                }
+            case ')':
+                /* Only need a separate ')' token if the previous was a var */
+                if (*pc->p == '(' || pc->tt == JIM_TT_VAR) {
+                    if (pc->p == pc->tstart) {
+                        /* At the start of the token, so just return this char */
+                        pc->p++;
+                        pc->len--;
+                    }
+                    pc->tend = pc->p - 1;
+                    pc->tt = JIM_TT_ESC;
+                    return JIM_OK;
+                }
+                break;
+
+            case '$':
+            case '[':
+                pc->tend = pc->p - 1;
+                pc->tt = JIM_TT_ESC;
+                return JIM_OK;
+            case ' ':
+            case '\t':
+            case '\n':
+            case '\r':
+            case ';':
+                if (pc->state == JIM_PS_DEF) {
+                    pc->tend = pc->p - 1;
+                    pc->tt = JIM_TT_ESC;
+                    return JIM_OK;
+                }
+                else if (*pc->p == '\n') {
+                    pc->linenr++;
+                }
+                break;
+            case '"':
+                if (pc->state == JIM_PS_QUOTE) {
+                    pc->tend = pc->p - 1;
+                    pc->tt = JIM_TT_ESC;
+                    pc->p++;
+                    pc->len--;
+                    pc->state = JIM_PS_DEF;
+                    return JIM_OK;
+                }
+                break;
+        }
+        pc->p++;
+        pc->len--;
+    }
+    return JIM_OK;              /* unreached */
+}
+
+static int JimParseComment(struct JimParserCtx *pc)
+{
+    while (*pc->p) {
+        if (*pc->p == '\n') {
+            pc->linenr++;
+            if (*(pc->p - 1) != '\\') {
+                pc->p++;
+                pc->len--;
+                return JIM_OK;
+            }
+        }
+        pc->p++;
+        pc->len--;
+    }
+    return JIM_OK;
+}
+
+/* xdigitval and odigitval are helper functions for JimEscape() */
+static int xdigitval(int c)
+{
+    if (c >= '0' && c <= '9')
+        return c - '0';
+    if (c >= 'a' && c <= 'f')
+        return c - 'a' + 10;
+    if (c >= 'A' && c <= 'F')
+        return c - 'A' + 10;
+    return -1;
+}
+
+static int odigitval(int c)
+{
+    if (c >= '0' && c <= '7')
+        return c - '0';
+    return -1;
+}
+
+/* Perform Tcl escape substitution of 's', storing the result
+ * string into 'dest'. The escaped string is guaranteed to
+ * be the same length or shorted than the source string.
+ * Slen is the length of the string at 's', if it's -1 the string
+ * length will be calculated by the function.
+ *
+ * The function returns the length of the resulting string. */
+static int JimEscape(char *dest, const char *s, int slen)
+{
+    char *p = dest;
+    int i, len;
+
+    if (slen == -1)
+        slen = strlen(s);
+
+    for (i = 0; i < slen; i++) {
+        switch (s[i]) {
+            case '\\':
+                switch (s[i + 1]) {
+                    case 'a':
+                        *p++ = 0x7;
+                        i++;
+                        break;
+                    case 'b':
+                        *p++ = 0x8;
+                        i++;
+                        break;
+                    case 'f':
+                        *p++ = 0xc;
+                        i++;
+                        break;
+                    case 'n':
+                        *p++ = 0xa;
+                        i++;
+                        break;
+                    case 'r':
+                        *p++ = 0xd;
+                        i++;
+                        break;
+                    case 't':
+                        *p++ = 0x9;
+                        i++;
+                        break;
+                    case 'u':
+                    case 'x':
+                        /* A unicode or hex sequence.
+                         * \u Expect 1-4 hex chars and convert to utf-8.
+                         * \x Expect 1-2 hex chars and convert to hex.
+                         * An invalid sequence means simply the escaped char.
+                         */
+                        {
+                            int val = 0;
+                            int k;
+
+                            i++;
+
+                            for (k = 0; k < (s[i] == 'u' ? 4 : 2); k++) {
+                                int c = xdigitval(s[i + k + 1]);
+                                if (c == -1) {
+                                    break;
+                                }
+                                val = (val << 4) | c;
+                            }
+                            if (k) {
+                                /* Got a valid sequence, so convert */
+                                if (s[i] == 'u') {
+                                    p += utf8_fromunicode(p, val);
+                                }
+                                else {
+                                    *p++ = val;
+                                }
+                                i += k;
+                                break;
+                            }
+                            /* Not a valid codepoint, just an escaped char */
+                            *p++ = s[i];
+                        }
+                        break;
+                    case 'v':
+                        *p++ = 0xb;
+                        i++;
+                        break;
+                    case '\0':
+                        *p++ = '\\';
+                        i++;
+                        break;
+                    case '\n':
+                        /* Replace all spaces and tabs after backslash newline with a single space*/
+                        *p++ = ' ';
+                        do {
+                            i++;
+                        } while (s[i + 1] == ' ' || s[i + 1] == '\t');
+                        break;
+                    case '0':
+                    case '1':
+                    case '2':
+                    case '3':
+                    case '4':
+                    case '5':
+                    case '6':
+                    case '7':
+                        /* octal escape */
+                        {
+                            int val = 0;
+                            int c = odigitval(s[i + 1]);
+
+                            val = c;
+                            c = odigitval(s[i + 2]);
+                            if (c == -1) {
+                                *p++ = val;
+                                i++;
+                                break;
+                            }
+                            val = (val * 8) + c;
+                            c = odigitval(s[i + 3]);
+                            if (c == -1) {
+                                *p++ = val;
+                                i += 2;
+                                break;
+                            }
+                            val = (val * 8) + c;
+                            *p++ = val;
+                            i += 3;
+                        }
+                        break;
+                    default:
+                        *p++ = s[i + 1];
+                        i++;
+                        break;
+                }
+                break;
+            default:
+                *p++ = s[i];
+                break;
+        }
+    }
+    len = p - dest;
+    *p = '\0';
+    return len;
+}
+
+/* Returns a dynamically allocated copy of the current token in the
+ * parser context. The function performs conversion of escapes if
+ * the token is of type JIM_TT_ESC.
+ *
+ * Note that after the conversion, tokens that are grouped with
+ * braces in the source code, are always recognizable from the
+ * identical string obtained in a different way from the type.
+ *
+ * For example the string:
+ *
+ * {*}$a
+ *
+ * will return as first token "*", of type JIM_TT_STR
+ *
+ * While the string:
+ *
+ * *$a
+ *
+ * will return as first token "*", of type JIM_TT_ESC
+ */
+static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc)
+{
+    const char *start, *end;
+    char *token;
+    int len;
+
+    start = pc->tstart;
+    end = pc->tend;
+    if (start > end) {
+        len = 0;
+        token = Jim_Alloc(1);
+        token[0] = '\0';
+    }
+    else {
+        len = (end - start) + 1;
+        token = Jim_Alloc(len + 1);
+        if (pc->tt != JIM_TT_ESC) {
+            /* No escape conversion needed? Just copy it. */
+            memcpy(token, start, len);
+            token[len] = '\0';
+        }
+        else {
+            /* Else convert the escape chars. */
+            len = JimEscape(token, start, len);
+        }
+    }
+
+    return Jim_NewStringObjNoAlloc(interp, token, len);
+}
+
+/* Parses the given string to determine if it represents a complete script.
+ *
+ * This is useful for interactive shells implementation, for [info complete].
+ *
+ * If 'stateCharPtr' != NULL, the function stores ' ' on complete script,
+ * '{' on scripts incomplete missing one or more '}' to be balanced.
+ * '[' on scripts incomplete missing one or more ']' to be balanced.
+ * '"' on scripts incomplete missing a '"' char.
+ *
+ * If the script is complete, 1 is returned, otherwise 0.
+ */
+int Jim_ScriptIsComplete(const char *s, int len, char *stateCharPtr)
+{
+    struct JimParserCtx parser;
+
+    JimParserInit(&parser, s, len, 1);
+    while (!parser.eof) {
+        JimParseScript(&parser);
+    }
+    if (stateCharPtr) {
+        *stateCharPtr = parser.missing;
+    }
+    return parser.missing == ' ';
+}
+
+/* -----------------------------------------------------------------------------
+ * Tcl Lists parsing
+ * ---------------------------------------------------------------------------*/
+static int JimParseListSep(struct JimParserCtx *pc);
+static int JimParseListStr(struct JimParserCtx *pc);
+static int JimParseListQuote(struct JimParserCtx *pc);
+
+static int JimParseList(struct JimParserCtx *pc)
+{
+    switch (*pc->p) {
+        case ' ':
+        case '\n':
+        case '\t':
+        case '\r':
+            return JimParseListSep(pc);
+
+        case '"':
+            return JimParseListQuote(pc);
+
+        case '{':
+            return JimParseBrace(pc);
+
+        default:
+            if (pc->len) {
+                return JimParseListStr(pc);
+            }
+            break;
+    }
+
+    pc->tstart = pc->tend = pc->p;
+    pc->tline = pc->linenr;
+    pc->tt = JIM_TT_EOL;
+    pc->eof = 1;
+    return JIM_OK;
+}
+
+static int JimParseListSep(struct JimParserCtx *pc)
+{
+    pc->tstart = pc->p;
+    pc->tline = pc->linenr;
+    while (*pc->p == ' ' || *pc->p == '\t' || *pc->p == '\r' || *pc->p == '\n') {
+        if (*pc->p == '\n') {
+            pc->linenr++;
+        }
+        pc->p++;
+        pc->len--;
+    }
+    pc->tend = pc->p - 1;
+    pc->tt = JIM_TT_SEP;
+    return JIM_OK;
+}
+
+static int JimParseListQuote(struct JimParserCtx *pc)
+{
+    pc->p++;
+    pc->len--;
+
+    pc->tstart = pc->p;
+    pc->tline = pc->linenr;
+    pc->tt = JIM_TT_STR;
+
+    while (pc->len) {
+        switch (*pc->p) {
+            case '\\':
+                pc->tt = JIM_TT_ESC;
+                if (--pc->len == 0) {
+                    /* Trailing backslash */
+                    pc->tend = pc->p;
+                    return JIM_OK;
+                }
+                pc->p++;
+                break;
+            case '\n':
+                pc->linenr++;
+                break;
+            case '"':
+                pc->tend = pc->p - 1;
+                pc->p++;
+                pc->len--;
+                return JIM_OK;
+        }
+        pc->p++;
+        pc->len--;
+    }
+
+    pc->tend = pc->p - 1;
+    return JIM_OK;
+}
+
+static int JimParseListStr(struct JimParserCtx *pc)
+{
+    pc->tstart = pc->p;
+    pc->tline = pc->linenr;
+    pc->tt = JIM_TT_STR;
+
+    while (pc->len) {
+        switch (*pc->p) {
+            case '\\':
+                if (--pc->len == 0) {
+                    /* Trailing backslash */
+                    pc->tend = pc->p;
+                    return JIM_OK;
+                }
+                pc->tt = JIM_TT_ESC;
+                pc->p++;
+                break;
+            case ' ':
+            case '\t':
+            case '\n':
+            case '\r':
+                pc->tend = pc->p - 1;
+                return JIM_OK;
+        }
+        pc->p++;
+        pc->len--;
+    }
+    pc->tend = pc->p - 1;
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * Jim_Obj related functions
+ * ---------------------------------------------------------------------------*/
+
+/* Return a new initialized object. */
+Jim_Obj *Jim_NewObj(Jim_Interp *interp)
+{
+    Jim_Obj *objPtr;
+
+    /* -- Check if there are objects in the free list -- */
+    if (interp->freeList != NULL) {
+        /* -- Unlink the object from the free list -- */
+        objPtr = interp->freeList;
+        interp->freeList = objPtr->nextObjPtr;
+    }
+    else {
+        /* -- No ready to use objects: allocate a new one -- */
+        objPtr = Jim_Alloc(sizeof(*objPtr));
+    }
+
+    /* Object is returned with refCount of 0. Every
+     * kind of GC implemented should take care to don't try
+     * to scan objects with refCount == 0. */
+    objPtr->refCount = 0;
+    /* All the other fields are left not initialized to save time.
+     * The caller will probably want to set them to the right
+     * value anyway. */
+
+    /* -- Put the object into the live list -- */
+    objPtr->prevObjPtr = NULL;
+    objPtr->nextObjPtr = interp->liveList;
+    if (interp->liveList)
+        interp->liveList->prevObjPtr = objPtr;
+    interp->liveList = objPtr;
+
+    return objPtr;
+}
+
+/* Free an object. Actually objects are never freed, but
+ * just moved to the free objects list, where they will be
+ * reused by Jim_NewObj(). */
+void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    /* Check if the object was already freed, panic. */
+    JimPanic((objPtr->refCount != 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr,
+        objPtr->refCount, objPtr->typePtr ? objPtr->typePtr->name : "<none>"));
+
+    /* Free the internal representation */
+    Jim_FreeIntRep(interp, objPtr);
+    /* Free the string representation */
+    if (objPtr->bytes != NULL) {
+        if (objPtr->bytes != JimEmptyStringRep)
+            Jim_Free(objPtr->bytes);
+    }
+    /* Unlink the object from the live objects list */
+    if (objPtr->prevObjPtr)
+        objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr;
+    if (objPtr->nextObjPtr)
+        objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr;
+    if (interp->liveList == objPtr)
+        interp->liveList = objPtr->nextObjPtr;
+    /* Link the object into the free objects list */
+    objPtr->prevObjPtr = NULL;
+    objPtr->nextObjPtr = interp->freeList;
+    if (interp->freeList)
+        interp->freeList->prevObjPtr = objPtr;
+    interp->freeList = objPtr;
+    objPtr->refCount = -1;
+}
+
+/* Invalidate the string representation of an object. */
+void Jim_InvalidateStringRep(Jim_Obj *objPtr)
+{
+    if (objPtr->bytes != NULL) {
+        if (objPtr->bytes != JimEmptyStringRep)
+            Jim_Free(objPtr->bytes);
+    }
+    objPtr->bytes = NULL;
+}
+
+#define Jim_SetStringRep(o, b, l) \
+    do { (o)->bytes = b; (o)->length = l; } while (0)
+
+/* Set the initial string representation for an object.
+ * Does not try to free an old one. */
+void Jim_InitStringRep(Jim_Obj *objPtr, const char *bytes, int length)
+{
+    if (length == 0) {
+        objPtr->bytes = JimEmptyStringRep;
+        objPtr->length = 0;
+    }
+    else {
+        objPtr->bytes = Jim_Alloc(length + 1);
+        objPtr->length = length;
+        memcpy(objPtr->bytes, bytes, length);
+        objPtr->bytes[length] = '\0';
+    }
+}
+
+/* Duplicate an object. The returned object has refcount = 0. */
+Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    Jim_Obj *dupPtr;
+
+    dupPtr = Jim_NewObj(interp);
+    if (objPtr->bytes == NULL) {
+        /* Object does not have a valid string representation. */
+        dupPtr->bytes = NULL;
+    }
+    else {
+        Jim_InitStringRep(dupPtr, objPtr->bytes, objPtr->length);
+    }
+
+    /* By default, the new object has the same type as the old object */
+    dupPtr->typePtr = objPtr->typePtr;
+    if (objPtr->typePtr != NULL) {
+        if (objPtr->typePtr->dupIntRepProc == NULL) {
+            dupPtr->internalRep = objPtr->internalRep;
+        }
+        else {
+            /* The dup proc may set a different type, e.g. NULL */
+            objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr);
+        }
+    }
+    return dupPtr;
+}
+
+/* Return the string representation for objPtr. If the object
+ * string representation is invalid, calls the method to create
+ * a new one starting from the internal representation of the object. */
+const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr)
+{
+    if (objPtr->bytes == NULL) {
+        /* Invalid string repr. Generate it. */
+        JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
+        objPtr->typePtr->updateStringProc(objPtr);
+    }
+    if (lenPtr)
+        *lenPtr = objPtr->length;
+    return objPtr->bytes;
+}
+
+/* Just returns the length of the object's string rep */
+int Jim_Length(Jim_Obj *objPtr)
+{
+    int len;
+
+    Jim_GetString(objPtr, &len);
+    return len;
+}
+
+static void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+
+static const Jim_ObjType dictSubstObjType = {
+    "dict-substitution",
+    FreeDictSubstInternalRep,
+    DupDictSubstInternalRep,
+    NULL,
+    JIM_TYPE_NONE,
+};
+
+static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    Jim_DecrRefCount(interp, (Jim_Obj *)objPtr->internalRep.twoPtrValue.ptr2);
+}
+
+static const Jim_ObjType interpolatedObjType = {
+    "interpolated",
+    FreeInterpolatedInternalRep,
+    NULL,
+    NULL,
+    JIM_TYPE_NONE,
+};
+
+/* -----------------------------------------------------------------------------
+ * String Object
+ * ---------------------------------------------------------------------------*/
+static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType stringObjType = {
+    "string",
+    NULL,
+    DupStringInternalRep,
+    NULL,
+    JIM_TYPE_REFERENCES,
+};
+
+static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+    JIM_NOTUSED(interp);
+
+    /* This is a bit subtle: the only caller of this function
+     * should be Jim_DuplicateObj(), that will copy the
+     * string representaion. After the copy, the duplicated
+     * object will not have more room in teh buffer than
+     * srcPtr->length bytes. So we just set it to length. */
+    dupPtr->internalRep.strValue.maxLength = srcPtr->length;
+
+    dupPtr->internalRep.strValue.charLength = srcPtr->internalRep.strValue.charLength;
+}
+
+static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    /* Get a fresh string representation. */
+    (void)Jim_String(objPtr);
+    /* Free any other internal representation. */
+    Jim_FreeIntRep(interp, objPtr);
+    /* Set it as string, i.e. just set the maxLength field. */
+    objPtr->typePtr = &stringObjType;
+    objPtr->internalRep.strValue.maxLength = objPtr->length;
+    /* Don't know the utf-8 length yet */
+    objPtr->internalRep.strValue.charLength = -1;
+    return JIM_OK;
+}
+
+/**
+ * Returns the length of the object string in chars, not bytes.
+ *
+ * These may be different for a utf-8 string.
+ */
+int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+#ifdef JIM_UTF8
+    if (objPtr->typePtr != &stringObjType)
+        SetStringFromAny(interp, objPtr);
+
+    if (objPtr->internalRep.strValue.charLength < 0) {
+        objPtr->internalRep.strValue.charLength = utf8_strlen(objPtr->bytes, objPtr->length);
+    }
+    return objPtr->internalRep.strValue.charLength;
+#else
+    return Jim_Length(objPtr);
+#endif
+}
+
+/* len is in bytes -- see also Jim_NewStringObjUtf8() */
+Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len)
+{
+    Jim_Obj *objPtr = Jim_NewObj(interp);
+
+    /* Need to find out how many bytes the string requires */
+    if (len == -1)
+        len = strlen(s);
+    /* Alloc/Set the string rep. */
+    if (len == 0) {
+        objPtr->bytes = JimEmptyStringRep;
+        objPtr->length = 0;
+    }
+    else {
+        objPtr->bytes = Jim_Alloc(len + 1);
+        objPtr->length = len;
+        memcpy(objPtr->bytes, s, len);
+        objPtr->bytes[len] = '\0';
+    }
+
+    /* No typePtr field for the vanilla string object. */
+    objPtr->typePtr = NULL;
+    return objPtr;
+}
+
+/* charlen is in characters -- see also Jim_NewStringObj() */
+Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, const char *s, int charlen)
+{
+#ifdef JIM_UTF8
+    /* Need to find out how many bytes the string requires */
+    int bytelen = utf8_index(s, charlen);
+
+    Jim_Obj *objPtr = Jim_NewStringObj(interp, s, bytelen);
+
+    /* Remember the utf8 length, so set the type */
+    objPtr->typePtr = &stringObjType;
+    objPtr->internalRep.strValue.maxLength = bytelen;
+    objPtr->internalRep.strValue.charLength = charlen;
+
+    return objPtr;
+#else
+    return Jim_NewStringObj(interp, s, charlen);
+#endif
+}
+
+/* This version does not try to duplicate the 's' pointer, but
+ * use it directly. */
+Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len)
+{
+    Jim_Obj *objPtr = Jim_NewObj(interp);
+
+    if (len == -1)
+        len = strlen(s);
+    Jim_SetStringRep(objPtr, s, len);
+    objPtr->typePtr = NULL;
+    return objPtr;
+}
+
+/* Low-level string append. Use it only against objects
+ * of type "string". */
+static void StringAppendString(Jim_Obj *objPtr, const char *str, int len)
+{
+    int needlen;
+
+    if (len == -1)
+        len = strlen(str);
+    needlen = objPtr->length + len;
+    if (objPtr->internalRep.strValue.maxLength < needlen ||
+        objPtr->internalRep.strValue.maxLength == 0) {
+        needlen *= 2;
+        /* Inefficient to malloc() for less than 8 bytes */
+        if (needlen < 7) {
+            needlen = 7;
+        }
+        if (objPtr->bytes == JimEmptyStringRep) {
+            objPtr->bytes = Jim_Alloc(needlen + 1);
+        }
+        else {
+            objPtr->bytes = Jim_Realloc(objPtr->bytes, needlen + 1);
+        }
+        objPtr->internalRep.strValue.maxLength = needlen;
+    }
+    memcpy(objPtr->bytes + objPtr->length, str, len);
+    objPtr->bytes[objPtr->length + len] = '\0';
+    if (objPtr->internalRep.strValue.charLength >= 0) {
+        /* Update the utf-8 char length */
+        objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len);
+    }
+    objPtr->length += len;
+}
+
+/* Higher level API to append strings to objects. */
+void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str, int len)
+{
+    JimPanic((Jim_IsShared(objPtr), "Jim_AppendString called with shared object"));
+    if (objPtr->typePtr != &stringObjType)
+        SetStringFromAny(interp, objPtr);
+    StringAppendString(objPtr, str, len);
+}
+
+void Jim_AppendObj(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *appendObjPtr)
+{
+    int len;
+    const char *str;
+
+    str = Jim_GetString(appendObjPtr, &len);
+    Jim_AppendString(interp, objPtr, str, len);
+}
+
+void Jim_AppendStrings(Jim_Interp *interp, Jim_Obj *objPtr, ...)
+{
+    va_list ap;
+
+    if (objPtr->typePtr != &stringObjType)
+        SetStringFromAny(interp, objPtr);
+    va_start(ap, objPtr);
+    while (1) {
+        char *s = va_arg(ap, char *);
+
+        if (s == NULL)
+            break;
+        Jim_AppendString(interp, objPtr, s, -1);
+    }
+    va_end(ap);
+}
+
+int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr)
+{
+    const char *aStr, *bStr;
+    int aLen, bLen;
+
+    if (aObjPtr == bObjPtr)
+        return 1;
+    aStr = Jim_GetString(aObjPtr, &aLen);
+    bStr = Jim_GetString(bObjPtr, &bLen);
+    if (aLen != bLen)
+        return 0;
+    return JimStringCompare(aStr, aLen, bStr, bLen) == 0;
+}
+
+int Jim_StringMatchObj(Jim_Interp *interp, Jim_Obj *patternObjPtr, Jim_Obj *objPtr, int nocase)
+{
+    return JimStringMatch(interp, patternObjPtr, Jim_String(objPtr), nocase);
+}
+
+int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase)
+{
+    const char *s1, *s2;
+    int l1, l2;
+
+    s1 = Jim_GetString(firstObjPtr, &l1);
+    s2 = Jim_GetString(secondObjPtr, &l2);
+
+    if (nocase) {
+        return JimStringCompareNoCase(s1, s2, -1);
+    }
+    return JimStringCompare(s1, l1, s2, l2);
+}
+
+/* Convert a range, as returned by Jim_GetRange(), into
+ * an absolute index into an object of the specified length.
+ * This function may return negative values, or values
+ * bigger or equal to the length of the list if the index
+ * is out of range. */
+static int JimRelToAbsIndex(int len, int idx)
+{
+    if (idx < 0)
+        return len + idx;
+    return idx;
+}
+
+/* Convert a pair of index as normalize by JimRelToAbsIndex(),
+ * into a range stored in *firstPtr, *lastPtr, *rangeLenPtr, suitable
+ * for implementation of commands like [string range] and [lrange].
+ *
+ * The resulting range is guaranteed to address valid elements of
+ * the structure. */
+static void JimRelToAbsRange(int len, int first, int last,
+    int *firstPtr, int *lastPtr, int *rangeLenPtr)
+{
+    int rangeLen;
+
+    if (first > last) {
+        rangeLen = 0;
+    }
+    else {
+        rangeLen = last - first + 1;
+        if (rangeLen) {
+            if (first < 0) {
+                rangeLen += first;
+                first = 0;
+            }
+            if (last >= len) {
+                rangeLen -= (last - (len - 1));
+                last = len - 1;
+            }
+        }
+    }
+    if (rangeLen < 0)
+        rangeLen = 0;
+
+    *firstPtr = first;
+    *lastPtr = last;
+    *rangeLenPtr = rangeLen;
+}
+
+Jim_Obj *Jim_StringByteRangeObj(Jim_Interp *interp,
+    Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
+{
+    int first, last;
+    const char *str;
+    int rangeLen;
+    int bytelen;
+
+    if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
+        Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
+        return NULL;
+    str = Jim_GetString(strObjPtr, &bytelen);
+    first = JimRelToAbsIndex(bytelen, first);
+    last = JimRelToAbsIndex(bytelen, last);
+    JimRelToAbsRange(bytelen, first, last, &first, &last, &rangeLen);
+    if (first == 0 && rangeLen == bytelen) {
+        return strObjPtr;
+    }
+    return Jim_NewStringObj(interp, str + first, rangeLen);
+}
+
+Jim_Obj *Jim_StringRangeObj(Jim_Interp *interp,
+    Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
+{
+#ifdef JIM_UTF8
+    int first, last;
+    const char *str;
+    int len, rangeLen;
+    int bytelen;
+
+    if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
+        Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
+        return NULL;
+    str = Jim_GetString(strObjPtr, &bytelen);
+    len = Jim_Utf8Length(interp, strObjPtr);
+    first = JimRelToAbsIndex(len, first);
+    last = JimRelToAbsIndex(len, last);
+    JimRelToAbsRange(len, first, last, &first, &last, &rangeLen);
+    if (first == 0 && rangeLen == len) {
+        return strObjPtr;
+    }
+    if (len == bytelen) {
+        /* ASCII optimisation */
+        return Jim_NewStringObj(interp, str + first, rangeLen);
+    }
+    return Jim_NewStringObjUtf8(interp, str + utf8_index(str, first), rangeLen);
+#else
+    return Jim_StringByteRangeObj(interp, strObjPtr, firstObjPtr, lastObjPtr);
+#endif
+}
+
+static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr)
+{
+    char *buf, *p;
+    int len;
+    const char *str;
+
+    if (strObjPtr->typePtr != &stringObjType) {
+        SetStringFromAny(interp, strObjPtr);
+    }
+
+    str = Jim_GetString(strObjPtr, &len);
+
+    buf = p = Jim_Alloc(len + 1);
+    while (*str) {
+        int c;
+        str += utf8_tounicode(str, &c);
+        p += utf8_fromunicode(p, utf8_lower(c));
+    }
+    *p = 0;
+    return Jim_NewStringObjNoAlloc(interp, buf, len);
+}
+
+static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr)
+{
+    char *buf, *p;
+    int len;
+    const char *str;
+
+    if (strObjPtr->typePtr != &stringObjType) {
+        SetStringFromAny(interp, strObjPtr);
+    }
+
+    str = Jim_GetString(strObjPtr, &len);
+
+    buf = p = Jim_Alloc(len + 1);
+    while (*str) {
+        int c;
+        str += utf8_tounicode(str, &c);
+        p += utf8_fromunicode(p, utf8_upper(c));
+    }
+    *p = 0;
+    return Jim_NewStringObjNoAlloc(interp, buf, len);
+}
+
+/* Similar to memchr() except searches a UTF-8 string 'str' of byte length 'len'
+ * for unicode character 'c'.
+ * Returns the position if found or NULL if not
+ */
+static const char *utf8_memchr(const char *str, int len, int c)
+{
+#ifdef JIM_UTF8
+    while (len) {
+        int sc;
+        int n = utf8_tounicode(str, &sc);
+        if (sc == c) {
+            return str;
+        }
+        str += n;
+        len -= n;
+    }
+    return NULL;
+#else
+    return memchr(str, c, len);
+#endif
+}
+
+/**
+ * Searches for the first non-trim char in string (str, len)
+ *
+ * If none is found, returns just past the last char.
+ *
+ * Lengths are in bytes.
+ */
+static const char *JimFindTrimLeft(const char *str, int len, const char *trimchars, int trimlen)
+{
+    while (len) {
+        int c;
+        int n = utf8_tounicode(str, &c);
+
+        if (utf8_memchr(trimchars, trimlen, c) == NULL) {
+            /* Not a trim char, so stop */
+            break;
+        }
+        str += n;
+        len -= n;
+    }
+    return str;
+}
+
+/**
+ * Searches backwards for a non-trim char in string (str, len).
+ *
+ * Returns a pointer to just after the non-trim char, or NULL if not found.
+ *
+ * Lengths are in bytes.
+ */
+static const char *JimFindTrimRight(const char *str, int len, const char *trimchars, int trimlen)
+{
+    str += len;
+
+    while (len) {
+        int c;
+        int n = utf8_prev_len(str, len);
+
+        len -= n;
+        str -= n;
+
+        n = utf8_tounicode(str, &c);
+
+        if (utf8_memchr(trimchars, trimlen, c) == NULL) {
+            return str + n;
+        }
+    }
+
+    return NULL;
+}
+
+static const char default_trim_chars[] = " \t\n\r";
+/* sizeof() here includes the null byte */
+static int default_trim_chars_len = sizeof(default_trim_chars);
+
+static Jim_Obj *JimStringTrimLeft(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
+{
+    int len;
+    const char *str = Jim_GetString(strObjPtr, &len);
+    const char *trimchars = default_trim_chars;
+    int trimcharslen = default_trim_chars_len;
+    const char *newstr;
+
+    if (trimcharsObjPtr) {
+        trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen);
+    }
+
+    newstr = JimFindTrimLeft(str, len, trimchars, trimcharslen);
+    if (newstr == str) {
+        return strObjPtr;
+    }
+
+    return Jim_NewStringObj(interp, newstr, len - (newstr - str));
+}
+
+static Jim_Obj *JimStringTrimRight(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
+{
+    int len;
+    const char *trimchars = default_trim_chars;
+    int trimcharslen = default_trim_chars_len;
+    const char *nontrim;
+
+    if (trimcharsObjPtr) {
+        trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen);
+    }
+
+    if (strObjPtr->typePtr != &stringObjType) {
+        SetStringFromAny(interp, strObjPtr);
+    }
+    len = Jim_Length(strObjPtr);
+    nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen);
+
+    if (nontrim == NULL) {
+        /* All trim, so return a zero-length string */
+        return Jim_NewEmptyStringObj(interp);
+    }
+    if (nontrim == strObjPtr->bytes + len) {
+        return strObjPtr;
+    }
+
+    if (Jim_IsShared(strObjPtr)) {
+        strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes));
+    }
+    else {
+        /* Can modify this string in place */
+        strObjPtr->bytes[nontrim - strObjPtr->bytes] = 0;
+        strObjPtr->length = (nontrim - strObjPtr->bytes);
+    }
+
+    return strObjPtr;
+}
+
+static Jim_Obj *JimStringTrim(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
+{
+    /* First trim left. */
+    Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr);
+
+    /* Now trim right */
+    strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr);
+
+    if (objPtr != strObjPtr) {
+        /* Note that we don't want this object to be leaked */
+        Jim_IncrRefCount(objPtr);
+        Jim_DecrRefCount(interp, objPtr);
+    }
+
+    return strObjPtr;
+}
+
+
+static int JimStringIs(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *strClass, int strict)
+{
+    static const char * const strclassnames[] = {
+        "integer", "alpha", "alnum", "ascii", "digit",
+        "double", "lower", "upper", "space", "xdigit",
+        "control", "print", "graph", "punct",
+        NULL
+    };
+    enum {
+        STR_IS_INTEGER, STR_IS_ALPHA, STR_IS_ALNUM, STR_IS_ASCII, STR_IS_DIGIT,
+        STR_IS_DOUBLE, STR_IS_LOWER, STR_IS_UPPER, STR_IS_SPACE, STR_IS_XDIGIT,
+        STR_IS_CONTROL, STR_IS_PRINT, STR_IS_GRAPH, STR_IS_PUNCT
+    };
+    int strclass;
+    int len;
+    int i;
+    const char *str;
+    int (*isclassfunc)(int c) = NULL;
+
+    if (Jim_GetEnum(interp, strClass, strclassnames, &strclass, "class", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    str = Jim_GetString(strObjPtr, &len);
+    if (len == 0) {
+        Jim_SetResultInt(interp, !strict);
+        return JIM_OK;
+    }
+
+    switch (strclass) {
+        case STR_IS_INTEGER:
+            {
+                jim_wide w;
+                Jim_SetResultInt(interp, JimGetWideNoErr(interp, strObjPtr, &w) == JIM_OK);
+                return JIM_OK;
+            }
+
+        case STR_IS_DOUBLE:
+            {
+                double d;
+                Jim_SetResultInt(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE);
+                return JIM_OK;
+            }
+
+        case STR_IS_ALPHA: isclassfunc = isalpha; break;
+        case STR_IS_ALNUM: isclassfunc = isalnum; break;
+        case STR_IS_ASCII: isclassfunc = isascii; break;
+        case STR_IS_DIGIT: isclassfunc = isdigit; break;
+        case STR_IS_LOWER: isclassfunc = islower; break;
+        case STR_IS_UPPER: isclassfunc = isupper; break;
+        case STR_IS_SPACE: isclassfunc = isspace; break;
+        case STR_IS_XDIGIT: isclassfunc = isxdigit; break;
+        case STR_IS_CONTROL: isclassfunc = iscntrl; break;
+        case STR_IS_PRINT: isclassfunc = isprint; break;
+        case STR_IS_GRAPH: isclassfunc = isgraph; break;
+        case STR_IS_PUNCT: isclassfunc = ispunct; break;
+        default:
+            return JIM_ERR;
+    }
+
+    for (i = 0; i < len; i++) {
+        if (!isclassfunc(str[i])) {
+            Jim_SetResultInt(interp, 0);
+            return JIM_OK;
+        }
+    }
+    Jim_SetResultInt(interp, 1);
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * Compared String Object
+ * ---------------------------------------------------------------------------*/
+
+/* This is strange object that allows to compare a C literal string
+ * with a Jim object in very short time if the same comparison is done
+ * multiple times. For example every time the [if] command is executed,
+ * Jim has to check if a given argument is "else". This comparions if
+ * the code has no errors are true most of the times, so we can cache
+ * inside the object the pointer of the string of the last matching
+ * comparison. Because most C compilers perform literal sharing,
+ * so that: char *x = "foo", char *y = "foo", will lead to x == y,
+ * this works pretty well even if comparisons are at different places
+ * inside the C code. */
+
+static const Jim_ObjType comparedStringObjType = {
+    "compared-string",
+    NULL,
+    NULL,
+    NULL,
+    JIM_TYPE_REFERENCES,
+};
+
+/* The only way this object is exposed to the API is via the following
+ * function. Returns true if the string and the object string repr.
+ * are the same, otherwise zero is returned.
+ *
+ * Note: this isn't binary safe, but it hardly needs to be.*/
+int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str)
+{
+    if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str)
+        return 1;
+    else {
+        const char *objStr = Jim_String(objPtr);
+
+        if (strcmp(str, objStr) != 0)
+            return 0;
+        if (objPtr->typePtr != &comparedStringObjType) {
+            Jim_FreeIntRep(interp, objPtr);
+            objPtr->typePtr = &comparedStringObjType;
+        }
+        objPtr->internalRep.ptr = (char *)str;  /*ATTENTION: const cast */
+        return 1;
+    }
+}
+
+static int qsortCompareStringPointers(const void *a, const void *b)
+{
+    char *const *sa = (char *const *)a;
+    char *const *sb = (char *const *)b;
+
+    return strcmp(*sa, *sb);
+}
+
+
+/* -----------------------------------------------------------------------------
+ * Source Object
+ *
+ * This object is just a string from the language point of view, but
+ * in the internal representation it contains the filename and line number
+ * where this given token was read. This information is used by
+ * Jim_EvalObj() if the object passed happens to be of type "source".
+ *
+ * This allows to propagate the information about line numbers and file
+ * names and give error messages with absolute line numbers.
+ *
+ * Note that this object uses shared strings for filenames, and the
+ * pointer to the filename together with the line number is taken into
+ * the space for the "inline" internal representation of the Jim_Object,
+ * so there is almost memory zero-overhead.
+ *
+ * Also the object will be converted to something else if the given
+ * token it represents in the source file is not something to be
+ * evaluated (not a script), and will be specialized in some other way,
+ * so the time overhead is also null.
+ * ---------------------------------------------------------------------------*/
+
+static void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+
+static const Jim_ObjType sourceObjType = {
+    "source",
+    FreeSourceInternalRep,
+    DupSourceInternalRep,
+    NULL,
+    JIM_TYPE_REFERENCES,
+};
+
+void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    Jim_DecrRefCount(interp, objPtr->internalRep.sourceValue.fileNameObj);
+}
+
+void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+    dupPtr->internalRep = srcPtr->internalRep;
+    Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj);
+}
+
+static void JimSetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
+    Jim_Obj *fileNameObj, int lineNumber)
+{
+    JimPanic((Jim_IsShared(objPtr), "JimSetSourceInfo called with shared object"));
+    JimPanic((objPtr->typePtr != NULL, "JimSetSourceInfo called with typePtr != NULL"));
+    Jim_IncrRefCount(fileNameObj);
+    objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
+    objPtr->internalRep.sourceValue.lineNumber = lineNumber;
+    objPtr->typePtr = &sourceObjType;
+}
+
+/* -----------------------------------------------------------------------------
+ * Script Object
+ * ---------------------------------------------------------------------------*/
+
+static const Jim_ObjType scriptLineObjType = {
+    "scriptline",
+    NULL,
+    NULL,
+    NULL,
+    0,
+};
+
+static Jim_Obj *JimNewScriptLineObj(Jim_Interp *interp, int argc, int line)
+{
+    Jim_Obj *objPtr;
+
+#ifdef DEBUG_SHOW_SCRIPT
+    char buf[100];
+    snprintf(buf, sizeof(buf), "line=%d, argc=%d", line, argc);
+    objPtr = Jim_NewStringObj(interp, buf, -1);
+#else
+    objPtr = Jim_NewEmptyStringObj(interp);
+#endif
+    objPtr->typePtr = &scriptLineObjType;
+    objPtr->internalRep.scriptLineValue.argc = argc;
+    objPtr->internalRep.scriptLineValue.line = line;
+
+    return objPtr;
+}
+
+#define JIM_CMDSTRUCT_EXPAND -1
+
+static void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, struct JimParseResult *result);
+
+static const Jim_ObjType scriptObjType = {
+    "script",
+    FreeScriptInternalRep,
+    DupScriptInternalRep,
+    NULL,
+    JIM_TYPE_REFERENCES,
+};
+
+/* The ScriptToken structure represents every token into a scriptObj.
+ * Every token contains an associated Jim_Obj that can be specialized
+ * by commands operating on it. */
+typedef struct ScriptToken
+{
+    int type;
+    Jim_Obj *objPtr;
+} ScriptToken;
+
+/* This is the script object internal representation. An array of
+ * ScriptToken structures, including a pre-computed representation of the
+ * command length and arguments.
+ *
+ * For example the script:
+ *
+ * puts hello
+ * set $i $x$y [foo]BAR
+ *
+ * will produce a ScriptObj with the following Tokens:
+ *
+ * LIN 2
+ * ESC puts
+ * ESC hello
+ * LIN 4
+ * ESC set
+ * VAR i
+ * WRD 2
+ * VAR x
+ * VAR y
+ * WRD 2
+ * CMD foo
+ * ESC BAR
+ *
+ * "puts hello" has two args (LIN 2), composed of single tokens.
+ * (Note that the WRD token is omitted for the common case of a single token.)
+ *
+ * "set $i $x$y [foo]BAR" has four (LIN 4) args, the first word
+ * has 1 token (ESC SET), and the last has two tokens (WRD 2 CMD foo ESC BAR)
+ *
+ * The precomputation of the command structure makes Jim_Eval() faster,
+ * and simpler because there aren't dynamic lengths / allocations.
+ *
+ * -- {expand}/{*} handling --
+ *
+ * Expand is handled in a special way.
+ *
+ *   If a "word" begins with {*}, the word token count is -ve.
+ *
+ * For example the command:
+ *
+ * list {*}{a b}
+ *
+ * Will produce the following cmdstruct array:
+ *
+ * LIN 2
+ * ESC list
+ * WRD -1
+ * STR a b
+ *
+ * Note that the 'LIN' token also contains the source information for the
+ * first word of the line for error reporting purposes
+ *
+ * -- the substFlags field of the structure --
+ *
+ * The scriptObj structure is used to represent both "script" objects
+ * and "subst" objects. In the second case, the there are no LIN and WRD
+ * tokens. Instead SEP and EOL tokens are added as-is.
+ * In addition, the field 'substFlags' is used to represent the flags used to turn
+ * the string into the internal representation used to perform the
+ * substitution. If this flags are not what the application requires
+ * the scriptObj is created again. For example the script:
+ *
+ * subst -nocommands $string
+ * subst -novariables $string
+ *
+ * Will recreate the internal representation of the $string object
+ * two times.
+ */
+typedef struct ScriptObj
+{
+    int len;                    /* Length as number of tokens. */
+    ScriptToken *token;         /* Tokens array. */
+    int substFlags;             /* flags used for the compilation of "subst" objects */
+    int inUse;                  /* Used to share a ScriptObj. Currently
+                                   only used by Jim_EvalObj() as protection against
+                                   shimmering of the currently evaluated object. */
+    Jim_Obj *fileNameObj;
+    int line;                   /* Line number of the first line */
+} ScriptObj;
+
+void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    int i;
+    struct ScriptObj *script = (void *)objPtr->internalRep.ptr;
+
+    script->inUse--;
+    if (script->inUse != 0)
+        return;
+    for (i = 0; i < script->len; i++) {
+        Jim_DecrRefCount(interp, script->token[i].objPtr);
+    }
+    Jim_Free(script->token);
+    Jim_DecrRefCount(interp, script->fileNameObj);
+    Jim_Free(script);
+}
+
+void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+    JIM_NOTUSED(interp);
+    JIM_NOTUSED(srcPtr);
+
+    /* Just returns an simple string. */
+    dupPtr->typePtr = NULL;
+}
+
+/* A simple parser token.
+ * All the simple tokens for the script point into the same script string rep.
+ */
+typedef struct
+{
+    const char *token;          /* Pointer to the start of the token */
+    int len;                    /* Length of this token */
+    int type;                   /* Token type */
+    int line;                   /* Line number */
+} ParseToken;
+
+/* A list of parsed tokens representing a script.
+ * Tokens are added to this list as the script is parsed.
+ * It grows as needed.
+ */
+typedef struct
+{
+    /* Start with a statically allocated list of tokens which will be expanded with realloc if needed */
+    ParseToken *list;           /* Array of tokens */
+    int size;                   /* Current size of the list */
+    int count;                  /* Number of entries used */
+    ParseToken static_list[20]; /* Small initial token space to avoid allocation */
+} ParseTokenList;
+
+static void ScriptTokenListInit(ParseTokenList *tokenlist)
+{
+    tokenlist->list = tokenlist->static_list;
+    tokenlist->size = sizeof(tokenlist->static_list) / sizeof(ParseToken);
+    tokenlist->count = 0;
+}
+
+static void ScriptTokenListFree(ParseTokenList *tokenlist)
+{
+    if (tokenlist->list != tokenlist->static_list) {
+        Jim_Free(tokenlist->list);
+    }
+}
+
+/**
+ * Adds the new token to the tokenlist.
+ * The token has the given length, type and line number.
+ * The token list is resized as necessary.
+ */
+static void ScriptAddToken(ParseTokenList *tokenlist, const char *token, int len, int type,
+    int line)
+{
+    ParseToken *t;
+
+    if (tokenlist->count == tokenlist->size) {
+        /* Resize the list */
+        tokenlist->size *= 2;
+        if (tokenlist->list != tokenlist->static_list) {
+            tokenlist->list =
+                Jim_Realloc(tokenlist->list, tokenlist->size * sizeof(*tokenlist->list));
+        }
+        else {
+            /* The list needs to become allocated */
+            tokenlist->list = Jim_Alloc(tokenlist->size * sizeof(*tokenlist->list));
+            memcpy(tokenlist->list, tokenlist->static_list,
+                tokenlist->count * sizeof(*tokenlist->list));
+        }
+    }
+    t = &tokenlist->list[tokenlist->count++];
+    t->token = token;
+    t->len = len;
+    t->type = type;
+    t->line = line;
+}
+
+/* Counts the number of adjoining non-separator.
+ *
+ * Returns -ve if the first token is the expansion
+ * operator (in which case the count doesn't include
+ * that token).
+ */
+static int JimCountWordTokens(ParseToken *t)
+{
+    int expand = 1;
+    int count = 0;
+
+    /* Is the first word {*} or {expand}? */
+    if (t->type == JIM_TT_STR && !TOKEN_IS_SEP(t[1].type)) {
+        if ((t->len == 1 && *t->token == '*') || (t->len == 6 && strncmp(t->token, "expand", 6) == 0)) {
+            /* Create an expand token */
+            expand = -1;
+            t++;
+        }
+    }
+
+    /* Now count non-separator words */
+    while (!TOKEN_IS_SEP(t->type)) {
+        t++;
+        count++;
+    }
+
+    return count * expand;
+}
+
+/**
+ * Create a script/subst object from the given token.
+ */
+static Jim_Obj *JimMakeScriptObj(Jim_Interp *interp, const ParseToken *t)
+{
+    Jim_Obj *objPtr;
+
+    if (t->type == JIM_TT_ESC && memchr(t->token, '\\', t->len) != NULL) {
+        /* Convert the backlash escapes . */
+        int len = t->len;
+        char *str = Jim_Alloc(len + 1);
+        len = JimEscape(str, t->token, len);
+        objPtr = Jim_NewStringObjNoAlloc(interp, str, len);
+    }
+    else {
+        /* REVIST: Strictly, JIM_TT_STR should replace <backslash><newline><whitespace>
+         *         with a single space. This is currently not done.
+         */
+        objPtr = Jim_NewStringObj(interp, t->token, t->len);
+    }
+    return objPtr;
+}
+
+/**
+ * Takes a tokenlist and creates the allocated list of script tokens
+ * in script->token, of length script->len.
+ *
+ * Unnecessary tokens are discarded, and LINE and WORD tokens are inserted
+ * as required.
+ *
+ * Also sets script->line to the line number of the first token
+ */
+static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
+    ParseTokenList *tokenlist)
+{
+    int i;
+    struct ScriptToken *token;
+    /* Number of tokens so far for the current command */
+    int lineargs = 0;
+    /* This is the first token for the current command */
+    ScriptToken *linefirst;
+    int count;
+    int linenr;
+
+#ifdef DEBUG_SHOW_SCRIPT_TOKENS
+    printf("==== Tokens ====\n");
+    for (i = 0; i < tokenlist->count; i++) {
+        printf("[%2d]@%d %s '%.*s'\n", i, tokenlist->list[i].line, jim_tt_name(tokenlist->list[i].type),
+            tokenlist->list[i].len, tokenlist->list[i].token);
+    }
+#endif
+
+    /* May need up to one extra script token for each EOL in the worst case */
+    count = tokenlist->count;
+    for (i = 0; i < tokenlist->count; i++) {
+        if (tokenlist->list[i].type == JIM_TT_EOL) {
+            count++;
+        }
+    }
+    linenr = script->line = tokenlist->list[0].line;
+
+    token = script->token = Jim_Alloc(sizeof(ScriptToken) * count);
+
+    /* This is the first token for the current command */
+    linefirst = token++;
+
+    for (i = 0; i < tokenlist->count; ) {
+        /* Look ahead to find out how many tokens make up the next word */
+        int wordtokens;
+
+        /* Skip any leading separators */
+        while (tokenlist->list[i].type == JIM_TT_SEP) {
+            i++;
+        }
+
+        wordtokens = JimCountWordTokens(tokenlist->list + i);
+
+        if (wordtokens == 0) {
+            /* None, so at end of line */
+            if (lineargs) {
+                linefirst->type = JIM_TT_LINE;
+                linefirst->objPtr = JimNewScriptLineObj(interp, lineargs, linenr);
+                Jim_IncrRefCount(linefirst->objPtr);
+
+                /* Reset for new line */
+                lineargs = 0;
+                linefirst = token++;
+            }
+            i++;
+            continue;
+        }
+        else if (wordtokens != 1) {
+            /* More than 1, or {expand}, so insert a WORD token */
+            token->type = JIM_TT_WORD;
+            token->objPtr = Jim_NewIntObj(interp, wordtokens);
+            Jim_IncrRefCount(token->objPtr);
+            token++;
+            if (wordtokens < 0) {
+                /* Skip the expand token */
+                i++;
+                wordtokens = -wordtokens - 1;
+                lineargs--;
+            }
+        }
+
+        if (lineargs == 0) {
+            /* First real token on the line, so record the line number */
+            linenr = tokenlist->list[i].line;
+        }
+        lineargs++;
+
+        /* Add each non-separator word token to the line */
+        while (wordtokens--) {
+            const ParseToken *t = &tokenlist->list[i++];
+
+            token->type = t->type;
+            token->objPtr = JimMakeScriptObj(interp, t);
+            Jim_IncrRefCount(token->objPtr);
+
+            /* Every object is initially a string, but the
+             * internal type may be specialized during execution of the
+             * script. */
+            JimSetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line);
+            token++;
+        }
+    }
+
+    if (lineargs == 0) {
+        token--;
+    }
+
+    script->len = token - script->token;
+
+    assert(script->len < count);
+
+#ifdef DEBUG_SHOW_SCRIPT
+    printf("==== Script (%s) ====\n", Jim_String(script->fileNameObj));
+    for (i = 0; i < script->len; i++) {
+        const ScriptToken *t = &script->token[i];
+        printf("[%2d] %s %s\n", i, jim_tt_name(t->type), Jim_String(t->objPtr));
+    }
+#endif
+
+}
+
+/**
+ * Similar to ScriptObjAddTokens(), but for subst objects.
+ */
+static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
+    ParseTokenList *tokenlist)
+{
+    int i;
+    struct ScriptToken *token;
+
+    token = script->token = Jim_Alloc(sizeof(ScriptToken) * tokenlist->count);
+
+    for (i = 0; i < tokenlist->count; i++) {
+        const ParseToken *t = &tokenlist->list[i];
+
+        /* Create a token for 't' */
+        token->type = t->type;
+        token->objPtr = JimMakeScriptObj(interp, t);
+        Jim_IncrRefCount(token->objPtr);
+        token++;
+    }
+
+    script->len = i;
+}
+
+/* This method takes the string representation of an object
+ * as a Tcl script, and generates the pre-parsed internal representation
+ * of the script. */
+static int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, struct JimParseResult *result)
+{
+    int scriptTextLen;
+    const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
+    struct JimParserCtx parser;
+    struct ScriptObj *script;
+    ParseTokenList tokenlist;
+    int line = 1;
+
+    /* Try to get information about filename / line number */
+    if (objPtr->typePtr == &sourceObjType) {
+        line = objPtr->internalRep.sourceValue.lineNumber;
+    }
+
+    /* Initially parse the script into tokens (in tokenlist) */
+    ScriptTokenListInit(&tokenlist);
+
+    JimParserInit(&parser, scriptText, scriptTextLen, line);
+    while (!parser.eof) {
+        JimParseScript(&parser);
+        ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
+            parser.tline);
+    }
+    if (result && parser.missing != ' ') {
+        ScriptTokenListFree(&tokenlist);
+        result->missing = parser.missing;
+        result->line = parser.missingline;
+        return JIM_ERR;
+    }
+
+    /* Add a final EOF token */
+    ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0);
+
+    /* Create the "real" script tokens from the initial token list */
+    script = Jim_Alloc(sizeof(*script));
+    memset(script, 0, sizeof(*script));
+    script->inUse = 1;
+    script->line = line;
+    if (objPtr->typePtr == &sourceObjType) {
+        script->fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
+    }
+    else {
+        script->fileNameObj = interp->emptyObj;
+    }
+    Jim_IncrRefCount(script->fileNameObj);
+
+    ScriptObjAddTokens(interp, script, &tokenlist);
+
+    /* No longer need the token list */
+    ScriptTokenListFree(&tokenlist);
+
+    /* Free the old internal rep and set the new one. */
+    Jim_FreeIntRep(interp, objPtr);
+    Jim_SetIntRepPtr(objPtr, script);
+    objPtr->typePtr = &scriptObjType;
+
+    return JIM_OK;
+}
+
+ScriptObj *Jim_GetScript(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    struct ScriptObj *script = Jim_GetIntRepPtr(objPtr);
+
+    if (objPtr->typePtr != &scriptObjType || script->substFlags) {
+        SetScriptFromAny(interp, objPtr, NULL);
+    }
+    return (ScriptObj *) Jim_GetIntRepPtr(objPtr);
+}
+
+/* -----------------------------------------------------------------------------
+ * Commands
+ * ---------------------------------------------------------------------------*/
+static void JimIncrCmdRefCount(Jim_Cmd *cmdPtr)
+{
+    cmdPtr->inUse++;
+}
+
+static void JimDecrCmdRefCount(Jim_Interp *interp, Jim_Cmd *cmdPtr)
+{
+    if (--cmdPtr->inUse == 0) {
+        if (cmdPtr->isproc) {
+            Jim_DecrRefCount(interp, cmdPtr->u.proc.argListObjPtr);
+            Jim_DecrRefCount(interp, cmdPtr->u.proc.bodyObjPtr);
+            if (cmdPtr->u.proc.staticVars) {
+                Jim_FreeHashTable(cmdPtr->u.proc.staticVars);
+                Jim_Free(cmdPtr->u.proc.staticVars);
+            }
+            if (cmdPtr->u.proc.prevCmd) {
+                /* Delete any pushed command too */
+                JimDecrCmdRefCount(interp, cmdPtr->u.proc.prevCmd);
+            }
+        }
+        else {
+            /* native (C) */
+            if (cmdPtr->u.native.delProc) {
+                cmdPtr->u.native.delProc(interp, cmdPtr->u.native.privData);
+            }
+        }
+        Jim_Free(cmdPtr);
+    }
+}
+
+/* Commands HashTable Type.
+ *
+ * Keys are dynamic allocated strings, Values are Jim_Cmd structures. */
+static void JimCommandsHT_ValDestructor(void *interp, void *val)
+{
+    JimDecrCmdRefCount(interp, val);
+}
+
+static const Jim_HashTableType JimCommandsHashTableType = {
+    JimStringCopyHTHashFunction,        /* hash function */
+    JimStringCopyHTKeyDup,      /* key dup */
+    NULL,                       /* val dup */
+    JimStringCopyHTKeyCompare,  /* key compare */
+    JimStringCopyHTKeyDestructor,       /* key destructor */
+    JimCommandsHT_ValDestructor        /* val destructor */
+};
+
+/* ------------------------- Commands related functions --------------------- */
+
+int Jim_CreateCommand(Jim_Interp *interp, const char *cmdName,
+    Jim_CmdProc cmdProc, void *privData, Jim_DelCmdProc delProc)
+{
+    Jim_Cmd *cmdPtr;
+
+    if (Jim_DeleteHashEntry(&interp->commands, cmdName) != JIM_ERR) {
+        /* Command existed so incr proc epoch */
+        Jim_InterpIncrProcEpoch(interp);
+    }
+
+    cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
+
+    /* Store the new details for this proc */
+    memset(cmdPtr, 0, sizeof(*cmdPtr));
+    cmdPtr->inUse = 1;
+    cmdPtr->u.native.delProc = delProc;
+    cmdPtr->u.native.cmdProc = cmdProc;
+    cmdPtr->u.native.privData = privData;
+
+    Jim_AddHashEntry(&interp->commands, cmdName, cmdPtr);
+
+    /* There is no need to increment the 'proc epoch' because
+     * creation of a new procedure can never affect existing
+     * cached commands. We don't do negative caching. */
+    return JIM_OK;
+}
+
+static int JimCreateProcedure(Jim_Interp *interp, Jim_Obj *cmdName,
+    Jim_Obj *argListObjPtr, Jim_Obj *staticsListObjPtr, Jim_Obj *bodyObjPtr)
+{
+    Jim_Cmd *cmdPtr;
+    Jim_HashEntry *he;
+    int argListLen;
+    int i;
+
+    if (JimValidName(interp, "procedure", cmdName) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    argListLen = Jim_ListLength(interp, argListObjPtr);
+
+    /* Allocate space for both the command pointer and the arg list */
+    cmdPtr = Jim_Alloc(sizeof(*cmdPtr) + sizeof(struct Jim_ProcArg) * argListLen);
+    memset(cmdPtr, 0, sizeof(*cmdPtr));
+    cmdPtr->inUse = 1;
+    cmdPtr->isproc = 1;
+    cmdPtr->u.proc.argListObjPtr = argListObjPtr;
+    cmdPtr->u.proc.argListLen = argListLen;
+    cmdPtr->u.proc.bodyObjPtr = bodyObjPtr;
+    cmdPtr->u.proc.argsPos = -1;
+    cmdPtr->u.proc.arglist = (struct Jim_ProcArg *)(cmdPtr + 1);
+    Jim_IncrRefCount(argListObjPtr);
+    Jim_IncrRefCount(bodyObjPtr);
+
+    /* Create the statics hash table. */
+    if (staticsListObjPtr) {
+        int len, i;
+
+        len = Jim_ListLength(interp, staticsListObjPtr);
+        if (len != 0) {
+            cmdPtr->u.proc.staticVars = Jim_Alloc(sizeof(Jim_HashTable));
+            Jim_InitHashTable(cmdPtr->u.proc.staticVars, &JimVariablesHashTableType, interp);
+            for (i = 0; i < len; i++) {
+                Jim_Obj *objPtr = 0, *initObjPtr = 0, *nameObjPtr = 0;
+                Jim_Var *varPtr;
+                int subLen;
+
+                Jim_ListIndex(interp, staticsListObjPtr, i, &objPtr, JIM_NONE);
+                /* Check if it's composed of two elements. */
+                subLen = Jim_ListLength(interp, objPtr);
+                if (subLen == 1 || subLen == 2) {
+                    /* Try to get the variable value from the current
+                     * environment. */
+                    Jim_ListIndex(interp, objPtr, 0, &nameObjPtr, JIM_NONE);
+                    if (subLen == 1) {
+                        initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE);
+                        if (initObjPtr == NULL) {
+                            Jim_SetResultFormatted(interp,
+                                "variable for initialization of static \"%#s\" not found in the local context",
+                                nameObjPtr);
+                            goto err;
+                        }
+                    }
+                    else {
+                        Jim_ListIndex(interp, objPtr, 1, &initObjPtr, JIM_NONE);
+                    }
+                    if (JimValidName(interp, "static variable", nameObjPtr) != JIM_OK) {
+                        goto err;
+                    }
+
+                    varPtr = Jim_Alloc(sizeof(*varPtr));
+                    varPtr->objPtr = initObjPtr;
+                    Jim_IncrRefCount(initObjPtr);
+                    varPtr->linkFramePtr = NULL;
+                    if (Jim_AddHashEntry(cmdPtr->u.proc.staticVars,
+                        Jim_String(nameObjPtr), varPtr) != JIM_OK) {
+                        Jim_SetResultFormatted(interp,
+                            "static variable name \"%#s\" duplicated in statics list", nameObjPtr);
+                        Jim_DecrRefCount(interp, initObjPtr);
+                        Jim_Free(varPtr);
+                        goto err;
+                    }
+                }
+                else {
+                    Jim_SetResultFormatted(interp, "too many fields in static specifier \"%#s\"",
+                        objPtr);
+                    goto err;
+                }
+            }
+        }
+    }
+
+    /* Parse the args out into arglist, validating as we go */
+    /* Examine the argument list for default parameters and 'args' */
+    for (i = 0; i < argListLen; i++) {
+        Jim_Obj *argPtr;
+        Jim_Obj *nameObjPtr;
+        Jim_Obj *defaultObjPtr;
+        int len;
+        int n = 1;
+
+        /* Examine a parameter */
+        Jim_ListIndex(interp, argListObjPtr, i, &argPtr, JIM_NONE);
+        len = Jim_ListLength(interp, argPtr);
+        if (len == 0) {
+            Jim_SetResultString(interp, "procedure has argument with no name", -1);
+            goto err;
+        }
+        if (len > 2) {
+            Jim_SetResultString(interp, "procedure has argument with too many fields", -1);
+            goto err;
+        }
+
+        if (len == 2) {
+            /* Optional parameter */
+            Jim_ListIndex(interp, argPtr, 0, &nameObjPtr, JIM_NONE);
+            Jim_ListIndex(interp, argPtr, 1, &defaultObjPtr, JIM_NONE);
+        }
+        else {
+            /* Required parameter */
+            nameObjPtr = argPtr;
+            defaultObjPtr = NULL;
+        }
+
+
+        if (Jim_CompareStringImmediate(interp, nameObjPtr, "args")) {
+            if (cmdPtr->u.proc.argsPos >= 0) {
+                Jim_SetResultString(interp, "procedure has 'args' specified more than once", -1);
+                goto err;
+            }
+            cmdPtr->u.proc.argsPos = i;
+        }
+        else {
+            if (len == 2) {
+                cmdPtr->u.proc.optArity += n;
+            }
+            else {
+                cmdPtr->u.proc.reqArity += n;
+            }
+        }
+
+        cmdPtr->u.proc.arglist[i].nameObjPtr = nameObjPtr;
+        cmdPtr->u.proc.arglist[i].defaultObjPtr = defaultObjPtr;
+    }
+
+    /* Add the new command */
+
+    /* It may already exist, so we try to delete the old one.
+     * Note that reference count means that it won't be deleted yet if
+     * it exists in the call stack.
+     *
+     * BUT, if 'local' is in force, instead of deleting the existing
+     * proc, we stash a reference to the old proc here.
+     */
+    he = Jim_FindHashEntry(&interp->commands, Jim_String(cmdName));
+    if (he) {
+        /* There was an old procedure with the same name, this requires
+         * a 'proc epoch' update. */
+
+        /* If a procedure with the same name didn't existed there is no need
+         * to increment the 'proc epoch' because creation of a new procedure
+         * can never affect existing cached commands. We don't do
+         * negative caching. */
+        Jim_InterpIncrProcEpoch(interp);
+    }
+
+    if (he && interp->local) {
+        /* Just push this proc over the top of the previous one */
+        cmdPtr->u.proc.prevCmd = he->u.val;
+        he->u.val = cmdPtr;
+    }
+    else {
+        if (he) {
+            /* Replace the existing proc */
+            Jim_DeleteHashEntry(&interp->commands, Jim_String(cmdName));
+        }
+
+        Jim_AddHashEntry(&interp->commands, Jim_String(cmdName), cmdPtr);
+    }
+
+    /* Unlike Tcl, set the name of the proc as the result */
+    Jim_SetResult(interp, cmdName);
+    return JIM_OK;
+
+  err:
+    if (cmdPtr->u.proc.staticVars) {
+        Jim_FreeHashTable(cmdPtr->u.proc.staticVars);
+    }
+    Jim_Free(cmdPtr->u.proc.staticVars);
+    Jim_DecrRefCount(interp, argListObjPtr);
+    Jim_DecrRefCount(interp, bodyObjPtr);
+    Jim_Free(cmdPtr);
+    return JIM_ERR;
+}
+
+int Jim_DeleteCommand(Jim_Interp *interp, const char *cmdName)
+{
+    if (Jim_DeleteHashEntry(&interp->commands, cmdName) == JIM_ERR)
+        return JIM_ERR;
+    Jim_InterpIncrProcEpoch(interp);
+    return JIM_OK;
+}
+
+int Jim_RenameCommand(Jim_Interp *interp, const char *oldName, const char *newName)
+{
+    Jim_HashEntry *he;
+
+    /* Does it exist? */
+    he = Jim_FindHashEntry(&interp->commands, oldName);
+    if (he == NULL) {
+        Jim_SetResultFormatted(interp, "can't %s \"%s\": command doesn't exist",
+            newName[0] ? "rename" : "delete", oldName);
+        return JIM_ERR;
+    }
+
+    if (newName[0] == '\0')     /* Delete! */
+        return Jim_DeleteCommand(interp, oldName);
+
+    /* rename */
+    if (Jim_FindHashEntry(&interp->commands, newName)) {
+        Jim_SetResultFormatted(interp, "can't rename to \"%s\": command already exists", newName);
+        return JIM_ERR;
+    }
+
+    /* Add the new name first */
+    JimIncrCmdRefCount(he->u.val);
+    Jim_AddHashEntry(&interp->commands, newName, he->u.val);
+
+    /* Now remove the old name */
+    Jim_DeleteHashEntry(&interp->commands, oldName);
+
+    /* Increment the epoch */
+    Jim_InterpIncrProcEpoch(interp);
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * Command object
+ * ---------------------------------------------------------------------------*/
+
+static int SetCommandFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType commandObjType = {
+    "command",
+    NULL,
+    NULL,
+    NULL,
+    JIM_TYPE_REFERENCES,
+};
+
+int SetCommandFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    Jim_HashEntry *he;
+    const char *cmdName;
+
+    /* Get the string representation */
+    cmdName = Jim_String(objPtr);
+    /* Lookup this name into the commands hash table */
+    he = Jim_FindHashEntry(&interp->commands, cmdName);
+    if (he == NULL)
+        return JIM_ERR;
+
+    /* Free the old internal repr and set the new one. */
+    Jim_FreeIntRep(interp, objPtr);
+    objPtr->typePtr = &commandObjType;
+    objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch;
+    objPtr->internalRep.cmdValue.cmdPtr = (void *)he->u.val;
+    return JIM_OK;
+}
+
+/* This function returns the command structure for the command name
+ * stored in objPtr. It tries to specialize the objPtr to contain
+ * a cached info instead to perform the lookup into the hash table
+ * every time. The information cached may not be uptodate, in such
+ * a case the lookup is performed and the cache updated.
+ *
+ * Respects the 'upcall' setting
+ */
+Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+    Jim_Cmd *cmd;
+
+    if ((objPtr->typePtr != &commandObjType ||
+            objPtr->internalRep.cmdValue.procEpoch != interp->procEpoch) &&
+        SetCommandFromAny(interp, objPtr) == JIM_ERR) {
+        if (flags & JIM_ERRMSG) {
+            Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr);
+        }
+        return NULL;
+    }
+    cmd = objPtr->internalRep.cmdValue.cmdPtr;
+    while (cmd->isproc && cmd->u.proc.upcall) {
+        cmd = cmd->u.proc.prevCmd;
+    }
+    return cmd;
+}
+
+/* -----------------------------------------------------------------------------
+ * Variables
+ * ---------------------------------------------------------------------------*/
+
+/* Variables HashTable Type.
+ *
+ * Keys are dynamic allocated strings, Values are Jim_Var structures. */
+static void JimVariablesHTValDestructor(void *interp, void *val)
+{
+    Jim_Var *varPtr = (void *)val;
+
+    Jim_DecrRefCount(interp, varPtr->objPtr);
+    Jim_Free(val);
+}
+
+static const Jim_HashTableType JimVariablesHashTableType = {
+    JimStringCopyHTHashFunction,        /* hash function */
+    JimStringCopyHTKeyDup,      /* key dup */
+    NULL,                       /* val dup */
+    JimStringCopyHTKeyCompare,  /* key compare */
+    JimStringCopyHTKeyDestructor,       /* key destructor */
+    JimVariablesHTValDestructor /* val destructor */
+};
+
+/* -----------------------------------------------------------------------------
+ * Variable object
+ * ---------------------------------------------------------------------------*/
+
+#define JIM_DICT_SUGAR 100      /* Only returned by SetVariableFromAny() */
+
+static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType variableObjType = {
+    "variable",
+    NULL,
+    NULL,
+    NULL,
+    JIM_TYPE_REFERENCES,
+};
+
+/* Return true if the string "str" looks like syntax sugar for [dict]. I.e.
+ * is in the form "varname(key)". */
+static int JimNameIsDictSugar(const char *str, int len)
+{
+    if (len && str[len - 1] == ')' && strchr(str, '(') != NULL)
+        return 1;
+    return 0;
+}
+
+/**
+ * Check that the name does not contain embedded nulls.
+ *
+ * Variable and procedure names are maniplated as null terminated strings, so
+ * don't allow names with embedded nulls.
+ */
+static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr)
+{
+    /* Variable names and proc names can't contain embedded nulls */
+    if (nameObjPtr->typePtr != &variableObjType) {
+        int len;
+        const char *str = Jim_GetString(nameObjPtr, &len);
+        if (memchr(str, '\0', len)) {
+            Jim_SetResultFormatted(interp, "%s name contains embedded null", type);
+            return JIM_ERR;
+        }
+    }
+    return JIM_OK;
+}
+
+/* This method should be called only by the variable API.
+ * It returns JIM_OK on success (variable already exists),
+ * JIM_ERR if it does not exists, JIM_DICT_SUGAR if it's not
+ * a variable name, but syntax glue for [dict] i.e. the last
+ * character is ')' */
+static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+    Jim_HashEntry *he;
+    const char *varName;
+    int len;
+    Jim_CallFrame *framePtr = interp->framePtr;
+
+    /* Check if the object is already an uptodate variable */
+    if (objPtr->typePtr == &variableObjType &&
+        objPtr->internalRep.varValue.callFrameId == framePtr->id) {
+        return JIM_OK;          /* nothing to do */
+    }
+
+    if (objPtr->typePtr == &dictSubstObjType) {
+        return JIM_DICT_SUGAR;
+    }
+
+    if (JimValidName(interp, "variable", objPtr) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    /* Get the string representation */
+    varName = Jim_GetString(objPtr, &len);
+
+    /* Make sure it's not syntax glue to get/set dict. */
+    if (JimNameIsDictSugar(varName, len)) {
+        return JIM_DICT_SUGAR;
+    }
+
+    if (varName[0] == ':' && varName[1] == ':') {
+        framePtr = interp->topFramePtr;
+        he = Jim_FindHashEntry(&framePtr->vars, varName + 2);
+        if (he == NULL) {
+            return JIM_ERR;
+        }
+    }
+    else {
+        /* Lookup this name into the variables hash table */
+        he = Jim_FindHashEntry(&framePtr->vars, varName);
+        if (he == NULL) {
+            /* Try with static vars. */
+            if (framePtr->staticVars == NULL)
+                return JIM_ERR;
+            if (!(he = Jim_FindHashEntry(framePtr->staticVars, varName)))
+                return JIM_ERR;
+        }
+    }
+    /* Free the old internal repr and set the new one. */
+    Jim_FreeIntRep(interp, objPtr);
+    objPtr->typePtr = &variableObjType;
+    objPtr->internalRep.varValue.callFrameId = framePtr->id;
+    objPtr->internalRep.varValue.varPtr = (void *)he->u.val;
+    return JIM_OK;
+}
+
+/* -------------------- Variables related functions ------------------------- */
+static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr, Jim_Obj *valObjPtr);
+static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr, int flags);
+
+/* For now that's dummy. Variables lookup should be optimized
+ * in many ways, with caching of lookups, and possibly with
+ * a table of pre-allocated vars in every CallFrame for local vars.
+ * All the caching should also have an 'epoch' mechanism similar
+ * to the one used by Tcl for procedures lookup caching. */
+
+int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
+{
+    const char *name;
+    Jim_Var *var;
+    int err;
+
+    if ((err = SetVariableFromAny(interp, nameObjPtr)) != JIM_OK) {
+        Jim_CallFrame *framePtr = interp->framePtr;
+
+        /* Check for [dict] syntax sugar. */
+        if (err == JIM_DICT_SUGAR)
+            return JimDictSugarSet(interp, nameObjPtr, valObjPtr);
+
+        if (JimValidName(interp, "variable", nameObjPtr) != JIM_OK) {
+            return JIM_ERR;
+        }
+
+        /* New variable to create */
+        name = Jim_String(nameObjPtr);
+
+        var = Jim_Alloc(sizeof(*var));
+        var->objPtr = valObjPtr;
+        Jim_IncrRefCount(valObjPtr);
+        var->linkFramePtr = NULL;
+        /* Insert the new variable */
+        if (name[0] == ':' && name[1] == ':') {
+            /* Into the top level frame */
+            framePtr = interp->topFramePtr;
+            Jim_AddHashEntry(&framePtr->vars, name + 2, var);
+        }
+        else {
+            Jim_AddHashEntry(&framePtr->vars, name, var);
+        }
+        /* Make the object int rep a variable */
+        Jim_FreeIntRep(interp, nameObjPtr);
+        nameObjPtr->typePtr = &variableObjType;
+        nameObjPtr->internalRep.varValue.callFrameId = framePtr->id;
+        nameObjPtr->internalRep.varValue.varPtr = var;
+    }
+    else {
+        var = nameObjPtr->internalRep.varValue.varPtr;
+        if (var->linkFramePtr == NULL) {
+            Jim_IncrRefCount(valObjPtr);
+            Jim_DecrRefCount(interp, var->objPtr);
+            var->objPtr = valObjPtr;
+        }
+        else {                  /* Else handle the link */
+            Jim_CallFrame *savedCallFrame;
+
+            savedCallFrame = interp->framePtr;
+            interp->framePtr = var->linkFramePtr;
+            err = Jim_SetVariable(interp, var->objPtr, valObjPtr);
+            interp->framePtr = savedCallFrame;
+            if (err != JIM_OK)
+                return err;
+        }
+    }
+    return JIM_OK;
+}
+
+int Jim_SetVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
+{
+    Jim_Obj *nameObjPtr;
+    int result;
+
+    nameObjPtr = Jim_NewStringObj(interp, name, -1);
+    Jim_IncrRefCount(nameObjPtr);
+    result = Jim_SetVariable(interp, nameObjPtr, objPtr);
+    Jim_DecrRefCount(interp, nameObjPtr);
+    return result;
+}
+
+int Jim_SetGlobalVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
+{
+    Jim_CallFrame *savedFramePtr;
+    int result;
+
+    savedFramePtr = interp->framePtr;
+    interp->framePtr = interp->topFramePtr;
+    result = Jim_SetVariableStr(interp, name, objPtr);
+    interp->framePtr = savedFramePtr;
+    return result;
+}
+
+int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val)
+{
+    Jim_Obj *nameObjPtr, *valObjPtr;
+    int result;
+
+    nameObjPtr = Jim_NewStringObj(interp, name, -1);
+    valObjPtr = Jim_NewStringObj(interp, val, -1);
+    Jim_IncrRefCount(nameObjPtr);
+    Jim_IncrRefCount(valObjPtr);
+    result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
+    Jim_DecrRefCount(interp, nameObjPtr);
+    Jim_DecrRefCount(interp, valObjPtr);
+    return result;
+}
+
+int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
+    Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame)
+{
+    const char *varName;
+    int len;
+
+    varName = Jim_GetString(nameObjPtr, &len);
+
+    if (varName[0] == ':' && varName[1] == ':') {
+        /* Linking a global var does nothing */
+        return JIM_OK;
+    }
+
+    if (JimNameIsDictSugar(varName, len)) {
+        Jim_SetResultString(interp, "Dict key syntax invalid as link source", -1);
+        return JIM_ERR;
+    }
+
+    /* Check for an existing variable or link */
+    if (SetVariableFromAny(interp, nameObjPtr) == JIM_OK) {
+        Jim_Var *varPtr = nameObjPtr->internalRep.varValue.varPtr;
+
+        if (varPtr->linkFramePtr == NULL) {
+            Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr);
+            return JIM_ERR;
+        }
+
+        /* It exists, but is a link, so delete the link */
+        varPtr->linkFramePtr = NULL;
+    }
+
+    /* Check for cycles. */
+    if (interp->framePtr == targetCallFrame) {
+        Jim_Obj *objPtr = targetNameObjPtr;
+        Jim_Var *varPtr;
+
+        /* Cycles are only possible with 'uplevel 0' */
+        while (1) {
+            if (Jim_StringEqObj(objPtr, nameObjPtr)) {
+                Jim_SetResultString(interp, "can't upvar from variable to itself", -1);
+                return JIM_ERR;
+            }
+            if (SetVariableFromAny(interp, objPtr) != JIM_OK)
+                break;
+            varPtr = objPtr->internalRep.varValue.varPtr;
+            if (varPtr->linkFramePtr != targetCallFrame)
+                break;
+            objPtr = varPtr->objPtr;
+        }
+    }
+
+    /* Perform the binding */
+    Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr);
+    /* We are now sure 'nameObjPtr' type is variableObjType */
+    nameObjPtr->internalRep.varValue.varPtr->linkFramePtr = targetCallFrame;
+    return JIM_OK;
+}
+
+/* Return the Jim_Obj pointer associated with a variable name,
+ * or NULL if the variable was not found in the current context.
+ * The same optimization discussed in the comment to the
+ * 'SetVariable' function should apply here.
+ *
+ * If JIM_UNSHARED is set and the variable is an array element (dict sugar)
+ * in a dictionary which is shared, the array variable value is duplicated first.
+ * This allows the array element to be updated (e.g. append, lappend) without
+ * affecting other references to the dictionary.
+ */
+Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
+{
+    switch (SetVariableFromAny(interp, nameObjPtr)) {
+        case JIM_OK:{
+                Jim_Var *varPtr = nameObjPtr->internalRep.varValue.varPtr;
+
+                if (varPtr->linkFramePtr == NULL) {
+                    return varPtr->objPtr;
+                }
+                else {
+                    Jim_Obj *objPtr;
+
+                    /* The variable is a link? Resolve it. */
+                    Jim_CallFrame *savedCallFrame = interp->framePtr;
+
+                    interp->framePtr = varPtr->linkFramePtr;
+                    objPtr = Jim_GetVariable(interp, varPtr->objPtr, flags);
+                    interp->framePtr = savedCallFrame;
+                    if (objPtr) {
+                        return objPtr;
+                    }
+                    /* Error, so fall through to the error message */
+                }
+            }
+            break;
+
+        case JIM_DICT_SUGAR:
+            /* [dict] syntax sugar. */
+            return JimDictSugarGet(interp, nameObjPtr, flags);
+    }
+    if (flags & JIM_ERRMSG) {
+        Jim_SetResultFormatted(interp, "can't read \"%#s\": no such variable", nameObjPtr);
+    }
+    return NULL;
+}
+
+Jim_Obj *Jim_GetGlobalVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
+{
+    Jim_CallFrame *savedFramePtr;
+    Jim_Obj *objPtr;
+
+    savedFramePtr = interp->framePtr;
+    interp->framePtr = interp->topFramePtr;
+    objPtr = Jim_GetVariable(interp, nameObjPtr, flags);
+    interp->framePtr = savedFramePtr;
+
+    return objPtr;
+}
+
+Jim_Obj *Jim_GetVariableStr(Jim_Interp *interp, const char *name, int flags)
+{
+    Jim_Obj *nameObjPtr, *varObjPtr;
+
+    nameObjPtr = Jim_NewStringObj(interp, name, -1);
+    Jim_IncrRefCount(nameObjPtr);
+    varObjPtr = Jim_GetVariable(interp, nameObjPtr, flags);
+    Jim_DecrRefCount(interp, nameObjPtr);
+    return varObjPtr;
+}
+
+Jim_Obj *Jim_GetGlobalVariableStr(Jim_Interp *interp, const char *name, int flags)
+{
+    Jim_CallFrame *savedFramePtr;
+    Jim_Obj *objPtr;
+
+    savedFramePtr = interp->framePtr;
+    interp->framePtr = interp->topFramePtr;
+    objPtr = Jim_GetVariableStr(interp, name, flags);
+    interp->framePtr = savedFramePtr;
+
+    return objPtr;
+}
+
+/* Unset a variable.
+ * Note: On success unset invalidates all the variable objects created
+ * in the current call frame incrementing. */
+int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
+{
+    const char *name;
+    Jim_Var *varPtr;
+    int retval;
+
+    retval = SetVariableFromAny(interp, nameObjPtr);
+    if (retval == JIM_DICT_SUGAR) {
+        /* [dict] syntax sugar. */
+        return JimDictSugarSet(interp, nameObjPtr, NULL);
+    }
+    else if (retval == JIM_OK) {
+        varPtr = nameObjPtr->internalRep.varValue.varPtr;
+
+        /* If it's a link call UnsetVariable recursively */
+        if (varPtr->linkFramePtr) {
+            Jim_CallFrame *savedCallFrame;
+
+            savedCallFrame = interp->framePtr;
+            interp->framePtr = varPtr->linkFramePtr;
+            retval = Jim_UnsetVariable(interp, varPtr->objPtr, JIM_NONE);
+            interp->framePtr = savedCallFrame;
+        }
+        else {
+            Jim_CallFrame *framePtr = interp->framePtr;
+
+            name = Jim_String(nameObjPtr);
+            if (name[0] == ':' && name[1] == ':') {
+                framePtr = interp->topFramePtr;
+                name += 2;
+            }
+            retval = Jim_DeleteHashEntry(&framePtr->vars, name);
+            if (retval == JIM_OK) {
+                /* Change the callframe id, invalidating var lookup caching */
+                JimChangeCallFrameId(interp, framePtr);
+            }
+        }
+    }
+    if (retval != JIM_OK && (flags & JIM_ERRMSG)) {
+        Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such variable", nameObjPtr);
+    }
+    return retval;
+}
+
+/* ----------  Dict syntax sugar (similar to array Tcl syntax) -------------- */
+
+/* Given a variable name for [dict] operation syntax sugar,
+ * this function returns two objects, the first with the name
+ * of the variable to set, and the second with the rispective key.
+ * For example "foo(bar)" will return objects with string repr. of
+ * "foo" and "bar".
+ *
+ * The returned objects have refcount = 1. The function can't fail. */
+static void JimDictSugarParseVarKey(Jim_Interp *interp, Jim_Obj *objPtr,
+    Jim_Obj **varPtrPtr, Jim_Obj **keyPtrPtr)
+{
+    const char *str, *p;
+    int len, keyLen;
+    Jim_Obj *varObjPtr, *keyObjPtr;
+
+    str = Jim_GetString(objPtr, &len);
+
+    p = strchr(str, '(');
+    JimPanic((p == NULL, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str));
+
+    varObjPtr = Jim_NewStringObj(interp, str, p - str);
+
+    p++;
+    keyLen = (str + len) - p;
+    if (str[len - 1] == ')') {
+        keyLen--;
+    }
+
+    /* Create the objects with the variable name and key. */
+    keyObjPtr = Jim_NewStringObj(interp, p, keyLen);
+
+    Jim_IncrRefCount(varObjPtr);
+    Jim_IncrRefCount(keyObjPtr);
+    *varPtrPtr = varObjPtr;
+    *keyPtrPtr = keyObjPtr;
+}
+
+/* Helper of Jim_SetVariable() to deal with dict-syntax variable names.
+ * Also used by Jim_UnsetVariable() with valObjPtr = NULL. */
+static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *valObjPtr)
+{
+    int err;
+
+    SetDictSubstFromAny(interp, objPtr);
+
+    err = Jim_SetDictKeysVector(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
+        &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_ERRMSG);
+
+    if (err == JIM_OK) {
+        /* Don't keep an extra ref to the result */
+        Jim_SetEmptyResult(interp);
+    }
+    else {
+        if (!valObjPtr) {
+            /* Better error message for unset a(2) where a exists but a(2) doesn't */
+            if (Jim_GetVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_NONE)) {
+                Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such element in array",
+                    objPtr);
+                return err;
+            }
+        }
+        /* Make the error more informative and Tcl-compatible */
+        Jim_SetResultFormatted(interp, "can't %s \"%#s\": variable isn't array",
+            (valObjPtr ? "set" : "unset"), objPtr);
+    }
+    return err;
+}
+
+/**
+ * Expands the array variable (dict sugar) and returns the result, or NULL on error.
+ *
+ * If JIM_UNSHARED is set and the dictionary is shared, it will be duplicated
+ * and stored back to the variable before expansion.
+ */
+static Jim_Obj *JimDictExpandArrayVariable(Jim_Interp *interp, Jim_Obj *varObjPtr,
+    Jim_Obj *keyObjPtr, int flags)
+{
+    Jim_Obj *dictObjPtr;
+    Jim_Obj *resObjPtr = NULL;
+    int ret;
+
+    dictObjPtr = Jim_GetVariable(interp, varObjPtr, JIM_ERRMSG);
+    if (!dictObjPtr) {
+        return NULL;
+    }
+
+    ret = Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE);
+    if (ret != JIM_OK) {
+        resObjPtr = NULL;
+        if (ret < 0) {
+            Jim_SetResultFormatted(interp,
+                "can't read \"%#s(%#s)\": variable isn't array", varObjPtr, keyObjPtr);
+        }
+        else {
+            Jim_SetResultFormatted(interp,
+                "can't read \"%#s(%#s)\": no such element in array", varObjPtr, keyObjPtr);
+        }
+    }
+    else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) {
+        dictObjPtr = Jim_DuplicateObj(interp, dictObjPtr);
+        if (Jim_SetVariable(interp, varObjPtr, dictObjPtr) != JIM_OK) {
+            /* This can probably never happen */
+            JimPanic((1, "SetVariable failed for JIM_UNSHARED"));
+        }
+        /* We know that the key exists. Get the result in the now-unshared dictionary */
+        Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE);
+    }
+
+    return resObjPtr;
+}
+
+/* Helper of Jim_GetVariable() to deal with dict-syntax variable names */
+static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+    SetDictSubstFromAny(interp, objPtr);
+
+    return JimDictExpandArrayVariable(interp,
+        objPtr->internalRep.dictSubstValue.varNameObjPtr,
+        objPtr->internalRep.dictSubstValue.indexObjPtr, flags);
+}
+
+/* --------- $var(INDEX) substitution, using a specialized object ----------- */
+
+void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr);
+    Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
+}
+
+void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+    JIM_NOTUSED(interp);
+
+    dupPtr->internalRep.dictSubstValue.varNameObjPtr =
+        srcPtr->internalRep.dictSubstValue.varNameObjPtr;
+    dupPtr->internalRep.dictSubstValue.indexObjPtr = srcPtr->internalRep.dictSubstValue.indexObjPtr;
+    dupPtr->typePtr = &dictSubstObjType;
+}
+
+/* Note: The object *must* be in dict-sugar format */
+static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    if (objPtr->typePtr != &dictSubstObjType) {
+        Jim_Obj *varObjPtr, *keyObjPtr;
+
+        if (objPtr->typePtr == &interpolatedObjType) {
+            /* An interpolated object in dict-sugar form */
+
+            const ScriptToken *token = objPtr->internalRep.twoPtrValue.ptr1;
+
+            varObjPtr = token[0].objPtr;
+            keyObjPtr = objPtr->internalRep.twoPtrValue.ptr2;
+
+            Jim_IncrRefCount(varObjPtr);
+            Jim_IncrRefCount(keyObjPtr);
+        }
+        else {
+            JimDictSugarParseVarKey(interp, objPtr, &varObjPtr, &keyObjPtr);
+        }
+
+        Jim_FreeIntRep(interp, objPtr);
+        objPtr->typePtr = &dictSubstObjType;
+        objPtr->internalRep.dictSubstValue.varNameObjPtr = varObjPtr;
+        objPtr->internalRep.dictSubstValue.indexObjPtr = keyObjPtr;
+    }
+}
+
+/* This function is used to expand [dict get] sugar in the form
+ * of $var(INDEX). The function is mainly used by Jim_EvalObj()
+ * to deal with tokens of type JIM_TT_DICTSUGAR. objPtr points to an
+ * object that is *guaranteed* to be in the form VARNAME(INDEX).
+ * The 'index' part is [subst]ituted, and is used to lookup a key inside
+ * the [dict]ionary contained in variable VARNAME. */
+static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    Jim_Obj *resObjPtr = NULL;
+    Jim_Obj *substKeyObjPtr = NULL;
+
+    SetDictSubstFromAny(interp, objPtr);
+
+    if (Jim_SubstObj(interp, objPtr->internalRep.dictSubstValue.indexObjPtr,
+            &substKeyObjPtr, JIM_NONE)
+        != JIM_OK) {
+        return NULL;
+    }
+    Jim_IncrRefCount(substKeyObjPtr);
+    resObjPtr =
+        JimDictExpandArrayVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
+        substKeyObjPtr, 0);
+    Jim_DecrRefCount(interp, substKeyObjPtr);
+
+    return resObjPtr;
+}
+
+static Jim_Obj *JimExpandExprSugar(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    Jim_Obj *resultObjPtr;
+
+    if (Jim_EvalExpression(interp, objPtr, &resultObjPtr) == JIM_OK) {
+        /* Note that the result has a ref count of 1, but we need a ref count of 0 */
+        resultObjPtr->refCount--;
+        return resultObjPtr;
+    }
+    return NULL;
+}
+
+/* -----------------------------------------------------------------------------
+ * CallFrame
+ * ---------------------------------------------------------------------------*/
+
+static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent)
+{
+    Jim_CallFrame *cf;
+
+    if (interp->freeFramesList) {
+        cf = interp->freeFramesList;
+        interp->freeFramesList = cf->nextFramePtr;
+    }
+    else {
+        cf = Jim_Alloc(sizeof(*cf));
+        cf->vars.table = NULL;
+    }
+
+    cf->id = interp->callFrameEpoch++;
+    cf->parentCallFrame = parent;
+    cf->level = parent ? parent->level + 1 : 0;
+    cf->argv = NULL;
+    cf->argc = 0;
+    cf->procArgsObjPtr = NULL;
+    cf->procBodyObjPtr = NULL;
+    cf->nextFramePtr = NULL;
+    cf->staticVars = NULL;
+    if (cf->vars.table == NULL)
+        Jim_InitHashTable(&cf->vars, &JimVariablesHashTableType, interp);
+    return cf;
+}
+
+/* Used to invalidate every caching related to callframe stability. */
+static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf)
+{
+    cf->id = interp->callFrameEpoch++;
+}
+
+#define JIM_FCF_NONE 0          /* no flags */
+#define JIM_FCF_NOHT 1          /* don't free the hash table */
+static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags)
+{
+    if (cf->procArgsObjPtr)
+        Jim_DecrRefCount(interp, cf->procArgsObjPtr);
+    if (cf->procBodyObjPtr)
+        Jim_DecrRefCount(interp, cf->procBodyObjPtr);
+    if (!(flags & JIM_FCF_NOHT))
+        Jim_FreeHashTable(&cf->vars);
+    else {
+        int i;
+        Jim_HashEntry **table = cf->vars.table, *he;
+
+        for (i = 0; i < JIM_HT_INITIAL_SIZE; i++) {
+            he = table[i];
+            while (he != NULL) {
+                Jim_HashEntry *nextEntry = he->next;
+                Jim_Var *varPtr = (void *)he->u.val;
+
+                Jim_DecrRefCount(interp, varPtr->objPtr);
+                Jim_Free(he->u.val);
+                Jim_Free((void *)he->key);      /* ATTENTION: const cast */
+                Jim_Free(he);
+                table[i] = NULL;
+                he = nextEntry;
+            }
+        }
+        cf->vars.used = 0;
+    }
+    cf->nextFramePtr = interp->freeFramesList;
+    interp->freeFramesList = cf;
+}
+
+/* -----------------------------------------------------------------------------
+ * References
+ * ---------------------------------------------------------------------------*/
+#ifdef JIM_REFERENCES
+
+/* References HashTable Type.
+ *
+ * Keys are jim_wide integers, dynamically allocated for now but in the
+ * future it's worth to cache this 8 bytes objects. Values are poitners
+ * to Jim_References. */
+static void JimReferencesHTValDestructor(void *interp, void *val)
+{
+    Jim_Reference *refPtr = (void *)val;
+
+    Jim_DecrRefCount(interp, refPtr->objPtr);
+    if (refPtr->finalizerCmdNamePtr != NULL) {
+        Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr);
+    }
+    Jim_Free(val);
+}
+
+static unsigned int JimReferencesHTHashFunction(const void *key)
+{
+    /* Only the least significant bits are used. */
+    const jim_wide *widePtr = key;
+    unsigned int intValue = (unsigned int)*widePtr;
+
+    return Jim_IntHashFunction(intValue);
+}
+
+static const void *JimReferencesHTKeyDup(void *privdata, const void *key)
+{
+    void *copy = Jim_Alloc(sizeof(jim_wide));
+
+    JIM_NOTUSED(privdata);
+
+    memcpy(copy, key, sizeof(jim_wide));
+    return copy;
+}
+
+static int JimReferencesHTKeyCompare(void *privdata, const void *key1, const void *key2)
+{
+    JIM_NOTUSED(privdata);
+
+    return memcmp(key1, key2, sizeof(jim_wide)) == 0;
+}
+
+static void JimReferencesHTKeyDestructor(void *privdata, const void *key)
+{
+    JIM_NOTUSED(privdata);
+
+    Jim_Free((void *)key);
+}
+
+static const Jim_HashTableType JimReferencesHashTableType = {
+    JimReferencesHTHashFunction,        /* hash function */
+    JimReferencesHTKeyDup,      /* key dup */
+    NULL,                       /* val dup */
+    JimReferencesHTKeyCompare,  /* key compare */
+    JimReferencesHTKeyDestructor,       /* key destructor */
+    JimReferencesHTValDestructor        /* val destructor */
+};
+
+/* -----------------------------------------------------------------------------
+ * Reference object type and References API
+ * ---------------------------------------------------------------------------*/
+
+/* The string representation of references has two features in order
+ * to make the GC faster. The first is that every reference starts
+ * with a non common character '<', in order to make the string matching
+ * faster. The second is that the reference string rep is 42 characters
+ * in length, this allows to avoid to check every object with a string
+ * repr < 42, and usually there aren't many of these objects. */
+
+#define JIM_REFERENCE_SPACE (35+JIM_REFERENCE_TAGLEN)
+
+static int JimFormatReference(char *buf, Jim_Reference *refPtr, jim_wide id)
+{
+    const char *fmt = "<reference.<%s>.%020" JIM_WIDE_MODIFIER ">";
+
+    sprintf(buf, fmt, refPtr->tag, id);
+    return JIM_REFERENCE_SPACE;
+}
+
+static void UpdateStringOfReference(struct Jim_Obj *objPtr);
+
+static const Jim_ObjType referenceObjType = {
+    "reference",
+    NULL,
+    NULL,
+    UpdateStringOfReference,
+    JIM_TYPE_REFERENCES,
+};
+
+void UpdateStringOfReference(struct Jim_Obj *objPtr)
+{
+    int len;
+    char buf[JIM_REFERENCE_SPACE + 1];
+    Jim_Reference *refPtr;
+
+    refPtr = objPtr->internalRep.refValue.refPtr;
+    len = JimFormatReference(buf, refPtr, objPtr->internalRep.refValue.id);
+    objPtr->bytes = Jim_Alloc(len + 1);
+    memcpy(objPtr->bytes, buf, len + 1);
+    objPtr->length = len;
+}
+
+/* returns true if 'c' is a valid reference tag character.
+ * i.e. inside the range [_a-zA-Z0-9] */
+static int isrefchar(int c)
+{
+    return (c == '_' || isalnum(c));
+}
+
+static int SetReferenceFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    jim_wide wideValue;
+    int i, len;
+    const char *str, *start, *end;
+    char refId[21];
+    Jim_Reference *refPtr;
+    Jim_HashEntry *he;
+
+    /* Get the string representation */
+    str = Jim_GetString(objPtr, &len);
+    /* Check if it looks like a reference */
+    if (len < JIM_REFERENCE_SPACE)
+        goto badformat;
+    /* Trim spaces */
+    start = str;
+    end = str + len - 1;
+    while (*start == ' ')
+        start++;
+    while (*end == ' ' && end > start)
+        end--;
+    if (end - start + 1 != JIM_REFERENCE_SPACE)
+        goto badformat;
+    /* <reference.<1234567>.%020> */
+    if (memcmp(start, "<reference.<", 12) != 0)
+        goto badformat;
+    if (start[12 + JIM_REFERENCE_TAGLEN] != '>' || end[0] != '>')
+        goto badformat;
+    /* The tag can't contain chars other than a-zA-Z0-9 + '_'. */
+    for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) {
+        if (!isrefchar(start[12 + i]))
+            goto badformat;
+    }
+    /* Extract info from the reference. */
+    memcpy(refId, start + 14 + JIM_REFERENCE_TAGLEN, 20);
+    refId[20] = '\0';
+    /* Try to convert the ID into a jim_wide */
+    if (Jim_StringToWide(refId, &wideValue, 10) != JIM_OK)
+        goto badformat;
+    /* Check if the reference really exists! */
+    he = Jim_FindHashEntry(&interp->references, &wideValue);
+    if (he == NULL) {
+        Jim_SetResultFormatted(interp, "invalid reference id \"%#s\"", objPtr);
+        return JIM_ERR;
+    }
+    refPtr = he->u.val;
+    /* Free the old internal repr and set the new one. */
+    Jim_FreeIntRep(interp, objPtr);
+    objPtr->typePtr = &referenceObjType;
+    objPtr->internalRep.refValue.id = wideValue;
+    objPtr->internalRep.refValue.refPtr = refPtr;
+    return JIM_OK;
+
+  badformat:
+    Jim_SetResultFormatted(interp, "expected reference but got \"%#s\"", objPtr);
+    return JIM_ERR;
+}
+
+/* Returns a new reference pointing to objPtr, having cmdNamePtr
+ * as finalizer command (or NULL if there is no finalizer).
+ * The returned reference object has refcount = 0. */
+Jim_Obj *Jim_NewReference(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr)
+{
+    struct Jim_Reference *refPtr;
+    jim_wide wideValue = interp->referenceNextId;
+    Jim_Obj *refObjPtr;
+    const char *tag;
+    int tagLen, i;
+
+    /* Perform the Garbage Collection if needed. */
+    Jim_CollectIfNeeded(interp);
+
+    refPtr = Jim_Alloc(sizeof(*refPtr));
+    refPtr->objPtr = objPtr;
+    Jim_IncrRefCount(objPtr);
+    refPtr->finalizerCmdNamePtr = cmdNamePtr;
+    if (cmdNamePtr)
+        Jim_IncrRefCount(cmdNamePtr);
+    Jim_AddHashEntry(&interp->references, &wideValue, refPtr);
+    refObjPtr = Jim_NewObj(interp);
+    refObjPtr->typePtr = &referenceObjType;
+    refObjPtr->bytes = NULL;
+    refObjPtr->internalRep.refValue.id = interp->referenceNextId;
+    refObjPtr->internalRep.refValue.refPtr = refPtr;
+    interp->referenceNextId++;
+    /* Set the tag. Trimmed at JIM_REFERENCE_TAGLEN. Everything
+     * that does not pass the 'isrefchar' test is replaced with '_' */
+    tag = Jim_GetString(tagPtr, &tagLen);
+    if (tagLen > JIM_REFERENCE_TAGLEN)
+        tagLen = JIM_REFERENCE_TAGLEN;
+    for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) {
+        if (i < tagLen && isrefchar(tag[i]))
+            refPtr->tag[i] = tag[i];
+        else
+            refPtr->tag[i] = '_';
+    }
+    refPtr->tag[JIM_REFERENCE_TAGLEN] = '\0';
+    return refObjPtr;
+}
+
+Jim_Reference *Jim_GetReference(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    if (objPtr->typePtr != &referenceObjType && SetReferenceFromAny(interp, objPtr) == JIM_ERR)
+        return NULL;
+    return objPtr->internalRep.refValue.refPtr;
+}
+
+int Jim_SetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr)
+{
+    Jim_Reference *refPtr;
+
+    if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL)
+        return JIM_ERR;
+    Jim_IncrRefCount(cmdNamePtr);
+    if (refPtr->finalizerCmdNamePtr)
+        Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr);
+    refPtr->finalizerCmdNamePtr = cmdNamePtr;
+    return JIM_OK;
+}
+
+int Jim_GetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr)
+{
+    Jim_Reference *refPtr;
+
+    if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL)
+        return JIM_ERR;
+    *cmdNamePtrPtr = refPtr->finalizerCmdNamePtr;
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * References Garbage Collection
+ * ---------------------------------------------------------------------------*/
+
+/* This the hash table type for the "MARK" phase of the GC */
+static const Jim_HashTableType JimRefMarkHashTableType = {
+    JimReferencesHTHashFunction,        /* hash function */
+    JimReferencesHTKeyDup,      /* key dup */
+    NULL,                       /* val dup */
+    JimReferencesHTKeyCompare,  /* key compare */
+    JimReferencesHTKeyDestructor,       /* key destructor */
+    NULL                        /* val destructor */
+};
+
+/* Performs the garbage collection. */
+int Jim_Collect(Jim_Interp *interp)
+{
+    int collected = 0;
+#ifndef JIM_BOOTSTRAP
+    Jim_HashTable marks;
+    Jim_HashTableIterator *htiter;
+    Jim_HashEntry *he;
+    Jim_Obj *objPtr;
+
+    /* Avoid recursive calls */
+    if (interp->lastCollectId == -1) {
+        /* Jim_Collect() already running. Return just now. */
+        return 0;
+    }
+    interp->lastCollectId = -1;
+
+    /* Mark all the references found into the 'mark' hash table.
+     * The references are searched in every live object that
+     * is of a type that can contain references. */
+    Jim_InitHashTable(&marks, &JimRefMarkHashTableType, NULL);
+    objPtr = interp->liveList;
+    while (objPtr) {
+        if (objPtr->typePtr == NULL || objPtr->typePtr->flags & JIM_TYPE_REFERENCES) {
+            const char *str, *p;
+            int len;
+
+            /* If the object is of type reference, to get the
+             * Id is simple... */
+            if (objPtr->typePtr == &referenceObjType) {
+                Jim_AddHashEntry(&marks, &objPtr->internalRep.refValue.id, NULL);
+#ifdef JIM_DEBUG_GC
+                printf("MARK (reference): %d refcount: %d" JIM_NL,
+                    (int)objPtr->internalRep.refValue.id, objPtr->refCount);
+#endif
+                objPtr = objPtr->nextObjPtr;
+                continue;
+            }
+            /* Get the string repr of the object we want
+             * to scan for references. */
+            p = str = Jim_GetString(objPtr, &len);
+            /* Skip objects too little to contain references. */
+            if (len < JIM_REFERENCE_SPACE) {
+                objPtr = objPtr->nextObjPtr;
+                continue;
+            }
+            /* Extract references from the object string repr. */
+            while (1) {
+                int i;
+                jim_wide id;
+                char buf[21];
+
+                if ((p = strstr(p, "<reference.<")) == NULL)
+                    break;
+                /* Check if it's a valid reference. */
+                if (len - (p - str) < JIM_REFERENCE_SPACE)
+                    break;
+                if (p[41] != '>' || p[19] != '>' || p[20] != '.')
+                    break;
+                for (i = 21; i <= 40; i++)
+                    if (!isdigit(UCHAR(p[i])))
+                        break;
+                /* Get the ID */
+                memcpy(buf, p + 21, 20);
+                buf[20] = '\0';
+                Jim_StringToWide(buf, &id, 10);
+
+                /* Ok, a reference for the given ID
+                 * was found. Mark it. */
+                Jim_AddHashEntry(&marks, &id, NULL);
+#ifdef JIM_DEBUG_GC
+                printf("MARK: %d" JIM_NL, (int)id);
+#endif
+                p += JIM_REFERENCE_SPACE;
+            }
+        }
+        objPtr = objPtr->nextObjPtr;
+    }
+
+    /* Run the references hash table to destroy every reference that
+     * is not referenced outside (not present in the mark HT). */
+    htiter = Jim_GetHashTableIterator(&interp->references);
+    while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+        const jim_wide *refId;
+        Jim_Reference *refPtr;
+
+        refId = he->key;
+        /* Check if in the mark phase we encountered
+         * this reference. */
+        if (Jim_FindHashEntry(&marks, refId) == NULL) {
+#ifdef JIM_DEBUG_GC
+            printf("COLLECTING %d" JIM_NL, (int)*refId);
+#endif
+            collected++;
+            /* Drop the reference, but call the
+             * finalizer first if registered. */
+            refPtr = he->u.val;
+            if (refPtr->finalizerCmdNamePtr) {
+                char *refstr = Jim_Alloc(JIM_REFERENCE_SPACE + 1);
+                Jim_Obj *objv[3], *oldResult;
+
+                JimFormatReference(refstr, refPtr, *refId);
+
+                objv[0] = refPtr->finalizerCmdNamePtr;
+                objv[1] = Jim_NewStringObjNoAlloc(interp, refstr, 32);
+                objv[2] = refPtr->objPtr;
+                Jim_IncrRefCount(objv[0]);
+                Jim_IncrRefCount(objv[1]);
+                Jim_IncrRefCount(objv[2]);
+
+                /* Drop the reference itself */
+                Jim_DeleteHashEntry(&interp->references, refId);
+
+                /* Call the finalizer. Errors ignored. */
+                oldResult = interp->result;
+                Jim_IncrRefCount(oldResult);
+                Jim_EvalObjVector(interp, 3, objv);
+                Jim_SetResult(interp, oldResult);
+                Jim_DecrRefCount(interp, oldResult);
+
+                Jim_DecrRefCount(interp, objv[0]);
+                Jim_DecrRefCount(interp, objv[1]);
+                Jim_DecrRefCount(interp, objv[2]);
+            }
+            else {
+                Jim_DeleteHashEntry(&interp->references, refId);
+            }
+        }
+    }
+    Jim_FreeHashTableIterator(htiter);
+    Jim_FreeHashTable(&marks);
+    interp->lastCollectId = interp->referenceNextId;
+    interp->lastCollectTime = time(NULL);
+#endif /* JIM_BOOTSTRAP */
+    return collected;
+}
+
+#define JIM_COLLECT_ID_PERIOD 5000
+#define JIM_COLLECT_TIME_PERIOD 300
+
+void Jim_CollectIfNeeded(Jim_Interp *interp)
+{
+    jim_wide elapsedId;
+    int elapsedTime;
+
+    elapsedId = interp->referenceNextId - interp->lastCollectId;
+    elapsedTime = time(NULL) - interp->lastCollectTime;
+
+
+    if (elapsedId > JIM_COLLECT_ID_PERIOD || elapsedTime > JIM_COLLECT_TIME_PERIOD) {
+        Jim_Collect(interp);
+    }
+}
+#endif
+
+static int JimIsBigEndian(void)
+{
+    union {
+        unsigned short s;
+        unsigned char c[2];
+    } uval = {0x0102};
+
+    return uval.c[0] == 1;
+}
+
+/* -----------------------------------------------------------------------------
+ * Interpreter related functions
+ * ---------------------------------------------------------------------------*/
+
+Jim_Interp *Jim_CreateInterp(void)
+{
+    Jim_Interp *i = Jim_Alloc(sizeof(*i));
+
+    memset(i, 0, sizeof(*i));
+
+    i->maxNestingDepth = JIM_MAX_NESTING_DEPTH;
+    i->lastCollectTime = time(NULL);
+
+    /* Note that we can create objects only after the
+     * interpreter liveList and freeList pointers are
+     * initialized to NULL. */
+    Jim_InitHashTable(&i->commands, &JimCommandsHashTableType, i);
+#ifdef JIM_REFERENCES
+    Jim_InitHashTable(&i->references, &JimReferencesHashTableType, i);
+#endif
+    Jim_InitHashTable(&i->assocData, &JimAssocDataHashTableType, i);
+    Jim_InitHashTable(&i->packages, &JimStringKeyValCopyHashTableType, NULL);
+    i->framePtr = i->topFramePtr = JimCreateCallFrame(i, NULL);
+    i->emptyObj = Jim_NewEmptyStringObj(i);
+    i->trueObj = Jim_NewIntObj(i, 1);
+    i->falseObj = Jim_NewIntObj(i, 0);
+    i->errorFileNameObj = i->emptyObj;
+    i->result = i->emptyObj;
+    i->stackTrace = Jim_NewListObj(i, NULL, 0);
+    i->unknown = Jim_NewStringObj(i, "unknown", -1);
+    i->errorProc = i->emptyObj;
+    i->currentScriptObj = Jim_NewEmptyStringObj(i);
+    Jim_IncrRefCount(i->emptyObj);
+    Jim_IncrRefCount(i->errorFileNameObj);
+    Jim_IncrRefCount(i->result);
+    Jim_IncrRefCount(i->stackTrace);
+    Jim_IncrRefCount(i->unknown);
+    Jim_IncrRefCount(i->currentScriptObj);
+    Jim_IncrRefCount(i->errorProc);
+    Jim_IncrRefCount(i->trueObj);
+    Jim_IncrRefCount(i->falseObj);
+
+    /* Initialize key variables every interpreter should contain */
+    Jim_SetVariableStrWithStr(i, JIM_LIBPATH, TCL_LIBRARY);
+    Jim_SetVariableStrWithStr(i, JIM_INTERACTIVE, "0");
+
+    Jim_SetVariableStrWithStr(i, "tcl_platform(os)", TCL_PLATFORM_OS);
+    Jim_SetVariableStrWithStr(i, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM);
+    Jim_SetVariableStrWithStr(i, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR);
+    Jim_SetVariableStrWithStr(i, "tcl_platform(byteOrder)", JimIsBigEndian() ? "bigEndian" : "littleEndian");
+    Jim_SetVariableStrWithStr(i, "tcl_platform(threaded)", "0");
+    Jim_SetVariableStr(i, "tcl_platform(pointerSize)", Jim_NewIntObj(i, sizeof(void *)));
+    Jim_SetVariableStr(i, "tcl_platform(wordSize)", Jim_NewIntObj(i, sizeof(jim_wide)));
+
+    return i;
+}
+
+void Jim_FreeInterp(Jim_Interp *i)
+{
+    Jim_CallFrame *cf = i->framePtr, *prevcf, *nextcf;
+    Jim_Obj *objPtr, *nextObjPtr;
+
+    Jim_DecrRefCount(i, i->emptyObj);
+    Jim_DecrRefCount(i, i->trueObj);
+    Jim_DecrRefCount(i, i->falseObj);
+    Jim_DecrRefCount(i, i->result);
+    Jim_DecrRefCount(i, i->stackTrace);
+    Jim_DecrRefCount(i, i->errorProc);
+    Jim_DecrRefCount(i, i->unknown);
+    Jim_DecrRefCount(i, i->errorFileNameObj);
+    Jim_DecrRefCount(i, i->currentScriptObj);
+    Jim_FreeHashTable(&i->commands);
+#ifdef JIM_REFERENCES
+    Jim_FreeHashTable(&i->references);
+#endif
+    Jim_FreeHashTable(&i->packages);
+    Jim_Free(i->prngState);
+    Jim_FreeHashTable(&i->assocData);
+    JimDeleteLocalProcs(i);
+
+    /* Free the call frames list */
+    while (cf) {
+        prevcf = cf->parentCallFrame;
+        JimFreeCallFrame(i, cf, JIM_FCF_NONE);
+        cf = prevcf;
+    }
+    /* Check that the live object list is empty, otherwise
+     * there is a memory leak. */
+    if (i->liveList != NULL) {
+        objPtr = i->liveList;
+
+        printf(JIM_NL "-------------------------------------" JIM_NL);
+        printf("Objects still in the free list:" JIM_NL);
+        while (objPtr) {
+            const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string";
+
+            printf("%p (%d) %-10s: '%.20s'" JIM_NL,
+                (void *)objPtr, objPtr->refCount, type, objPtr->bytes ? objPtr->bytes : "(null)");
+            if (objPtr->typePtr == &sourceObjType) {
+                printf("FILE %s LINE %d" JIM_NL,
+                    Jim_String(objPtr->internalRep.sourceValue.fileNameObj),
+                    objPtr->internalRep.sourceValue.lineNumber);
+            }
+            objPtr = objPtr->nextObjPtr;
+        }
+        printf("-------------------------------------" JIM_NL JIM_NL);
+        JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
+    }
+    /* Free all the freed objects. */
+    objPtr = i->freeList;
+    while (objPtr) {
+        nextObjPtr = objPtr->nextObjPtr;
+        Jim_Free(objPtr);
+        objPtr = nextObjPtr;
+    }
+    /* Free cached CallFrame structures */
+    cf = i->freeFramesList;
+    while (cf) {
+        nextcf = cf->nextFramePtr;
+        if (cf->vars.table != NULL)
+            Jim_Free(cf->vars.table);
+        Jim_Free(cf);
+        cf = nextcf;
+    }
+#ifdef jim_ext_load
+    Jim_FreeLoadHandles(i);
+#endif
+
+    /* Free the interpreter structure. */
+    Jim_Free(i);
+}
+
+/* Returns the call frame relative to the level represented by
+ * levelObjPtr. If levelObjPtr == NULL, the * level is assumed to be '1'.
+ *
+ * This function accepts the 'level' argument in the form
+ * of the commands [uplevel] and [upvar].
+ *
+ * For a function accepting a relative integer as level suitable
+ * for implementation of [info level ?level?] check the
+ * JimGetCallFrameByInteger() function.
+ *
+ * Returns NULL on error.
+ */
+Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr)
+{
+    long level;
+    const char *str;
+    Jim_CallFrame *framePtr;
+
+    if (levelObjPtr) {
+        str = Jim_String(levelObjPtr);
+        if (str[0] == '#') {
+            char *endptr;
+
+            level = strtol(str + 1, &endptr, 0);
+            if (str[1] == '\0' || endptr[0] != '\0') {
+                level = -1;
+            }
+        }
+        else {
+            if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0) {
+                level = -1;
+            }
+            else {
+                /* Convert from a relative to an absolute level */
+                level = interp->framePtr->level - level;
+            }
+        }
+    }
+    else {
+        str = "1";              /* Needed to format the error message. */
+        level = interp->framePtr->level - 1;
+    }
+
+    if (level == 0) {
+        return interp->topFramePtr;
+    }
+    if (level > 0) {
+        /* Lookup */
+        for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parentCallFrame) {
+            if (framePtr->level == level) {
+                return framePtr;
+            }
+        }
+    }
+
+    Jim_SetResultFormatted(interp, "bad level \"%s\"", str);
+    return NULL;
+}
+
+/* Similar to Jim_GetCallFrameByLevel() but the level is specified
+ * as a relative integer like in the [info level ?level?] command.
+ **/
+static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, Jim_Obj *levelObjPtr)
+{
+    long level;
+    Jim_CallFrame *framePtr;
+
+    if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
+        if (level <= 0) {
+            /* Convert from a relative to an absolute level */
+            level = interp->framePtr->level + level;
+        }
+
+        if (level == 0) {
+            return interp->topFramePtr;
+        }
+
+        /* Lookup */
+        for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parentCallFrame) {
+            if (framePtr->level == level) {
+                return framePtr;
+            }
+        }
+    }
+
+    Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
+    return NULL;
+}
+
+static void JimResetStackTrace(Jim_Interp *interp)
+{
+    Jim_DecrRefCount(interp, interp->stackTrace);
+    interp->stackTrace = Jim_NewListObj(interp, NULL, 0);
+    Jim_IncrRefCount(interp->stackTrace);
+}
+
+static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj)
+{
+    int len;
+
+    /* Increment reference first in case these are the same object */
+    Jim_IncrRefCount(stackTraceObj);
+    Jim_DecrRefCount(interp, interp->stackTrace);
+    interp->stackTrace = stackTraceObj;
+    interp->errorFlag = 1;
+
+    /* This is a bit ugly.
+     * If the filename of the last entry of the stack trace is empty,
+     * the next stack level should be added.
+     */
+    len = Jim_ListLength(interp, interp->stackTrace);
+    if (len >= 3) {
+        Jim_Obj *filenameObj;
+
+        Jim_ListIndex(interp, interp->stackTrace, len - 2, &filenameObj, JIM_NONE);
+
+        Jim_GetString(filenameObj, &len);
+
+        if (!Jim_Length(filenameObj)) {
+            interp->addStackTrace = 1;
+        }
+    }
+}
+
+/* Returns 1 if the stack trace information was used or 0 if not */
+static void JimAppendStackTrace(Jim_Interp *interp, const char *procname,
+    Jim_Obj *fileNameObj, int linenr)
+{
+    if (strcmp(procname, "unknown") == 0) {
+        procname = "";
+    }
+    if (!*procname && !Jim_Length(fileNameObj)) {
+        /* No useful info here */
+        return;
+    }
+
+    if (Jim_IsShared(interp->stackTrace)) {
+        Jim_DecrRefCount(interp, interp->stackTrace);
+        interp->stackTrace = Jim_DuplicateObj(interp, interp->stackTrace);
+        Jim_IncrRefCount(interp->stackTrace);
+    }
+
+    /* If we have no procname but the previous element did, merge with that frame */
+    if (!*procname && Jim_Length(fileNameObj)) {
+        /* Just a filename. Check the previous entry */
+        int len = Jim_ListLength(interp, interp->stackTrace);
+
+        if (len >= 3) {
+            Jim_Obj *objPtr;
+            if (Jim_ListIndex(interp, interp->stackTrace, len - 3, &objPtr, JIM_NONE) == JIM_OK && Jim_Length(objPtr)) {
+                /* Yes, the previous level had procname */
+                if (Jim_ListIndex(interp, interp->stackTrace, len - 2, &objPtr, JIM_NONE) == JIM_OK && !Jim_Length(objPtr)) {
+                    /* But no filename, so merge the new info with that frame */
+                    ListSetIndex(interp, interp->stackTrace, len - 2, fileNameObj, 0);
+                    ListSetIndex(interp, interp->stackTrace, len - 1, Jim_NewIntObj(interp, linenr), 0);
+                    return;
+                }
+            }
+        }
+    }
+
+    Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewStringObj(interp, procname, -1));
+    Jim_ListAppendElement(interp, interp->stackTrace, fileNameObj);
+    Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewIntObj(interp, linenr));
+}
+
+int Jim_SetAssocData(Jim_Interp *interp, const char *key, Jim_InterpDeleteProc * delProc,
+    void *data)
+{
+    AssocDataValue *assocEntryPtr = (AssocDataValue *) Jim_Alloc(sizeof(AssocDataValue));
+
+    assocEntryPtr->delProc = delProc;
+    assocEntryPtr->data = data;
+    return Jim_AddHashEntry(&interp->assocData, key, assocEntryPtr);
+}
+
+void *Jim_GetAssocData(Jim_Interp *interp, const char *key)
+{
+    Jim_HashEntry *entryPtr = Jim_FindHashEntry(&interp->assocData, key);
+
+    if (entryPtr != NULL) {
+        AssocDataValue *assocEntryPtr = (AssocDataValue *) entryPtr->u.val;
+
+        return assocEntryPtr->data;
+    }
+    return NULL;
+}
+
+int Jim_DeleteAssocData(Jim_Interp *interp, const char *key)
+{
+    return Jim_DeleteHashEntry(&interp->assocData, key);
+}
+
+int Jim_GetExitCode(Jim_Interp *interp)
+{
+    return interp->exitCode;
+}
+
+/* -----------------------------------------------------------------------------
+ * Integer object
+ * ---------------------------------------------------------------------------*/
+#define JIM_INTEGER_SPACE 24
+
+static void UpdateStringOfInt(struct Jim_Obj *objPtr);
+static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
+
+static const Jim_ObjType intObjType = {
+    "int",
+    NULL,
+    NULL,
+    UpdateStringOfInt,
+    JIM_TYPE_NONE,
+};
+
+/* A coerced double is closer to an int than a double.
+ * It is an int value temporarily masquerading as a double value.
+ * i.e. it has the same string value as an int and Jim_GetWide()
+ * succeeds, but also Jim_GetDouble() returns the value directly.
+ */
+static const Jim_ObjType coercedDoubleObjType = {
+    "coerced-double",
+    NULL,
+    NULL,
+    UpdateStringOfInt,
+    JIM_TYPE_NONE,
+};
+
+
+void UpdateStringOfInt(struct Jim_Obj *objPtr)
+{
+    int len;
+    char buf[JIM_INTEGER_SPACE + 1];
+
+    len = Jim_WideToString(buf, JimWideValue(objPtr));
+    objPtr->bytes = Jim_Alloc(len + 1);
+    memcpy(objPtr->bytes, buf, len + 1);
+    objPtr->length = len;
+}
+
+int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+    jim_wide wideValue;
+    const char *str;
+
+    if (objPtr->typePtr == &coercedDoubleObjType) {
+        /* Simple switcheroo */
+        objPtr->typePtr = &intObjType;
+        return JIM_OK;
+    }
+
+    /* Get the string representation */
+    str = Jim_String(objPtr);
+    /* Try to convert into a jim_wide */
+    if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) {
+        if (flags & JIM_ERRMSG) {
+            Jim_SetResultFormatted(interp, "expected integer but got \"%#s\"", objPtr);
+        }
+        return JIM_ERR;
+    }
+    if ((wideValue == JIM_WIDE_MIN || wideValue == JIM_WIDE_MAX) && errno == ERANGE) {
+        Jim_SetResultString(interp, "Integer value too big to be represented", -1);
+        return JIM_ERR;
+    }
+    /* Free the old internal repr and set the new one. */
+    Jim_FreeIntRep(interp, objPtr);
+    objPtr->typePtr = &intObjType;
+    objPtr->internalRep.wideValue = wideValue;
+    return JIM_OK;
+}
+
+#ifdef JIM_OPTIMIZATION
+static int JimIsWide(Jim_Obj *objPtr)
+{
+    return objPtr->typePtr == &intObjType;
+}
+#endif
+
+int Jim_GetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
+{
+    if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR)
+        return JIM_ERR;
+    *widePtr = JimWideValue(objPtr);
+    return JIM_OK;
+}
+
+/* Get a wide but does not set an error if the format is bad. */
+static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
+{
+    if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_NONE) == JIM_ERR)
+        return JIM_ERR;
+    *widePtr = JimWideValue(objPtr);
+    return JIM_OK;
+}
+
+int Jim_GetLong(Jim_Interp *interp, Jim_Obj *objPtr, long *longPtr)
+{
+    jim_wide wideValue;
+    int retval;
+
+    retval = Jim_GetWide(interp, objPtr, &wideValue);
+    if (retval == JIM_OK) {
+        *longPtr = (long)wideValue;
+        return JIM_OK;
+    }
+    return JIM_ERR;
+}
+
+Jim_Obj *Jim_NewIntObj(Jim_Interp *interp, jim_wide wideValue)
+{
+    Jim_Obj *objPtr;
+
+    objPtr = Jim_NewObj(interp);
+    objPtr->typePtr = &intObjType;
+    objPtr->bytes = NULL;
+    objPtr->internalRep.wideValue = wideValue;
+    return objPtr;
+}
+
+/* -----------------------------------------------------------------------------
+ * Double object
+ * ---------------------------------------------------------------------------*/
+#define JIM_DOUBLE_SPACE 30
+
+static void UpdateStringOfDouble(struct Jim_Obj *objPtr);
+static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
+
+static const Jim_ObjType doubleObjType = {
+    "double",
+    NULL,
+    NULL,
+    UpdateStringOfDouble,
+    JIM_TYPE_NONE,
+};
+
+void UpdateStringOfDouble(struct Jim_Obj *objPtr)
+{
+    int len;
+    char buf[JIM_DOUBLE_SPACE + 1];
+
+    len = Jim_DoubleToString(buf, objPtr->internalRep.doubleValue);
+    objPtr->bytes = Jim_Alloc(len + 1);
+    memcpy(objPtr->bytes, buf, len + 1);
+    objPtr->length = len;
+}
+
+int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    double doubleValue;
+    jim_wide wideValue;
+    const char *str;
+
+    /* Preserve the string representation.
+     * Needed so we can convert back to int without loss
+     */
+    str = Jim_String(objPtr);
+
+#ifdef HAVE_LONG_LONG
+    /* Assume a 53 bit mantissa */
+#define MIN_INT_IN_DOUBLE -(1LL << 53)
+#define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1)
+
+    if (objPtr->typePtr == &intObjType
+        && JimWideValue(objPtr) >= MIN_INT_IN_DOUBLE
+        && JimWideValue(objPtr) <= MAX_INT_IN_DOUBLE) {
+
+        /* Direct conversion to coerced double */
+        objPtr->typePtr = &coercedDoubleObjType;
+        return JIM_OK;
+    }
+    else
+#endif
+    if (Jim_StringToWide(str, &wideValue, 10) == JIM_OK) {
+        /* Managed to convert to an int, so we can use this as a cooerced double */
+        Jim_FreeIntRep(interp, objPtr);
+        objPtr->typePtr = &coercedDoubleObjType;
+        objPtr->internalRep.wideValue = wideValue;
+        return JIM_OK;
+    }
+    else {
+        /* Try to convert into a double */
+        if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) {
+            Jim_SetResultFormatted(interp, "expected number but got \"%#s\"", objPtr);
+            return JIM_ERR;
+        }
+        /* Free the old internal repr and set the new one. */
+        Jim_FreeIntRep(interp, objPtr);
+    }
+    objPtr->typePtr = &doubleObjType;
+    objPtr->internalRep.doubleValue = doubleValue;
+    return JIM_OK;
+}
+
+int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double *doublePtr)
+{
+    if (objPtr->typePtr == &coercedDoubleObjType) {
+        *doublePtr = JimWideValue(objPtr);
+        return JIM_OK;
+    }
+    if (objPtr->typePtr != &doubleObjType && SetDoubleFromAny(interp, objPtr) == JIM_ERR)
+        return JIM_ERR;
+
+    if (objPtr->typePtr == &coercedDoubleObjType) {
+        *doublePtr = JimWideValue(objPtr);
+    }
+    else {
+        *doublePtr = objPtr->internalRep.doubleValue;
+    }
+    return JIM_OK;
+}
+
+Jim_Obj *Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue)
+{
+    Jim_Obj *objPtr;
+
+    objPtr = Jim_NewObj(interp);
+    objPtr->typePtr = &doubleObjType;
+    objPtr->bytes = NULL;
+    objPtr->internalRep.doubleValue = doubleValue;
+    return objPtr;
+}
+
+/* -----------------------------------------------------------------------------
+ * List object
+ * ---------------------------------------------------------------------------*/
+static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr);
+static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static void UpdateStringOfList(struct Jim_Obj *objPtr);
+static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+/* Note that while the elements of the list may contain references,
+ * the list object itself can't. This basically means that the
+ * list object string representation as a whole can't contain references
+ * that are not presents in the single elements. */
+static const Jim_ObjType listObjType = {
+    "list",
+    FreeListInternalRep,
+    DupListInternalRep,
+    UpdateStringOfList,
+    JIM_TYPE_NONE,
+};
+
+void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    int i;
+
+    for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
+        Jim_DecrRefCount(interp, objPtr->internalRep.listValue.ele[i]);
+    }
+    Jim_Free(objPtr->internalRep.listValue.ele);
+}
+
+void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+    int i;
+
+    JIM_NOTUSED(interp);
+
+    dupPtr->internalRep.listValue.len = srcPtr->internalRep.listValue.len;
+    dupPtr->internalRep.listValue.maxLen = srcPtr->internalRep.listValue.maxLen;
+    dupPtr->internalRep.listValue.ele =
+        Jim_Alloc(sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.maxLen);
+    memcpy(dupPtr->internalRep.listValue.ele, srcPtr->internalRep.listValue.ele,
+        sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.len);
+    for (i = 0; i < dupPtr->internalRep.listValue.len; i++) {
+        Jim_IncrRefCount(dupPtr->internalRep.listValue.ele[i]);
+    }
+    dupPtr->typePtr = &listObjType;
+}
+
+/* The following function checks if a given string can be encoded
+ * into a list element without any kind of quoting, surrounded by braces,
+ * or using escapes to quote. */
+#define JIM_ELESTR_SIMPLE 0
+#define JIM_ELESTR_BRACE 1
+#define JIM_ELESTR_QUOTE 2
+static int ListElementQuotingType(const char *s, int len)
+{
+    int i, level, blevel, trySimple = 1;
+
+    /* Try with the SIMPLE case */
+    if (len == 0)
+        return JIM_ELESTR_BRACE;
+    if (s[0] == '#')
+        return JIM_ELESTR_BRACE;
+    if (s[0] == '"' || s[0] == '{') {
+        trySimple = 0;
+        goto testbrace;
+    }
+    for (i = 0; i < len; i++) {
+        switch (s[i]) {
+            case ' ':
+            case '$':
+            case '"':
+            case '[':
+            case ']':
+            case ';':
+            case '\\':
+            case '\r':
+            case '\n':
+            case '\t':
+            case '\f':
+            case '\v':
+                trySimple = 0;
+            case '{':
+            case '}':
+                goto testbrace;
+        }
+    }
+    return JIM_ELESTR_SIMPLE;
+
+  testbrace:
+    /* Test if it's possible to do with braces */
+    if (s[len - 1] == '\\')
+        return JIM_ELESTR_QUOTE;
+    level = 0;
+    blevel = 0;
+    for (i = 0; i < len; i++) {
+        switch (s[i]) {
+            case '{':
+                level++;
+                break;
+            case '}':
+                level--;
+                if (level < 0)
+                    return JIM_ELESTR_QUOTE;
+                break;
+            case '[':
+                blevel++;
+                break;
+            case ']':
+                blevel--;
+                break;
+            case '\\':
+                if (s[i + 1] == '\n')
+                    return JIM_ELESTR_QUOTE;
+                else if (s[i + 1] != '\0')
+                    i++;
+                break;
+        }
+    }
+    if (blevel < 0) {
+        return JIM_ELESTR_QUOTE;
+    }
+
+    if (level == 0) {
+        if (!trySimple)
+            return JIM_ELESTR_BRACE;
+        for (i = 0; i < len; i++) {
+            switch (s[i]) {
+                case ' ':
+                case '$':
+                case '"':
+                case '[':
+                case ']':
+                case ';':
+                case '\\':
+                case '\r':
+                case '\n':
+                case '\t':
+                case '\f':
+                case '\v':
+                    return JIM_ELESTR_BRACE;
+                    break;
+            }
+        }
+        return JIM_ELESTR_SIMPLE;
+    }
+    return JIM_ELESTR_QUOTE;
+}
+
+/* Returns the malloc-ed representation of a string
+ * using backslash to quote special chars. */
+static char *BackslashQuoteString(const char *s, int len, int *qlenPtr)
+{
+    char *q = Jim_Alloc(len * 2 + 1), *p;
+
+    p = q;
+    while (*s) {
+        switch (*s) {
+            case ' ':
+            case '$':
+            case '"':
+            case '[':
+            case ']':
+            case '{':
+            case '}':
+            case ';':
+            case '\\':
+                *p++ = '\\';
+                *p++ = *s++;
+                break;
+            case '\n':
+                *p++ = '\\';
+                *p++ = 'n';
+                s++;
+                break;
+            case '\r':
+                *p++ = '\\';
+                *p++ = 'r';
+                s++;
+                break;
+            case '\t':
+                *p++ = '\\';
+                *p++ = 't';
+                s++;
+                break;
+            case '\f':
+                *p++ = '\\';
+                *p++ = 'f';
+                s++;
+                break;
+            case '\v':
+                *p++ = '\\';
+                *p++ = 'v';
+                s++;
+                break;
+            default:
+                *p++ = *s++;
+                break;
+        }
+    }
+    *p = '\0';
+    *qlenPtr = p - q;
+    return q;
+}
+
+static void UpdateStringOfList(struct Jim_Obj *objPtr)
+{
+    int i, bufLen, realLength;
+    const char *strRep;
+    char *p;
+    int *quotingType;
+    Jim_Obj **ele = objPtr->internalRep.listValue.ele;
+
+    /* (Over) Estimate the space needed. */
+    quotingType = Jim_Alloc(sizeof(int) * objPtr->internalRep.listValue.len + 1);
+    bufLen = 0;
+    for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
+        int len;
+
+        strRep = Jim_GetString(ele[i], &len);
+        quotingType[i] = ListElementQuotingType(strRep, len);
+        switch (quotingType[i]) {
+            case JIM_ELESTR_SIMPLE:
+                bufLen += len;
+                break;
+            case JIM_ELESTR_BRACE:
+                bufLen += len + 2;
+                break;
+            case JIM_ELESTR_QUOTE:
+                bufLen += len * 2;
+                break;
+        }
+        bufLen++;               /* elements separator. */
+    }
+    bufLen++;
+
+    /* Generate the string rep. */
+    p = objPtr->bytes = Jim_Alloc(bufLen + 1);
+    realLength = 0;
+    for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
+        int len, qlen;
+        char *q;
+
+        strRep = Jim_GetString(ele[i], &len);
+
+        switch (quotingType[i]) {
+            case JIM_ELESTR_SIMPLE:
+                memcpy(p, strRep, len);
+                p += len;
+                realLength += len;
+                break;
+            case JIM_ELESTR_BRACE:
+                *p++ = '{';
+                memcpy(p, strRep, len);
+                p += len;
+                *p++ = '}';
+                realLength += len + 2;
+                break;
+            case JIM_ELESTR_QUOTE:
+                q = BackslashQuoteString(strRep, len, &qlen);
+                memcpy(p, q, qlen);
+                Jim_Free(q);
+                p += qlen;
+                realLength += qlen;
+                break;
+        }
+        /* Add a separating space */
+        if (i + 1 != objPtr->internalRep.listValue.len) {
+            *p++ = ' ';
+            realLength++;
+        }
+    }
+    *p = '\0';                  /* nul term. */
+    objPtr->length = realLength;
+    Jim_Free(quotingType);
+}
+
+int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+    struct JimParserCtx parser;
+    const char *str;
+    int strLen;
+    Jim_Obj *fileNameObj;
+    int linenr;
+
+    /* Try to preserve information about filename / line number */
+    if (objPtr->typePtr == &sourceObjType) {
+        fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
+        linenr = objPtr->internalRep.sourceValue.lineNumber;
+    }
+    else {
+        fileNameObj = interp->emptyObj;
+        linenr = 1;
+    }
+    Jim_IncrRefCount(fileNameObj);
+
+    /* Get the string representation */
+    str = Jim_GetString(objPtr, &strLen);
+
+    /* Free the old internal repr just now and initialize the
+     * new one just now. The string->list conversion can't fail. */
+    Jim_FreeIntRep(interp, objPtr);
+    objPtr->typePtr = &listObjType;
+    objPtr->internalRep.listValue.len = 0;
+    objPtr->internalRep.listValue.maxLen = 0;
+    objPtr->internalRep.listValue.ele = NULL;
+
+    /* Convert into a list */
+    JimParserInit(&parser, str, strLen, linenr);
+    while (!parser.eof) {
+        Jim_Obj *elementPtr;
+
+        JimParseList(&parser);
+        if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC)
+            continue;
+        elementPtr = JimParserGetTokenObj(interp, &parser);
+        JimSetSourceInfo(interp, elementPtr, fileNameObj, parser.tline);
+        ListAppendElement(objPtr, elementPtr);
+    }
+    Jim_DecrRefCount(interp, fileNameObj);
+    return JIM_OK;
+}
+
+Jim_Obj *Jim_NewListObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
+{
+    Jim_Obj *objPtr;
+    int i;
+
+    objPtr = Jim_NewObj(interp);
+    objPtr->typePtr = &listObjType;
+    objPtr->bytes = NULL;
+    objPtr->internalRep.listValue.ele = NULL;
+    objPtr->internalRep.listValue.len = 0;
+    objPtr->internalRep.listValue.maxLen = 0;
+    for (i = 0; i < len; i++) {
+        ListAppendElement(objPtr, elements[i]);
+    }
+    return objPtr;
+}
+
+/* Return a vector of Jim_Obj with the elements of a Jim list, and the
+ * length of the vector. Note that the user of this function should make
+ * sure that the list object can't shimmer while the vector returned
+ * is in use, this vector is the one stored inside the internal representation
+ * of the list object. This function is not exported, extensions should
+ * always access to the List object elements using Jim_ListIndex(). */
+static void JimListGetElements(Jim_Interp *interp, Jim_Obj *listObj, int *listLen,
+    Jim_Obj ***listVec)
+{
+    *listLen = Jim_ListLength(interp, listObj);
+    *listVec = listObj->internalRep.listValue.ele;
+}
+
+/* Sorting uses ints, but commands may return wide */
+static int JimSign(jim_wide w)
+{
+    if (w == 0) {
+        return 0;
+    }
+    else if (w < 0) {
+        return -1;
+    }
+    return 1;
+}
+
+/* ListSortElements type values */
+struct lsort_info {
+    jmp_buf jmpbuf;
+    Jim_Obj *command;
+    Jim_Interp *interp;
+    enum {
+        JIM_LSORT_ASCII,
+        JIM_LSORT_NOCASE,
+        JIM_LSORT_INTEGER,
+        JIM_LSORT_COMMAND
+    } type;
+    int order;
+    int index;
+    int indexed;
+    int (*subfn)(Jim_Obj **, Jim_Obj **);
+};
+
+static struct lsort_info *sort_info;
+
+static int ListSortIndexHelper(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+    Jim_Obj *lObj, *rObj;
+
+    if (Jim_ListIndex(sort_info->interp, *lhsObj, sort_info->index, &lObj, JIM_ERRMSG) != JIM_OK ||
+        Jim_ListIndex(sort_info->interp, *rhsObj, sort_info->index, &rObj, JIM_ERRMSG) != JIM_OK) {
+        longjmp(sort_info->jmpbuf, JIM_ERR);
+    }
+    return sort_info->subfn(&lObj, &rObj);
+}
+
+/* Sort the internal rep of a list. */
+static int ListSortString(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+    return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
+}
+
+static int ListSortStringNoCase(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+    return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 1) * sort_info->order;
+}
+
+static int ListSortInteger(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+    jim_wide lhs = 0, rhs = 0;
+
+    if (Jim_GetWide(sort_info->interp, *lhsObj, &lhs) != JIM_OK ||
+        Jim_GetWide(sort_info->interp, *rhsObj, &rhs) != JIM_OK) {
+        longjmp(sort_info->jmpbuf, JIM_ERR);
+    }
+
+    return JimSign(lhs - rhs) * sort_info->order;
+}
+
+static int ListSortCommand(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+    Jim_Obj *compare_script;
+    int rc;
+
+    jim_wide ret = 0;
+
+    /* This must be a valid list */
+    compare_script = Jim_DuplicateObj(sort_info->interp, sort_info->command);
+    Jim_ListAppendElement(sort_info->interp, compare_script, *lhsObj);
+    Jim_ListAppendElement(sort_info->interp, compare_script, *rhsObj);
+
+    rc = Jim_EvalObj(sort_info->interp, compare_script);
+
+    if (rc != JIM_OK || Jim_GetWide(sort_info->interp, Jim_GetResult(sort_info->interp), &ret) != JIM_OK) {
+        longjmp(sort_info->jmpbuf, rc);
+    }
+
+    return JimSign(ret) * sort_info->order;
+}
+
+/* Sort a list *in place*. MUST be called with non-shared objects. */
+static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info)
+{
+    struct lsort_info *prev_info;
+
+    typedef int (qsort_comparator) (const void *, const void *);
+    int (*fn) (Jim_Obj **, Jim_Obj **);
+    Jim_Obj **vector;
+    int len;
+    int rc;
+
+    JimPanic((Jim_IsShared(listObjPtr), "Jim_ListSortElements called with shared object"));
+    if (!Jim_IsList(listObjPtr))
+        SetListFromAny(interp, listObjPtr);
+
+    /* Allow lsort to be called reentrantly */
+    prev_info = sort_info;
+    sort_info = info;
+
+    vector = listObjPtr->internalRep.listValue.ele;
+    len = listObjPtr->internalRep.listValue.len;
+    switch (info->type) {
+        case JIM_LSORT_ASCII:
+            fn = ListSortString;
+            break;
+        case JIM_LSORT_NOCASE:
+            fn = ListSortStringNoCase;
+            break;
+        case JIM_LSORT_INTEGER:
+            fn = ListSortInteger;
+            break;
+        case JIM_LSORT_COMMAND:
+            fn = ListSortCommand;
+            break;
+        default:
+            fn = NULL;          /* avoid warning */
+            JimPanic((1, "ListSort called with invalid sort type"));
+    }
+
+    if (info->indexed) {
+        /* Need to interpose a "list index" function */
+        info->subfn = fn;
+        fn = ListSortIndexHelper;
+    }
+
+    if ((rc = setjmp(info->jmpbuf)) == 0) {
+        qsort(vector, len, sizeof(Jim_Obj *), (qsort_comparator *) fn);
+    }
+    Jim_InvalidateStringRep(listObjPtr);
+    sort_info = prev_info;
+
+    return rc;
+}
+
+/* This is the low-level function to insert elements into a list.
+ * The higher-level Jim_ListInsertElements() performs shared object
+ * check and invalidate the string repr. This version is used
+ * in the internals of the List Object and is not exported.
+ *
+ * NOTE: this function can be called only against objects
+ * with internal type of List. */
+static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec)
+{
+    int currentLen = listPtr->internalRep.listValue.len;
+    int requiredLen = currentLen + elemc;
+    int i;
+    Jim_Obj **point;
+
+    if (requiredLen > listPtr->internalRep.listValue.maxLen) {
+        int maxLen = requiredLen * 2;
+
+        listPtr->internalRep.listValue.ele =
+            Jim_Realloc(listPtr->internalRep.listValue.ele, sizeof(Jim_Obj *) * maxLen);
+        listPtr->internalRep.listValue.maxLen = maxLen;
+    }
+    point = listPtr->internalRep.listValue.ele + idx;
+    memmove(point + elemc, point, (currentLen - idx) * sizeof(Jim_Obj *));
+    for (i = 0; i < elemc; ++i) {
+        point[i] = elemVec[i];
+        Jim_IncrRefCount(point[i]);
+    }
+    listPtr->internalRep.listValue.len += elemc;
+}
+
+/* Convenience call to ListInsertElements() to append a single element.
+ */
+static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr)
+{
+    ListInsertElements(listPtr, listPtr->internalRep.listValue.len, 1, &objPtr);
+}
+
+
+/* Appends every element of appendListPtr into listPtr.
+ * Both have to be of the list type.
+ * Convenience call to ListInsertElements()
+ */
+static void ListAppendList(Jim_Obj *listPtr, Jim_Obj *appendListPtr)
+{
+    ListInsertElements(listPtr, listPtr->internalRep.listValue.len,
+        appendListPtr->internalRep.listValue.len, appendListPtr->internalRep.listValue.ele);
+}
+
+void Jim_ListAppendElement(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *objPtr)
+{
+    JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendElement called with shared object"));
+    if (!Jim_IsList(listPtr))
+        SetListFromAny(interp, listPtr);
+    Jim_InvalidateStringRep(listPtr);
+    ListAppendElement(listPtr, objPtr);
+}
+
+void Jim_ListAppendList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *appendListPtr)
+{
+    JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendList called with shared object"));
+    if (!Jim_IsList(listPtr))
+        SetListFromAny(interp, listPtr);
+    Jim_InvalidateStringRep(listPtr);
+    ListAppendList(listPtr, appendListPtr);
+}
+
+int Jim_ListLength(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    if (!Jim_IsList(objPtr))
+        SetListFromAny(interp, objPtr);
+    return objPtr->internalRep.listValue.len;
+}
+
+void Jim_ListInsertElements(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
+    int objc, Jim_Obj *const *objVec)
+{
+    JimPanic((Jim_IsShared(listPtr), "Jim_ListInsertElement called with shared object"));
+    if (!Jim_IsList(listPtr))
+        SetListFromAny(interp, listPtr);
+    if (idx >= 0 && idx > listPtr->internalRep.listValue.len)
+        idx = listPtr->internalRep.listValue.len;
+    else if (idx < 0)
+        idx = 0;
+    Jim_InvalidateStringRep(listPtr);
+    ListInsertElements(listPtr, idx, objc, objVec);
+}
+
+int Jim_ListIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx, Jim_Obj **objPtrPtr, int flags)
+{
+    if (!Jim_IsList(listPtr))
+        SetListFromAny(interp, listPtr);
+    if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) ||
+        (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) {
+        if (flags & JIM_ERRMSG) {
+            Jim_SetResultString(interp, "list index out of range", -1);
+        }
+        *objPtrPtr = NULL;
+        return JIM_ERR;
+    }
+    if (idx < 0)
+        idx = listPtr->internalRep.listValue.len + idx;
+    *objPtrPtr = listPtr->internalRep.listValue.ele[idx];
+    return JIM_OK;
+}
+
+static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
+    Jim_Obj *newObjPtr, int flags)
+{
+    if (!Jim_IsList(listPtr))
+        SetListFromAny(interp, listPtr);
+    if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) ||
+        (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) {
+        if (flags & JIM_ERRMSG) {
+            Jim_SetResultString(interp, "list index out of range", -1);
+        }
+        return JIM_ERR;
+    }
+    if (idx < 0)
+        idx = listPtr->internalRep.listValue.len + idx;
+    Jim_DecrRefCount(interp, listPtr->internalRep.listValue.ele[idx]);
+    listPtr->internalRep.listValue.ele[idx] = newObjPtr;
+    Jim_IncrRefCount(newObjPtr);
+    return JIM_OK;
+}
+
+/* Modify the list stored into the variable named 'varNamePtr'
+ * setting the element specified by the 'indexc' indexes objects in 'indexv',
+ * with the new element 'newObjptr'. */
+int Jim_SetListIndex(Jim_Interp *interp, Jim_Obj *varNamePtr,
+    Jim_Obj *const *indexv, int indexc, Jim_Obj *newObjPtr)
+{
+    Jim_Obj *varObjPtr, *objPtr, *listObjPtr;
+    int shared, i, idx;
+
+    varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG | JIM_UNSHARED);
+    if (objPtr == NULL)
+        return JIM_ERR;
+    if ((shared = Jim_IsShared(objPtr)))
+        varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
+    for (i = 0; i < indexc - 1; i++) {
+        listObjPtr = objPtr;
+        if (Jim_GetIndex(interp, indexv[i], &idx) != JIM_OK)
+            goto err;
+        if (Jim_ListIndex(interp, listObjPtr, idx, &objPtr, JIM_ERRMSG) != JIM_OK) {
+            goto err;
+        }
+        if (Jim_IsShared(objPtr)) {
+            objPtr = Jim_DuplicateObj(interp, objPtr);
+            ListSetIndex(interp, listObjPtr, idx, objPtr, JIM_NONE);
+        }
+        Jim_InvalidateStringRep(listObjPtr);
+    }
+    if (Jim_GetIndex(interp, indexv[indexc - 1], &idx) != JIM_OK)
+        goto err;
+    if (ListSetIndex(interp, objPtr, idx, newObjPtr, JIM_ERRMSG) == JIM_ERR)
+        goto err;
+    Jim_InvalidateStringRep(objPtr);
+    Jim_InvalidateStringRep(varObjPtr);
+    if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK)
+        goto err;
+    Jim_SetResult(interp, varObjPtr);
+    return JIM_OK;
+  err:
+    if (shared) {
+        Jim_FreeNewObj(interp, varObjPtr);
+    }
+    return JIM_ERR;
+}
+
+Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
+{
+    int i;
+
+    /* If all the objects in objv are lists,
+     * it's possible to return a list as result, that's the
+     * concatenation of all the lists. */
+    for (i = 0; i < objc; i++) {
+        if (!Jim_IsList(objv[i]))
+            break;
+    }
+    if (i == objc) {
+        Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
+
+        for (i = 0; i < objc; i++)
+            Jim_ListAppendList(interp, objPtr, objv[i]);
+        return objPtr;
+    }
+    else {
+        /* Else... we have to glue strings together */
+        int len = 0, objLen;
+        char *bytes, *p;
+
+        /* Compute the length */
+        for (i = 0; i < objc; i++) {
+            Jim_GetString(objv[i], &objLen);
+            len += objLen;
+        }
+        if (objc)
+            len += objc - 1;
+        /* Create the string rep, and a string object holding it. */
+        p = bytes = Jim_Alloc(len + 1);
+        for (i = 0; i < objc; i++) {
+            const char *s = Jim_GetString(objv[i], &objLen);
+
+            /* Remove leading space */
+            while (objLen && (*s == ' ' || *s == '\t' || *s == '\n')) {
+                s++;
+                objLen--;
+                len--;
+            }
+            /* And trailing space */
+            while (objLen && (s[objLen - 1] == ' ' ||
+                    s[objLen - 1] == '\n' || s[objLen - 1] == '\t')) {
+                /* Handle trailing backslash-space case */
+                if (objLen > 1 && s[objLen - 2] == '\\') {
+                    break;
+                }
+                objLen--;
+                len--;
+            }
+            memcpy(p, s, objLen);
+            p += objLen;
+            if (objLen && i + 1 != objc) {
+                *p++ = ' ';
+            }
+            else if (i + 1 != objc) {
+                /* Drop the space calcuated for this
+                 * element that is instead null. */
+                len--;
+            }
+        }
+        *p = '\0';
+        return Jim_NewStringObjNoAlloc(interp, bytes, len);
+    }
+}
+
+/* Returns a list composed of the elements in the specified range.
+ * first and start are directly accepted as Jim_Objects and
+ * processed for the end?-index? case. */
+Jim_Obj *Jim_ListRange(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *firstObjPtr,
+    Jim_Obj *lastObjPtr)
+{
+    int first, last;
+    int len, rangeLen;
+
+    if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
+        Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
+        return NULL;
+    len = Jim_ListLength(interp, listObjPtr);   /* will convert into list */
+    first = JimRelToAbsIndex(len, first);
+    last = JimRelToAbsIndex(len, last);
+    JimRelToAbsRange(len, first, last, &first, &last, &rangeLen);
+    if (first == 0 && last == len) {
+        return listObjPtr;
+    }
+    return Jim_NewListObj(interp, listObjPtr->internalRep.listValue.ele + first, rangeLen);
+}
+
+/* -----------------------------------------------------------------------------
+ * Dict object
+ * ---------------------------------------------------------------------------*/
+static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static void UpdateStringOfDict(struct Jim_Obj *objPtr);
+static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+/* Dict HashTable Type.
+ *
+ * Keys and Values are Jim objects. */
+
+static unsigned int JimObjectHTHashFunction(const void *key)
+{
+    const char *str;
+    Jim_Obj *objPtr = (Jim_Obj *)key;
+    int len;
+
+    str = Jim_GetString(objPtr, &len);
+    return Jim_GenHashFunction((unsigned char *)str, len);
+}
+
+static int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2)
+{
+    JIM_NOTUSED(privdata);
+
+    return Jim_StringEqObj((Jim_Obj *)key1, (Jim_Obj *)key2);
+}
+
+static void JimObjectHTKeyValDestructor(void *interp, void *val)
+{
+    Jim_Obj *objPtr = val;
+
+    Jim_DecrRefCount(interp, objPtr);
+}
+
+static const Jim_HashTableType JimDictHashTableType = {
+    JimObjectHTHashFunction,    /* hash function */
+    NULL,                       /* key dup */
+    NULL,                       /* val dup */
+    JimObjectHTKeyCompare,      /* key compare */
+    (void (*)(void *, const void *))    /* ATTENTION: const cast */
+        JimObjectHTKeyValDestructor,    /* key destructor */
+    JimObjectHTKeyValDestructor /* val destructor */
+};
+
+/* Note that while the elements of the dict may contain references,
+ * the list object itself can't. This basically means that the
+ * dict object string representation as a whole can't contain references
+ * that are not presents in the single elements. */
+static const Jim_ObjType dictObjType = {
+    "dict",
+    FreeDictInternalRep,
+    DupDictInternalRep,
+    UpdateStringOfDict,
+    JIM_TYPE_NONE,
+};
+
+void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    JIM_NOTUSED(interp);
+
+    Jim_FreeHashTable(objPtr->internalRep.ptr);
+    Jim_Free(objPtr->internalRep.ptr);
+}
+
+void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+    Jim_HashTable *ht, *dupHt;
+    Jim_HashTableIterator *htiter;
+    Jim_HashEntry *he;
+
+    /* Create a new hash table */
+    ht = srcPtr->internalRep.ptr;
+    dupHt = Jim_Alloc(sizeof(*dupHt));
+    Jim_InitHashTable(dupHt, &JimDictHashTableType, interp);
+    if (ht->size != 0)
+        Jim_ExpandHashTable(dupHt, ht->size);
+    /* Copy every element from the source to the dup hash table */
+    htiter = Jim_GetHashTableIterator(ht);
+    while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+        const Jim_Obj *keyObjPtr = he->key;
+        Jim_Obj *valObjPtr = he->u.val;
+
+        Jim_IncrRefCount((Jim_Obj *)keyObjPtr); /* ATTENTION: const cast */
+        Jim_IncrRefCount(valObjPtr);
+        Jim_AddHashEntry(dupHt, keyObjPtr, valObjPtr);
+    }
+    Jim_FreeHashTableIterator(htiter);
+
+    dupPtr->internalRep.ptr = dupHt;
+    dupPtr->typePtr = &dictObjType;
+}
+
+void UpdateStringOfDict(struct Jim_Obj *objPtr)
+{
+    int i, bufLen, realLength;
+    const char *strRep;
+    char *p;
+    int *quotingType, objc;
+    Jim_HashTable *ht;
+    Jim_HashTableIterator *htiter;
+    Jim_HashEntry *he;
+    Jim_Obj **objv;
+
+    /* Trun the hash table into a flat vector of Jim_Objects. */
+    ht = objPtr->internalRep.ptr;
+    objc = ht->used * 2;
+    objv = Jim_Alloc(objc * sizeof(Jim_Obj *));
+    htiter = Jim_GetHashTableIterator(ht);
+    i = 0;
+    while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+        objv[i++] = (Jim_Obj *)he->key; /* ATTENTION: const cast */
+        objv[i++] = he->u.val;
+    }
+    Jim_FreeHashTableIterator(htiter);
+    /* (Over) Estimate the space needed. */
+    quotingType = Jim_Alloc(sizeof(int) * objc);
+    bufLen = 0;
+    for (i = 0; i < objc; i++) {
+        int len;
+
+        strRep = Jim_GetString(objv[i], &len);
+        quotingType[i] = ListElementQuotingType(strRep, len);
+        switch (quotingType[i]) {
+            case JIM_ELESTR_SIMPLE:
+                bufLen += len;
+                break;
+            case JIM_ELESTR_BRACE:
+                bufLen += len + 2;
+                break;
+            case JIM_ELESTR_QUOTE:
+                bufLen += len * 2;
+                break;
+        }
+        bufLen++;               /* elements separator. */
+    }
+    bufLen++;
+
+    /* Generate the string rep. */
+    p = objPtr->bytes = Jim_Alloc(bufLen + 1);
+    realLength = 0;
+    for (i = 0; i < objc; i++) {
+        int len, qlen;
+        char *q;
+
+        strRep = Jim_GetString(objv[i], &len);
+
+        switch (quotingType[i]) {
+            case JIM_ELESTR_SIMPLE:
+                memcpy(p, strRep, len);
+                p += len;
+                realLength += len;
+                break;
+            case JIM_ELESTR_BRACE:
+                *p++ = '{';
+                memcpy(p, strRep, len);
+                p += len;
+                *p++ = '}';
+                realLength += len + 2;
+                break;
+            case JIM_ELESTR_QUOTE:
+                q = BackslashQuoteString(strRep, len, &qlen);
+                memcpy(p, q, qlen);
+                Jim_Free(q);
+                p += qlen;
+                realLength += qlen;
+                break;
+        }
+        /* Add a separating space */
+        if (i + 1 != objc) {
+            *p++ = ' ';
+            realLength++;
+        }
+    }
+    *p = '\0';                  /* nul term. */
+    objPtr->length = realLength;
+    Jim_Free(quotingType);
+    Jim_Free(objv);
+}
+
+static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+    int listlen;
+
+    /* Get the string representation. Do this first so we don't
+     * change order in case of fast conversion to dict.
+     */
+    Jim_String(objPtr);
+
+    /* For simplicity, convert a non-list object to a list and then to a dict */
+    listlen = Jim_ListLength(interp, objPtr);
+    if (listlen % 2) {
+        Jim_SetResultString(interp,
+            "invalid dictionary value: must be a list with an even number of elements", -1);
+        return JIM_ERR;
+    }
+    else {
+        /* Now it is easy to convert to a dict from a list, and it can't fail */
+        Jim_HashTable *ht;
+        int i;
+
+        ht = Jim_Alloc(sizeof(*ht));
+        Jim_InitHashTable(ht, &JimDictHashTableType, interp);
+
+        for (i = 0; i < listlen; i += 2) {
+            Jim_Obj *keyObjPtr;
+            Jim_Obj *valObjPtr;
+
+            Jim_ListIndex(interp, objPtr, i, &keyObjPtr, JIM_NONE);
+            Jim_ListIndex(interp, objPtr, i + 1, &valObjPtr, JIM_NONE);
+
+            Jim_IncrRefCount(keyObjPtr);
+            Jim_IncrRefCount(valObjPtr);
+
+            if (Jim_AddHashEntry(ht, keyObjPtr, valObjPtr) != JIM_OK) {
+                Jim_HashEntry *he;
+
+                he = Jim_FindHashEntry(ht, keyObjPtr);
+                Jim_DecrRefCount(interp, keyObjPtr);
+                /* ATTENTION: const cast */
+                Jim_DecrRefCount(interp, (Jim_Obj *)he->u.val);
+                he->u.val = valObjPtr;
+            }
+        }
+
+        Jim_FreeIntRep(interp, objPtr);
+        objPtr->typePtr = &dictObjType;
+        objPtr->internalRep.ptr = ht;
+
+        return JIM_OK;
+    }
+}
+
+/* Dict object API */
+
+/* Add an element to a dict. objPtr must be of the "dict" type.
+ * The higer-level exported function is Jim_DictAddElement().
+ * If an element with the specified key already exists, the value
+ * associated is replaced with the new one.
+ *
+ * if valueObjPtr == NULL, the key is instead removed if it exists. */
+static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
+    Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
+{
+    Jim_HashTable *ht = objPtr->internalRep.ptr;
+
+    if (valueObjPtr == NULL) {  /* unset */
+        return Jim_DeleteHashEntry(ht, keyObjPtr);
+    }
+    Jim_IncrRefCount(keyObjPtr);
+    Jim_IncrRefCount(valueObjPtr);
+    if (Jim_AddHashEntry(ht, keyObjPtr, valueObjPtr) != JIM_OK) {
+        Jim_HashEntry *he = Jim_FindHashEntry(ht, keyObjPtr);
+
+        Jim_DecrRefCount(interp, keyObjPtr);
+        /* ATTENTION: const cast */
+        Jim_DecrRefCount(interp, (Jim_Obj *)he->u.val);
+        he->u.val = valueObjPtr;
+    }
+    return JIM_OK;
+}
+
+/* Add an element, higher-level interface for DictAddElement().
+ * If valueObjPtr == NULL, the key is removed if it exists. */
+int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
+    Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
+{
+    int retcode;
+
+    JimPanic((Jim_IsShared(objPtr), "Jim_DictAddElement called with shared object"));
+    if (objPtr->typePtr != &dictObjType) {
+        if (SetDictFromAny(interp, objPtr) != JIM_OK)
+            return JIM_ERR;
+    }
+    retcode = DictAddElement(interp, objPtr, keyObjPtr, valueObjPtr);
+    Jim_InvalidateStringRep(objPtr);
+    return retcode;
+}
+
+Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
+{
+    Jim_Obj *objPtr;
+    int i;
+
+    JimPanic((len % 2, "Jim_NewDictObj() 'len' argument must be even"));
+
+    objPtr = Jim_NewObj(interp);
+    objPtr->typePtr = &dictObjType;
+    objPtr->bytes = NULL;
+    objPtr->internalRep.ptr = Jim_Alloc(sizeof(Jim_HashTable));
+    Jim_InitHashTable(objPtr->internalRep.ptr, &JimDictHashTableType, interp);
+    for (i = 0; i < len; i += 2)
+        DictAddElement(interp, objPtr, elements[i], elements[i + 1]);
+    return objPtr;
+}
+
+/* Return the value associated to the specified dict key
+ * Note: Returns JIM_OK if OK, JIM_ERR if entry not found or -1 if can't create dict value
+ */
+int Jim_DictKey(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *keyPtr,
+    Jim_Obj **objPtrPtr, int flags)
+{
+    Jim_HashEntry *he;
+    Jim_HashTable *ht;
+
+    if (dictPtr->typePtr != &dictObjType) {
+        if (SetDictFromAny(interp, dictPtr) != JIM_OK)
+            return -1;
+    }
+    ht = dictPtr->internalRep.ptr;
+    if ((he = Jim_FindHashEntry(ht, keyPtr)) == NULL) {
+        if (flags & JIM_ERRMSG) {
+            Jim_SetResultFormatted(interp, "key \"%#s\" not found in dictionary", keyPtr);
+        }
+        return JIM_ERR;
+    }
+    *objPtrPtr = he->u.val;
+    return JIM_OK;
+}
+
+/* Return an allocated array of key/value pairs for the dictionary. Stores the length in *len */
+int Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len)
+{
+    Jim_HashTable *ht;
+    Jim_HashTableIterator *htiter;
+    Jim_HashEntry *he;
+    Jim_Obj **objv;
+    int i;
+
+    if (dictPtr->typePtr != &dictObjType) {
+        if (SetDictFromAny(interp, dictPtr) != JIM_OK)
+            return JIM_ERR;
+    }
+    ht = dictPtr->internalRep.ptr;
+
+    /* Turn the hash table into a flat vector of Jim_Objects. */
+    objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *));
+    htiter = Jim_GetHashTableIterator(ht);
+    i = 0;
+    while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+        objv[i++] = (Jim_Obj *)he->key; /* ATTENTION: const cast */
+        objv[i++] = he->u.val;
+    }
+    *len = i;
+    Jim_FreeHashTableIterator(htiter);
+    *objPtrPtr = objv;
+    return JIM_OK;
+}
+
+
+/* Return the value associated to the specified dict keys */
+int Jim_DictKeysVector(Jim_Interp *interp, Jim_Obj *dictPtr,
+    Jim_Obj *const *keyv, int keyc, Jim_Obj **objPtrPtr, int flags)
+{
+    int i;
+
+    if (keyc == 0) {
+        *objPtrPtr = dictPtr;
+        return JIM_OK;
+    }
+
+    for (i = 0; i < keyc; i++) {
+        Jim_Obj *objPtr;
+
+        if (Jim_DictKey(interp, dictPtr, keyv[i], &objPtr, flags)
+            != JIM_OK)
+            return JIM_ERR;
+        dictPtr = objPtr;
+    }
+    *objPtrPtr = dictPtr;
+    return JIM_OK;
+}
+
+/* Modify the dict stored into the variable named 'varNamePtr'
+ * setting the element specified by the 'keyc' keys objects in 'keyv',
+ * with the new value of the element 'newObjPtr'.
+ *
+ * If newObjPtr == NULL the operation is to remove the given key
+ * from the dictionary.
+ *
+ * If flags & JIM_ERRMSG, then failure to remove the key is considered an error
+ * and JIM_ERR is returned. Otherwise it is ignored and JIM_OK is returned.
+ */
+int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr,
+    Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr, int flags)
+{
+    Jim_Obj *varObjPtr, *objPtr, *dictObjPtr;
+    int shared, i;
+
+    varObjPtr = objPtr =
+        Jim_GetVariable(interp, varNamePtr, newObjPtr == NULL ? JIM_ERRMSG : JIM_NONE);
+    if (objPtr == NULL) {
+        if (newObjPtr == NULL)  /* Cannot remove a key from non existing var */ {
+            return JIM_ERR;
+        }
+        varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0);
+        if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) {
+            Jim_FreeNewObj(interp, varObjPtr);
+            return JIM_ERR;
+        }
+    }
+    if ((shared = Jim_IsShared(objPtr)))
+        varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
+    for (i = 0; i < keyc - 1; i++) {
+        dictObjPtr = objPtr;
+
+        /* Check if it's a valid dictionary */
+        if (dictObjPtr->typePtr != &dictObjType) {
+            if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) {
+                goto err;
+            }
+        }
+        /* Check if the given key exists. */
+        Jim_InvalidateStringRep(dictObjPtr);
+        if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr,
+                newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK) {
+            /* This key exists at the current level.
+             * Make sure it's not shared!. */
+            if (Jim_IsShared(objPtr)) {
+                objPtr = Jim_DuplicateObj(interp, objPtr);
+                DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
+            }
+        }
+        else {
+            /* Key not found. If it's an [unset] operation
+             * this is an error. Only the last key may not
+             * exist. */
+            if (newObjPtr == NULL) {
+                goto err;
+            }
+            /* Otherwise set an empty dictionary
+             * as key's value. */
+            objPtr = Jim_NewDictObj(interp, NULL, 0);
+            DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
+        }
+    }
+    /* Note error on unset with missing last key is OK */
+    if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) {
+        if (newObjPtr || (flags & JIM_ERRMSG)) {
+            goto err;
+        }
+    }
+    Jim_InvalidateStringRep(objPtr);
+    Jim_InvalidateStringRep(varObjPtr);
+    if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) {
+        goto err;
+    }
+    Jim_SetResult(interp, varObjPtr);
+    return JIM_OK;
+  err:
+    if (shared) {
+        Jim_FreeNewObj(interp, varObjPtr);
+    }
+    return JIM_ERR;
+}
+
+/* -----------------------------------------------------------------------------
+ * Index object
+ * ---------------------------------------------------------------------------*/
+static void UpdateStringOfIndex(struct Jim_Obj *objPtr);
+static int SetIndexFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType indexObjType = {
+    "index",
+    NULL,
+    NULL,
+    UpdateStringOfIndex,
+    JIM_TYPE_NONE,
+};
+
+void UpdateStringOfIndex(struct Jim_Obj *objPtr)
+{
+    int len;
+    char buf[JIM_INTEGER_SPACE + 1];
+
+    if (objPtr->internalRep.indexValue >= 0)
+        len = sprintf(buf, "%d", objPtr->internalRep.indexValue);
+    else if (objPtr->internalRep.indexValue == -1)
+        len = sprintf(buf, "end");
+    else {
+        len = sprintf(buf, "end%d", objPtr->internalRep.indexValue + 1);
+    }
+    objPtr->bytes = Jim_Alloc(len + 1);
+    memcpy(objPtr->bytes, buf, len + 1);
+    objPtr->length = len;
+}
+
+int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    int idx, end = 0;
+    const char *str;
+    char *endptr;
+
+    /* Get the string representation */
+    str = Jim_String(objPtr);
+
+    /* Try to convert into an index */
+    if (strncmp(str, "end", 3) == 0) {
+        end = 1;
+        str += 3;
+        idx = 0;
+    }
+    else {
+        idx = strtol(str, &endptr, 10);
+
+        if (endptr == str) {
+            goto badindex;
+        }
+        str = endptr;
+    }
+
+    /* Now str may include or +<num> or -<num> */
+    if (*str == '+' || *str == '-') {
+        int sign = (*str == '+' ? 1 : -1);
+
+        idx += sign * strtol(++str, &endptr, 10);
+        if (str == endptr || *endptr) {
+            goto badindex;
+        }
+        str = endptr;
+    }
+    /* The only thing left should be spaces */
+    while (isspace(UCHAR(*str))) {
+        str++;
+    }
+    if (*str) {
+        goto badindex;
+    }
+    if (end) {
+        if (idx > 0) {
+            idx = INT_MAX;
+        }
+        else {
+            /* end-1 is repesented as -2 */
+            idx--;
+        }
+    }
+    else if (idx < 0) {
+        idx = -INT_MAX;
+    }
+
+    /* Free the old internal repr and set the new one. */
+    Jim_FreeIntRep(interp, objPtr);
+    objPtr->typePtr = &indexObjType;
+    objPtr->internalRep.indexValue = idx;
+    return JIM_OK;
+
+  badindex:
+    Jim_SetResultFormatted(interp,
+        "bad index \"%#s\": must be integer?[+-]integer? or end?[+-]integer?", objPtr);
+    return JIM_ERR;
+}
+
+int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
+{
+    /* Avoid shimmering if the object is an integer. */
+    if (objPtr->typePtr == &intObjType) {
+        jim_wide val = JimWideValue(objPtr);
+
+        if (!(val < LONG_MIN) && !(val > LONG_MAX)) {
+            *indexPtr = (val < 0) ? -INT_MAX : (long)val;;
+            return JIM_OK;
+        }
+    }
+    if (objPtr->typePtr != &indexObjType && SetIndexFromAny(interp, objPtr) == JIM_ERR)
+        return JIM_ERR;
+    *indexPtr = objPtr->internalRep.indexValue;
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * Return Code Object.
+ * ---------------------------------------------------------------------------*/
+
+/* NOTE: These must be kept in the same order as JIM_OK, JIM_ERR, ... */
+static const char * const jimReturnCodes[] = {
+    [JIM_OK] = "ok",
+    [JIM_ERR] = "error",
+    [JIM_RETURN] = "return",
+    [JIM_BREAK] = "break",
+    [JIM_CONTINUE] = "continue",
+    [JIM_SIGNAL] = "signal",
+    [JIM_EXIT] = "exit",
+    [JIM_EVAL] = "eval",
+    NULL
+};
+
+#define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes))
+
+static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
+
+static const Jim_ObjType returnCodeObjType = {
+    "return-code",
+    NULL,
+    NULL,
+    NULL,
+    JIM_TYPE_NONE,
+};
+
+/* Converts a (standard) return code to a string. Returns "?" for
+ * non-standard return codes.
+ */
+const char *Jim_ReturnCode(int code)
+{
+    if (code < 0 || code >= (int)jimReturnCodesSize) {
+        return "?";
+    }
+    else {
+        return jimReturnCodes[code];
+    }
+}
+
+int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    int returnCode;
+    jim_wide wideValue;
+
+    /* Try to convert into an integer */
+    if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR)
+        returnCode = (int)wideValue;
+    else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) {
+        Jim_SetResultFormatted(interp, "expected return code but got \"%#s\"", objPtr);
+        return JIM_ERR;
+    }
+    /* Free the old internal repr and set the new one. */
+    Jim_FreeIntRep(interp, objPtr);
+    objPtr->typePtr = &returnCodeObjType;
+    objPtr->internalRep.returnCode = returnCode;
+    return JIM_OK;
+}
+
+int Jim_GetReturnCode(Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr)
+{
+    if (objPtr->typePtr != &returnCodeObjType && SetReturnCodeFromAny(interp, objPtr) == JIM_ERR)
+        return JIM_ERR;
+    *intPtr = objPtr->internalRep.returnCode;
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * Expression Parsing
+ * ---------------------------------------------------------------------------*/
+static int JimParseExprOperator(struct JimParserCtx *pc);
+static int JimParseExprNumber(struct JimParserCtx *pc);
+static int JimParseExprIrrational(struct JimParserCtx *pc);
+
+/* Exrp's Stack machine operators opcodes. */
+
+/* Binary operators (numbers) */
+enum
+{
+    /* Continues on from the JIM_TT_ space */
+    /* Operations */
+    JIM_EXPROP_MUL = JIM_TT_EXPR_OP,    /* 15 */
+    JIM_EXPROP_DIV,
+    JIM_EXPROP_MOD,
+    JIM_EXPROP_SUB,
+    JIM_EXPROP_ADD,
+    JIM_EXPROP_LSHIFT,
+    JIM_EXPROP_RSHIFT,
+    JIM_EXPROP_ROTL,
+    JIM_EXPROP_ROTR,
+    JIM_EXPROP_LT,
+    JIM_EXPROP_GT,
+    JIM_EXPROP_LTE,
+    JIM_EXPROP_GTE,
+    JIM_EXPROP_NUMEQ,
+    JIM_EXPROP_NUMNE,
+    JIM_EXPROP_BITAND,          /* 30 */
+    JIM_EXPROP_BITXOR,
+    JIM_EXPROP_BITOR,
+
+    /* Note must keep these together */
+    JIM_EXPROP_LOGICAND,        /* 33 */
+    JIM_EXPROP_LOGICAND_LEFT,
+    JIM_EXPROP_LOGICAND_RIGHT,
+
+    /* and these */
+    JIM_EXPROP_LOGICOR,         /* 36 */
+    JIM_EXPROP_LOGICOR_LEFT,
+    JIM_EXPROP_LOGICOR_RIGHT,
+
+    /* and these */
+    /* Ternary operators */
+    JIM_EXPROP_TERNARY,         /* 39 */
+    JIM_EXPROP_TERNARY_LEFT,
+    JIM_EXPROP_TERNARY_RIGHT,
+
+    /* and these */
+    JIM_EXPROP_COLON,           /* 42 */
+    JIM_EXPROP_COLON_LEFT,
+    JIM_EXPROP_COLON_RIGHT,
+
+    JIM_EXPROP_POW,             /* 45 */
+
+/* Binary operators (strings) */
+    JIM_EXPROP_STREQ,
+    JIM_EXPROP_STRNE,
+    JIM_EXPROP_STRIN,
+    JIM_EXPROP_STRNI,
+
+/* Unary operators (numbers) */
+    JIM_EXPROP_NOT,
+    JIM_EXPROP_BITNOT,
+    JIM_EXPROP_UNARYMINUS,
+    JIM_EXPROP_UNARYPLUS,
+
+    /* Functions */
+    JIM_EXPROP_FUNC_FIRST,
+    JIM_EXPROP_FUNC_INT = JIM_EXPROP_FUNC_FIRST,
+    JIM_EXPROP_FUNC_ABS,
+    JIM_EXPROP_FUNC_DOUBLE,
+    JIM_EXPROP_FUNC_ROUND,
+    JIM_EXPROP_FUNC_RAND,
+    JIM_EXPROP_FUNC_SRAND,
+
+    /* math functions from libm */
+    JIM_EXPROP_FUNC_SIN,
+    JIM_EXPROP_FUNC_COS,
+    JIM_EXPROP_FUNC_TAN,
+    JIM_EXPROP_FUNC_ASIN,
+    JIM_EXPROP_FUNC_ACOS,
+    JIM_EXPROP_FUNC_ATAN,
+    JIM_EXPROP_FUNC_SINH,
+    JIM_EXPROP_FUNC_COSH,
+    JIM_EXPROP_FUNC_TANH,
+    JIM_EXPROP_FUNC_CEIL,
+    JIM_EXPROP_FUNC_FLOOR,
+    JIM_EXPROP_FUNC_EXP,
+    JIM_EXPROP_FUNC_LOG,
+    JIM_EXPROP_FUNC_LOG10,
+    JIM_EXPROP_FUNC_SQRT,
+    JIM_EXPROP_FUNC_POW,
+};
+
+struct JimExprState
+{
+    Jim_Obj **stack;
+    int stacklen;
+    int opcode;
+    int skip;
+};
+
+/* Operators table */
+typedef struct Jim_ExprOperator
+{
+    const char *name;
+    int precedence;
+    int arity;
+    int (*funcop) (Jim_Interp *interp, struct JimExprState * e);
+    int lazy;
+} Jim_ExprOperator;
+
+static void ExprPush(struct JimExprState *e, Jim_Obj *obj)
+{
+    Jim_IncrRefCount(obj);
+    e->stack[e->stacklen++] = obj;
+}
+
+static Jim_Obj *ExprPop(struct JimExprState *e)
+{
+    return e->stack[--e->stacklen];
+}
+
+static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprState *e)
+{
+    int intresult = 0;
+    int rc = JIM_OK;
+    Jim_Obj *A = ExprPop(e);
+    double dA, dC = 0;
+    jim_wide wA, wC = 0;
+
+    if ((A->typePtr != &doubleObjType || A->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK) {
+        intresult = 1;
+
+        switch (e->opcode) {
+            case JIM_EXPROP_FUNC_INT:
+                wC = wA;
+                break;
+            case JIM_EXPROP_FUNC_ROUND:
+                wC = wA;
+                break;
+            case JIM_EXPROP_FUNC_DOUBLE:
+                dC = wA;
+                intresult = 0;
+                break;
+            case JIM_EXPROP_FUNC_ABS:
+                wC = wA >= 0 ? wA : -wA;
+                break;
+            case JIM_EXPROP_UNARYMINUS:
+                wC = -wA;
+                break;
+            case JIM_EXPROP_UNARYPLUS:
+                wC = wA;
+                break;
+            case JIM_EXPROP_NOT:
+                wC = !wA;
+                break;
+            default:
+                abort();
+        }
+    }
+    else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) {
+        switch (e->opcode) {
+            case JIM_EXPROP_FUNC_INT:
+                wC = dA;
+                intresult = 1;
+                break;
+            case JIM_EXPROP_FUNC_ROUND:
+                wC = dA < 0 ? (dA - 0.5) : (dA + 0.5);
+                intresult = 1;
+                break;
+            case JIM_EXPROP_FUNC_DOUBLE:
+                dC = dA;
+                break;
+            case JIM_EXPROP_FUNC_ABS:
+                dC = dA >= 0 ? dA : -dA;
+                break;
+            case JIM_EXPROP_UNARYMINUS:
+                dC = -dA;
+                break;
+            case JIM_EXPROP_UNARYPLUS:
+                dC = dA;
+                break;
+            case JIM_EXPROP_NOT:
+                wC = !dA;
+                intresult = 1;
+                break;
+            default:
+                abort();
+        }
+    }
+
+    if (rc == JIM_OK) {
+        if (intresult) {
+            ExprPush(e, Jim_NewIntObj(interp, wC));
+        }
+        else {
+            ExprPush(e, Jim_NewDoubleObj(interp, dC));
+        }
+    }
+
+    Jim_DecrRefCount(interp, A);
+
+    return rc;
+}
+
+static double JimRandDouble(Jim_Interp *interp)
+{
+    unsigned long x;
+    JimRandomBytes(interp, &x, sizeof(x));
+
+    return (double)x / (unsigned long)~0;
+}
+
+static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprState *e)
+{
+    Jim_Obj *A = ExprPop(e);
+    jim_wide wA;
+
+    int rc = Jim_GetWide(interp, A, &wA);
+    if (rc == JIM_OK) {
+        switch (e->opcode) {
+            case JIM_EXPROP_BITNOT:
+                ExprPush(e, Jim_NewIntObj(interp, ~wA));
+                break;
+            case JIM_EXPROP_FUNC_SRAND:
+                JimPrngSeed(interp, (unsigned char *)&wA, sizeof(wA));
+                ExprPush(e, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
+                break;
+            default:
+                abort();
+        }
+    }
+
+    Jim_DecrRefCount(interp, A);
+
+    return rc;
+}
+
+static int JimExprOpNone(Jim_Interp *interp, struct JimExprState *e)
+{
+    JimPanic((e->opcode != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()"));
+
+    ExprPush(e, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
+
+    return JIM_OK;
+}
+
+#ifdef JIM_MATH_FUNCTIONS
+static int JimExprOpDoubleUnary(Jim_Interp *interp, struct JimExprState *e)
+{
+    int rc;
+    Jim_Obj *A = ExprPop(e);
+    double dA, dC;
+
+    rc = Jim_GetDouble(interp, A, &dA);
+    if (rc == JIM_OK) {
+        switch (e->opcode) {
+            case JIM_EXPROP_FUNC_SIN:
+                dC = sin(dA);
+                break;
+            case JIM_EXPROP_FUNC_COS:
+                dC = cos(dA);
+                break;
+            case JIM_EXPROP_FUNC_TAN:
+                dC = tan(dA);
+                break;
+            case JIM_EXPROP_FUNC_ASIN:
+                dC = asin(dA);
+                break;
+            case JIM_EXPROP_FUNC_ACOS:
+                dC = acos(dA);
+                break;
+            case JIM_EXPROP_FUNC_ATAN:
+                dC = atan(dA);
+                break;
+            case JIM_EXPROP_FUNC_SINH:
+                dC = sinh(dA);
+                break;
+            case JIM_EXPROP_FUNC_COSH:
+                dC = cosh(dA);
+                break;
+            case JIM_EXPROP_FUNC_TANH:
+                dC = tanh(dA);
+                break;
+            case JIM_EXPROP_FUNC_CEIL:
+                dC = ceil(dA);
+                break;
+            case JIM_EXPROP_FUNC_FLOOR:
+                dC = floor(dA);
+                break;
+            case JIM_EXPROP_FUNC_EXP:
+                dC = exp(dA);
+                break;
+            case JIM_EXPROP_FUNC_LOG:
+                dC = log(dA);
+                break;
+            case JIM_EXPROP_FUNC_LOG10:
+                dC = log10(dA);
+                break;
+            case JIM_EXPROP_FUNC_SQRT:
+                dC = sqrt(dA);
+                break;
+            default:
+                abort();
+        }
+        ExprPush(e, Jim_NewDoubleObj(interp, dC));
+    }
+
+    Jim_DecrRefCount(interp, A);
+
+    return rc;
+}
+#endif
+
+/* A binary operation on two ints */
+static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprState *e)
+{
+    Jim_Obj *B = ExprPop(e);
+    Jim_Obj *A = ExprPop(e);
+    jim_wide wA, wB;
+    int rc = JIM_ERR;
+
+    if (Jim_GetWide(interp, A, &wA) == JIM_OK && Jim_GetWide(interp, B, &wB) == JIM_OK) {
+        jim_wide wC;
+
+        rc = JIM_OK;
+
+        switch (e->opcode) {
+            case JIM_EXPROP_LSHIFT:
+                wC = wA << wB;
+                break;
+            case JIM_EXPROP_RSHIFT:
+                wC = wA >> wB;
+                break;
+            case JIM_EXPROP_BITAND:
+                wC = wA & wB;
+                break;
+            case JIM_EXPROP_BITXOR:
+                wC = wA ^ wB;
+                break;
+            case JIM_EXPROP_BITOR:
+                wC = wA | wB;
+                break;
+            case JIM_EXPROP_MOD:
+                if (wB == 0) {
+                    wC = 0;
+                    Jim_SetResultString(interp, "Division by zero", -1);
+                    rc = JIM_ERR;
+                }
+                else {
+                    /*
+                     * From Tcl 8.x
+                     *
+                     * This code is tricky: C doesn't guarantee much
+                     * about the quotient or remainder, but Tcl does.
+                     * The remainder always has the same sign as the
+                     * divisor and a smaller absolute value.
+                     */
+                    int negative = 0;
+
+                    if (wB < 0) {
+                        wB = -wB;
+                        wA = -wA;
+                        negative = 1;
+                    }
+                    wC = wA % wB;
+                    if (wC < 0) {
+                        wC += wB;
+                    }
+                    if (negative) {
+                        wC = -wC;
+                    }
+                }
+                break;
+            case JIM_EXPROP_ROTL:
+            case JIM_EXPROP_ROTR:{
+                    /* uint32_t would be better. But not everyone has inttypes.h? */
+                    unsigned long uA = (unsigned long)wA;
+                    unsigned long uB = (unsigned long)wB;
+                    const unsigned int S = sizeof(unsigned long) * 8;
+
+                    /* Shift left by the word size or more is undefined. */
+                    uB %= S;
+
+                    if (e->opcode == JIM_EXPROP_ROTR) {
+                        uB = S - uB;
+                    }
+                    wC = (unsigned long)(uA << uB) | (uA >> (S - uB));
+                    break;
+                }
+            default:
+                abort();
+        }
+        ExprPush(e, Jim_NewIntObj(interp, wC));
+
+    }
+
+    Jim_DecrRefCount(interp, A);
+    Jim_DecrRefCount(interp, B);
+
+    return rc;
+}
+
+
+/* A binary operation on two ints or two doubles (or two strings for some ops) */
+static int JimExprOpBin(Jim_Interp *interp, struct JimExprState *e)
+{
+    int intresult = 0;
+    int rc = JIM_OK;
+    double dA, dB, dC = 0;
+    jim_wide wA, wB, wC = 0;
+
+    Jim_Obj *B = ExprPop(e);
+    Jim_Obj *A = ExprPop(e);
+
+    if ((A->typePtr != &doubleObjType || A->bytes) &&
+        (B->typePtr != &doubleObjType || B->bytes) &&
+        JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) {
+
+        /* Both are ints */
+
+        intresult = 1;
+
+        switch (e->opcode) {
+            case JIM_EXPROP_POW:
+            case JIM_EXPROP_FUNC_POW:
+                wC = JimPowWide(wA, wB);
+                break;
+            case JIM_EXPROP_ADD:
+                wC = wA + wB;
+                break;
+            case JIM_EXPROP_SUB:
+                wC = wA - wB;
+                break;
+            case JIM_EXPROP_MUL:
+                wC = wA * wB;
+                break;
+            case JIM_EXPROP_DIV:
+                if (wB == 0) {
+                    Jim_SetResultString(interp, "Division by zero", -1);
+                    rc = JIM_ERR;
+                }
+                else {
+                    /*
+                     * From Tcl 8.x
+                     *
+                     * This code is tricky: C doesn't guarantee much
+                     * about the quotient or remainder, but Tcl does.
+                     * The remainder always has the same sign as the
+                     * divisor and a smaller absolute value.
+                     */
+                    if (wB < 0) {
+                        wB = -wB;
+                        wA = -wA;
+                    }
+                    wC = wA / wB;
+                    if (wA % wB < 0) {
+                        wC--;
+                    }
+                }
+                break;
+            case JIM_EXPROP_LT:
+                wC = wA < wB;
+                break;
+            case JIM_EXPROP_GT:
+                wC = wA > wB;
+                break;
+            case JIM_EXPROP_LTE:
+                wC = wA <= wB;
+                break;
+            case JIM_EXPROP_GTE:
+                wC = wA >= wB;
+                break;
+            case JIM_EXPROP_NUMEQ:
+                wC = wA == wB;
+                break;
+            case JIM_EXPROP_NUMNE:
+                wC = wA != wB;
+                break;
+            default:
+                abort();
+        }
+    }
+    else if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) {
+        switch (e->opcode) {
+            case JIM_EXPROP_POW:
+            case JIM_EXPROP_FUNC_POW:
+#ifdef JIM_MATH_FUNCTIONS
+                dC = pow(dA, dB);
+#else
+                Jim_SetResultString(interp, "unsupported", -1);
+                rc = JIM_ERR;
+#endif
+                break;
+            case JIM_EXPROP_ADD:
+                dC = dA + dB;
+                break;
+            case JIM_EXPROP_SUB:
+                dC = dA - dB;
+                break;
+            case JIM_EXPROP_MUL:
+                dC = dA * dB;
+                break;
+            case JIM_EXPROP_DIV:
+                if (dB == 0) {
+#ifdef INFINITY
+                    dC = dA < 0 ? -INFINITY : INFINITY;
+#else
+                    dC = (dA < 0 ? -1.0 : 1.0) * strtod("Inf", NULL);
+#endif
+                }
+                else {
+                    dC = dA / dB;
+                }
+                break;
+            case JIM_EXPROP_LT:
+                wC = dA < dB;
+                intresult = 1;
+                break;
+            case JIM_EXPROP_GT:
+                wC = dA > dB;
+                intresult = 1;
+                break;
+            case JIM_EXPROP_LTE:
+                wC = dA <= dB;
+                intresult = 1;
+                break;
+            case JIM_EXPROP_GTE:
+                wC = dA >= dB;
+                intresult = 1;
+                break;
+            case JIM_EXPROP_NUMEQ:
+                wC = dA == dB;
+                intresult = 1;
+                break;
+            case JIM_EXPROP_NUMNE:
+                wC = dA != dB;
+                intresult = 1;
+                break;
+            default:
+                abort();
+        }
+    }
+    else {
+        /* Handle the string case */
+
+        /* REVISIT: Could optimise the eq/ne case by checking lengths */
+        int i = Jim_StringCompareObj(interp, A, B, 0);
+
+        intresult = 1;
+
+        switch (e->opcode) {
+            case JIM_EXPROP_LT:
+                wC = i < 0;
+                break;
+            case JIM_EXPROP_GT:
+                wC = i > 0;
+                break;
+            case JIM_EXPROP_LTE:
+                wC = i <= 0;
+                break;
+            case JIM_EXPROP_GTE:
+                wC = i >= 0;
+                break;
+            case JIM_EXPROP_NUMEQ:
+                wC = i == 0;
+                break;
+            case JIM_EXPROP_NUMNE:
+                wC = i != 0;
+                break;
+            default:
+                rc = JIM_ERR;
+                break;
+        }
+    }
+
+    if (rc == JIM_OK) {
+        if (intresult) {
+            ExprPush(e, Jim_NewIntObj(interp, wC));
+        }
+        else {
+            ExprPush(e, Jim_NewDoubleObj(interp, dC));
+        }
+    }
+
+    Jim_DecrRefCount(interp, A);
+    Jim_DecrRefCount(interp, B);
+
+    return rc;
+}
+
+static int JimSearchList(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *valObj)
+{
+    int listlen;
+    int i;
+
+    listlen = Jim_ListLength(interp, listObjPtr);
+    for (i = 0; i < listlen; i++) {
+        Jim_Obj *objPtr;
+
+        Jim_ListIndex(interp, listObjPtr, i, &objPtr, JIM_NONE);
+
+        if (Jim_StringEqObj(objPtr, valObj)) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprState *e)
+{
+    Jim_Obj *B = ExprPop(e);
+    Jim_Obj *A = ExprPop(e);
+
+    jim_wide wC;
+
+    switch (e->opcode) {
+        case JIM_EXPROP_STREQ:
+        case JIM_EXPROP_STRNE: {
+            int Alen, Blen;
+            const char *sA = Jim_GetString(A, &Alen);
+            const char *sB = Jim_GetString(B, &Blen);
+
+            if (e->opcode == JIM_EXPROP_STREQ) {
+                wC = (Alen == Blen && memcmp(sA, sB, Alen) == 0);
+            }
+            else {
+                wC = (Alen != Blen || memcmp(sA, sB, Alen) != 0);
+            }
+            break;
+        }
+        case JIM_EXPROP_STRIN:
+            wC = JimSearchList(interp, B, A);
+            break;
+        case JIM_EXPROP_STRNI:
+            wC = !JimSearchList(interp, B, A);
+            break;
+        default:
+            abort();
+    }
+    ExprPush(e, Jim_NewIntObj(interp, wC));
+
+    Jim_DecrRefCount(interp, A);
+    Jim_DecrRefCount(interp, B);
+
+    return JIM_OK;
+}
+
+static int ExprBool(Jim_Interp *interp, Jim_Obj *obj)
+{
+    long l;
+    double d;
+
+    if (Jim_GetLong(interp, obj, &l) == JIM_OK) {
+        return l != 0;
+    }
+    if (Jim_GetDouble(interp, obj, &d) == JIM_OK) {
+        return d != 0;
+    }
+    return -1;
+}
+
+static int JimExprOpAndLeft(Jim_Interp *interp, struct JimExprState *e)
+{
+    Jim_Obj *skip = ExprPop(e);
+    Jim_Obj *A = ExprPop(e);
+    int rc = JIM_OK;
+
+    switch (ExprBool(interp, A)) {
+        case 0:
+            /* false, so skip RHS opcodes with a 0 result */
+            e->skip = JimWideValue(skip);
+            ExprPush(e, Jim_NewIntObj(interp, 0));
+            break;
+
+        case 1:
+            /* true so continue */
+            break;
+
+        case -1:
+            /* Invalid */
+            rc = JIM_ERR;
+    }
+    Jim_DecrRefCount(interp, A);
+    Jim_DecrRefCount(interp, skip);
+
+    return rc;
+}
+
+static int JimExprOpOrLeft(Jim_Interp *interp, struct JimExprState *e)
+{
+    Jim_Obj *skip = ExprPop(e);
+    Jim_Obj *A = ExprPop(e);
+    int rc = JIM_OK;
+
+    switch (ExprBool(interp, A)) {
+        case 0:
+            /* false, so do nothing */
+            break;
+
+        case 1:
+            /* true so skip RHS opcodes with a 1 result */
+            e->skip = JimWideValue(skip);
+            ExprPush(e, Jim_NewIntObj(interp, 1));
+            break;
+
+        case -1:
+            /* Invalid */
+            rc = JIM_ERR;
+            break;
+    }
+    Jim_DecrRefCount(interp, A);
+    Jim_DecrRefCount(interp, skip);
+
+    return rc;
+}
+
+static int JimExprOpAndOrRight(Jim_Interp *interp, struct JimExprState *e)
+{
+    Jim_Obj *A = ExprPop(e);
+    int rc = JIM_OK;
+
+    switch (ExprBool(interp, A)) {
+        case 0:
+            ExprPush(e, Jim_NewIntObj(interp, 0));
+            break;
+
+        case 1:
+            ExprPush(e, Jim_NewIntObj(interp, 1));
+            break;
+
+        case -1:
+            /* Invalid */
+            rc = JIM_ERR;
+            break;
+    }
+    Jim_DecrRefCount(interp, A);
+
+    return rc;
+}
+
+static int JimExprOpTernaryLeft(Jim_Interp *interp, struct JimExprState *e)
+{
+    Jim_Obj *skip = ExprPop(e);
+    Jim_Obj *A = ExprPop(e);
+    int rc = JIM_OK;
+
+    /* Repush A */
+    ExprPush(e, A);
+
+    switch (ExprBool(interp, A)) {
+        case 0:
+            /* false, skip RHS opcodes */
+            e->skip = JimWideValue(skip);
+            /* Push a dummy value */
+            ExprPush(e, Jim_NewIntObj(interp, 0));
+            break;
+
+        case 1:
+            /* true so do nothing */
+            break;
+
+        case -1:
+            /* Invalid */
+            rc = JIM_ERR;
+            break;
+    }
+    Jim_DecrRefCount(interp, A);
+    Jim_DecrRefCount(interp, skip);
+
+    return rc;
+}
+
+static int JimExprOpColonLeft(Jim_Interp *interp, struct JimExprState *e)
+{
+    Jim_Obj *skip = ExprPop(e);
+    Jim_Obj *B = ExprPop(e);
+    Jim_Obj *A = ExprPop(e);
+
+    /* No need to check for A as non-boolean */
+    if (ExprBool(interp, A)) {
+        /* true, so skip RHS opcodes */
+        e->skip = JimWideValue(skip);
+        /* Repush B as the answer */
+        ExprPush(e, B);
+    }
+
+    Jim_DecrRefCount(interp, skip);
+    Jim_DecrRefCount(interp, A);
+    Jim_DecrRefCount(interp, B);
+    return JIM_OK;
+}
+
+static int JimExprOpNull(Jim_Interp *interp, struct JimExprState *e)
+{
+    return JIM_OK;
+}
+
+enum
+{
+    LAZY_NONE,
+    LAZY_OP,
+    LAZY_LEFT,
+    LAZY_RIGHT
+};
+
+/* name - precedence - arity - opcode */
+static const struct Jim_ExprOperator Jim_ExprOperators[] = {
+    [JIM_EXPROP_FUNC_INT] = {"int", 400, 1, JimExprOpNumUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_DOUBLE] = {"double", 400, 1, JimExprOpNumUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_ABS] = {"abs", 400, 1, JimExprOpNumUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_ROUND] = {"round", 400, 1, JimExprOpNumUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_RAND] = {"rand", 400, 0, JimExprOpNone, LAZY_NONE},
+    [JIM_EXPROP_FUNC_SRAND] = {"srand", 400, 1, JimExprOpIntUnary, LAZY_NONE},
+
+#ifdef JIM_MATH_FUNCTIONS
+    [JIM_EXPROP_FUNC_SIN] = {"sin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_COS] = {"cos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_TAN] = {"tan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_ASIN] = {"asin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_ACOS] = {"acos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_ATAN] = {"atan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_SINH] = {"sinh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_COSH] = {"cosh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_TANH] = {"tanh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_CEIL] = {"ceil", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_FLOOR] = {"floor", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_EXP] = {"exp", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_LOG] = {"log", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_LOG10] = {"log10", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_SQRT] = {"sqrt", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    [JIM_EXPROP_FUNC_POW] = {"pow", 400, 2, JimExprOpBin, LAZY_NONE},
+#endif
+
+    [JIM_EXPROP_NOT] = {"!", 300, 1, JimExprOpNumUnary, LAZY_NONE},
+    [JIM_EXPROP_BITNOT] = {"~", 300, 1, JimExprOpIntUnary, LAZY_NONE},
+    [JIM_EXPROP_UNARYMINUS] = {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE},
+    [JIM_EXPROP_UNARYPLUS] = {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE},
+
+    [JIM_EXPROP_POW] = {"**", 250, 2, JimExprOpBin, LAZY_NONE},
+
+    [JIM_EXPROP_MUL] = {"*", 200, 2, JimExprOpBin, LAZY_NONE},
+    [JIM_EXPROP_DIV] = {"/", 200, 2, JimExprOpBin, LAZY_NONE},
+    [JIM_EXPROP_MOD] = {"%", 200, 2, JimExprOpIntBin, LAZY_NONE},
+
+    [JIM_EXPROP_SUB] = {"-", 100, 2, JimExprOpBin, LAZY_NONE},
+    [JIM_EXPROP_ADD] = {"+", 100, 2, JimExprOpBin, LAZY_NONE},
+
+    [JIM_EXPROP_ROTL] = {"<<<", 90, 2, JimExprOpIntBin, LAZY_NONE},
+    [JIM_EXPROP_ROTR] = {">>>", 90, 2, JimExprOpIntBin, LAZY_NONE},
+    [JIM_EXPROP_LSHIFT] = {"<<", 90, 2, JimExprOpIntBin, LAZY_NONE},
+    [JIM_EXPROP_RSHIFT] = {">>", 90, 2, JimExprOpIntBin, LAZY_NONE},
+
+    [JIM_EXPROP_LT] = {"<", 80, 2, JimExprOpBin, LAZY_NONE},
+    [JIM_EXPROP_GT] = {">", 80, 2, JimExprOpBin, LAZY_NONE},
+    [JIM_EXPROP_LTE] = {"<=", 80, 2, JimExprOpBin, LAZY_NONE},
+    [JIM_EXPROP_GTE] = {">=", 80, 2, JimExprOpBin, LAZY_NONE},
+
+    [JIM_EXPROP_NUMEQ] = {"==", 70, 2, JimExprOpBin, LAZY_NONE},
+    [JIM_EXPROP_NUMNE] = {"!=", 70, 2, JimExprOpBin, LAZY_NONE},
+
+    [JIM_EXPROP_STREQ] = {"eq", 60, 2, JimExprOpStrBin, LAZY_NONE},
+    [JIM_EXPROP_STRNE] = {"ne", 60, 2, JimExprOpStrBin, LAZY_NONE},
+
+    [JIM_EXPROP_STRIN] = {"in", 55, 2, JimExprOpStrBin, LAZY_NONE},
+    [JIM_EXPROP_STRNI] = {"ni", 55, 2, JimExprOpStrBin, LAZY_NONE},
+
+    [JIM_EXPROP_BITAND] = {"&", 50, 2, JimExprOpIntBin, LAZY_NONE},
+    [JIM_EXPROP_BITXOR] = {"^", 49, 2, JimExprOpIntBin, LAZY_NONE},
+    [JIM_EXPROP_BITOR] = {"|", 48, 2, JimExprOpIntBin, LAZY_NONE},
+
+    [JIM_EXPROP_LOGICAND] = {"&&", 10, 2, NULL, LAZY_OP},
+    [JIM_EXPROP_LOGICOR] = {"||", 9, 2, NULL, LAZY_OP},
+
+    [JIM_EXPROP_TERNARY] = {"?", 5, 2, JimExprOpNull, LAZY_OP},
+    [JIM_EXPROP_COLON] = {":", 5, 2, JimExprOpNull, LAZY_OP},
+
+    /* private operators */
+    [JIM_EXPROP_TERNARY_LEFT] = {NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT},
+    [JIM_EXPROP_TERNARY_RIGHT] = {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT},
+    [JIM_EXPROP_COLON_LEFT] = {NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT},
+    [JIM_EXPROP_COLON_RIGHT] = {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT},
+    [JIM_EXPROP_LOGICAND_LEFT] = {NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT},
+    [JIM_EXPROP_LOGICAND_RIGHT] = {NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT},
+    [JIM_EXPROP_LOGICOR_LEFT] = {NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT},
+    [JIM_EXPROP_LOGICOR_RIGHT] = {NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT},
+};
+
+#define JIM_EXPR_OPERATORS_NUM \
+    (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
+
+static int JimParseExpression(struct JimParserCtx *pc)
+{
+    /* Discard spaces and quoted newline */
+    while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
+        if (*pc->p == '\n') {
+            pc->linenr++;
+        }
+        pc->p++;
+        pc->len--;
+    }
+
+    if (pc->len == 0) {
+        pc->tstart = pc->tend = pc->p;
+        pc->tline = pc->linenr;
+        pc->tt = JIM_TT_EOL;
+        pc->eof = 1;
+        return JIM_OK;
+    }
+    switch (*(pc->p)) {
+        case '(':
+                pc->tt = JIM_TT_SUBEXPR_START;
+                goto singlechar;
+        case ')':
+                pc->tt = JIM_TT_SUBEXPR_END;
+                goto singlechar;
+        case ',':
+            pc->tt = JIM_TT_SUBEXPR_COMMA;
+singlechar:
+            pc->tstart = pc->tend = pc->p;
+            pc->tline = pc->linenr;
+            pc->p++;
+            pc->len--;
+            break;
+        case '[':
+            return JimParseCmd(pc);
+        case '$':
+            if (JimParseVar(pc) == JIM_ERR)
+                return JimParseExprOperator(pc);
+            else {
+                /* Don't allow expr sugar in expressions */
+                if (pc->tt == JIM_TT_EXPRSUGAR) {
+                    return JIM_ERR;
+                }
+                return JIM_OK;
+            }
+            break;
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+        case '.':
+            return JimParseExprNumber(pc);
+        case '"':
+            return JimParseQuote(pc);
+        case '{':
+            return JimParseBrace(pc);
+
+        case 'N':
+        case 'I':
+        case 'n':
+        case 'i':
+            if (JimParseExprIrrational(pc) == JIM_ERR)
+                return JimParseExprOperator(pc);
+            break;
+        default:
+            return JimParseExprOperator(pc);
+            break;
+    }
+    return JIM_OK;
+}
+
+static int JimParseExprNumber(struct JimParserCtx *pc)
+{
+    int allowdot = 1;
+    int allowhex = 0;
+
+    /* Assume an integer for now */
+    pc->tt = JIM_TT_EXPR_INT;
+    pc->tstart = pc->p;
+    pc->tline = pc->linenr;
+    while (isdigit(UCHAR(*pc->p))
+        || (allowhex && isxdigit(UCHAR(*pc->p)))
+        || (allowdot && *pc->p == '.')
+        || (pc->p - pc->tstart == 1 && *pc->tstart == '0' && (*pc->p == 'x' || *pc->p == 'X'))
+        ) {
+        if ((*pc->p == 'x') || (*pc->p == 'X')) {
+            allowhex = 1;
+            allowdot = 0;
+        }
+        if (*pc->p == '.') {
+            allowdot = 0;
+            pc->tt = JIM_TT_EXPR_DOUBLE;
+        }
+        pc->p++;
+        pc->len--;
+        if (!allowhex && (*pc->p == 'e' || *pc->p == 'E') && (pc->p[1] == '-' || pc->p[1] == '+'
+                || isdigit(UCHAR(pc->p[1])))) {
+            pc->p += 2;
+            pc->len -= 2;
+            pc->tt = JIM_TT_EXPR_DOUBLE;
+        }
+    }
+    pc->tend = pc->p - 1;
+    return JIM_OK;
+}
+
+static int JimParseExprIrrational(struct JimParserCtx *pc)
+{
+    const char *Tokens[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL };
+    const char **token;
+
+    for (token = Tokens; *token != NULL; token++) {
+        int len = strlen(*token);
+
+        if (strncmp(*token, pc->p, len) == 0) {
+            pc->tstart = pc->p;
+            pc->tend = pc->p + len - 1;
+            pc->p += len;
+            pc->len -= len;
+            pc->tline = pc->linenr;
+            pc->tt = JIM_TT_EXPR_DOUBLE;
+            return JIM_OK;
+        }
+    }
+    return JIM_ERR;
+}
+
+static int JimParseExprOperator(struct JimParserCtx *pc)
+{
+    int i;
+    int bestIdx = -1, bestLen = 0;
+
+    /* Try to get the longest match. */
+    for (i = JIM_TT_EXPR_OP; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
+        const char *opname;
+        int oplen;
+
+        opname = Jim_ExprOperators[i].name;
+        if (opname == NULL) {
+            continue;
+        }
+        oplen = strlen(opname);
+
+        if (strncmp(opname, pc->p, oplen) == 0 && oplen > bestLen) {
+            bestIdx = i;
+            bestLen = oplen;
+        }
+    }
+    if (bestIdx == -1) {
+        return JIM_ERR;
+    }
+
+    /* Validate paretheses around function arguments */
+    if (bestIdx >= JIM_EXPROP_FUNC_FIRST) {
+        const char *p = pc->p + bestLen;
+        int len = pc->len - bestLen;
+
+        while (len && isspace(UCHAR(*p))) {
+            len--;
+            p++;
+        }
+        if (*p != '(') {
+            return JIM_ERR;
+        }
+    }
+    pc->tstart = pc->p;
+    pc->tend = pc->p + bestLen - 1;
+    pc->p += bestLen;
+    pc->len -= bestLen;
+    pc->tline = pc->linenr;
+
+    pc->tt = bestIdx;
+    return JIM_OK;
+}
+
+static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode)
+{
+    return &Jim_ExprOperators[opcode];
+}
+
+const char *jim_tt_name(int type)
+{
+    static const char * const tt_names[JIM_TT_EXPR_OP] =
+        { "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT",
+            "DBL", "$()" };
+    if (type < JIM_TT_EXPR_OP) {
+        return tt_names[type];
+    }
+    else {
+        const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(type);
+        static char buf[20];
+
+        if (op && op->name) {
+            return op->name;
+        }
+        sprintf(buf, "(%d)", type);
+        return buf;
+    }
+}
+
+/* -----------------------------------------------------------------------------
+ * Expression Object
+ * ---------------------------------------------------------------------------*/
+static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType exprObjType = {
+    "expression",
+    FreeExprInternalRep,
+    DupExprInternalRep,
+    NULL,
+    JIM_TYPE_REFERENCES,
+};
+
+/* Expr bytecode structure */
+typedef struct ExprByteCode
+{
+    int len;                    /* Length as number of tokens. */
+    ScriptToken *token;         /* Tokens array. */
+    int inUse;                  /* Used for sharing. */
+} ExprByteCode;
+
+static void ExprFreeByteCode(Jim_Interp *interp, ExprByteCode * expr)
+{
+    int i;
+
+    for (i = 0; i < expr->len; i++) {
+        Jim_DecrRefCount(interp, expr->token[i].objPtr);
+    }
+    Jim_Free(expr->token);
+    Jim_Free(expr);
+}
+
+static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    ExprByteCode *expr = (void *)objPtr->internalRep.ptr;
+
+    if (expr) {
+        if (--expr->inUse != 0) {
+            return;
+        }
+
+        ExprFreeByteCode(interp, expr);
+    }
+}
+
+static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+    JIM_NOTUSED(interp);
+    JIM_NOTUSED(srcPtr);
+
+    /* Just returns an simple string. */
+    dupPtr->typePtr = NULL;
+}
+
+/* Check if an expr program looks correct. */
+static int ExprCheckCorrectness(ExprByteCode * expr)
+{
+    int i;
+    int stacklen = 0;
+    int ternary = 0;
+
+    /* Try to check if there are stack underflows,
+     * and make sure at the end of the program there is
+     * a single result on the stack. */
+    for (i = 0; i < expr->len; i++) {
+        ScriptToken *t = &expr->token[i];
+        const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type);
+
+        if (op) {
+            stacklen -= op->arity;
+            if (stacklen < 0) {
+                break;
+            }
+            if (t->type == JIM_EXPROP_TERNARY || t->type == JIM_EXPROP_TERNARY_LEFT) {
+                ternary++;
+            }
+            else if (t->type == JIM_EXPROP_COLON || t->type == JIM_EXPROP_COLON_LEFT) {
+                ternary--;
+            }
+        }
+
+        /* All operations and operands add one to the stack */
+        stacklen++;
+    }
+    if (stacklen != 1 || ternary != 0) {
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+/* This procedure converts every occurrence of || and && opereators
+ * in lazy unary versions.
+ *
+ * a b || is converted into:
+ *
+ * a <offset> |L b |R
+ *
+ * a b && is converted into:
+ *
+ * a <offset> &L b &R
+ *
+ * "|L" checks if 'a' is true:
+ *   1) if it is true pushes 1 and skips <offset> instructions to reach
+ *      the opcode just after |R.
+ *   2) if it is false does nothing.
+ * "|R" checks if 'b' is true:
+ *   1) if it is true pushes 1, otherwise pushes 0.
+ *
+ * "&L" checks if 'a' is true:
+ *   1) if it is true does nothing.
+ *   2) If it is false pushes 0 and skips <offset> instructions to reach
+ *      the opcode just after &R
+ * "&R" checks if 'a' is true:
+ *      if it is true pushes 1, otherwise pushes 0.
+ */
+static int ExprAddLazyOperator(Jim_Interp *interp, ExprByteCode * expr, ParseToken *t)
+{
+    int i;
+
+    int leftindex, arity, offset;
+
+    /* Search for the end of the first operator */
+    leftindex = expr->len - 1;
+
+    arity = 1;
+    while (arity) {
+        ScriptToken *tt = &expr->token[leftindex];
+
+        if (tt->type >= JIM_TT_EXPR_OP) {
+            arity += JimExprOperatorInfoByOpcode(tt->type)->arity;
+        }
+        arity--;
+        if (--leftindex < 0) {
+            return JIM_ERR;
+        }
+    }
+    leftindex++;
+
+    /* Move them up */
+    memmove(&expr->token[leftindex + 2], &expr->token[leftindex],
+        sizeof(*expr->token) * (expr->len - leftindex));
+    expr->len += 2;
+    offset = (expr->len - leftindex) - 1;
+
+    /* Now we rely on the fact the the left and right version have opcodes
+     * 1 and 2 after the main opcode respectively
+     */
+    expr->token[leftindex + 1].type = t->type + 1;
+    expr->token[leftindex + 1].objPtr = interp->emptyObj;
+
+    expr->token[leftindex].type = JIM_TT_EXPR_INT;
+    expr->token[leftindex].objPtr = Jim_NewIntObj(interp, offset);
+
+    /* Now add the 'R' operator */
+    expr->token[expr->len].objPtr = interp->emptyObj;
+    expr->token[expr->len].type = t->type + 2;
+    expr->len++;
+
+    /* Do we need to adjust the skip count for any &L, |L, ?L or :L in the left operand? */
+    for (i = leftindex - 1; i > 0; i--) {
+        if (JimExprOperatorInfoByOpcode(expr->token[i].type)->lazy == LAZY_LEFT) {
+            if (JimWideValue(expr->token[i - 1].objPtr) + i - 1 >= leftindex) {
+                JimWideValue(expr->token[i - 1].objPtr) += 2;
+            }
+        }
+    }
+    return JIM_OK;
+}
+
+static int ExprAddOperator(Jim_Interp *interp, ExprByteCode * expr, ParseToken *t)
+{
+    struct ScriptToken *token = &expr->token[expr->len];
+    const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type);
+
+    if (op->lazy == LAZY_OP) {
+        if (ExprAddLazyOperator(interp, expr, t) != JIM_OK) {
+            Jim_SetResultFormatted(interp, "Expression has bad operands to %s", op->name);
+            return JIM_ERR;
+        }
+    }
+    else {
+        token->objPtr = interp->emptyObj;
+        token->type = t->type;
+        expr->len++;
+    }
+    return JIM_OK;
+}
+
+/**
+ * Returns the index of the COLON_LEFT to the left of 'right_index'
+ * taking into account nesting.
+ *
+ * The expression *must* be well formed, thus a COLON_LEFT will always be found.
+ */
+static int ExprTernaryGetColonLeftIndex(ExprByteCode *expr, int right_index)
+{
+    int ternary_count = 1;
+
+    right_index--;
+
+    while (right_index > 1) {
+        if (expr->token[right_index].type == JIM_EXPROP_TERNARY_LEFT) {
+            ternary_count--;
+        }
+        else if (expr->token[right_index].type == JIM_EXPROP_COLON_RIGHT) {
+            ternary_count++;
+        }
+        else if (expr->token[right_index].type == JIM_EXPROP_COLON_LEFT && ternary_count == 1) {
+            return right_index;
+        }
+        right_index--;
+    }
+
+    /*notreached*/
+    return -1;
+}
+
+/**
+ * Find the left/right indices for the ternary expression to the left of 'right_index'.
+ *
+ * Returns 1 if found, and fills in *prev_right_index and *prev_left_index.
+ * Otherwise returns 0.
+ */
+static int ExprTernaryGetMoveIndices(ExprByteCode *expr, int right_index, int *prev_right_index, int *prev_left_index)
+{
+    int i = right_index - 1;
+    int ternary_count = 1;
+
+    while (i > 1) {
+        if (expr->token[i].type == JIM_EXPROP_TERNARY_LEFT) {
+            if (--ternary_count == 0 && expr->token[i - 2].type == JIM_EXPROP_COLON_RIGHT) {
+                *prev_right_index = i - 2;
+                *prev_left_index = ExprTernaryGetColonLeftIndex(expr, *prev_right_index);
+                return 1;
+            }
+        }
+        else if (expr->token[i].type == JIM_EXPROP_COLON_RIGHT) {
+            if (ternary_count == 0) {
+                return 0;
+            }
+            ternary_count++;
+        }
+        i--;
+    }
+    return 0;
+}
+
+/*
+* ExprTernaryReorderExpression description
+* ========================================
+*
+* ?: is right-to-left associative which doesn't work with the stack-based
+* expression engine. The fix is to reorder the bytecode.
+*
+* The expression:
+*
+*    expr 1?2:0?3:4
+*
+* Has initial bytecode:
+*
+*    '1' '2' (40=TERNARY_LEFT) '2' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '0' (44=COLON_RIGHT)
+*    '2' (40=TERNARY_LEFT) '3' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '4' (44=COLON_RIGHT)
+*
+* The fix involves simulating this expression instead:
+*
+*    expr 1?2:(0?3:4)
+*
+* With the following bytecode:
+*
+*    '1' '2' (40=TERNARY_LEFT) '2' (41=TERNARY_RIGHT) '10' (43=COLON_LEFT) '0' '2' (40=TERNARY_LEFT)
+*    '3' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '4' (44=COLON_RIGHT) (44=COLON_RIGHT)
+*
+* i.e. The token COLON_RIGHT at index 8 is moved towards the end of the stack, all tokens above 8
+*      are shifted down and the skip count of the token JIM_EXPROP_COLON_LEFT at index 5 is
+*      incremented by the amount tokens shifted down. The token JIM_EXPROP_COLON_RIGHT that is moved
+*      is identified as immediately preceeding a token JIM_EXPROP_TERNARY_LEFT
+*
+* ExprTernaryReorderExpression works thus as follows :
+* - start from the end of the stack
+* - while walking towards the beginning of the stack
+*     if token=JIM_EXPROP_COLON_RIGHT then
+*        find the associated token JIM_EXPROP_TERNARY_LEFT, which allows to
+*            find the associated token previous(JIM_EXPROP_COLON_RIGHT)
+*            find the associated token previous(JIM_EXPROP_LEFT_RIGHT)
+*        if all found then
+*            perform the rotation
+*            update the skip count of the token previous(JIM_EXPROP_LEFT_RIGHT)
+*        end if
+*    end if
+*
+* Note: care has to be taken for nested ternary constructs!!!
+*/
+static void ExprTernaryReorderExpression(Jim_Interp *interp, ExprByteCode *expr)
+{
+    int i;
+
+    for (i = expr->len - 1; i > 1; i--) {
+        int prev_right_index;
+        int prev_left_index;
+        int j;
+        ScriptToken tmp;
+
+        if (expr->token[i].type != JIM_EXPROP_COLON_RIGHT) {
+            continue;
+        }
+
+        /* COLON_RIGHT found: get the indexes needed to move the tokens in the stack (if any) */
+        if (ExprTernaryGetMoveIndices(expr, i, &prev_right_index, &prev_left_index) == 0) {
+            continue;
+        }
+
+        /*
+        ** rotate tokens down
+        **
+        ** +->  [i]                         : JIM_EXPROP_COLON_RIGHT
+        ** |     |                             |
+        ** |     V                             V
+        ** |   [...]                        : ...
+        ** |     |                             |
+        ** |     V                             V
+        ** |   [...]                        : ...
+        ** |     |                             |
+        ** |     V                             V
+        ** +-  [prev_right_index]           : JIM_EXPROP_COLON_RIGHT
+        */
+        tmp = expr->token[prev_right_index];
+        for (j = prev_right_index; j < i; j++) {
+            expr->token[j] = expr->token[j + 1];
+        }
+        expr->token[i] = tmp;
+
+        /* Increment the 'skip' count associated to the previous JIM_EXPROP_COLON_LEFT token
+         *
+         * This is 'colon left increment' = i - prev_right_index
+         *
+         * [prev_left_index]      : JIM_EXPROP_LEFT_RIGHT
+         * [prev_left_index-1]    : skip_count
+         *
+         */
+        JimWideValue(expr->token[prev_left_index-1].objPtr) += (i - prev_right_index);
+
+        /* Adjust for i-- in the loop */
+        i++;
+    }
+}
+
+static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *fileNameObj)
+{
+    Jim_Stack stack;
+    ExprByteCode *expr;
+    int ok = 1;
+    int i;
+    int prevtt = JIM_TT_NONE;
+    int have_ternary = 0;
+
+    /* -1 for EOL */
+    int count = tokenlist->count - 1;
+
+    expr = Jim_Alloc(sizeof(*expr));
+    expr->inUse = 1;
+    expr->len = 0;
+
+    Jim_InitStack(&stack);
+
+    /* Need extra bytecodes for lazy operators.
+     * Also check for the ternary operator
+     */
+    for (i = 0; i < tokenlist->count; i++) {
+        ParseToken *t = &tokenlist->list[i];
+
+        if (JimExprOperatorInfoByOpcode(t->type)->lazy == LAZY_OP) {
+            count += 2;
+            /* Ternary is a lazy op but also needs reordering */
+            if (t->type == JIM_EXPROP_TERNARY) {
+                have_ternary = 1;
+            }
+        }
+    }
+
+    expr->token = Jim_Alloc(sizeof(ScriptToken) * count);
+
+    for (i = 0; i < tokenlist->count && ok; i++) {
+        ParseToken *t = &tokenlist->list[i];
+
+        /* Next token will be stored here */
+        struct ScriptToken *token = &expr->token[expr->len];
+
+        if (t->type == JIM_TT_EOL) {
+            break;
+        }
+
+        switch (t->type) {
+            case JIM_TT_STR:
+            case JIM_TT_ESC:
+            case JIM_TT_VAR:
+            case JIM_TT_DICTSUGAR:
+            case JIM_TT_EXPRSUGAR:
+            case JIM_TT_CMD:
+                token->objPtr = Jim_NewStringObj(interp, t->token, t->len);
+                token->type = t->type;
+                if (t->type == JIM_TT_CMD) {
+                    /* Only commands need source info */
+                    JimSetSourceInfo(interp, token->objPtr, fileNameObj, t->line);
+                }
+                expr->len++;
+                break;
+
+            case JIM_TT_EXPR_INT:
+                token->objPtr = Jim_NewIntObj(interp, strtoull(t->token, NULL, 0));
+                token->type = t->type;
+                expr->len++;
+                break;
+
+            case JIM_TT_EXPR_DOUBLE:
+                token->objPtr = Jim_NewDoubleObj(interp, strtod(t->token, NULL));
+                token->type = t->type;
+                expr->len++;
+                break;
+
+            case JIM_TT_SUBEXPR_START:
+                Jim_StackPush(&stack, t);
+                prevtt = JIM_TT_NONE;
+                continue;
+
+            case JIM_TT_SUBEXPR_COMMA:
+                /* Simple approach. Comma is simply ignored */
+                continue;
+
+            case JIM_TT_SUBEXPR_END:
+                ok = 0;
+                while (Jim_StackLen(&stack)) {
+                    ParseToken *tt = Jim_StackPop(&stack);
+
+                    if (tt->type == JIM_TT_SUBEXPR_START) {
+                        ok = 1;
+                        break;
+                    }
+
+                    if (ExprAddOperator(interp, expr, tt) != JIM_OK) {
+                        goto err;
+                    }
+                }
+                if (!ok) {
+                    Jim_SetResultString(interp, "Unexpected close parenthesis", -1);
+                    goto err;
+                }
+                break;
+
+
+            default:{
+                    /* Must be an operator */
+                    const struct Jim_ExprOperator *op;
+                    ParseToken *tt;
+
+                    /* Convert -/+ to unary minus or unary plus if necessary */
+                    if (prevtt == JIM_TT_NONE || prevtt >= JIM_TT_EXPR_OP) {
+                        if (t->type == JIM_EXPROP_SUB) {
+                            t->type = JIM_EXPROP_UNARYMINUS;
+                        }
+                        else if (t->type == JIM_EXPROP_ADD) {
+                            t->type = JIM_EXPROP_UNARYPLUS;
+                        }
+                    }
+
+                    op = JimExprOperatorInfoByOpcode(t->type);
+
+                    /* Now handle precedence */
+                    while ((tt = Jim_StackPeek(&stack)) != NULL) {
+                        const struct Jim_ExprOperator *tt_op =
+                            JimExprOperatorInfoByOpcode(tt->type);
+
+                        /* Note that right-to-left associativity of ?: operator is handled later */
+
+                        if (op->arity != 1 && tt_op->precedence >= op->precedence) {
+                            if (ExprAddOperator(interp, expr, tt) != JIM_OK) {
+                                ok = 0;
+                                goto err;
+                            }
+                            Jim_StackPop(&stack);
+                        }
+                        else {
+                            break;
+                        }
+                    }
+                    Jim_StackPush(&stack, t);
+                    break;
+                }
+        }
+        prevtt = t->type;
+    }
+
+    /* Reduce any remaining subexpr */
+    while (Jim_StackLen(&stack)) {
+        ParseToken *tt = Jim_StackPop(&stack);
+
+        if (tt->type == JIM_TT_SUBEXPR_START) {
+            ok = 0;
+            Jim_SetResultString(interp, "Missing close parenthesis", -1);
+            goto err;
+        }
+        if (ExprAddOperator(interp, expr, tt) != JIM_OK) {
+            ok = 0;
+            goto err;
+        }
+    }
+
+    if (have_ternary) {
+        ExprTernaryReorderExpression(interp, expr);
+    }
+
+  err:
+    /* Free the stack used for the compilation. */
+    Jim_FreeStack(&stack);
+
+    for (i = 0; i < expr->len; i++) {
+        Jim_IncrRefCount(expr->token[i].objPtr);
+    }
+
+    if (!ok) {
+        ExprFreeByteCode(interp, expr);
+        return NULL;
+    }
+
+    return expr;
+}
+
+
+/* This method takes the string representation of an expression
+ * and generates a program for the Expr's stack-based VM. */
+static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+    int exprTextLen;
+    const char *exprText;
+    struct JimParserCtx parser;
+    struct ExprByteCode *expr;
+    ParseTokenList tokenlist;
+    int line;
+    Jim_Obj *fileNameObj;
+    int rc = JIM_ERR;
+
+    /* Try to get information about filename / line number */
+    if (objPtr->typePtr == &sourceObjType) {
+        fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
+        line = objPtr->internalRep.sourceValue.lineNumber;
+    }
+    else {
+        fileNameObj = interp->emptyObj;
+        line = 1;
+    }
+    Jim_IncrRefCount(fileNameObj);
+
+    exprText = Jim_GetString(objPtr, &exprTextLen);
+
+    /* Initially tokenise the expression into tokenlist */
+    ScriptTokenListInit(&tokenlist);
+
+    JimParserInit(&parser, exprText, exprTextLen, line);
+    while (!parser.eof) {
+        if (JimParseExpression(&parser) != JIM_OK) {
+            ScriptTokenListFree(&tokenlist);
+          invalidexpr:
+            Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr);
+            expr = NULL;
+            goto err;
+        }
+
+        ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
+            parser.tline);
+    }
+
+#ifdef DEBUG_SHOW_EXPR_TOKENS
+    {
+        int i;
+        printf("==== Expr Tokens ====\n");
+        for (i = 0; i < tokenlist.count; i++) {
+            printf("[%2d]@%d %s '%.*s'\n", i, tokenlist.list[i].line, jim_tt_name(tokenlist.list[i].type),
+                tokenlist.list[i].len, tokenlist.list[i].token);
+        }
+    }
+#endif
+
+    /* Now create the expression bytecode from the tokenlist */
+    expr = ExprCreateByteCode(interp, &tokenlist, fileNameObj);
+
+    /* No longer need the token list */
+    ScriptTokenListFree(&tokenlist);
+
+    if (!expr) {
+        goto err;
+    }
+
+#ifdef DEBUG_SHOW_EXPR
+    {
+        int i;
+
+        printf("==== Expr ====\n");
+        for (i = 0; i < expr->len; i++) {
+            ScriptToken *t = &expr->token[i];
+
+            printf("[%2d] %s '%s'\n", i, jim_tt_name(t->type), Jim_String(t->objPtr));
+        }
+    }
+#endif
+
+    /* Check program correctness. */
+    if (ExprCheckCorrectness(expr) != JIM_OK) {
+        ExprFreeByteCode(interp, expr);
+        goto invalidexpr;
+    }
+
+    rc = JIM_OK;
+
+  err:
+    /* Free the old internal rep and set the new one. */
+    Jim_DecrRefCount(interp, fileNameObj);
+    Jim_FreeIntRep(interp, objPtr);
+    Jim_SetIntRepPtr(objPtr, expr);
+    objPtr->typePtr = &exprObjType;
+    return rc;
+}
+
+static ExprByteCode *JimGetExpression(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    if (objPtr->typePtr != &exprObjType) {
+        if (SetExprFromAny(interp, objPtr) != JIM_OK) {
+            return NULL;
+        }
+    }
+    return (ExprByteCode *) Jim_GetIntRepPtr(objPtr);
+}
+
+/* -----------------------------------------------------------------------------
+ * Expressions evaluation.
+ * Jim uses a specialized stack-based virtual machine for expressions,
+ * that takes advantage of the fact that expr's operators
+ * can't be redefined.
+ *
+ * Jim_EvalExpression() uses the bytecode compiled by
+ * SetExprFromAny() method of the "expression" object.
+ *
+ * On success a Tcl Object containing the result of the evaluation
+ * is stored into expResultPtrPtr (having refcount of 1), and JIM_OK is
+ * returned.
+ * On error the function returns a retcode != to JIM_OK and set a suitable
+ * error on the interp.
+ * ---------------------------------------------------------------------------*/
+#define JIM_EE_STATICSTACK_LEN 10
+
+int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr)
+{
+    ExprByteCode *expr;
+    Jim_Obj *staticStack[JIM_EE_STATICSTACK_LEN];
+    int i;
+    int retcode = JIM_OK;
+    struct JimExprState e;
+
+    expr = JimGetExpression(interp, exprObjPtr);
+    if (!expr) {
+        return JIM_ERR;         /* error in expression. */
+    }
+
+#ifdef JIM_OPTIMIZATION
+    /* Check for one of the following common expressions used by while/for
+     *
+     *   CONST
+     *   $a
+     *   !$a
+     *   $a < CONST, $a < $b
+     *   $a <= CONST, $a <= $b
+     *   $a > CONST, $a > $b
+     *   $a >= CONST, $a >= $b
+     *   $a != CONST, $a != $b
+     *   $a == CONST, $a == $b
+     */
+    {
+        Jim_Obj *objPtr;
+
+        /* STEP 1 -- Check if there are the conditions to run the specialized
+         * version of while */
+
+        switch (expr->len) {
+            case 1:
+                if (expr->token[0].type == JIM_TT_EXPR_INT) {
+                    *exprResultPtrPtr = expr->token[0].objPtr;
+                    Jim_IncrRefCount(*exprResultPtrPtr);
+                    return JIM_OK;
+                }
+                if (expr->token[0].type == JIM_TT_VAR) {
+                    objPtr = Jim_GetVariable(interp, expr->token[0].objPtr, JIM_ERRMSG);
+                    if (objPtr) {
+                        *exprResultPtrPtr = objPtr;
+                        Jim_IncrRefCount(*exprResultPtrPtr);
+                        return JIM_OK;
+                    }
+                }
+                break;
+
+            case 2:
+                if (expr->token[1].type == JIM_EXPROP_NOT && expr->token[0].type == JIM_TT_VAR) {
+                    jim_wide wideValue;
+
+                    objPtr = Jim_GetVariable(interp, expr->token[0].objPtr, JIM_NONE);
+                    if (objPtr && JimIsWide(objPtr)
+                        && Jim_GetWide(interp, objPtr, &wideValue) == JIM_OK) {
+                        *exprResultPtrPtr = wideValue ? interp->falseObj : interp->trueObj;
+                        Jim_IncrRefCount(*exprResultPtrPtr);
+                        return JIM_OK;
+                    }
+                }
+                break;
+
+            case 3:
+                if (expr->token[0].type == JIM_TT_VAR && (expr->token[1].type == JIM_TT_EXPR_INT
+                        || expr->token[1].type == JIM_TT_VAR)) {
+                    switch (expr->token[2].type) {
+                        case JIM_EXPROP_LT:
+                        case JIM_EXPROP_LTE:
+                        case JIM_EXPROP_GT:
+                        case JIM_EXPROP_GTE:
+                        case JIM_EXPROP_NUMEQ:
+                        case JIM_EXPROP_NUMNE:{
+                                /* optimise ok */
+                                jim_wide wideValueA;
+                                jim_wide wideValueB;
+
+                                objPtr = Jim_GetVariable(interp, expr->token[0].objPtr, JIM_NONE);
+                                if (objPtr && JimIsWide(objPtr)
+                                    && Jim_GetWide(interp, objPtr, &wideValueA) == JIM_OK) {
+                                    if (expr->token[1].type == JIM_TT_VAR) {
+                                        objPtr =
+                                            Jim_GetVariable(interp, expr->token[1].objPtr,
+                                            JIM_NONE);
+                                    }
+                                    else {
+                                        objPtr = expr->token[1].objPtr;
+                                    }
+                                    if (objPtr && JimIsWide(objPtr)
+                                        && Jim_GetWide(interp, objPtr, &wideValueB) == JIM_OK) {
+                                        int cmpRes;
+
+                                        switch (expr->token[2].type) {
+                                            case JIM_EXPROP_LT:
+                                                cmpRes = wideValueA < wideValueB;
+                                                break;
+                                            case JIM_EXPROP_LTE:
+                                                cmpRes = wideValueA <= wideValueB;
+                                                break;
+                                            case JIM_EXPROP_GT:
+                                                cmpRes = wideValueA > wideValueB;
+                                                break;
+                                            case JIM_EXPROP_GTE:
+                                                cmpRes = wideValueA >= wideValueB;
+                                                break;
+                                            case JIM_EXPROP_NUMEQ:
+                                                cmpRes = wideValueA == wideValueB;
+                                                break;
+                                            case JIM_EXPROP_NUMNE:
+                                                cmpRes = wideValueA != wideValueB;
+                                                break;
+                                            default:   /*notreached */
+                                                cmpRes = 0;
+                                        }
+                                        *exprResultPtrPtr =
+                                            cmpRes ? interp->trueObj : interp->falseObj;
+                                        Jim_IncrRefCount(*exprResultPtrPtr);
+                                        return JIM_OK;
+                                    }
+                                }
+                            }
+                    }
+                }
+                break;
+        }
+    }
+#endif
+
+    /* In order to avoid that the internal repr gets freed due to
+     * shimmering of the exprObjPtr's object, we make the internal rep
+     * shared. */
+    expr->inUse++;
+
+    /* The stack-based expr VM itself */
+
+    /* Stack allocation. Expr programs have the feature that
+     * a program of length N can't require a stack longer than
+     * N. */
+    if (expr->len > JIM_EE_STATICSTACK_LEN)
+        e.stack = Jim_Alloc(sizeof(Jim_Obj *) * expr->len);
+    else
+        e.stack = staticStack;
+
+    e.stacklen = 0;
+
+    /* Execute every instruction */
+    for (i = 0; i < expr->len && retcode == JIM_OK; i++) {
+        Jim_Obj *objPtr;
+
+        switch (expr->token[i].type) {
+            case JIM_TT_EXPR_INT:
+            case JIM_TT_EXPR_DOUBLE:
+            case JIM_TT_STR:
+                ExprPush(&e, expr->token[i].objPtr);
+                break;
+
+            case JIM_TT_VAR:
+                objPtr = Jim_GetVariable(interp, expr->token[i].objPtr, JIM_ERRMSG);
+                if (objPtr) {
+                    ExprPush(&e, objPtr);
+                }
+                else {
+                    retcode = JIM_ERR;
+                }
+                break;
+
+            case JIM_TT_DICTSUGAR:
+                objPtr = JimExpandDictSugar(interp, expr->token[i].objPtr);
+                if (objPtr) {
+                    ExprPush(&e, objPtr);
+                }
+                else {
+                    retcode = JIM_ERR;
+                }
+                break;
+
+            case JIM_TT_ESC:
+                retcode = Jim_SubstObj(interp, expr->token[i].objPtr, &objPtr, JIM_NONE);
+                if (retcode == JIM_OK) {
+                    ExprPush(&e, objPtr);
+                }
+                break;
+
+            case JIM_TT_CMD:
+                retcode = Jim_EvalObj(interp, expr->token[i].objPtr);
+                if (retcode == JIM_OK) {
+                    ExprPush(&e, Jim_GetResult(interp));
+                }
+                break;
+
+            default:{
+                    /* Find and execute the operation */
+                    e.skip = 0;
+                    e.opcode = expr->token[i].type;
+
+                    retcode = JimExprOperatorInfoByOpcode(e.opcode)->funcop(interp, &e);
+                    /* Skip some opcodes if necessary */
+                    i += e.skip;
+                    continue;
+                }
+        }
+    }
+
+    expr->inUse--;
+
+    if (retcode == JIM_OK) {
+        *exprResultPtrPtr = ExprPop(&e);
+    }
+    else {
+        for (i = 0; i < e.stacklen; i++) {
+            Jim_DecrRefCount(interp, e.stack[i]);
+        }
+    }
+    if (e.stack != staticStack) {
+        Jim_Free(e.stack);
+    }
+    return retcode;
+}
+
+int Jim_GetBoolFromExpr(Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr)
+{
+    int retcode;
+    jim_wide wideValue;
+    double doubleValue;
+    Jim_Obj *exprResultPtr;
+
+    retcode = Jim_EvalExpression(interp, exprObjPtr, &exprResultPtr);
+    if (retcode != JIM_OK)
+        return retcode;
+
+    if (JimGetWideNoErr(interp, exprResultPtr, &wideValue) != JIM_OK) {
+        if (Jim_GetDouble(interp, exprResultPtr, &doubleValue) != JIM_OK) {
+            Jim_DecrRefCount(interp, exprResultPtr);
+            return JIM_ERR;
+        }
+        else {
+            Jim_DecrRefCount(interp, exprResultPtr);
+            *boolPtr = doubleValue != 0;
+            return JIM_OK;
+        }
+    }
+    *boolPtr = wideValue != 0;
+
+    Jim_DecrRefCount(interp, exprResultPtr);
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * ScanFormat String Object
+ * ---------------------------------------------------------------------------*/
+
+/* This Jim_Obj will held a parsed representation of a format string passed to
+ * the Jim_ScanString command. For error diagnostics, the scanformat string has
+ * to be parsed in its entirely first and then, if correct, can be used for
+ * scanning. To avoid endless re-parsing, the parsed representation will be
+ * stored in an internal representation and re-used for performance reason. */
+
+/* A ScanFmtPartDescr will held the information of /one/ part of the whole
+ * scanformat string. This part will later be used to extract information
+ * out from the string to be parsed by Jim_ScanString */
+
+typedef struct ScanFmtPartDescr
+{
+    char type;                  /* Type of conversion (e.g. c, d, f) */
+    char modifier;              /* Modify type (e.g. l - long, h - short */
+    size_t width;               /* Maximal width of input to be converted */
+    int pos;                    /* -1 - no assign, 0 - natural pos, >0 - XPG3 pos */
+    char *arg;                  /* Specification of a CHARSET conversion */
+    char *prefix;               /* Prefix to be scanned literally before conversion */
+} ScanFmtPartDescr;
+
+/* The ScanFmtStringObj will hold the internal representation of a scanformat
+ * string parsed and separated in part descriptions. Furthermore it contains
+ * the original string representation of the scanformat string to allow for
+ * fast update of the Jim_Obj's string representation part.
+ *
+ * As an add-on the internal object representation adds some scratch pad area
+ * for usage by Jim_ScanString to avoid endless allocating and freeing of
+ * memory for purpose of string scanning.
+ *
+ * The error member points to a static allocated string in case of a mal-
+ * formed scanformat string or it contains '0' (NULL) in case of a valid
+ * parse representation.
+ *
+ * The whole memory of the internal representation is allocated as a single
+ * area of memory that will be internally separated. So freeing and duplicating
+ * of such an object is cheap */
+
+typedef struct ScanFmtStringObj
+{
+    jim_wide size;              /* Size of internal repr in bytes */
+    char *stringRep;            /* Original string representation */
+    size_t count;               /* Number of ScanFmtPartDescr contained */
+    size_t convCount;           /* Number of conversions that will assign */
+    size_t maxPos;              /* Max position index if XPG3 is used */
+    const char *error;          /* Ptr to error text (NULL if no error */
+    char *scratch;              /* Some scratch pad used by Jim_ScanString */
+    ScanFmtPartDescr descr[1];  /* The vector of partial descriptions */
+} ScanFmtStringObj;
+
+
+static void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static void UpdateStringOfScanFmt(Jim_Obj *objPtr);
+
+static const Jim_ObjType scanFmtStringObjType = {
+    "scanformatstring",
+    FreeScanFmtInternalRep,
+    DupScanFmtInternalRep,
+    UpdateStringOfScanFmt,
+    JIM_TYPE_NONE,
+};
+
+void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    JIM_NOTUSED(interp);
+    Jim_Free((char *)objPtr->internalRep.ptr);
+    objPtr->internalRep.ptr = 0;
+}
+
+void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+    size_t size = (size_t) ((ScanFmtStringObj *) srcPtr->internalRep.ptr)->size;
+    ScanFmtStringObj *newVec = (ScanFmtStringObj *) Jim_Alloc(size);
+
+    JIM_NOTUSED(interp);
+    memcpy(newVec, srcPtr->internalRep.ptr, size);
+    dupPtr->internalRep.ptr = newVec;
+    dupPtr->typePtr = &scanFmtStringObjType;
+}
+
+void UpdateStringOfScanFmt(Jim_Obj *objPtr)
+{
+    char *bytes = ((ScanFmtStringObj *) objPtr->internalRep.ptr)->stringRep;
+
+    objPtr->bytes = Jim_StrDup(bytes);
+    objPtr->length = strlen(bytes);
+}
+
+/* SetScanFmtFromAny will parse a given string and create the internal
+ * representation of the format specification. In case of an error
+ * the error data member of the internal representation will be set
+ * to an descriptive error text and the function will be left with
+ * JIM_ERR to indicate unsucessful parsing (aka. malformed scanformat
+ * specification */
+
+static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    ScanFmtStringObj *fmtObj;
+    char *buffer;
+    int maxCount, i, approxSize, lastPos = -1;
+    const char *fmt = objPtr->bytes;
+    int maxFmtLen = objPtr->length;
+    const char *fmtEnd = fmt + maxFmtLen;
+    int curr;
+
+    Jim_FreeIntRep(interp, objPtr);
+    /* Count how many conversions could take place maximally */
+    for (i = 0, maxCount = 0; i < maxFmtLen; ++i)
+        if (fmt[i] == '%')
+            ++maxCount;
+    /* Calculate an approximation of the memory necessary */
+    approxSize = sizeof(ScanFmtStringObj)       /* Size of the container */
+        +(maxCount + 1) * sizeof(ScanFmtPartDescr)      /* Size of all partials */
+        +maxFmtLen * sizeof(char) + 3 + 1       /* Scratch + "%n" + '\0' */
+        + maxFmtLen * sizeof(char) + 1  /* Original stringrep */
+        + maxFmtLen * sizeof(char)      /* Arg for CHARSETs */
+        +(maxCount + 1) * sizeof(char)  /* '\0' for every partial */
+        +1;                     /* safety byte */
+    fmtObj = (ScanFmtStringObj *) Jim_Alloc(approxSize);
+    memset(fmtObj, 0, approxSize);
+    fmtObj->size = approxSize;
+    fmtObj->maxPos = 0;
+    fmtObj->scratch = (char *)&fmtObj->descr[maxCount + 1];
+    fmtObj->stringRep = fmtObj->scratch + maxFmtLen + 3 + 1;
+    memcpy(fmtObj->stringRep, fmt, maxFmtLen);
+    buffer = fmtObj->stringRep + maxFmtLen + 1;
+    objPtr->internalRep.ptr = fmtObj;
+    objPtr->typePtr = &scanFmtStringObjType;
+    for (i = 0, curr = 0; fmt < fmtEnd; ++fmt) {
+        int width = 0, skip;
+        ScanFmtPartDescr *descr = &fmtObj->descr[curr];
+
+        fmtObj->count++;
+        descr->width = 0;       /* Assume width unspecified */
+        /* Overread and store any "literal" prefix */
+        if (*fmt != '%' || fmt[1] == '%') {
+            descr->type = 0;
+            descr->prefix = &buffer[i];
+            for (; fmt < fmtEnd; ++fmt) {
+                if (*fmt == '%') {
+                    if (fmt[1] != '%')
+                        break;
+                    ++fmt;
+                }
+                buffer[i++] = *fmt;
+            }
+            buffer[i++] = 0;
+        }
+        /* Skip the conversion introducing '%' sign */
+        ++fmt;
+        /* End reached due to non-conversion literal only? */
+        if (fmt >= fmtEnd)
+            goto done;
+        descr->pos = 0;         /* Assume "natural" positioning */
+        if (*fmt == '*') {
+            descr->pos = -1;    /* Okay, conversion will not be assigned */
+            ++fmt;
+        }
+        else
+            fmtObj->convCount++;        /* Otherwise count as assign-conversion */
+        /* Check if next token is a number (could be width or pos */
+        if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
+            fmt += skip;
+            /* Was the number a XPG3 position specifier? */
+            if (descr->pos != -1 && *fmt == '$') {
+                int prev;
+
+                ++fmt;
+                descr->pos = width;
+                width = 0;
+                /* Look if "natural" postioning and XPG3 one was mixed */
+                if ((lastPos == 0 && descr->pos > 0)
+                    || (lastPos > 0 && descr->pos == 0)) {
+                    fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers";
+                    return JIM_ERR;
+                }
+                /* Look if this position was already used */
+                for (prev = 0; prev < curr; ++prev) {
+                    if (fmtObj->descr[prev].pos == -1)
+                        continue;
+                    if (fmtObj->descr[prev].pos == descr->pos) {
+                        fmtObj->error =
+                            "variable is assigned by multiple \"%n$\" conversion specifiers";
+                        return JIM_ERR;
+                    }
+                }
+                /* Try to find a width after the XPG3 specifier */
+                if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
+                    descr->width = width;
+                    fmt += skip;
+                }
+                if (descr->pos > 0 && (size_t) descr->pos > fmtObj->maxPos)
+                    fmtObj->maxPos = descr->pos;
+            }
+            else {
+                /* Number was not a XPG3, so it has to be a width */
+                descr->width = width;
+            }
+        }
+        /* If positioning mode was undetermined yet, fix this */
+        if (lastPos == -1)
+            lastPos = descr->pos;
+        /* Handle CHARSET conversion type ... */
+        if (*fmt == '[') {
+            int swapped = 1, beg = i, end, j;
+
+            descr->type = '[';
+            descr->arg = &buffer[i];
+            ++fmt;
+            if (*fmt == '^')
+                buffer[i++] = *fmt++;
+            if (*fmt == ']')
+                buffer[i++] = *fmt++;
+            while (*fmt && *fmt != ']')
+                buffer[i++] = *fmt++;
+            if (*fmt != ']') {
+                fmtObj->error = "unmatched [ in format string";
+                return JIM_ERR;
+            }
+            end = i;
+            buffer[i++] = 0;
+            /* In case a range fence was given "backwards", swap it */
+            while (swapped) {
+                swapped = 0;
+                for (j = beg + 1; j < end - 1; ++j) {
+                    if (buffer[j] == '-' && buffer[j - 1] > buffer[j + 1]) {
+                        char tmp = buffer[j - 1];
+
+                        buffer[j - 1] = buffer[j + 1];
+                        buffer[j + 1] = tmp;
+                        swapped = 1;
+                    }
+                }
+            }
+        }
+        else {
+            /* Remember any valid modifier if given */
+            if (strchr("hlL", *fmt) != 0)
+                descr->modifier = tolower((int)*fmt++);
+
+            descr->type = *fmt;
+            if (strchr("efgcsndoxui", *fmt) == 0) {
+                fmtObj->error = "bad scan conversion character";
+                return JIM_ERR;
+            }
+            else if (*fmt == 'c' && descr->width != 0) {
+                fmtObj->error = "field width may not be specified in %c " "conversion";
+                return JIM_ERR;
+            }
+            else if (*fmt == 'u' && descr->modifier == 'l') {
+                fmtObj->error = "unsigned wide not supported";
+                return JIM_ERR;
+            }
+        }
+        curr++;
+    }
+  done:
+    return JIM_OK;
+}
+
+/* Some accessor macros to allow lowlevel access to fields of internal repr */
+
+#define FormatGetCnvCount(_fo_) \
+    ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount
+#define FormatGetMaxPos(_fo_) \
+    ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos
+#define FormatGetError(_fo_) \
+    ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error
+
+/* JimScanAString is used to scan an unspecified string that ends with
+ * next WS, or a string that is specified via a charset.
+ *
+ */
+static Jim_Obj *JimScanAString(Jim_Interp *interp, const char *sdescr, const char *str)
+{
+    char *buffer = Jim_StrDup(str);
+    char *p = buffer;
+
+    while (*str) {
+        int c;
+        int n;
+
+        if (!sdescr && isspace(UCHAR(*str)))
+            break;              /* EOS via WS if unspecified */
+
+        n = utf8_tounicode(str, &c);
+        if (sdescr && !JimCharsetMatch(sdescr, c, JIM_CHARSET_SCAN))
+            break;
+        while (n--)
+            *p++ = *str++;
+    }
+    *p = 0;
+    return Jim_NewStringObjNoAlloc(interp, buffer, p - buffer);
+}
+
+/* ScanOneEntry will scan one entry out of the string passed as argument.
+ * It use the sscanf() function for this task. After extracting and
+ * converting of the value, the count of scanned characters will be
+ * returned of -1 in case of no conversion tool place and string was
+ * already scanned thru */
+
+static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int strLen,
+    ScanFmtStringObj * fmtObj, long idx, Jim_Obj **valObjPtr)
+{
+    const char *tok;
+    const ScanFmtPartDescr *descr = &fmtObj->descr[idx];
+    size_t scanned = 0;
+    size_t anchor = pos;
+    int i;
+    Jim_Obj *tmpObj = NULL;
+
+    /* First pessimistically assume, we will not scan anything :-) */
+    *valObjPtr = 0;
+    if (descr->prefix) {
+        /* There was a prefix given before the conversion, skip it and adjust
+         * the string-to-be-parsed accordingly */
+        /* XXX: Should be checking strLen, not str[pos] */
+        for (i = 0; pos < strLen && descr->prefix[i]; ++i) {
+            /* If prefix require, skip WS */
+            if (isspace(UCHAR(descr->prefix[i])))
+                while (pos < strLen && isspace(UCHAR(str[pos])))
+                    ++pos;
+            else if (descr->prefix[i] != str[pos])
+                break;          /* Prefix do not match here, leave the loop */
+            else
+                ++pos;          /* Prefix matched so far, next round */
+        }
+        if (pos >= strLen) {
+            return -1;          /* All of str consumed: EOF condition */
+        }
+        else if (descr->prefix[i] != 0)
+            return 0;           /* Not whole prefix consumed, no conversion possible */
+    }
+    /* For all but following conversion, skip leading WS */
+    if (descr->type != 'c' && descr->type != '[' && descr->type != 'n')
+        while (isspace(UCHAR(str[pos])))
+            ++pos;
+    /* Determine how much skipped/scanned so far */
+    scanned = pos - anchor;
+
+    /* %c is a special, simple case. no width */
+    if (descr->type == 'n') {
+        /* Return pseudo conversion means: how much scanned so far? */
+        *valObjPtr = Jim_NewIntObj(interp, anchor + scanned);
+    }
+    else if (pos >= strLen) {
+        /* Cannot scan anything, as str is totally consumed */
+        return -1;
+    }
+    else if (descr->type == 'c') {
+            int c;
+            scanned += utf8_tounicode(&str[pos], &c);
+            *valObjPtr = Jim_NewIntObj(interp, c);
+            return scanned;
+    }
+    else {
+        /* Processing of conversions follows ... */
+        if (descr->width > 0) {
+            /* Do not try to scan as fas as possible but only the given width.
+             * To ensure this, we copy the part that should be scanned. */
+            size_t sLen = utf8_strlen(&str[pos], strLen - pos);
+            size_t tLen = descr->width > sLen ? sLen : descr->width;
+
+            tmpObj = Jim_NewStringObjUtf8(interp, str + pos, tLen);
+            tok = tmpObj->bytes;
+        }
+        else {
+            /* As no width was given, simply refer to the original string */
+            tok = &str[pos];
+        }
+        switch (descr->type) {
+            case 'd':
+            case 'o':
+            case 'x':
+            case 'u':
+            case 'i':{
+                    char *endp; /* Position where the number finished */
+                    jim_wide w;
+
+                    int base = descr->type == 'o' ? 8
+                        : descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10;
+
+                    /* Try to scan a number with the given base */
+                    w = strtoull(tok, &endp, base);
+                    if (endp == tok && base == 0) {
+                        /* If scanning failed, and base was undetermined, simply
+                         * put it to 10 and try once more. This should catch the
+                         * case where %i begin to parse a number prefix (e.g.
+                         * '0x' but no further digits follows. This will be
+                         * handled as a ZERO followed by a char 'x' by Tcl */
+                        w = strtoull(tok, &endp, 10);
+                    }
+
+                    if (endp != tok) {
+                        /* There was some number sucessfully scanned! */
+                        *valObjPtr = Jim_NewIntObj(interp, w);
+
+                        /* Adjust the number-of-chars scanned so far */
+                        scanned += endp - tok;
+                    }
+                    else {
+                        /* Nothing was scanned. We have to determine if this
+                         * happened due to e.g. prefix mismatch or input str
+                         * exhausted */
+                        scanned = *tok ? 0 : -1;
+                    }
+                    break;
+                }
+            case 's':
+            case '[':{
+                    *valObjPtr = JimScanAString(interp, descr->arg, tok);
+                    scanned += Jim_Length(*valObjPtr);
+                    break;
+                }
+            case 'e':
+            case 'f':
+            case 'g':{
+                    char *endp;
+                    double value = strtod(tok, &endp);
+
+                    if (endp != tok) {
+                        /* There was some number sucessfully scanned! */
+                        *valObjPtr = Jim_NewDoubleObj(interp, value);
+                        /* Adjust the number-of-chars scanned so far */
+                        scanned += endp - tok;
+                    }
+                    else {
+                        /* Nothing was scanned. We have to determine if this
+                         * happened due to e.g. prefix mismatch or input str
+                         * exhausted */
+                        scanned = *tok ? 0 : -1;
+                    }
+                    break;
+                }
+        }
+        /* If a substring was allocated (due to pre-defined width) do not
+         * forget to free it */
+        if (tmpObj) {
+            Jim_FreeNewObj(interp, tmpObj);
+        }
+    }
+    return scanned;
+}
+
+/* Jim_ScanString is the workhorse of string scanning. It will scan a given
+ * string and returns all converted (and not ignored) values in a list back
+ * to the caller. If an error occured, a NULL pointer will be returned */
+
+Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjPtr, int flags)
+{
+    size_t i, pos;
+    int scanned = 1;
+    const char *str = Jim_String(strObjPtr);
+    int strLen = Jim_Utf8Length(interp, strObjPtr);
+    Jim_Obj *resultList = 0;
+    Jim_Obj **resultVec = 0;
+    int resultc;
+    Jim_Obj *emptyStr = 0;
+    ScanFmtStringObj *fmtObj;
+
+    /* This should never happen. The format object should already be of the correct type */
+    JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, "Jim_ScanString() for non-scan format"));
+
+    fmtObj = (ScanFmtStringObj *) fmtObjPtr->internalRep.ptr;
+    /* Check if format specification was valid */
+    if (fmtObj->error != 0) {
+        if (flags & JIM_ERRMSG)
+            Jim_SetResultString(interp, fmtObj->error, -1);
+        return 0;
+    }
+    /* Allocate a new "shared" empty string for all unassigned conversions */
+    emptyStr = Jim_NewEmptyStringObj(interp);
+    Jim_IncrRefCount(emptyStr);
+    /* Create a list and fill it with empty strings up to max specified XPG3 */
+    resultList = Jim_NewListObj(interp, 0, 0);
+    if (fmtObj->maxPos > 0) {
+        for (i = 0; i < fmtObj->maxPos; ++i)
+            Jim_ListAppendElement(interp, resultList, emptyStr);
+        JimListGetElements(interp, resultList, &resultc, &resultVec);
+    }
+    /* Now handle every partial format description */
+    for (i = 0, pos = 0; i < fmtObj->count; ++i) {
+        ScanFmtPartDescr *descr = &(fmtObj->descr[i]);
+        Jim_Obj *value = 0;
+
+        /* Only last type may be "literal" w/o conversion - skip it! */
+        if (descr->type == 0)
+            continue;
+        /* As long as any conversion could be done, we will proceed */
+        if (scanned > 0)
+            scanned = ScanOneEntry(interp, str, pos, strLen, fmtObj, i, &value);
+        /* In case our first try results in EOF, we will leave */
+        if (scanned == -1 && i == 0)
+            goto eof;
+        /* Advance next pos-to-be-scanned for the amount scanned already */
+        pos += scanned;
+
+        /* value == 0 means no conversion took place so take empty string */
+        if (value == 0)
+            value = Jim_NewEmptyStringObj(interp);
+        /* If value is a non-assignable one, skip it */
+        if (descr->pos == -1) {
+            Jim_FreeNewObj(interp, value);
+        }
+        else if (descr->pos == 0)
+            /* Otherwise append it to the result list if no XPG3 was given */
+            Jim_ListAppendElement(interp, resultList, value);
+        else if (resultVec[descr->pos - 1] == emptyStr) {
+            /* But due to given XPG3, put the value into the corr. slot */
+            Jim_DecrRefCount(interp, resultVec[descr->pos - 1]);
+            Jim_IncrRefCount(value);
+            resultVec[descr->pos - 1] = value;
+        }
+        else {
+            /* Otherwise, the slot was already used - free obj and ERROR */
+            Jim_FreeNewObj(interp, value);
+            goto err;
+        }
+    }
+    Jim_DecrRefCount(interp, emptyStr);
+    return resultList;
+  eof:
+    Jim_DecrRefCount(interp, emptyStr);
+    Jim_FreeNewObj(interp, resultList);
+    return (Jim_Obj *)EOF;
+  err:
+    Jim_DecrRefCount(interp, emptyStr);
+    Jim_FreeNewObj(interp, resultList);
+    return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Pseudo Random Number Generation
+ * ---------------------------------------------------------------------------*/
+/* Initialize the sbox with the numbers from 0 to 255 */
+static void JimPrngInit(Jim_Interp *interp)
+{
+#define PRNG_SEED_SIZE 256
+    int i;
+    unsigned int *seed;
+    time_t t = time(NULL);
+
+    interp->prngState = Jim_Alloc(sizeof(Jim_PrngState));
+
+    seed = Jim_Alloc(PRNG_SEED_SIZE * sizeof(*seed));
+    for (i = 0; i < PRNG_SEED_SIZE; i++) {
+        seed[i] = (rand() ^ t ^ clock());
+    }
+    JimPrngSeed(interp, (unsigned char *)seed, PRNG_SEED_SIZE * sizeof(*seed));
+    Jim_Free(seed);
+}
+
+/* Generates N bytes of random data */
+static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len)
+{
+    Jim_PrngState *prng;
+    unsigned char *destByte = (unsigned char *)dest;
+    unsigned int si, sj, x;
+
+    /* initialization, only needed the first time */
+    if (interp->prngState == NULL)
+        JimPrngInit(interp);
+    prng = interp->prngState;
+    /* generates 'len' bytes of pseudo-random numbers */
+    for (x = 0; x < len; x++) {
+        prng->i = (prng->i + 1) & 0xff;
+        si = prng->sbox[prng->i];
+        prng->j = (prng->j + si) & 0xff;
+        sj = prng->sbox[prng->j];
+        prng->sbox[prng->i] = sj;
+        prng->sbox[prng->j] = si;
+        *destByte++ = prng->sbox[(si + sj) & 0xff];
+    }
+}
+
+/* Re-seed the generator with user-provided bytes */
+static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen)
+{
+    int i;
+    Jim_PrngState *prng;
+
+    /* initialization, only needed the first time */
+    if (interp->prngState == NULL)
+        JimPrngInit(interp);
+    prng = interp->prngState;
+
+    /* Set the sbox[i] with i */
+    for (i = 0; i < 256; i++)
+        prng->sbox[i] = i;
+    /* Now use the seed to perform a random permutation of the sbox */
+    for (i = 0; i < seedLen; i++) {
+        unsigned char t;
+
+        t = prng->sbox[i & 0xFF];
+        prng->sbox[i & 0xFF] = prng->sbox[seed[i]];
+        prng->sbox[seed[i]] = t;
+    }
+    prng->i = prng->j = 0;
+
+    /* discard at least the first 256 bytes of stream.
+     * borrow the seed buffer for this
+     */
+    for (i = 0; i < 256; i += seedLen) {
+        JimRandomBytes(interp, seed, seedLen);
+    }
+}
+
+/* [incr] */
+static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    jim_wide wideValue, increment = 1;
+    Jim_Obj *intObjPtr;
+
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "varName ?increment?");
+        return JIM_ERR;
+    }
+    if (argc == 3) {
+        if (Jim_GetWide(interp, argv[2], &increment) != JIM_OK)
+            return JIM_ERR;
+    }
+    intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
+    if (!intObjPtr) {
+        /* Set missing variable to 0 */
+        wideValue = 0;
+    }
+    else if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK) {
+        return JIM_ERR;
+    }
+    if (!intObjPtr || Jim_IsShared(intObjPtr)) {
+        intObjPtr = Jim_NewIntObj(interp, wideValue + increment);
+        if (Jim_SetVariable(interp, argv[1], intObjPtr) != JIM_OK) {
+            Jim_FreeNewObj(interp, intObjPtr);
+            return JIM_ERR;
+        }
+    }
+    else {
+        /* Can do it the quick way */
+        Jim_InvalidateStringRep(intObjPtr);
+        JimWideValue(intObjPtr) = wideValue + increment;
+
+        /* The following step is required in order to invalidate the
+         * string repr of "FOO" if the var name is on the form of "FOO(IDX)" */
+        if (argv[1]->typePtr != &variableObjType) {
+            /* Note that this can't fail since GetVariable already succeeded */
+            Jim_SetVariable(interp, argv[1], intObjPtr);
+        }
+    }
+    Jim_SetResult(interp, intObjPtr);
+    return JIM_OK;
+}
+
+
+/* -----------------------------------------------------------------------------
+ * Eval
+ * ---------------------------------------------------------------------------*/
+#define JIM_EVAL_SARGV_LEN 8    /* static arguments vector length */
+#define JIM_EVAL_SINTV_LEN 8    /* static interpolation vector length */
+
+/* Handle calls to the [unknown] command */
+static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv, Jim_Obj *fileNameObj,
+    int linenr)
+{
+    Jim_Obj **v, *sv[JIM_EVAL_SARGV_LEN];
+    int retCode;
+
+    /* If JimUnknown() is recursively called too many times...
+     * done here
+     */
+    if (interp->unknown_called > 50) {
+        return JIM_ERR;
+    }
+
+    /* If the [unknown] command does not exists returns
+     * just now */
+    if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL)
+        return JIM_ERR;
+
+    /* The object interp->unknown just contains
+     * the "unknown" string, it is used in order to
+     * avoid to lookup the unknown command every time
+     * but instread to cache the result. */
+    if (argc + 1 <= JIM_EVAL_SARGV_LEN)
+        v = sv;
+    else
+        v = Jim_Alloc(sizeof(Jim_Obj *) * (argc + 1));
+    /* Make a copy of the arguments vector, but shifted on
+     * the right of one position. The command name of the
+     * command will be instead the first argument of the
+     * [unknown] call. */
+    memcpy(v + 1, argv, sizeof(Jim_Obj *) * argc);
+    v[0] = interp->unknown;
+    /* Call it */
+    interp->unknown_called++;
+    retCode = JimEvalObjVector(interp, argc + 1, v, fileNameObj, linenr);
+    interp->unknown_called--;
+
+    /* Clean up */
+    if (v != sv)
+        Jim_Free(v);
+    return retCode;
+}
+
+/* Eval the object vector 'objv' composed of 'objc' elements.
+ * Every element is used as single argument.
+ * Jim_EvalObj() will call this function every time its object
+ * argument is of "list" type, with no string representation.
+ *
+ * This is possible because the string representation of a
+ * list object generated by the UpdateStringOfList is made
+ * in a way that ensures that every list element is a different
+ * command argument. */
+static int JimEvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv,
+    Jim_Obj *fileNameObj, int linenr)
+{
+    int i, retcode;
+    Jim_Cmd *cmdPtr;
+
+    /* Incr refcount of arguments. */
+    for (i = 0; i < objc; i++)
+        Jim_IncrRefCount(objv[i]);
+    /* Command lookup */
+    cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
+    if (cmdPtr == NULL) {
+        retcode = JimUnknown(interp, objc, objv, fileNameObj, linenr);
+    }
+    else {
+        /* Call it -- Make sure result is an empty object. */
+        JimIncrCmdRefCount(cmdPtr);
+        Jim_SetEmptyResult(interp);
+        if (cmdPtr->isproc) {
+            retcode = JimCallProcedure(interp, cmdPtr, fileNameObj, linenr, objc, objv);
+        }
+        else {
+            interp->cmdPrivData = cmdPtr->u.native.privData;
+            retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
+        }
+        JimDecrCmdRefCount(interp, cmdPtr);
+    }
+    /* Decr refcount of arguments and return the retcode */
+    for (i = 0; i < objc; i++)
+        Jim_DecrRefCount(interp, objv[i]);
+
+    return retcode;
+}
+
+int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
+{
+    return JimEvalObjVector(interp, objc, objv, interp->emptyObj, 1);
+}
+
+/**
+ * Invokes 'prefix' as a command with the objv array as arguments.
+ */
+int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *const *objv)
+{
+    int i;
+    int ret;
+    Jim_Obj **nargv = Jim_Alloc((objc + 1) * sizeof(*nargv));
+
+    nargv[0] = prefix;
+    for (i = 0; i < objc; i++) {
+        nargv[i + 1] = objv[i];
+    }
+    ret = Jim_EvalObjVector(interp, objc + 1, nargv);
+    Jim_Free(nargv);
+    return ret;
+}
+
+static void JimAddErrorToStack(Jim_Interp *interp, int retcode, Jim_Obj *fileNameObj, int line)
+{
+    int rc = retcode;
+
+    if (rc == JIM_ERR && !interp->errorFlag) {
+        /* This is the first error, so save the file/line information and reset the stack */
+        interp->errorFlag = 1;
+        Jim_IncrRefCount(fileNameObj);
+        Jim_DecrRefCount(interp, interp->errorFileNameObj);
+        interp->errorFileNameObj = fileNameObj;
+        interp->errorLine = line;
+
+        JimResetStackTrace(interp);
+        /* Always add a level where the error first occurs */
+        interp->addStackTrace++;
+    }
+
+    /* Now if this is an "interesting" level, add it to the stack trace */
+    if (rc == JIM_ERR && interp->addStackTrace > 0) {
+        /* Add the stack info for the current level */
+
+        JimAppendStackTrace(interp, Jim_String(interp->errorProc), fileNameObj, line);
+
+        /* Note: if we didn't have a filename for this level,
+         * don't clear the addStackTrace flag
+         * so we can pick it up at the next level
+         */
+        if (Jim_Length(fileNameObj)) {
+            interp->addStackTrace = 0;
+        }
+
+        Jim_DecrRefCount(interp, interp->errorProc);
+        interp->errorProc = interp->emptyObj;
+        Jim_IncrRefCount(interp->errorProc);
+    }
+    else if (rc == JIM_RETURN && interp->returnCode == JIM_ERR) {
+        /* Propagate the addStackTrace value through 'return -code error' */
+    }
+    else {
+        interp->addStackTrace = 0;
+    }
+}
+
+/* And delete any local procs */
+static void JimDeleteLocalProcs(Jim_Interp *interp)
+{
+    if (interp->localProcs) {
+        char *procname;
+
+        while ((procname = Jim_StackPop(interp->localProcs)) != NULL) {
+            /* If there is a pushed command, find it */
+            Jim_Cmd *prevCmd = NULL;
+            Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, procname);
+            if (he) {
+                Jim_Cmd *cmd = (Jim_Cmd *)he->u.val;
+                if (cmd->isproc && cmd->u.proc.prevCmd) {
+                    prevCmd = cmd->u.proc.prevCmd;
+                    cmd->u.proc.prevCmd = NULL;
+                }
+            }
+
+            /* Delete the local proc */
+            Jim_DeleteCommand(interp, procname);
+
+            if (prevCmd) {
+                /* And restore the pushed command */
+                Jim_AddHashEntry(&interp->commands, procname, prevCmd);
+            }
+            Jim_Free(procname);
+        }
+        Jim_FreeStack(interp->localProcs);
+        Jim_Free(interp->localProcs);
+        interp->localProcs = NULL;
+    }
+}
+
+static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Obj **objPtrPtr)
+{
+    Jim_Obj *objPtr;
+
+    switch (token->type) {
+        case JIM_TT_STR:
+        case JIM_TT_ESC:
+            objPtr = token->objPtr;
+            break;
+        case JIM_TT_VAR:
+            objPtr = Jim_GetVariable(interp, token->objPtr, JIM_ERRMSG);
+            break;
+        case JIM_TT_DICTSUGAR:
+            objPtr = JimExpandDictSugar(interp, token->objPtr);
+            break;
+        case JIM_TT_EXPRSUGAR:
+            objPtr = JimExpandExprSugar(interp, token->objPtr);
+            break;
+        case JIM_TT_CMD:
+            switch (Jim_EvalObj(interp, token->objPtr)) {
+                case JIM_OK:
+                case JIM_RETURN:
+                    objPtr = interp->result;
+                    break;
+                case JIM_BREAK:
+                    /* Stop substituting */
+                    return JIM_BREAK;
+                case JIM_CONTINUE:
+                    /* just skip this one */
+                    return JIM_CONTINUE;
+                default:
+                    return JIM_ERR;
+            }
+            break;
+        default:
+            JimPanic((1,
+                "default token type (%d) reached " "in Jim_SubstObj().", token->type));
+            objPtr = NULL;
+            break;
+    }
+    if (objPtr) {
+        *objPtrPtr = objPtr;
+        return JIM_OK;
+    }
+    return JIM_ERR;
+}
+
+/* Interpolate the given tokens into a unique Jim_Obj returned by reference
+ * via *objPtrPtr. This function is only called by Jim_EvalObj() and Jim_SubstObj()
+ * The returned object has refcount = 0.
+ */
+static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * token, int tokens, int flags)
+{
+    int totlen = 0, i;
+    Jim_Obj **intv;
+    Jim_Obj *sintv[JIM_EVAL_SINTV_LEN];
+    Jim_Obj *objPtr;
+    char *s;
+
+    if (tokens <= JIM_EVAL_SINTV_LEN)
+        intv = sintv;
+    else
+        intv = Jim_Alloc(sizeof(Jim_Obj *) * tokens);
+
+    /* Compute every token forming the argument
+     * in the intv objects vector. */
+    for (i = 0; i < tokens; i++) {
+        switch (JimSubstOneToken(interp, &token[i], &intv[i])) {
+            case JIM_OK:
+            case JIM_RETURN:
+                break;
+            case JIM_BREAK:
+                if (flags & JIM_SUBST_FLAG) {
+                    /* Stop here */
+                    tokens = i;
+                    continue;
+                }
+                /* XXX: Should probably set an error about break outside loop */
+                /* fall through to error */
+            case JIM_CONTINUE:
+                if (flags & JIM_SUBST_FLAG) {
+                    intv[i] = NULL;
+                    continue;
+                }
+                /* XXX: Ditto continue outside loop */
+                /* fall through to error */
+            default:
+                while (i--) {
+                    Jim_DecrRefCount(interp, intv[i]);
+                }
+                if (intv != sintv) {
+                    Jim_Free(intv);
+                }
+                return NULL;
+        }
+        Jim_IncrRefCount(intv[i]);
+        Jim_String(intv[i]);
+        totlen += intv[i]->length;
+    }
+
+    /* Fast path return for a single token */
+    if (tokens == 1 && intv[0] && intv == sintv) {
+        Jim_DecrRefCount(interp, intv[0]);
+        return intv[0];
+    }
+
+    /* Concatenate every token in an unique
+     * object. */
+    objPtr = Jim_NewStringObjNoAlloc(interp, NULL, 0);
+
+    if (tokens == 4 && token[0].type == JIM_TT_ESC && token[1].type == JIM_TT_ESC
+        && token[2].type == JIM_TT_VAR) {
+        /* May be able to do fast interpolated object -> dictSubst */
+        objPtr->typePtr = &interpolatedObjType;
+        objPtr->internalRep.twoPtrValue.ptr1 = (void *)token;
+        objPtr->internalRep.twoPtrValue.ptr2 = intv[2];
+        Jim_IncrRefCount(intv[2]);
+    }
+
+    s = objPtr->bytes = Jim_Alloc(totlen + 1);
+    objPtr->length = totlen;
+    for (i = 0; i < tokens; i++) {
+        if (intv[i]) {
+            memcpy(s, intv[i]->bytes, intv[i]->length);
+            s += intv[i]->length;
+            Jim_DecrRefCount(interp, intv[i]);
+        }
+    }
+    objPtr->bytes[totlen] = '\0';
+    /* Free the intv vector if not static. */
+    if (intv != sintv) {
+        Jim_Free(intv);
+    }
+
+    return objPtr;
+}
+
+
+/* If listPtr is a list, call JimEvalObjVector() with the given source info.
+ * Otherwise eval with Jim_EvalObj()
+ */
+static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *fileNameObj, int linenr)
+{
+    if (!Jim_IsList(listPtr)) {
+        return Jim_EvalObj(interp, listPtr);
+    }
+    else {
+        int retcode = JIM_OK;
+
+        if (listPtr->internalRep.listValue.len) {
+            Jim_IncrRefCount(listPtr);
+            retcode = JimEvalObjVector(interp,
+                listPtr->internalRep.listValue.len,
+                listPtr->internalRep.listValue.ele, fileNameObj, linenr);
+            Jim_DecrRefCount(interp, listPtr);
+        }
+        return retcode;
+    }
+}
+
+int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
+{
+    int i;
+    ScriptObj *script;
+    ScriptToken *token;
+    int retcode = JIM_OK;
+    Jim_Obj *sargv[JIM_EVAL_SARGV_LEN], **argv = NULL;
+    int linenr = 0;
+
+    interp->errorFlag = 0;
+
+    /* If the object is of type "list", with no string rep we can call
+     * a specialized version of Jim_EvalObj() */
+    if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) {
+        return JimEvalObjList(interp, scriptObjPtr, interp->emptyObj, 1);
+    }
+
+    Jim_IncrRefCount(scriptObjPtr);     /* Make sure it's shared. */
+    script = Jim_GetScript(interp, scriptObjPtr);
+
+    /* Reset the interpreter result. This is useful to
+     * return the empty result in the case of empty program. */
+    Jim_SetEmptyResult(interp);
+
+#ifdef JIM_OPTIMIZATION
+    /* Check for one of the following common scripts used by for, while
+     *
+     *   {}
+     *   incr a
+     */
+    if (script->len == 0) {
+        Jim_DecrRefCount(interp, scriptObjPtr);
+        return JIM_OK;
+    }
+    if (script->len == 3
+        && script->token[1].objPtr->typePtr == &commandObjType
+        && script->token[1].objPtr->internalRep.cmdValue.cmdPtr->isproc == 0
+        && script->token[1].objPtr->internalRep.cmdValue.cmdPtr->u.native.cmdProc == Jim_IncrCoreCommand
+        && script->token[2].objPtr->typePtr == &variableObjType) {
+
+        Jim_Obj *objPtr = Jim_GetVariable(interp, script->token[2].objPtr, JIM_NONE);
+
+        if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
+            JimWideValue(objPtr)++;
+            Jim_InvalidateStringRep(objPtr);
+            Jim_DecrRefCount(interp, scriptObjPtr);
+            Jim_SetResult(interp, objPtr);
+            return JIM_OK;
+        }
+    }
+#endif
+
+    /* Now we have to make sure the internal repr will not be
+     * freed on shimmering.
+     *
+     * Think for example to this:
+     *
+     * set x {llength $x; ... some more code ...}; eval $x
+     *
+     * In order to preserve the internal rep, we increment the
+     * inUse field of the script internal rep structure. */
+    script->inUse++;
+
+    token = script->token;
+    argv = sargv;
+
+    /* Execute every command sequentially until the end of the script
+     * or an error occurs.
+     */
+    for (i = 0; i < script->len && retcode == JIM_OK; ) {
+        int argc;
+        int j;
+        Jim_Cmd *cmd;
+
+        /* First token of the line is always JIM_TT_LINE */
+        argc = token[i].objPtr->internalRep.scriptLineValue.argc;
+        linenr = token[i].objPtr->internalRep.scriptLineValue.line;
+
+        /* Allocate the arguments vector if required */
+        if (argc > JIM_EVAL_SARGV_LEN)
+            argv = Jim_Alloc(sizeof(Jim_Obj *) * argc);
+
+        /* Skip the JIM_TT_LINE token */
+        i++;
+
+        /* Populate the arguments objects.
+         * If an error occurs, retcode will be set and
+         * 'j' will be set to the number of args expanded
+         */
+        for (j = 0; j < argc; j++) {
+            long wordtokens = 1;
+            int expand = 0;
+            Jim_Obj *wordObjPtr = NULL;
+
+            if (token[i].type == JIM_TT_WORD) {
+                wordtokens = JimWideValue(token[i++].objPtr);
+                if (wordtokens < 0) {
+                    expand = 1;
+                    wordtokens = -wordtokens;
+                }
+            }
+
+            if (wordtokens == 1) {
+                /* Fast path if the token does not
+                 * need interpolation */
+
+                switch (token[i].type) {
+                    case JIM_TT_ESC:
+                    case JIM_TT_STR:
+                        wordObjPtr = token[i].objPtr;
+                        break;
+                    case JIM_TT_VAR:
+                        wordObjPtr = Jim_GetVariable(interp, token[i].objPtr, JIM_ERRMSG);
+                        break;
+                    case JIM_TT_EXPRSUGAR:
+                        wordObjPtr = JimExpandExprSugar(interp, token[i].objPtr);
+                        break;
+                    case JIM_TT_DICTSUGAR:
+                        wordObjPtr = JimExpandDictSugar(interp, token[i].objPtr);
+                        break;
+                    case JIM_TT_CMD:
+                        retcode = Jim_EvalObj(interp, token[i].objPtr);
+                        if (retcode == JIM_OK) {
+                            wordObjPtr = Jim_GetResult(interp);
+                        }
+                        break;
+                    default:
+                        JimPanic((1, "default token type reached " "in Jim_EvalObj()."));
+                }
+            }
+            else {
+                /* For interpolation we call a helper
+                 * function to do the work for us. */
+                wordObjPtr = JimInterpolateTokens(interp, token + i, wordtokens, JIM_NONE);
+            }
+
+            if (!wordObjPtr) {
+                if (retcode == JIM_OK) {
+                    retcode = JIM_ERR;
+                }
+                break;
+            }
+
+            Jim_IncrRefCount(wordObjPtr);
+            i += wordtokens;
+
+            if (!expand) {
+                argv[j] = wordObjPtr;
+            }
+            else {
+                /* Need to expand wordObjPtr into multiple args from argv[j] ... */
+                int len = Jim_ListLength(interp, wordObjPtr);
+                int newargc = argc + len - 1;
+                int k;
+
+                if (len > 1) {
+                    if (argv == sargv) {
+                        if (newargc > JIM_EVAL_SARGV_LEN) {
+                            argv = Jim_Alloc(sizeof(*argv) * newargc);
+                            memcpy(argv, sargv, sizeof(*argv) * j);
+                        }
+                    }
+                    else {
+                        /* Need to realloc to make room for (len - 1) more entries */
+                        argv = Jim_Realloc(argv, sizeof(*argv) * newargc);
+                    }
+                }
+
+                /* Now copy in the expanded version */
+                for (k = 0; k < len; k++) {
+                    argv[j++] = wordObjPtr->internalRep.listValue.ele[k];
+                    Jim_IncrRefCount(wordObjPtr->internalRep.listValue.ele[k]);
+                }
+
+                /* The original object reference is no longer needed,
+                 * after the expansion it is no longer present on
+                 * the argument vector, but the single elements are
+                 * in its place. */
+                Jim_DecrRefCount(interp, wordObjPtr);
+
+                /* And update the indexes */
+                j--;
+                argc += len - 1;
+            }
+        }
+
+        if (retcode == JIM_OK && argc) {
+            /* Lookup the command to call */
+            cmd = Jim_GetCommand(interp, argv[0], JIM_ERRMSG);
+            if (cmd != NULL) {
+                /* Call it -- Make sure result is an empty object. */
+                JimIncrCmdRefCount(cmd);
+                Jim_SetEmptyResult(interp);
+                if (cmd->isproc) {
+                    retcode =
+                        JimCallProcedure(interp, cmd, script->fileNameObj, linenr, argc, argv);
+                } else {
+                    interp->cmdPrivData = cmd->u.native.privData;
+                    retcode = cmd->u.native.cmdProc(interp, argc, argv);
+                }
+                JimDecrCmdRefCount(interp, cmd);
+            }
+            else {
+                /* Call [unknown] */
+                retcode = JimUnknown(interp, argc, argv, script->fileNameObj, linenr);
+            }
+            if (interp->signal_level && interp->sigmask) {
+                /* Check for a signal after each command */
+                retcode = JIM_SIGNAL;
+            }
+        }
+
+        /* Finished with the command, so decrement ref counts of each argument */
+        while (j-- > 0) {
+            Jim_DecrRefCount(interp, argv[j]);
+        }
+
+        if (argv != sargv) {
+            Jim_Free(argv);
+            argv = sargv;
+        }
+    }
+
+    /* Possibly add to the error stack trace */
+    JimAddErrorToStack(interp, retcode, script->fileNameObj, linenr);
+
+    /* Note that we don't have to decrement inUse, because the
+     * following code transfers our use of the reference again to
+     * the script object. */
+    Jim_FreeIntRep(interp, scriptObjPtr);
+    scriptObjPtr->typePtr = &scriptObjType;
+    Jim_SetIntRepPtr(scriptObjPtr, script);
+    Jim_DecrRefCount(interp, scriptObjPtr);
+
+    return retcode;
+}
+
+static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argValObj)
+{
+    int retcode;
+    /* If argObjPtr begins with '&', do an automatic upvar */
+    const char *varname = Jim_String(argNameObj);
+    if (*varname == '&') {
+        /* First check that the target variable exists */
+        Jim_Obj *objPtr;
+        Jim_CallFrame *savedCallFrame = interp->framePtr;
+
+        interp->framePtr = interp->framePtr->parentCallFrame;
+        objPtr = Jim_GetVariable(interp, argValObj, JIM_ERRMSG);
+        interp->framePtr = savedCallFrame;
+        if (!objPtr) {
+            return JIM_ERR;
+        }
+
+        /* It exists, so perform the binding. */
+        objPtr = Jim_NewStringObj(interp, varname + 1, -1);
+        Jim_IncrRefCount(objPtr);
+        retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parentCallFrame);
+        Jim_DecrRefCount(interp, objPtr);
+    }
+    else {
+        retcode = Jim_SetVariable(interp, argNameObj, argValObj);
+    }
+    return retcode;
+}
+
+/**
+ * Sets the interp result to be an error message indicating the required proc args.
+ */
+static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cmd *cmd)
+{
+    /* Create a nice error message, consistent with Tcl 8.5 */
+    Jim_Obj *argmsg = Jim_NewStringObj(interp, "", 0);
+    int i;
+
+    for (i = 0; i < cmd->u.proc.argListLen; i++) {
+        Jim_AppendString(interp, argmsg, " ", 1);
+
+        if (i == cmd->u.proc.argsPos) {
+            if (cmd->u.proc.arglist[i].defaultObjPtr) {
+                /* Renamed args */
+                Jim_AppendString(interp, argmsg, "?", 1);
+                Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].defaultObjPtr);
+                Jim_AppendString(interp, argmsg, " ...?", -1);
+            }
+            else {
+                /* We have plain args */
+                Jim_AppendString(interp, argmsg, "?argument ...?", -1);
+            }
+        }
+        else {
+            if (cmd->u.proc.arglist[i].defaultObjPtr) {
+                Jim_AppendString(interp, argmsg, "?", 1);
+                Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].nameObjPtr);
+                Jim_AppendString(interp, argmsg, "?", 1);
+            }
+            else {
+                Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].nameObjPtr);
+            }
+        }
+    }
+    Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s%#s\"", procNameObj, argmsg);
+    Jim_FreeNewObj(interp, argmsg);
+}
+
+/* Call a procedure implemented in Tcl.
+ * It's possible to speed-up a lot this function, currently
+ * the callframes are not cached, but allocated and
+ * destroied every time. What is expecially costly is
+ * to create/destroy the local vars hash table every time.
+ *
+ * This can be fixed just implementing callframes caching
+ * in JimCreateCallFrame() and JimFreeCallFrame(). */
+static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, Jim_Obj *fileNameObj, int linenr, int argc,
+    Jim_Obj *const *argv)
+{
+    Jim_CallFrame *callFramePtr;
+    Jim_Stack *prevLocalProcs;
+    int i, d, retcode, optargs;
+
+    /* Check arity */
+    if (argc - 1 < cmd->u.proc.reqArity ||
+        (cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) {
+        JimSetProcWrongArgs(interp, argv[0], cmd);
+        return JIM_ERR;
+    }
+
+    /* Check if there are too nested calls */
+    if (interp->framePtr->level == interp->maxNestingDepth) {
+        Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
+        return JIM_ERR;
+    }
+
+    /* Create a new callframe */
+    callFramePtr = JimCreateCallFrame(interp, interp->framePtr);
+    callFramePtr->argv = argv;
+    callFramePtr->argc = argc;
+    callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr;
+    callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr;
+    callFramePtr->staticVars = cmd->u.proc.staticVars;
+    callFramePtr->fileNameObj = fileNameObj;
+    callFramePtr->line = linenr;
+    Jim_IncrRefCount(cmd->u.proc.argListObjPtr);
+    Jim_IncrRefCount(cmd->u.proc.bodyObjPtr);
+    interp->framePtr = callFramePtr;
+
+    /* How many optional args are available */
+    optargs = (argc - 1 - cmd->u.proc.reqArity);
+
+    /* Step 'i' along the actual args, and step 'd' along the formal args */
+    i = 1;
+    for (d = 0; d < cmd->u.proc.argListLen; d++) {
+        Jim_Obj *nameObjPtr = cmd->u.proc.arglist[d].nameObjPtr;
+        if (d == cmd->u.proc.argsPos) {
+            /* assign $args */
+            Jim_Obj *listObjPtr;
+            int argsLen = 0;
+            if (cmd->u.proc.reqArity + cmd->u.proc.optArity < argc - 1) {
+                argsLen = argc - 1 - (cmd->u.proc.reqArity + cmd->u.proc.optArity);
+            }
+            listObjPtr = Jim_NewListObj(interp, &argv[i], argsLen);
+
+            /* It is possible to rename args. */
+            if (cmd->u.proc.arglist[d].defaultObjPtr) {
+                nameObjPtr =cmd->u.proc.arglist[d].defaultObjPtr;
+            }
+            retcode = Jim_SetVariable(interp, nameObjPtr, listObjPtr);
+            if (retcode != JIM_OK) {
+                goto badargset;
+            }
+
+            i += argsLen;
+            continue;
+        }
+
+        /* Optional or required? */
+        if (cmd->u.proc.arglist[d].defaultObjPtr == NULL || optargs-- > 0) {
+            retcode = JimSetProcArg(interp, nameObjPtr, argv[i++]);
+        }
+        else {
+            /* Ran out, so use the default */
+            retcode = Jim_SetVariable(interp, nameObjPtr, cmd->u.proc.arglist[d].defaultObjPtr);
+        }
+        if (retcode != JIM_OK) {
+            goto badargset;
+        }
+    }
+
+    /* Install a new stack for local procs */
+    prevLocalProcs = interp->localProcs;
+    interp->localProcs = NULL;
+
+    /* Eval the body */
+    retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr);
+
+    /* Delete any local procs */
+    JimDeleteLocalProcs(interp);
+    interp->localProcs = prevLocalProcs;
+
+badargset:
+    /* Destroy the callframe */
+    interp->framePtr = interp->framePtr->parentCallFrame;
+    if (callFramePtr->vars.size != JIM_HT_INITIAL_SIZE) {
+        JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NONE);
+    }
+    else {
+        JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NOHT);
+    }
+    /* Handle the JIM_EVAL return code */
+    while (retcode == JIM_EVAL) {
+        Jim_Obj *resultScriptObjPtr = Jim_GetResult(interp);
+
+        Jim_IncrRefCount(resultScriptObjPtr);
+        /* Should be a list! */
+        retcode = JimEvalObjList(interp, resultScriptObjPtr, fileNameObj, linenr);
+        Jim_DecrRefCount(interp, resultScriptObjPtr);
+    }
+    /* Handle the JIM_RETURN return code */
+    if (retcode == JIM_RETURN) {
+        if (--interp->returnLevel <= 0) {
+            retcode = interp->returnCode;
+            interp->returnCode = JIM_OK;
+            interp->returnLevel = 0;
+        }
+    }
+    else if (retcode == JIM_ERR) {
+        interp->addStackTrace++;
+        Jim_DecrRefCount(interp, interp->errorProc);
+        interp->errorProc = argv[0];
+        Jim_IncrRefCount(interp->errorProc);
+    }
+    return retcode;
+}
+
+int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script)
+{
+    int retval;
+    Jim_Obj *scriptObjPtr;
+
+    scriptObjPtr = Jim_NewStringObj(interp, script, -1);
+    Jim_IncrRefCount(scriptObjPtr);
+
+    if (filename) {
+        Jim_Obj *prevScriptObj;
+
+        JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
+
+        prevScriptObj = interp->currentScriptObj;
+        interp->currentScriptObj = scriptObjPtr;
+
+        retval = Jim_EvalObj(interp, scriptObjPtr);
+
+        interp->currentScriptObj = prevScriptObj;
+    }
+    else {
+        retval = Jim_EvalObj(interp, scriptObjPtr);
+    }
+    Jim_DecrRefCount(interp, scriptObjPtr);
+    return retval;
+}
+
+int Jim_Eval(Jim_Interp *interp, const char *script)
+{
+    return Jim_EvalObj(interp, Jim_NewStringObj(interp, script, -1));
+}
+
+/* Execute script in the scope of the global level */
+int Jim_EvalGlobal(Jim_Interp *interp, const char *script)
+{
+    int retval;
+    Jim_CallFrame *savedFramePtr = interp->framePtr;
+
+    interp->framePtr = interp->topFramePtr;
+    retval = Jim_Eval(interp, script);
+    interp->framePtr = savedFramePtr;
+
+    return retval;
+}
+
+int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename)
+{
+    int retval;
+    Jim_CallFrame *savedFramePtr = interp->framePtr;
+
+    interp->framePtr = interp->topFramePtr;
+    retval = Jim_EvalFile(interp, filename);
+    interp->framePtr = savedFramePtr;
+
+    return retval;
+}
+
+#include <sys/stat.h>
+
+int Jim_EvalFile(Jim_Interp *interp, const char *filename)
+{
+    FILE *fp;
+    char *buf;
+    Jim_Obj *scriptObjPtr;
+    Jim_Obj *prevScriptObj;
+    struct stat sb;
+    int retcode;
+    int readlen;
+    struct JimParseResult result;
+
+    if (stat(filename, &sb) != 0 || (fp = fopen(filename, "rt")) == NULL) {
+        Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", filename, strerror(errno));
+        return JIM_ERR;
+    }
+    if (sb.st_size == 0) {
+        fclose(fp);
+        return JIM_OK;
+    }
+
+    buf = Jim_Alloc(sb.st_size + 1);
+    readlen = fread(buf, 1, sb.st_size, fp);
+    if (ferror(fp)) {
+        fclose(fp);
+        Jim_Free(buf);
+        Jim_SetResultFormatted(interp, "failed to load file \"%s\": %s", filename, strerror(errno));
+        return JIM_ERR;
+    }
+    fclose(fp);
+    buf[readlen] = 0;
+
+    scriptObjPtr = Jim_NewStringObjNoAlloc(interp, buf, readlen);
+    JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), 1);
+    Jim_IncrRefCount(scriptObjPtr);
+
+    /* Now check the script for unmatched braces, etc. */
+    if (SetScriptFromAny(interp, scriptObjPtr, &result) == JIM_ERR) {
+        const char *msg;
+        char linebuf[20];
+
+        switch (result.missing) {
+            case '[':
+                msg = "unmatched \"[\"";
+                break;
+            case '{':
+                msg = "missing close-brace";
+                break;
+            case '"':
+            default:
+                msg = "missing quote";
+                break;
+        }
+
+        snprintf(linebuf, sizeof(linebuf), "%d", result.line);
+
+        Jim_SetResultFormatted(interp, "%s in \"%s\" at line %s",
+            msg, filename, linebuf);
+        Jim_DecrRefCount(interp, scriptObjPtr);
+        return JIM_ERR;
+    }
+
+    prevScriptObj = interp->currentScriptObj;
+    interp->currentScriptObj = scriptObjPtr;
+
+    retcode = Jim_EvalObj(interp, scriptObjPtr);
+
+    /* Handle the JIM_RETURN return code */
+    if (retcode == JIM_RETURN) {
+        if (--interp->returnLevel <= 0) {
+            retcode = interp->returnCode;
+            interp->returnCode = JIM_OK;
+            interp->returnLevel = 0;
+        }
+    }
+    if (retcode == JIM_ERR) {
+        /* EvalFile changes context, so add a stack frame here */
+        interp->addStackTrace++;
+    }
+
+    interp->currentScriptObj = prevScriptObj;
+
+    Jim_DecrRefCount(interp, scriptObjPtr);
+
+    return retcode;
+}
+
+/* -----------------------------------------------------------------------------
+ * Subst
+ * ---------------------------------------------------------------------------*/
+static int JimParseSubstStr(struct JimParserCtx *pc)
+{
+    pc->tstart = pc->p;
+    pc->tline = pc->linenr;
+    while (pc->len && *pc->p != '$' && *pc->p != '[') {
+        if (*pc->p == '\\' && pc->len > 1) {
+            pc->p++;
+            pc->len--;
+        }
+        pc->p++;
+        pc->len--;
+    }
+    pc->tend = pc->p - 1;
+    pc->tt = JIM_TT_ESC;
+    return JIM_OK;
+}
+
+static int JimParseSubst(struct JimParserCtx *pc, int flags)
+{
+    int retval;
+
+    if (pc->len == 0) {
+        pc->tstart = pc->tend = pc->p;
+        pc->tline = pc->linenr;
+        pc->tt = JIM_TT_EOL;
+        pc->eof = 1;
+        return JIM_OK;
+    }
+    switch (*pc->p) {
+        case '[':
+            retval = JimParseCmd(pc);
+            if (flags & JIM_SUBST_NOCMD) {
+                pc->tstart--;
+                pc->tend++;
+                pc->tt = (flags & JIM_SUBST_NOESC) ? JIM_TT_STR : JIM_TT_ESC;
+            }
+            return retval;
+            break;
+        case '$':
+            if (JimParseVar(pc) == JIM_ERR) {
+                pc->tstart = pc->tend = pc->p++;
+                pc->len--;
+                pc->tline = pc->linenr;
+                pc->tt = JIM_TT_STR;
+            }
+            else {
+                if (flags & JIM_SUBST_NOVAR) {
+                    pc->tstart--;
+                    if (flags & JIM_SUBST_NOESC)
+                        pc->tt = JIM_TT_STR;
+                    else
+                        pc->tt = JIM_TT_ESC;
+                    if (*pc->tstart == '{') {
+                        pc->tstart--;
+                        if (*(pc->tend + 1))
+                            pc->tend++;
+                    }
+                }
+            }
+            break;
+        default:
+            retval = JimParseSubstStr(pc);
+            if (flags & JIM_SUBST_NOESC)
+                pc->tt = JIM_TT_STR;
+            return retval;
+            break;
+    }
+    return JIM_OK;
+}
+
+/* The subst object type reuses most of the data structures and functions
+ * of the script object. Script's data structures are a bit more complex
+ * for what is needed for [subst]itution tasks, but the reuse helps to
+ * deal with a single data structure at the cost of some more memory
+ * usage for substitutions. */
+
+/* This method takes the string representation of an object
+ * as a Tcl string where to perform [subst]itution, and generates
+ * the pre-parsed internal representation. */
+static int SetSubstFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, int flags)
+{
+    int scriptTextLen;
+    const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
+    struct JimParserCtx parser;
+    struct ScriptObj *script = Jim_Alloc(sizeof(*script));
+    ParseTokenList tokenlist;
+
+    /* Initially parse the subst into tokens (in tokenlist) */
+    ScriptTokenListInit(&tokenlist);
+
+    JimParserInit(&parser, scriptText, scriptTextLen, 1);
+    while (1) {
+        JimParseSubst(&parser, flags);
+        if (parser.eof) {
+            /* Note that subst doesn't need the EOL token */
+            break;
+        }
+        ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
+            parser.tline);
+    }
+
+    /* Create the "real" subst/script tokens from the initial token list */
+    script->inUse = 1;
+    script->substFlags = flags;
+    script->fileNameObj = interp->emptyObj;
+    Jim_IncrRefCount(script->fileNameObj);
+    SubstObjAddTokens(interp, script, &tokenlist);
+
+    /* No longer need the token list */
+    ScriptTokenListFree(&tokenlist);
+
+#ifdef DEBUG_SHOW_SUBST
+    {
+        int i;
+
+        printf("==== Subst ====\n");
+        for (i = 0; i < script->len; i++) {
+            printf("[%2d] %s '%s'\n", i, jim_tt_name(script->token[i].type),
+                Jim_String(script->token[i].objPtr));
+        }
+    }
+#endif
+
+    /* Free the old internal rep and set the new one. */
+    Jim_FreeIntRep(interp, objPtr);
+    Jim_SetIntRepPtr(objPtr, script);
+    objPtr->typePtr = &scriptObjType;
+    return JIM_OK;
+}
+
+static ScriptObj *Jim_GetSubst(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+    if (objPtr->typePtr != &scriptObjType || ((ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags != flags)
+        SetSubstFromAny(interp, objPtr, flags);
+    return (ScriptObj *) Jim_GetIntRepPtr(objPtr);
+}
+
+/* Performs commands,variables,blackslashes substitution,
+ * storing the result object (with refcount 0) into
+ * resObjPtrPtr. */
+int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags)
+{
+    ScriptObj *script = Jim_GetSubst(interp, substObjPtr, flags);
+
+    Jim_IncrRefCount(substObjPtr);      /* Make sure it's shared. */
+    /* In order to preserve the internal rep, we increment the
+     * inUse field of the script internal rep structure. */
+    script->inUse++;
+
+    *resObjPtrPtr = JimInterpolateTokens(interp, script->token, script->len, flags);
+
+    script->inUse--;
+    Jim_DecrRefCount(interp, substObjPtr);
+    if (*resObjPtrPtr == NULL) {
+        return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * Core commands utility functions
+ * ---------------------------------------------------------------------------*/
+void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg)
+{
+    int i;
+    Jim_Obj *objPtr = Jim_NewEmptyStringObj(interp);
+
+    Jim_AppendString(interp, objPtr, "wrong # args: should be \"", -1);
+    for (i = 0; i < argc; i++) {
+        Jim_AppendObj(interp, objPtr, argv[i]);
+        if (!(i + 1 == argc && msg[0] == '\0'))
+            Jim_AppendString(interp, objPtr, " ", 1);
+    }
+    Jim_AppendString(interp, objPtr, msg, -1);
+    Jim_AppendString(interp, objPtr, "\"", 1);
+    Jim_SetResult(interp, objPtr);
+}
+
+#define JimTrivialMatch(pattern)	(strpbrk((pattern), "*[?\\") == NULL)
+
+/* type is: 0=commands, 1=procs, 2=channels */
+static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int type)
+{
+    Jim_HashTableIterator *htiter;
+    Jim_HashEntry *he;
+    Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+    /* Check for the non-pattern case. We can do this much more efficiently. */
+    if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) {
+        Jim_Cmd *cmdPtr = Jim_GetCommand(interp, patternObjPtr, JIM_NONE);
+        if (cmdPtr) {
+            if (type == 1 && !cmdPtr->isproc) {
+                /* not a proc */
+            }
+            else if (type == 2 && !Jim_AioFilehandle(interp, patternObjPtr)) {
+                /* not a channel */
+            }
+            else {
+                Jim_ListAppendElement(interp, listObjPtr, patternObjPtr);
+            }
+        }
+        return listObjPtr;
+    }
+
+    htiter = Jim_GetHashTableIterator(&interp->commands);
+    while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+        Jim_Cmd *cmdPtr = he->u.val;
+        Jim_Obj *cmdNameObj;
+
+        if (type == 1 && !cmdPtr->isproc) {
+            /* not a proc */
+            continue;
+        }
+        if (patternObjPtr && !JimStringMatch(interp, patternObjPtr, he->key, 0))
+            continue;
+
+        cmdNameObj = Jim_NewStringObj(interp, he->key, -1);
+
+        /* Is it a channel? */
+        if (type == 2 && !Jim_AioFilehandle(interp, cmdNameObj)) {
+            Jim_FreeNewObj(interp, cmdNameObj);
+            continue;
+        }
+
+        Jim_ListAppendElement(interp, listObjPtr, cmdNameObj);
+    }
+    Jim_FreeHashTableIterator(htiter);
+    return listObjPtr;
+}
+
+/* Keep this in order */
+#define JIM_VARLIST_GLOBALS 0
+#define JIM_VARLIST_LOCALS 1
+#define JIM_VARLIST_VARS 2
+
+static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int mode)
+{
+    Jim_HashTableIterator *htiter;
+    Jim_HashEntry *he;
+    Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+    if (mode == JIM_VARLIST_GLOBALS) {
+        htiter = Jim_GetHashTableIterator(&interp->topFramePtr->vars);
+    }
+    else {
+        /* For [info locals], if we are at top level an emtpy list
+         * is returned. I don't agree, but we aim at compatibility (SS) */
+        if (mode == JIM_VARLIST_LOCALS && interp->framePtr == interp->topFramePtr)
+            return listObjPtr;
+        htiter = Jim_GetHashTableIterator(&interp->framePtr->vars);
+    }
+    while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+        Jim_Var *varPtr = (Jim_Var *)he->u.val;
+
+        if (mode == JIM_VARLIST_LOCALS) {
+            if (varPtr->linkFramePtr != NULL)
+                continue;
+        }
+        if (patternObjPtr && !JimStringMatch(interp, patternObjPtr, he->key, 0))
+            continue;
+        Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, he->key, -1));
+    }
+    Jim_FreeHashTableIterator(htiter);
+    return listObjPtr;
+}
+
+static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr,
+    Jim_Obj **objPtrPtr, int info_level_cmd)
+{
+    Jim_CallFrame *targetCallFrame;
+
+    targetCallFrame = JimGetCallFrameByInteger(interp, levelObjPtr);
+    if (targetCallFrame == NULL) {
+        return JIM_ERR;
+    }
+    /* No proc call at toplevel callframe */
+    if (targetCallFrame == interp->topFramePtr) {
+        Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
+        return JIM_ERR;
+    }
+    if (info_level_cmd) {
+        *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, targetCallFrame->argc);
+    }
+    else {
+        Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
+        Jim_ListAppendElement(interp, listObj, targetCallFrame->argv[0]);
+        Jim_ListAppendElement(interp, listObj, targetCallFrame->fileNameObj);
+        Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, targetCallFrame->line));
+        *objPtrPtr = listObj;
+    }
+    return JIM_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * Core commands
+ * ---------------------------------------------------------------------------*/
+
+/* fake [puts] -- not the real puts, just for debugging. */
+static int Jim_PutsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "?-nonewline? string");
+        return JIM_ERR;
+    }
+    if (argc == 3) {
+        if (!Jim_CompareStringImmediate(interp, argv[1], "-nonewline")) {
+            Jim_SetResultString(interp, "The second argument must " "be -nonewline", -1);
+            return JIM_ERR;
+        }
+        else {
+            fputs(Jim_String(argv[2]), stdout);
+        }
+    }
+    else {
+        puts(Jim_String(argv[1]));
+    }
+    return JIM_OK;
+}
+
+/* Helper for [+] and [*] */
+static int JimAddMulHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
+{
+    jim_wide wideValue, res;
+    double doubleValue, doubleRes;
+    int i;
+
+    res = (op == JIM_EXPROP_ADD) ? 0 : 1;
+
+    for (i = 1; i < argc; i++) {
+        if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK)
+            goto trydouble;
+        if (op == JIM_EXPROP_ADD)
+            res += wideValue;
+        else
+            res *= wideValue;
+    }
+    Jim_SetResultInt(interp, res);
+    return JIM_OK;
+  trydouble:
+    doubleRes = (double)res;
+    for (; i < argc; i++) {
+        if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
+            return JIM_ERR;
+        if (op == JIM_EXPROP_ADD)
+            doubleRes += doubleValue;
+        else
+            doubleRes *= doubleValue;
+    }
+    Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+    return JIM_OK;
+}
+
+/* Helper for [-] and [/] */
+static int JimSubDivHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
+{
+    jim_wide wideValue, res = 0;
+    double doubleValue, doubleRes = 0;
+    int i = 2;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "number ?number ... number?");
+        return JIM_ERR;
+    }
+    else if (argc == 2) {
+        /* The arity = 2 case is different. For [- x] returns -x,
+         * while [/ x] returns 1/x. */
+        if (Jim_GetWide(interp, argv[1], &wideValue) != JIM_OK) {
+            if (Jim_GetDouble(interp, argv[1], &doubleValue) != JIM_OK) {
+                return JIM_ERR;
+            }
+            else {
+                if (op == JIM_EXPROP_SUB)
+                    doubleRes = -doubleValue;
+                else
+                    doubleRes = 1.0 / doubleValue;
+                Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+                return JIM_OK;
+            }
+        }
+        if (op == JIM_EXPROP_SUB) {
+            res = -wideValue;
+            Jim_SetResultInt(interp, res);
+        }
+        else {
+            doubleRes = 1.0 / wideValue;
+            Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+        }
+        return JIM_OK;
+    }
+    else {
+        if (Jim_GetWide(interp, argv[1], &res) != JIM_OK) {
+            if (Jim_GetDouble(interp, argv[1], &doubleRes)
+                != JIM_OK) {
+                return JIM_ERR;
+            }
+            else {
+                goto trydouble;
+            }
+        }
+    }
+    for (i = 2; i < argc; i++) {
+        if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK) {
+            doubleRes = (double)res;
+            goto trydouble;
+        }
+        if (op == JIM_EXPROP_SUB)
+            res -= wideValue;
+        else
+            res /= wideValue;
+    }
+    Jim_SetResultInt(interp, res);
+    return JIM_OK;
+  trydouble:
+    for (; i < argc; i++) {
+        if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
+            return JIM_ERR;
+        if (op == JIM_EXPROP_SUB)
+            doubleRes -= doubleValue;
+        else
+            doubleRes /= doubleValue;
+    }
+    Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+    return JIM_OK;
+}
+
+
+/* [+] */
+static int Jim_AddCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_ADD);
+}
+
+/* [*] */
+static int Jim_MulCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_MUL);
+}
+
+/* [-] */
+static int Jim_SubCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_SUB);
+}
+
+/* [/] */
+static int Jim_DivCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_DIV);
+}
+
+/* [set] */
+static int Jim_SetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "varName ?newValue?");
+        return JIM_ERR;
+    }
+    if (argc == 2) {
+        Jim_Obj *objPtr;
+
+        objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
+        if (!objPtr)
+            return JIM_ERR;
+        Jim_SetResult(interp, objPtr);
+        return JIM_OK;
+    }
+    /* argc == 3 case. */
+    if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
+        return JIM_ERR;
+    Jim_SetResult(interp, argv[2]);
+    return JIM_OK;
+}
+
+/* [unset]
+ *
+ * unset ?-nocomplain? ?--? ?varName ...?
+ */
+static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int i = 1;
+    int complain = 1;
+
+    while (i < argc) {
+        if (Jim_CompareStringImmediate(interp, argv[i], "--")) {
+            i++;
+            break;
+        }
+        if (Jim_CompareStringImmediate(interp, argv[i], "-nocomplain")) {
+            complain = 0;
+            i++;
+            continue;
+        }
+        break;
+    }
+
+    while (i < argc) {
+        if (Jim_UnsetVariable(interp, argv[i], complain ? JIM_ERRMSG : JIM_NONE) != JIM_OK
+            && complain) {
+            return JIM_ERR;
+        }
+        i++;
+    }
+    return JIM_OK;
+}
+
+/* [while] */
+static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "condition body");
+        return JIM_ERR;
+    }
+
+    /* The general purpose implementation of while starts here */
+    while (1) {
+        int boolean, retval;
+
+        if ((retval = Jim_GetBoolFromExpr(interp, argv[1], &boolean)) != JIM_OK)
+            return retval;
+        if (!boolean)
+            break;
+
+        if ((retval = Jim_EvalObj(interp, argv[2])) != JIM_OK) {
+            switch (retval) {
+                case JIM_BREAK:
+                    goto out;
+                    break;
+                case JIM_CONTINUE:
+                    continue;
+                    break;
+                default:
+                    return retval;
+            }
+        }
+    }
+  out:
+    Jim_SetEmptyResult(interp);
+    return JIM_OK;
+}
+
+/* [for] */
+static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int retval;
+    int boolean = 1;
+    Jim_Obj *varNamePtr = NULL;
+    Jim_Obj *stopVarNamePtr = NULL;
+
+    if (argc != 5) {
+        Jim_WrongNumArgs(interp, 1, argv, "start test next body");
+        return JIM_ERR;
+    }
+
+    /* Do the initialisation */
+    if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK) {
+        return retval;
+    }
+
+    /* And do the first test now. Better for optimisation
+     * if we can do next/test at the bottom of the loop
+     */
+    retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
+
+    /* Ready to do the body as follows:
+     * while (1) {
+     *     body // check retcode
+     *     next // check retcode
+     *     test // check retcode/test bool
+     * }
+     */
+
+#ifdef JIM_OPTIMIZATION
+    /* Check if the for is on the form:
+     *      for ... {$i < CONST} {incr i}
+     *      for ... {$i < $j} {incr i}
+     */
+    if (retval == JIM_OK && boolean) {
+        ScriptObj *incrScript;
+        ExprByteCode *expr;
+        jim_wide stop, currentVal;
+        unsigned jim_wide procEpoch;
+        Jim_Obj *objPtr;
+        int cmpOffset;
+
+        /* Do it only if there aren't shared arguments */
+        expr = JimGetExpression(interp, argv[2]);
+        incrScript = Jim_GetScript(interp, argv[3]);
+
+        /* Ensure proper lengths to start */
+        if (incrScript->len != 3 || !expr || expr->len != 3) {
+            goto evalstart;
+        }
+        /* Ensure proper token types. */
+        if (incrScript->token[1].type != JIM_TT_ESC ||
+            expr->token[0].type != JIM_TT_VAR ||
+            (expr->token[1].type != JIM_TT_EXPR_INT && expr->token[1].type != JIM_TT_VAR)) {
+            goto evalstart;
+        }
+
+        if (expr->token[2].type == JIM_EXPROP_LT) {
+            cmpOffset = 0;
+        }
+        else if (expr->token[2].type == JIM_EXPROP_LTE) {
+            cmpOffset = 1;
+        }
+        else {
+            goto evalstart;
+        }
+
+        /* Update command must be incr */
+        if (!Jim_CompareStringImmediate(interp, incrScript->token[1].objPtr, "incr")) {
+            goto evalstart;
+        }
+
+        /* incr, expression must be about the same variable */
+        if (!Jim_StringEqObj(incrScript->token[2].objPtr, expr->token[0].objPtr)) {
+            goto evalstart;
+        }
+
+        /* Get the stop condition (must be a variable or integer) */
+        if (expr->token[1].type == JIM_TT_EXPR_INT) {
+            if (Jim_GetWide(interp, expr->token[1].objPtr, &stop) == JIM_ERR) {
+                goto evalstart;
+            }
+        }
+        else {
+            stopVarNamePtr = expr->token[1].objPtr;
+            Jim_IncrRefCount(stopVarNamePtr);
+            /* Keep the compiler happy */
+            stop = 0;
+        }
+
+        /* Initialization */
+        procEpoch = interp->procEpoch;
+        varNamePtr = expr->token[0].objPtr;
+        Jim_IncrRefCount(varNamePtr);
+
+        objPtr = Jim_GetVariable(interp, varNamePtr, JIM_NONE);
+        if (objPtr == NULL || Jim_GetWide(interp, objPtr, &currentVal) != JIM_OK) {
+            goto testcond;
+        }
+
+        /* --- OPTIMIZED FOR --- */
+        while (retval == JIM_OK) {
+            /* === Check condition === */
+            /* Note that currentVal is already set here */
+
+            /* Immediate or Variable? get the 'stop' value if the latter. */
+            if (stopVarNamePtr) {
+                objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE);
+                if (objPtr == NULL || Jim_GetWide(interp, objPtr, &stop) != JIM_OK) {
+                    goto testcond;
+                }
+            }
+
+            if (currentVal >= stop + cmpOffset) {
+                break;
+            }
+
+            /* Eval body */
+            retval = Jim_EvalObj(interp, argv[4]);
+            if (retval == JIM_OK || retval == JIM_CONTINUE) {
+                retval = JIM_OK;
+                /* If there was a change in procedures/command continue
+                 * with the usual [for] command implementation */
+                if (procEpoch != interp->procEpoch) {
+                    goto evalnext;
+                }
+
+                objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
+
+                /* Increment */
+                if (objPtr == NULL) {
+                    retval = JIM_ERR;
+                    goto out;
+                }
+                if (!Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
+                    currentVal = ++JimWideValue(objPtr);
+                    Jim_InvalidateStringRep(objPtr);
+                }
+                else {
+                    if (Jim_GetWide(interp, objPtr, &currentVal) != JIM_OK ||
+                        Jim_SetVariable(interp, varNamePtr, Jim_NewIntObj(interp,
+                                ++currentVal)) != JIM_OK) {
+                        goto evalnext;
+                    }
+                }
+            }
+        }
+        goto out;
+    }
+  evalstart:
+#endif
+
+    while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) {
+        /* Body */
+        retval = Jim_EvalObj(interp, argv[4]);
+
+        if (retval == JIM_OK || retval == JIM_CONTINUE) {
+            /* increment */
+          evalnext:
+            retval = Jim_EvalObj(interp, argv[3]);
+            if (retval == JIM_OK || retval == JIM_CONTINUE) {
+                /* test */
+              testcond:
+                retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
+            }
+        }
+    }
+  out:
+    if (stopVarNamePtr) {
+        Jim_DecrRefCount(interp, stopVarNamePtr);
+    }
+    if (varNamePtr) {
+        Jim_DecrRefCount(interp, varNamePtr);
+    }
+
+    if (retval == JIM_CONTINUE || retval == JIM_BREAK || retval == JIM_OK) {
+        Jim_SetEmptyResult(interp);
+        return JIM_OK;
+    }
+
+    return retval;
+}
+
+/* [loop] */
+static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int retval;
+    jim_wide i;
+    jim_wide limit;
+    jim_wide incr = 1;
+    Jim_Obj *bodyObjPtr;
+
+    if (argc != 5 && argc != 6) {
+        Jim_WrongNumArgs(interp, 1, argv, "var first limit ?incr? body");
+        return JIM_ERR;
+    }
+
+    if (Jim_GetWide(interp, argv[2], &i) != JIM_OK ||
+        Jim_GetWide(interp, argv[3], &limit) != JIM_OK ||
+          (argc == 6 && Jim_GetWide(interp, argv[4], &incr) != JIM_OK)) {
+        return JIM_ERR;
+    }
+    bodyObjPtr = (argc == 5) ? argv[4] : argv[5];
+
+    retval = Jim_SetVariable(interp, argv[1], argv[2]);
+
+    while (((i < limit && incr > 0) || (i > limit && incr < 0)) && retval == JIM_OK) {
+        retval = Jim_EvalObj(interp, bodyObjPtr);
+        if (retval == JIM_OK || retval == JIM_CONTINUE) {
+            Jim_Obj *objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
+
+            retval = JIM_OK;
+
+            /* Increment */
+            i += incr;
+
+            if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
+                if (argv[1]->typePtr != &variableObjType) {
+                    if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
+                        return JIM_ERR;
+                    }
+                }
+                JimWideValue(objPtr) = i;
+                Jim_InvalidateStringRep(objPtr);
+
+                /* The following step is required in order to invalidate the
+                 * string repr of "FOO" if the var name is of the form of "FOO(IDX)" */
+                if (argv[1]->typePtr != &variableObjType) {
+                    if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
+                        retval = JIM_ERR;
+                        break;
+                    }
+                }
+            }
+            else {
+                objPtr = Jim_NewIntObj(interp, i);
+                retval = Jim_SetVariable(interp, argv[1], objPtr);
+                if (retval != JIM_OK) {
+                    Jim_FreeNewObj(interp, objPtr);
+                }
+            }
+        }
+    }
+
+    if (retval == JIM_OK || retval == JIM_CONTINUE || retval == JIM_BREAK) {
+        Jim_SetEmptyResult(interp);
+        return JIM_OK;
+    }
+    return retval;
+}
+
+/* foreach + lmap implementation. */
+static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap)
+{
+    int result = JIM_ERR, i, nbrOfLists, *listsIdx, *listsEnd;
+    int nbrOfLoops = 0;
+    Jim_Obj *emptyStr, *script, *mapRes = NULL;
+
+    if (argc < 4 || argc % 2 != 0) {
+        Jim_WrongNumArgs(interp, 1, argv, "varList list ?varList list ...? script");
+        return JIM_ERR;
+    }
+    if (doMap) {
+        mapRes = Jim_NewListObj(interp, NULL, 0);
+        Jim_IncrRefCount(mapRes);
+    }
+    emptyStr = Jim_NewEmptyStringObj(interp);
+    Jim_IncrRefCount(emptyStr);
+    script = argv[argc - 1];    /* Last argument is a script */
+    nbrOfLists = (argc - 1 - 1) / 2;    /* argc - 'foreach' - script */
+    listsIdx = (int *)Jim_Alloc(nbrOfLists * sizeof(int));
+    listsEnd = (int *)Jim_Alloc(nbrOfLists * 2 * sizeof(int));
+    /* Initialize iterators and remember max nbr elements each list */
+    memset(listsIdx, 0, nbrOfLists * sizeof(int));
+    /* Remember lengths of all lists and calculate how much rounds to loop */
+    for (i = 0; i < nbrOfLists * 2; i += 2) {
+        div_t cnt;
+        int count;
+
+        listsEnd[i] = Jim_ListLength(interp, argv[i + 1]);
+        listsEnd[i + 1] = Jim_ListLength(interp, argv[i + 2]);
+        if (listsEnd[i] == 0) {
+            Jim_SetResultString(interp, "foreach varlist is empty", -1);
+            goto err;
+        }
+        cnt = div(listsEnd[i + 1], listsEnd[i]);
+        count = cnt.quot + (cnt.rem ? 1 : 0);
+        if (count > nbrOfLoops)
+            nbrOfLoops = count;
+    }
+    for (; nbrOfLoops-- > 0;) {
+        for (i = 0; i < nbrOfLists; ++i) {
+            int varIdx = 0, var = i * 2;
+
+            while (varIdx < listsEnd[var]) {
+                Jim_Obj *varName, *ele;
+                int lst = i * 2 + 1;
+
+                /* List index operations below can't fail */
+                Jim_ListIndex(interp, argv[var + 1], varIdx, &varName, JIM_NONE);
+                if (listsIdx[i] < listsEnd[lst]) {
+                    Jim_ListIndex(interp, argv[lst + 1], listsIdx[i], &ele, JIM_NONE);
+                    /* Avoid shimmering */
+                    Jim_IncrRefCount(ele);
+                    result = Jim_SetVariable(interp, varName, ele);
+                    Jim_DecrRefCount(interp, ele);
+                    if (result == JIM_OK) {
+                        ++listsIdx[i];  /* Remember next iterator of current list */
+                        ++varIdx;       /* Next variable */
+                        continue;
+                    }
+                }
+                else if (Jim_SetVariable(interp, varName, emptyStr) == JIM_OK) {
+                    ++varIdx;   /* Next variable */
+                    continue;
+                }
+                goto err;
+            }
+        }
+        switch (result = Jim_EvalObj(interp, script)) {
+            case JIM_OK:
+                if (doMap)
+                    Jim_ListAppendElement(interp, mapRes, interp->result);
+                break;
+            case JIM_CONTINUE:
+                break;
+            case JIM_BREAK:
+                goto out;
+                break;
+            default:
+                goto err;
+        }
+    }
+  out:
+    result = JIM_OK;
+    if (doMap)
+        Jim_SetResult(interp, mapRes);
+    else
+        Jim_SetEmptyResult(interp);
+  err:
+    if (doMap)
+        Jim_DecrRefCount(interp, mapRes);
+    Jim_DecrRefCount(interp, emptyStr);
+    Jim_Free(listsIdx);
+    Jim_Free(listsEnd);
+    return result;
+}
+
+/* [foreach] */
+static int Jim_ForeachCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return JimForeachMapHelper(interp, argc, argv, 0);
+}
+
+/* [lmap] */
+static int Jim_LmapCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    return JimForeachMapHelper(interp, argc, argv, 1);
+}
+
+/* [if] */
+static int Jim_IfCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int boolean, retval, current = 1, falsebody = 0;
+
+    if (argc >= 3) {
+        while (1) {
+            /* Far not enough arguments given! */
+            if (current >= argc)
+                goto err;
+            if ((retval = Jim_GetBoolFromExpr(interp, argv[current++], &boolean))
+                != JIM_OK)
+                return retval;
+            /* There lacks something, isn't it? */
+            if (current >= argc)
+                goto err;
+            if (Jim_CompareStringImmediate(interp, argv[current], "then"))
+                current++;
+            /* Tsk tsk, no then-clause? */
+            if (current >= argc)
+                goto err;
+            if (boolean)
+                return Jim_EvalObj(interp, argv[current]);
+            /* Ok: no else-clause follows */
+            if (++current >= argc) {
+                Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+                return JIM_OK;
+            }
+            falsebody = current++;
+            if (Jim_CompareStringImmediate(interp, argv[falsebody], "else")) {
+                /* IIICKS - else-clause isn't last cmd? */
+                if (current != argc - 1)
+                    goto err;
+                return Jim_EvalObj(interp, argv[current]);
+            }
+            else if (Jim_CompareStringImmediate(interp, argv[falsebody], "elseif"))
+                /* Ok: elseif follows meaning all the stuff
+                 * again (how boring...) */
+                continue;
+            /* OOPS - else-clause is not last cmd? */
+            else if (falsebody != argc - 1)
+                goto err;
+            return Jim_EvalObj(interp, argv[falsebody]);
+        }
+        return JIM_OK;
+    }
+  err:
+    Jim_WrongNumArgs(interp, 1, argv, "condition ?then? trueBody ?elseif ...? ?else? falseBody");
+    return JIM_ERR;
+}
+
+
+/* Returns 1 if match, 0 if no match or -<error> on error (e.g. -JIM_ERR, -JIM_BREAK)*/
+int Jim_CommandMatchObj(Jim_Interp *interp, Jim_Obj *commandObj, Jim_Obj *patternObj,
+    Jim_Obj *stringObj, int nocase)
+{
+    Jim_Obj *parms[4];
+    int argc = 0;
+    long eq;
+    int rc;
+
+    parms[argc++] = commandObj;
+    if (nocase) {
+        parms[argc++] = Jim_NewStringObj(interp, "-nocase", -1);
+    }
+    parms[argc++] = patternObj;
+    parms[argc++] = stringObj;
+
+    rc = Jim_EvalObjVector(interp, argc, parms);
+
+    if (rc != JIM_OK || Jim_GetLong(interp, Jim_GetResult(interp), &eq) != JIM_OK) {
+        eq = -rc;
+    }
+
+    return eq;
+}
+
+enum
+{ SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD };
+
+/* [switch] */
+static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int matchOpt = SWITCH_EXACT, opt = 1, patCount, i;
+    Jim_Obj *command = 0, *const *caseList = 0, *strObj;
+    Jim_Obj *script = 0;
+
+    if (argc < 3) {
+      wrongnumargs:
+        Jim_WrongNumArgs(interp, 1, argv, "?options? string "
+            "pattern body ... ?default body?   or   " "{pattern body ?pattern body ...?}");
+        return JIM_ERR;
+    }
+    for (opt = 1; opt < argc; ++opt) {
+        const char *option = Jim_String(argv[opt]);
+
+        if (*option != '-')
+            break;
+        else if (strncmp(option, "--", 2) == 0) {
+            ++opt;
+            break;
+        }
+        else if (strncmp(option, "-exact", 2) == 0)
+            matchOpt = SWITCH_EXACT;
+        else if (strncmp(option, "-glob", 2) == 0)
+            matchOpt = SWITCH_GLOB;
+        else if (strncmp(option, "-regexp", 2) == 0)
+            matchOpt = SWITCH_RE;
+        else if (strncmp(option, "-command", 2) == 0) {
+            matchOpt = SWITCH_CMD;
+            if ((argc - opt) < 2)
+                goto wrongnumargs;
+            command = argv[++opt];
+        }
+        else {
+            Jim_SetResultFormatted(interp,
+                "bad option \"%#s\": must be -exact, -glob, -regexp, -command procname or --",
+                argv[opt]);
+            return JIM_ERR;
+        }
+        if ((argc - opt) < 2)
+            goto wrongnumargs;
+    }
+    strObj = argv[opt++];
+    patCount = argc - opt;
+    if (patCount == 1) {
+        Jim_Obj **vector;
+
+        JimListGetElements(interp, argv[opt], &patCount, &vector);
+        caseList = vector;
+    }
+    else
+        caseList = &argv[opt];
+    if (patCount == 0 || patCount % 2 != 0)
+        goto wrongnumargs;
+    for (i = 0; script == 0 && i < patCount; i += 2) {
+        Jim_Obj *patObj = caseList[i];
+
+        if (!Jim_CompareStringImmediate(interp, patObj, "default")
+            || i < (patCount - 2)) {
+            switch (matchOpt) {
+                case SWITCH_EXACT:
+                    if (Jim_StringEqObj(strObj, patObj))
+                        script = caseList[i + 1];
+                    break;
+                case SWITCH_GLOB:
+                    if (Jim_StringMatchObj(interp, patObj, strObj, 0))
+                        script = caseList[i + 1];
+                    break;
+                case SWITCH_RE:
+                    command = Jim_NewStringObj(interp, "regexp", -1);
+                    /* Fall thru intentionally */
+                case SWITCH_CMD:{
+                        int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, 0);
+
+                        /* After the execution of a command we need to
+                         * make sure to reconvert the object into a list
+                         * again. Only for the single-list style [switch]. */
+                        if (argc - opt == 1) {
+                            Jim_Obj **vector;
+
+                            JimListGetElements(interp, argv[opt], &patCount, &vector);
+                            caseList = vector;
+                        }
+                        /* command is here already decref'd */
+                        if (rc < 0) {
+                            return -rc;
+                        }
+                        if (rc)
+                            script = caseList[i + 1];
+                        break;
+                    }
+            }
+        }
+        else {
+            script = caseList[i + 1];
+        }
+    }
+    for (; i < patCount && Jim_CompareStringImmediate(interp, script, "-"); i += 2)
+        script = caseList[i + 1];
+    if (script && Jim_CompareStringImmediate(interp, script, "-")) {
+        Jim_SetResultFormatted(interp, "no body specified for pattern \"%#s\"", caseList[i - 2]);
+        return JIM_ERR;
+    }
+    Jim_SetEmptyResult(interp);
+    if (script) {
+        return Jim_EvalObj(interp, script);
+    }
+    return JIM_OK;
+}
+
+/* [list] */
+static int Jim_ListCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *listObjPtr;
+
+    listObjPtr = Jim_NewListObj(interp, argv + 1, argc - 1);
+    Jim_SetResult(interp, listObjPtr);
+    return JIM_OK;
+}
+
+/* [lindex] */
+static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr, *listObjPtr;
+    int i;
+    int idx;
+
+    if (argc < 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "list index ?...?");
+        return JIM_ERR;
+    }
+    objPtr = argv[1];
+    Jim_IncrRefCount(objPtr);
+    for (i = 2; i < argc; i++) {
+        listObjPtr = objPtr;
+        if (Jim_GetIndex(interp, argv[i], &idx) != JIM_OK) {
+            Jim_DecrRefCount(interp, listObjPtr);
+            return JIM_ERR;
+        }
+        if (Jim_ListIndex(interp, listObjPtr, idx, &objPtr, JIM_NONE) != JIM_OK) {
+            /* Returns an empty object if the index
+             * is out of range. */
+            Jim_DecrRefCount(interp, listObjPtr);
+            Jim_SetEmptyResult(interp);
+            return JIM_OK;
+        }
+        Jim_IncrRefCount(objPtr);
+        Jim_DecrRefCount(interp, listObjPtr);
+    }
+    Jim_SetResult(interp, objPtr);
+    Jim_DecrRefCount(interp, objPtr);
+    return JIM_OK;
+}
+
+/* [llength] */
+static int Jim_LlengthCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "list");
+        return JIM_ERR;
+    }
+    Jim_SetResultInt(interp, Jim_ListLength(interp, argv[1]));
+    return JIM_OK;
+}
+
+/* [lsearch] */
+static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    static const char * const options[] = {
+        "-bool", "-not", "-nocase", "-exact", "-glob", "-regexp", "-all", "-inline", "-command",
+            NULL
+    };
+    enum
+    { OPT_BOOL, OPT_NOT, OPT_NOCASE, OPT_EXACT, OPT_GLOB, OPT_REGEXP, OPT_ALL, OPT_INLINE,
+            OPT_COMMAND };
+    int i;
+    int opt_bool = 0;
+    int opt_not = 0;
+    int opt_nocase = 0;
+    int opt_all = 0;
+    int opt_inline = 0;
+    int opt_match = OPT_EXACT;
+    int listlen;
+    int rc = JIM_OK;
+    Jim_Obj *listObjPtr = NULL;
+    Jim_Obj *commandObj = NULL;
+
+    if (argc < 3) {
+      wrongargs:
+        Jim_WrongNumArgs(interp, 1, argv,
+            "?-exact|-glob|-regexp|-command 'command'? ?-bool|-inline? ?-not? ?-nocase? ?-all? list value");
+        return JIM_ERR;
+    }
+
+    for (i = 1; i < argc - 2; i++) {
+        int option;
+
+        if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+            return JIM_ERR;
+        }
+        switch (option) {
+            case OPT_BOOL:
+                opt_bool = 1;
+                opt_inline = 0;
+                break;
+            case OPT_NOT:
+                opt_not = 1;
+                break;
+            case OPT_NOCASE:
+                opt_nocase = 1;
+                break;
+            case OPT_INLINE:
+                opt_inline = 1;
+                opt_bool = 0;
+                break;
+            case OPT_ALL:
+                opt_all = 1;
+                break;
+            case OPT_COMMAND:
+                if (i >= argc - 2) {
+                    goto wrongargs;
+                }
+                commandObj = argv[++i];
+                /* fallthru */
+            case OPT_EXACT:
+            case OPT_GLOB:
+            case OPT_REGEXP:
+                opt_match = option;
+                break;
+        }
+    }
+
+    argv += i;
+
+    if (opt_all) {
+        listObjPtr = Jim_NewListObj(interp, NULL, 0);
+    }
+    if (opt_match == OPT_REGEXP) {
+        commandObj = Jim_NewStringObj(interp, "regexp", -1);
+    }
+    if (commandObj) {
+        Jim_IncrRefCount(commandObj);
+    }
+
+    listlen = Jim_ListLength(interp, argv[0]);
+    for (i = 0; i < listlen; i++) {
+        Jim_Obj *objPtr;
+        int eq = 0;
+
+        Jim_ListIndex(interp, argv[0], i, &objPtr, JIM_NONE);
+        switch (opt_match) {
+            case OPT_EXACT:
+                eq = Jim_StringCompareObj(interp, objPtr, argv[1], opt_nocase) == 0;
+                break;
+
+            case OPT_GLOB:
+                eq = Jim_StringMatchObj(interp, argv[1], objPtr, opt_nocase);
+                break;
+
+            case OPT_REGEXP:
+            case OPT_COMMAND:
+                eq = Jim_CommandMatchObj(interp, commandObj, argv[1], objPtr, opt_nocase);
+                if (eq < 0) {
+                    if (listObjPtr) {
+                        Jim_FreeNewObj(interp, listObjPtr);
+                    }
+                    rc = JIM_ERR;
+                    goto done;
+                }
+                break;
+        }
+
+        /* If we have a non-match with opt_bool, opt_not, !opt_all, can't exit early */
+        if (!eq && opt_bool && opt_not && !opt_all) {
+            continue;
+        }
+
+        if ((!opt_bool && eq == !opt_not) || (opt_bool && (eq || opt_all))) {
+            /* Got a match (or non-match for opt_not), or (opt_bool && opt_all) */
+            Jim_Obj *resultObj;
+
+            if (opt_bool) {
+                resultObj = Jim_NewIntObj(interp, eq ^ opt_not);
+            }
+            else if (!opt_inline) {
+                resultObj = Jim_NewIntObj(interp, i);
+            }
+            else {
+                resultObj = objPtr;
+            }
+
+            if (opt_all) {
+                Jim_ListAppendElement(interp, listObjPtr, resultObj);
+            }
+            else {
+                Jim_SetResult(interp, resultObj);
+                goto done;
+            }
+        }
+    }
+
+    if (opt_all) {
+        Jim_SetResult(interp, listObjPtr);
+    }
+    else {
+        /* No match */
+        if (opt_bool) {
+            Jim_SetResultBool(interp, opt_not);
+        }
+        else if (!opt_inline) {
+            Jim_SetResultInt(interp, -1);
+        }
+    }
+
+  done:
+    if (commandObj) {
+        Jim_DecrRefCount(interp, commandObj);
+    }
+    return rc;
+}
+
+/* [lappend] */
+static int Jim_LappendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *listObjPtr;
+    int shared, i;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
+        return JIM_ERR;
+    }
+    listObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
+    if (!listObjPtr) {
+        /* Create the list if it does not exists */
+        listObjPtr = Jim_NewListObj(interp, NULL, 0);
+        if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) {
+            Jim_FreeNewObj(interp, listObjPtr);
+            return JIM_ERR;
+        }
+    }
+    shared = Jim_IsShared(listObjPtr);
+    if (shared)
+        listObjPtr = Jim_DuplicateObj(interp, listObjPtr);
+    for (i = 2; i < argc; i++)
+        Jim_ListAppendElement(interp, listObjPtr, argv[i]);
+    if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) {
+        if (shared)
+            Jim_FreeNewObj(interp, listObjPtr);
+        return JIM_ERR;
+    }
+    Jim_SetResult(interp, listObjPtr);
+    return JIM_OK;
+}
+
+/* [linsert] */
+static int Jim_LinsertCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int idx, len;
+    Jim_Obj *listPtr;
+
+    if (argc < 4) {
+        Jim_WrongNumArgs(interp, 1, argv, "list index element " "?element ...?");
+        return JIM_ERR;
+    }
+    listPtr = argv[1];
+    if (Jim_IsShared(listPtr))
+        listPtr = Jim_DuplicateObj(interp, listPtr);
+    if (Jim_GetIndex(interp, argv[2], &idx) != JIM_OK)
+        goto err;
+    len = Jim_ListLength(interp, listPtr);
+    if (idx >= len)
+        idx = len;
+    else if (idx < 0)
+        idx = len + idx + 1;
+    Jim_ListInsertElements(interp, listPtr, idx, argc - 3, &argv[3]);
+    Jim_SetResult(interp, listPtr);
+    return JIM_OK;
+  err:
+    if (listPtr != argv[1]) {
+        Jim_FreeNewObj(interp, listPtr);
+    }
+    return JIM_ERR;
+}
+
+/* [lreplace] */
+static int Jim_LreplaceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int first, last, len, rangeLen;
+    Jim_Obj *listObj;
+    Jim_Obj *newListObj;
+    int i;
+    int shared;
+
+    if (argc < 4) {
+        Jim_WrongNumArgs(interp, 1, argv, "list first last ?element element ...?");
+        return JIM_ERR;
+    }
+    if (Jim_GetIndex(interp, argv[2], &first) != JIM_OK ||
+        Jim_GetIndex(interp, argv[3], &last) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    listObj = argv[1];
+    len = Jim_ListLength(interp, listObj);
+
+    first = JimRelToAbsIndex(len, first);
+    last = JimRelToAbsIndex(len, last);
+    JimRelToAbsRange(len, first, last, &first, &last, &rangeLen);
+
+    /* Now construct a new list which consists of:
+     * <elements before first> <supplied elements> <elements after last>
+     */
+
+    /* Check to see if trying to replace past the end of the list */
+    if (first < len) {
+        /* OK. Not past the end */
+    }
+    else if (len == 0) {
+        /* Special for empty list, adjust first to 0 */
+        first = 0;
+    }
+    else {
+        Jim_SetResultString(interp, "list doesn't contain element ", -1);
+        Jim_AppendObj(interp, Jim_GetResult(interp), argv[2]);
+        return JIM_ERR;
+    }
+
+    newListObj = Jim_NewListObj(interp, NULL, 0);
+
+    shared = Jim_IsShared(listObj);
+    if (shared) {
+        listObj = Jim_DuplicateObj(interp, listObj);
+    }
+
+    /* Add the first set of elements */
+    for (i = 0; i < first; i++) {
+        Jim_ListAppendElement(interp, newListObj, listObj->internalRep.listValue.ele[i]);
+    }
+
+    /* Add supplied elements */
+    for (i = 4; i < argc; i++) {
+        Jim_ListAppendElement(interp, newListObj, argv[i]);
+    }
+
+    /* Add the remaining elements */
+    for (i = first + rangeLen; i < len; i++) {
+        Jim_ListAppendElement(interp, newListObj, listObj->internalRep.listValue.ele[i]);
+    }
+    Jim_SetResult(interp, newListObj);
+    if (shared) {
+        Jim_FreeNewObj(interp, listObj);
+    }
+    return JIM_OK;
+}
+
+/* [lset] */
+static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc < 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "listVar ?index...? newVal");
+        return JIM_ERR;
+    }
+    else if (argc == 3) {
+        if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
+            return JIM_ERR;
+        Jim_SetResult(interp, argv[2]);
+        return JIM_OK;
+    }
+    if (Jim_SetListIndex(interp, argv[1], argv + 2, argc - 3, argv[argc - 1])
+        == JIM_ERR)
+        return JIM_ERR;
+    return JIM_OK;
+}
+
+/* [lsort] */
+static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[])
+{
+    static const char * const options[] = {
+        "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-index", NULL
+    };
+    enum
+    { OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_INDEX };
+    Jim_Obj *resObj;
+    int i;
+    int retCode;
+
+    struct lsort_info info;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "?options? list");
+        return JIM_ERR;
+    }
+
+    info.type = JIM_LSORT_ASCII;
+    info.order = 1;
+    info.indexed = 0;
+    info.command = NULL;
+    info.interp = interp;
+
+    for (i = 1; i < (argc - 1); i++) {
+        int option;
+
+        if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG)
+            != JIM_OK)
+            return JIM_ERR;
+        switch (option) {
+            case OPT_ASCII:
+                info.type = JIM_LSORT_ASCII;
+                break;
+            case OPT_NOCASE:
+                info.type = JIM_LSORT_NOCASE;
+                break;
+            case OPT_INTEGER:
+                info.type = JIM_LSORT_INTEGER;
+                break;
+            case OPT_INCREASING:
+                info.order = 1;
+                break;
+            case OPT_DECREASING:
+                info.order = -1;
+                break;
+            case OPT_COMMAND:
+                if (i >= (argc - 2)) {
+                    Jim_SetResultString(interp, "\"-command\" option must be followed by comparison command", -1);
+                    return JIM_ERR;
+                }
+                info.type = JIM_LSORT_COMMAND;
+                info.command = argv[i + 1];
+                i++;
+                break;
+            case OPT_INDEX:
+                if (i >= (argc - 2)) {
+                    Jim_SetResultString(interp, "\"-index\" option must be followed by list index", -1);
+                    return JIM_ERR;
+                }
+                if (Jim_GetIndex(interp, argv[i + 1], &info.index) != JIM_OK) {
+                    return JIM_ERR;
+                }
+                info.indexed = 1;
+                i++;
+                break;
+        }
+    }
+    resObj = Jim_DuplicateObj(interp, argv[argc - 1]);
+    retCode = ListSortElements(interp, resObj, &info);
+    if (retCode == JIM_OK) {
+        Jim_SetResult(interp, resObj);
+    }
+    else {
+        Jim_FreeNewObj(interp, resObj);
+    }
+    return retCode;
+}
+
+/* [append] */
+static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *stringObjPtr;
+    int i;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
+        return JIM_ERR;
+    }
+    if (argc == 2) {
+        stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
+        if (!stringObjPtr)
+            return JIM_ERR;
+    }
+    else {
+        int freeobj = 0;
+        stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
+        if (!stringObjPtr) {
+            /* Create the string if it doesn't exist */
+            stringObjPtr = Jim_NewEmptyStringObj(interp);
+            freeobj = 1;
+        }
+        else if (Jim_IsShared(stringObjPtr)) {
+            freeobj = 1;
+            stringObjPtr = Jim_DuplicateObj(interp, stringObjPtr);
+        }
+        for (i = 2; i < argc; i++) {
+            Jim_AppendObj(interp, stringObjPtr, argv[i]);
+        }
+        if (Jim_SetVariable(interp, argv[1], stringObjPtr) != JIM_OK) {
+            if (freeobj) {
+                Jim_FreeNewObj(interp, stringObjPtr);
+            }
+            return JIM_ERR;
+        }
+    }
+    Jim_SetResult(interp, stringObjPtr);
+    return JIM_OK;
+}
+
+/* [debug] */
+static int Jim_DebugCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+#if defined(JIM_DEBUG_COMMAND) && !defined(JIM_BOOTSTRAP)
+    static const char * const options[] = {
+        "refcount", "objcount", "objects", "invstr", "scriptlen", "exprlen",
+        "exprbc", "show",
+        NULL
+    };
+    enum
+    {
+        OPT_REFCOUNT, OPT_OBJCOUNT, OPT_OBJECTS, OPT_INVSTR, OPT_SCRIPTLEN,
+        OPT_EXPRLEN, OPT_EXPRBC, OPT_SHOW,
+    };
+    int option;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "subcommand ?...?");
+        return JIM_ERR;
+    }
+    if (Jim_GetEnum(interp, argv[1], options, &option, "subcommand", JIM_ERRMSG) != JIM_OK)
+        return JIM_ERR;
+    if (option == OPT_REFCOUNT) {
+        if (argc != 3) {
+            Jim_WrongNumArgs(interp, 2, argv, "object");
+            return JIM_ERR;
+        }
+        Jim_SetResultInt(interp, argv[2]->refCount);
+        return JIM_OK;
+    }
+    else if (option == OPT_OBJCOUNT) {
+        int freeobj = 0, liveobj = 0;
+        char buf[256];
+        Jim_Obj *objPtr;
+
+        if (argc != 2) {
+            Jim_WrongNumArgs(interp, 2, argv, "");
+            return JIM_ERR;
+        }
+        /* Count the number of free objects. */
+        objPtr = interp->freeList;
+        while (objPtr) {
+            freeobj++;
+            objPtr = objPtr->nextObjPtr;
+        }
+        /* Count the number of live objects. */
+        objPtr = interp->liveList;
+        while (objPtr) {
+            liveobj++;
+            objPtr = objPtr->nextObjPtr;
+        }
+        /* Set the result string and return. */
+        sprintf(buf, "free %d used %d", freeobj, liveobj);
+        Jim_SetResultString(interp, buf, -1);
+        return JIM_OK;
+    }
+    else if (option == OPT_OBJECTS) {
+        Jim_Obj *objPtr, *listObjPtr, *subListObjPtr;
+
+        /* Count the number of live objects. */
+        objPtr = interp->liveList;
+        listObjPtr = Jim_NewListObj(interp, NULL, 0);
+        while (objPtr) {
+            char buf[128];
+            const char *type = objPtr->typePtr ? objPtr->typePtr->name : "";
+
+            subListObjPtr = Jim_NewListObj(interp, NULL, 0);
+            sprintf(buf, "%p", objPtr);
+            Jim_ListAppendElement(interp, subListObjPtr, Jim_NewStringObj(interp, buf, -1));
+            Jim_ListAppendElement(interp, subListObjPtr, Jim_NewStringObj(interp, type, -1));
+            Jim_ListAppendElement(interp, subListObjPtr, Jim_NewIntObj(interp, objPtr->refCount));
+            Jim_ListAppendElement(interp, subListObjPtr, objPtr);
+            Jim_ListAppendElement(interp, listObjPtr, subListObjPtr);
+            objPtr = objPtr->nextObjPtr;
+        }
+        Jim_SetResult(interp, listObjPtr);
+        return JIM_OK;
+    }
+    else if (option == OPT_INVSTR) {
+        Jim_Obj *objPtr;
+
+        if (argc != 3) {
+            Jim_WrongNumArgs(interp, 2, argv, "object");
+            return JIM_ERR;
+        }
+        objPtr = argv[2];
+        if (objPtr->typePtr != NULL)
+            Jim_InvalidateStringRep(objPtr);
+        Jim_SetEmptyResult(interp);
+        return JIM_OK;
+    }
+    else if (option == OPT_SHOW) {
+        const char *s;
+        int len, charlen;
+
+        if (argc != 3) {
+            Jim_WrongNumArgs(interp, 2, argv, "object");
+            return JIM_ERR;
+        }
+        s = Jim_GetString(argv[2], &len);
+#ifdef JIM_UTF8
+        charlen = utf8_strlen(s, len);
+#else
+        charlen = len;
+#endif
+        printf("refcount: %d, type: %s\n", argv[2]->refCount, JimObjTypeName(argv[2]));
+        printf("chars (%d): <<%s>>\n", charlen, s);
+        printf("bytes (%d):", len);
+        while (len--) {
+            printf(" %02x", (unsigned char)*s++);
+        }
+        printf("\n");
+        return JIM_OK;
+    }
+    else if (option == OPT_SCRIPTLEN) {
+        ScriptObj *script;
+
+        if (argc != 3) {
+            Jim_WrongNumArgs(interp, 2, argv, "script");
+            return JIM_ERR;
+        }
+        script = Jim_GetScript(interp, argv[2]);
+        Jim_SetResultInt(interp, script->len);
+        return JIM_OK;
+    }
+    else if (option == OPT_EXPRLEN) {
+        ExprByteCode *expr;
+
+        if (argc != 3) {
+            Jim_WrongNumArgs(interp, 2, argv, "expression");
+            return JIM_ERR;
+        }
+        expr = JimGetExpression(interp, argv[2]);
+        if (expr == NULL)
+            return JIM_ERR;
+        Jim_SetResultInt(interp, expr->len);
+        return JIM_OK;
+    }
+    else if (option == OPT_EXPRBC) {
+        Jim_Obj *objPtr;
+        ExprByteCode *expr;
+        int i;
+
+        if (argc != 3) {
+            Jim_WrongNumArgs(interp, 2, argv, "expression");
+            return JIM_ERR;
+        }
+        expr = JimGetExpression(interp, argv[2]);
+        if (expr == NULL)
+            return JIM_ERR;
+        objPtr = Jim_NewListObj(interp, NULL, 0);
+        for (i = 0; i < expr->len; i++) {
+            const char *type;
+            const Jim_ExprOperator *op;
+            Jim_Obj *obj = expr->token[i].objPtr;
+
+            switch (expr->token[i].type) {
+                case JIM_TT_EXPR_INT:
+                    type = "int";
+                    break;
+                case JIM_TT_EXPR_DOUBLE:
+                    type = "double";
+                    break;
+                case JIM_TT_CMD:
+                    type = "command";
+                    break;
+                case JIM_TT_VAR:
+                    type = "variable";
+                    break;
+                case JIM_TT_DICTSUGAR:
+                    type = "dictsugar";
+                    break;
+                case JIM_TT_EXPRSUGAR:
+                    type = "exprsugar";
+                    break;
+                case JIM_TT_ESC:
+                    type = "subst";
+                    break;
+                case JIM_TT_STR:
+                    type = "string";
+                    break;
+                default:
+                    op = JimExprOperatorInfoByOpcode(expr->token[i].type);
+                    if (op == NULL) {
+                        type = "private";
+                    }
+                    else {
+                        type = "operator";
+                    }
+                    obj = Jim_NewStringObj(interp, op ? op->name : "", -1);
+                    break;
+            }
+            Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, type, -1));
+            Jim_ListAppendElement(interp, objPtr, obj);
+        }
+        Jim_SetResult(interp, objPtr);
+        return JIM_OK;
+    }
+    else {
+        Jim_SetResultString(interp,
+            "bad option. Valid options are refcount, " "objcount, objects, invstr", -1);
+        return JIM_ERR;
+    }
+    /* unreached */
+#endif /* JIM_BOOTSTRAP */
+#if !defined(JIM_DEBUG_COMMAND)
+    Jim_SetResultString(interp, "unsupported", -1);
+    return JIM_ERR;
+#endif
+}
+
+/* [eval] */
+static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int rc;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "script ?...?");
+        return JIM_ERR;
+    }
+
+    if (argc == 2) {
+        rc = Jim_EvalObj(interp, argv[1]);
+    }
+    else {
+        rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
+    }
+
+    if (rc == JIM_ERR) {
+        /* eval is "interesting", so add a stack frame here */
+        interp->addStackTrace++;
+    }
+    return rc;
+}
+
+/* [uplevel] */
+static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc >= 2) {
+        int retcode;
+        Jim_CallFrame *savedCallFrame, *targetCallFrame;
+        Jim_Obj *objPtr;
+        const char *str;
+
+        /* Save the old callframe pointer */
+        savedCallFrame = interp->framePtr;
+
+        /* Lookup the target frame pointer */
+        str = Jim_String(argv[1]);
+        if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') {
+            targetCallFrame =Jim_GetCallFrameByLevel(interp, argv[1]);
+            argc--;
+            argv++;
+        }
+        else {
+            targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL);
+        }
+        if (targetCallFrame == NULL) {
+            return JIM_ERR;
+        }
+        if (argc < 2) {
+            argv--;
+            Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?");
+            return JIM_ERR;
+        }
+        /* Eval the code in the target callframe. */
+        interp->framePtr = targetCallFrame;
+        if (argc == 2) {
+            retcode = Jim_EvalObj(interp, argv[1]);
+        }
+        else {
+            objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1);
+            Jim_IncrRefCount(objPtr);
+            retcode = Jim_EvalObj(interp, objPtr);
+            Jim_DecrRefCount(interp, objPtr);
+        }
+        interp->framePtr = savedCallFrame;
+        return retcode;
+    }
+    else {
+        Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?");
+        return JIM_ERR;
+    }
+}
+
+/* [expr] */
+static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *exprResultPtr;
+    int retcode;
+
+    if (argc == 2) {
+        retcode = Jim_EvalExpression(interp, argv[1], &exprResultPtr);
+    }
+    else if (argc > 2) {
+        Jim_Obj *objPtr;
+
+        objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1);
+        Jim_IncrRefCount(objPtr);
+        retcode = Jim_EvalExpression(interp, objPtr, &exprResultPtr);
+        Jim_DecrRefCount(interp, objPtr);
+    }
+    else {
+        Jim_WrongNumArgs(interp, 1, argv, "expression ?...?");
+        return JIM_ERR;
+    }
+    if (retcode != JIM_OK)
+        return retcode;
+    Jim_SetResult(interp, exprResultPtr);
+    Jim_DecrRefCount(interp, exprResultPtr);
+    return JIM_OK;
+}
+
+/* [break] */
+static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 1) {
+        Jim_WrongNumArgs(interp, 1, argv, "");
+        return JIM_ERR;
+    }
+    return JIM_BREAK;
+}
+
+/* [continue] */
+static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 1) {
+        Jim_WrongNumArgs(interp, 1, argv, "");
+        return JIM_ERR;
+    }
+    return JIM_CONTINUE;
+}
+
+/* [return] */
+static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int i;
+    Jim_Obj *stackTraceObj = NULL;
+    Jim_Obj *errorCodeObj = NULL;
+    int returnCode = JIM_OK;
+    long level = 1;
+
+    for (i = 1; i < argc - 1; i += 2) {
+        if (Jim_CompareStringImmediate(interp, argv[i], "-code")) {
+            if (Jim_GetReturnCode(interp, argv[i + 1], &returnCode) == JIM_ERR) {
+                return JIM_ERR;
+            }
+        }
+        else if (Jim_CompareStringImmediate(interp, argv[i], "-errorinfo")) {
+            stackTraceObj = argv[i + 1];
+        }
+        else if (Jim_CompareStringImmediate(interp, argv[i], "-errorcode")) {
+            errorCodeObj = argv[i + 1];
+        }
+        else if (Jim_CompareStringImmediate(interp, argv[i], "-level")) {
+            if (Jim_GetLong(interp, argv[i + 1], &level) != JIM_OK || level < 0) {
+                Jim_SetResultFormatted(interp, "bad level \"%#s\"", argv[i + 1]);
+                return JIM_ERR;
+            }
+        }
+        else {
+            break;
+        }
+    }
+
+    if (i != argc - 1 && i != argc) {
+        Jim_WrongNumArgs(interp, 1, argv,
+            "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?");
+    }
+
+    /* If a stack trace is supplied and code is error, set the stack trace */
+    if (stackTraceObj && returnCode == JIM_ERR) {
+        JimSetStackTrace(interp, stackTraceObj);
+    }
+    /* If an error code list is supplied, set the global $errorCode */
+    if (errorCodeObj && returnCode == JIM_ERR) {
+        Jim_SetGlobalVariableStr(interp, "errorCode", errorCodeObj);
+    }
+    interp->returnCode = returnCode;
+    interp->returnLevel = level;
+
+    if (i == argc - 1) {
+        Jim_SetResult(interp, argv[i]);
+    }
+    return JIM_RETURN;
+}
+
+/* [tailcall] */
+static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr;
+
+    objPtr = Jim_NewListObj(interp, argv + 1, argc - 1);
+    Jim_SetResult(interp, objPtr);
+    return JIM_EVAL;
+}
+
+/* [proc] */
+static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 4 && argc != 5) {
+        Jim_WrongNumArgs(interp, 1, argv, "name arglist ?statics? body");
+        return JIM_ERR;
+    }
+
+    if (argc == 4) {
+        return JimCreateProcedure(interp, argv[1], argv[2], NULL, argv[3]);
+    }
+    else {
+        return JimCreateProcedure(interp, argv[1], argv[2], argv[3], argv[4]);
+    }
+}
+
+/* [local] */
+static int Jim_LocalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int retcode;
+
+    /* Evaluate the arguments with 'local' in force */
+    interp->local++;
+    retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
+    interp->local--;
+
+
+    /* If OK, and the result is a proc, add it to the list of local procs */
+    if (retcode == 0) {
+        const char *procname = Jim_String(Jim_GetResult(interp));
+
+        if (Jim_FindHashEntry(&interp->commands, procname) == NULL) {
+            Jim_SetResultFormatted(interp, "not a proc: \"%s\"", procname);
+            return JIM_ERR;
+        }
+        if (interp->localProcs == NULL) {
+            interp->localProcs = Jim_Alloc(sizeof(*interp->localProcs));
+            Jim_InitStack(interp->localProcs);
+        }
+        Jim_StackPush(interp->localProcs, Jim_StrDup(procname));
+    }
+
+    return retcode;
+}
+
+/* [upcall] */
+static int Jim_UpcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?");
+        return JIM_ERR;
+    }
+    else {
+        int retcode;
+
+        Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
+        if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->u.proc.prevCmd) {
+            Jim_SetResultFormatted(interp, "no previous proc: \"%#s\"", argv[1]);
+            return JIM_ERR;
+        }
+        /* OK. Mark this command as being in an upcall */
+        cmdPtr->u.proc.upcall++;
+        JimIncrCmdRefCount(cmdPtr);
+
+        /* Invoke the command as normal */
+        retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
+
+        /* No longer in an upcall */
+        cmdPtr->u.proc.upcall--;
+        JimDecrCmdRefCount(interp, cmdPtr);
+
+        return retcode;
+    }
+}
+
+/* [concat] */
+static int Jim_ConcatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_SetResult(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
+    return JIM_OK;
+}
+
+/* [upvar] */
+static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int i;
+    Jim_CallFrame *targetCallFrame;
+
+    /* Lookup the target frame pointer */
+    if (argc > 3 && (argc % 2 == 0)) {
+        targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
+        argc--;
+        argv++;
+    }
+    else {
+        targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL);
+    }
+    if (targetCallFrame == NULL) {
+        return JIM_ERR;
+    }
+
+    /* Check for arity */
+    if (argc < 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?");
+        return JIM_ERR;
+    }
+
+    /* Now... for every other/local couple: */
+    for (i = 1; i < argc; i += 2) {
+        if (Jim_SetVariableLink(interp, argv[i + 1], argv[i], targetCallFrame) != JIM_OK)
+            return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+/* [global] */
+static int Jim_GlobalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int i;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?");
+        return JIM_ERR;
+    }
+    /* Link every var to the toplevel having the same name */
+    if (interp->framePtr->level == 0)
+        return JIM_OK;          /* global at toplevel... */
+    for (i = 1; i < argc; i++) {
+        if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK)
+            return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+/* does the [string map] operation. On error NULL is returned,
+ * otherwise a new string object with the result, having refcount = 0,
+ * is returned. */
+static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr,
+    Jim_Obj *objPtr, int nocase)
+{
+    int numMaps;
+    const char *str, *noMatchStart = NULL;
+    int strLen, i;
+    Jim_Obj *resultObjPtr;
+
+    numMaps = Jim_ListLength(interp, mapListObjPtr);
+    if (numMaps % 2) {
+        Jim_SetResultString(interp, "list must contain an even number of elements", -1);
+        return NULL;
+    }
+
+    str = Jim_String(objPtr);
+    strLen = Jim_Utf8Length(interp, objPtr);
+
+    /* Map it */
+    resultObjPtr = Jim_NewStringObj(interp, "", 0);
+    while (strLen) {
+        for (i = 0; i < numMaps; i += 2) {
+            Jim_Obj *objPtr;
+            const char *k;
+            int kl;
+
+            Jim_ListIndex(interp, mapListObjPtr, i, &objPtr, JIM_NONE);
+            k = Jim_String(objPtr);
+            kl = Jim_Utf8Length(interp, objPtr);
+
+            if (strLen >= kl && kl) {
+                int rc;
+                if (nocase) {
+                    rc = JimStringCompareNoCase(str, k, kl);
+                }
+                else {
+                    rc = JimStringCompare(str, kl, k, kl);
+                }
+                if (rc == 0) {
+                    if (noMatchStart) {
+                        Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
+                        noMatchStart = NULL;
+                    }
+                    Jim_ListIndex(interp, mapListObjPtr, i + 1, &objPtr, JIM_NONE);
+                    Jim_AppendObj(interp, resultObjPtr, objPtr);
+                    str += utf8_index(str, kl);
+                    strLen -= kl;
+                    break;
+                }
+            }
+        }
+        if (i == numMaps) {     /* no match */
+            int c;
+            if (noMatchStart == NULL)
+                noMatchStart = str;
+            str += utf8_tounicode(str, &c);
+            strLen--;
+        }
+    }
+    if (noMatchStart) {
+        Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
+    }
+    return resultObjPtr;
+}
+
+/* [string] */
+static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int len;
+    int opt_case = 1;
+    int option;
+    static const char * const options[] = {
+        "bytelength", "length", "compare", "match", "equal", "is", "byterange", "range", "map",
+        "repeat", "reverse", "index", "first", "last",
+        "trim", "trimleft", "trimright", "tolower", "toupper", NULL
+    };
+    enum
+    {
+        OPT_BYTELENGTH, OPT_LENGTH, OPT_COMPARE, OPT_MATCH, OPT_EQUAL, OPT_IS, OPT_BYTERANGE, OPT_RANGE, OPT_MAP,
+        OPT_REPEAT, OPT_REVERSE, OPT_INDEX, OPT_FIRST, OPT_LAST,
+        OPT_TRIM, OPT_TRIMLEFT, OPT_TRIMRIGHT, OPT_TOLOWER, OPT_TOUPPER
+    };
+    static const char * const nocase_options[] = {
+        "-nocase", NULL
+    };
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?");
+        return JIM_ERR;
+    }
+    if (Jim_GetEnum(interp, argv[1], options, &option, NULL,
+            JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK)
+        return JIM_ERR;
+
+    switch (option) {
+        case OPT_LENGTH:
+        case OPT_BYTELENGTH:
+            if (argc != 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "string");
+                return JIM_ERR;
+            }
+            if (option == OPT_LENGTH) {
+                len = Jim_Utf8Length(interp, argv[2]);
+            }
+            else {
+                len = Jim_Length(argv[2]);
+            }
+            Jim_SetResultInt(interp, len);
+            return JIM_OK;
+
+        case OPT_COMPARE:
+        case OPT_EQUAL:
+            if (argc != 4 &&
+                (argc != 5 ||
+                    Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
+                        JIM_ENUM_ABBREV) != JIM_OK)) {
+                Jim_WrongNumArgs(interp, 2, argv, "?-nocase? string1 string2");
+                return JIM_ERR;
+            }
+            if (opt_case == 0) {
+                argv++;
+            }
+            if (option == OPT_COMPARE || !opt_case) {
+                Jim_SetResultInt(interp, Jim_StringCompareObj(interp, argv[2], argv[3], !opt_case));
+            }
+            else {
+                Jim_SetResultBool(interp, Jim_StringEqObj(argv[2], argv[3]));
+            }
+            return JIM_OK;
+
+        case OPT_MATCH:
+            if (argc != 4 &&
+                (argc != 5 ||
+                    Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
+                        JIM_ENUM_ABBREV) != JIM_OK)) {
+                Jim_WrongNumArgs(interp, 2, argv, "?-nocase? pattern string");
+                return JIM_ERR;
+            }
+            if (opt_case == 0) {
+                argv++;
+            }
+            Jim_SetResultBool(interp, Jim_StringMatchObj(interp, argv[2], argv[3], !opt_case));
+            return JIM_OK;
+
+        case OPT_MAP:{
+                Jim_Obj *objPtr;
+
+                if (argc != 4 &&
+                    (argc != 5 ||
+                        Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
+                            JIM_ENUM_ABBREV) != JIM_OK)) {
+                    Jim_WrongNumArgs(interp, 2, argv, "?-nocase? mapList string");
+                    return JIM_ERR;
+                }
+
+                if (opt_case == 0) {
+                    argv++;
+                }
+                objPtr = JimStringMap(interp, argv[2], argv[3], !opt_case);
+                if (objPtr == NULL) {
+                    return JIM_ERR;
+                }
+                Jim_SetResult(interp, objPtr);
+                return JIM_OK;
+            }
+
+        case OPT_RANGE:
+        case OPT_BYTERANGE:{
+                Jim_Obj *objPtr;
+
+                if (argc != 5) {
+                    Jim_WrongNumArgs(interp, 2, argv, "string first last");
+                    return JIM_ERR;
+                }
+                if (option == OPT_RANGE) {
+                    objPtr = Jim_StringRangeObj(interp, argv[2], argv[3], argv[4]);
+                }
+                else
+                {
+                    objPtr = Jim_StringByteRangeObj(interp, argv[2], argv[3], argv[4]);
+                }
+
+                if (objPtr == NULL) {
+                    return JIM_ERR;
+                }
+                Jim_SetResult(interp, objPtr);
+                return JIM_OK;
+            }
+
+        case OPT_REPEAT:{
+                Jim_Obj *objPtr;
+                jim_wide count;
+
+                if (argc != 4) {
+                    Jim_WrongNumArgs(interp, 2, argv, "string count");
+                    return JIM_ERR;
+                }
+                if (Jim_GetWide(interp, argv[3], &count) != JIM_OK) {
+                    return JIM_ERR;
+                }
+                objPtr = Jim_NewStringObj(interp, "", 0);
+                if (count > 0) {
+                    while (count--) {
+                        Jim_AppendObj(interp, objPtr, argv[2]);
+                    }
+                }
+                Jim_SetResult(interp, objPtr);
+                return JIM_OK;
+            }
+
+        case OPT_REVERSE:{
+                char *buf, *p;
+                const char *str;
+                int len;
+                int i;
+
+                if (argc != 3) {
+                    Jim_WrongNumArgs(interp, 2, argv, "string");
+                    return JIM_ERR;
+                }
+
+                str = Jim_GetString(argv[2], &len);
+                buf = Jim_Alloc(len + 1);
+                p = buf + len;
+                *p = 0;
+                for (i = 0; i < len; ) {
+                    int c;
+                    int l = utf8_tounicode(str, &c);
+                    memcpy(p - l, str, l);
+                    p -= l;
+                    i += l;
+                    str += l;
+                }
+                Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
+                return JIM_OK;
+            }
+
+        case OPT_INDEX:{
+                int idx;
+                const char *str;
+
+                if (argc != 4) {
+                    Jim_WrongNumArgs(interp, 2, argv, "string index");
+                    return JIM_ERR;
+                }
+                if (Jim_GetIndex(interp, argv[3], &idx) != JIM_OK) {
+                    return JIM_ERR;
+                }
+                str = Jim_String(argv[2]);
+                len = Jim_Utf8Length(interp, argv[2]);
+                if (idx != INT_MIN && idx != INT_MAX) {
+                    idx = JimRelToAbsIndex(len, idx);
+                }
+                if (idx < 0 || idx >= len || str == NULL) {
+                    Jim_SetResultString(interp, "", 0);
+                }
+                else if (len == Jim_Length(argv[2])) {
+                    /* ASCII optimisation */
+                    Jim_SetResultString(interp, str + idx, 1);
+                }
+                else {
+                    int c;
+                    int i = utf8_index(str, idx);
+                    Jim_SetResultString(interp, str + i, utf8_tounicode(str + i, &c));
+                }
+                return JIM_OK;
+            }
+
+        case OPT_FIRST:
+        case OPT_LAST:{
+                int idx = 0, l1, l2;
+                const char *s1, *s2;
+
+                if (argc != 4 && argc != 5) {
+                    Jim_WrongNumArgs(interp, 2, argv, "subString string ?index?");
+                    return JIM_ERR;
+                }
+                s1 = Jim_String(argv[2]);
+                s2 = Jim_String(argv[3]);
+                l1 = Jim_Utf8Length(interp, argv[2]);
+                l2 = Jim_Utf8Length(interp, argv[3]);
+                if (argc == 5) {
+                    if (Jim_GetIndex(interp, argv[4], &idx) != JIM_OK) {
+                        return JIM_ERR;
+                    }
+                    idx = JimRelToAbsIndex(l2, idx);
+                }
+                else if (option == OPT_LAST) {
+                    idx = l2;
+                }
+                if (option == OPT_FIRST) {
+                    Jim_SetResultInt(interp, JimStringFirst(s1, l1, s2, l2, idx));
+                }
+                else {
+#ifdef JIM_UTF8
+                    Jim_SetResultInt(interp, JimStringLastUtf8(s1, l1, s2, idx));
+#else
+                    Jim_SetResultInt(interp, JimStringLast(s1, l1, s2, idx));
+#endif
+                }
+                return JIM_OK;
+            }
+
+        case OPT_TRIM:
+        case OPT_TRIMLEFT:
+        case OPT_TRIMRIGHT:{
+                Jim_Obj *trimchars;
+
+                if (argc != 3 && argc != 4) {
+                    Jim_WrongNumArgs(interp, 2, argv, "string ?trimchars?");
+                    return JIM_ERR;
+                }
+                trimchars = (argc == 4 ? argv[3] : NULL);
+                if (option == OPT_TRIM) {
+                    Jim_SetResult(interp, JimStringTrim(interp, argv[2], trimchars));
+                }
+                else if (option == OPT_TRIMLEFT) {
+                    Jim_SetResult(interp, JimStringTrimLeft(interp, argv[2], trimchars));
+                }
+                else if (option == OPT_TRIMRIGHT) {
+                    Jim_SetResult(interp, JimStringTrimRight(interp, argv[2], trimchars));
+                }
+                return JIM_OK;
+            }
+
+        case OPT_TOLOWER:
+        case OPT_TOUPPER:
+            if (argc != 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "string");
+                return JIM_ERR;
+            }
+            if (option == OPT_TOLOWER) {
+                Jim_SetResult(interp, JimStringToLower(interp, argv[2]));
+            }
+            else {
+                Jim_SetResult(interp, JimStringToUpper(interp, argv[2]));
+            }
+            return JIM_OK;
+
+        case OPT_IS:
+            if (argc == 4 || (argc == 5 && Jim_CompareStringImmediate(interp, argv[3], "-strict"))) {
+                return JimStringIs(interp, argv[argc - 1], argv[2], argc == 5);
+            }
+            Jim_WrongNumArgs(interp, 2, argv, "class ?-strict? str");
+            return JIM_ERR;
+    }
+    return JIM_OK;
+}
+
+/* [time] */
+static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    long i, count = 1;
+    jim_wide start, elapsed;
+    char buf[60];
+    const char *fmt = "%" JIM_WIDE_MODIFIER " microseconds per iteration";
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "script ?count?");
+        return JIM_ERR;
+    }
+    if (argc == 3) {
+        if (Jim_GetLong(interp, argv[2], &count) != JIM_OK)
+            return JIM_ERR;
+    }
+    if (count < 0)
+        return JIM_OK;
+    i = count;
+    start = JimClock();
+    while (i-- > 0) {
+        int retval;
+
+        retval = Jim_EvalObj(interp, argv[1]);
+        if (retval != JIM_OK) {
+            return retval;
+        }
+    }
+    elapsed = JimClock() - start;
+    sprintf(buf, fmt, count == 0 ? 0 : elapsed / count);
+    Jim_SetResultString(interp, buf, -1);
+    return JIM_OK;
+}
+
+/* [exit] */
+static int Jim_ExitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    long exitCode = 0;
+
+    if (argc > 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "?exitCode?");
+        return JIM_ERR;
+    }
+    if (argc == 2) {
+        if (Jim_GetLong(interp, argv[1], &exitCode) != JIM_OK)
+            return JIM_ERR;
+    }
+    interp->exitCode = exitCode;
+    return JIM_EXIT;
+}
+
+/* [catch] */
+static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int exitCode = 0;
+    int i;
+    int sig = 0;
+
+    /* Which return codes are ignored (passed through)? By default, only exit, eval and signal */
+    jim_wide ignore_mask = (1 << JIM_EXIT) | (1 << JIM_EVAL) | (1 << JIM_SIGNAL);
+    static const int max_ignore_code = sizeof(ignore_mask) * 8;
+
+    /* Reset the error code before catch.
+     * Note that this is not strictly correct.
+     */
+    Jim_SetGlobalVariableStr(interp, "errorCode", Jim_NewStringObj(interp, "NONE", -1));
+
+    for (i = 1; i < argc - 1; i++) {
+        const char *arg = Jim_String(argv[i]);
+        jim_wide option;
+        int ignore;
+
+        /* It's a pity we can't use Jim_GetEnum here :-( */
+        if (strcmp(arg, "--") == 0) {
+            i++;
+            break;
+        }
+        if (*arg != '-') {
+            break;
+        }
+
+        if (strncmp(arg, "-no", 3) == 0) {
+            arg += 3;
+            ignore = 1;
+        }
+        else {
+            arg++;
+            ignore = 0;
+        }
+
+        if (Jim_StringToWide(arg, &option, 10) != JIM_OK) {
+            option = -1;
+        }
+        if (option < 0) {
+            option = Jim_FindByName(arg, jimReturnCodes, jimReturnCodesSize);
+        }
+        if (option < 0) {
+            goto wrongargs;
+        }
+
+        if (ignore) {
+            ignore_mask |= (1 << option);
+        }
+        else {
+            ignore_mask &= ~(1 << option);
+        }
+    }
+
+    argc -= i;
+    if (argc < 1 || argc > 3) {
+      wrongargs:
+        Jim_WrongNumArgs(interp, 1, argv,
+            "?-?no?code ... --? script ?resultVarName? ?optionVarName?");
+        return JIM_ERR;
+    }
+    argv += i;
+
+    if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) {
+        sig++;
+    }
+
+    interp->signal_level += sig;
+    if (interp->signal_level && interp->sigmask) {
+        /* If a signal is set, don't even try to execute the body */
+        exitCode = JIM_SIGNAL;
+    }
+    else {
+        exitCode = Jim_EvalObj(interp, argv[0]);
+    }
+    interp->signal_level -= sig;
+
+    /* Catch or pass through? Only the first 32/64 codes can be passed through */
+    if (exitCode >= 0 && exitCode < max_ignore_code && ((1 << exitCode) & ignore_mask)) {
+        /* Not caught, pass it up */
+        return exitCode;
+    }
+
+    if (sig && exitCode == JIM_SIGNAL) {
+        /* Catch the signal at this level */
+        if (interp->signal_set_result) {
+            interp->signal_set_result(interp, interp->sigmask);
+        }
+        else {
+            Jim_SetResultInt(interp, interp->sigmask);
+        }
+        interp->sigmask = 0;
+    }
+
+    if (argc >= 2) {
+        if (Jim_SetVariable(interp, argv[1], Jim_GetResult(interp)) != JIM_OK) {
+            return JIM_ERR;
+        }
+        if (argc == 3) {
+            Jim_Obj *optListObj = Jim_NewListObj(interp, NULL, 0);
+
+            Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-code", -1));
+            Jim_ListAppendElement(interp, optListObj,
+                Jim_NewIntObj(interp, exitCode == JIM_RETURN ? interp->returnCode : exitCode));
+            Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-level", -1));
+            Jim_ListAppendElement(interp, optListObj, Jim_NewIntObj(interp, interp->returnLevel));
+            if (exitCode == JIM_ERR) {
+                Jim_Obj *errorCode;
+                Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorinfo",
+                    -1));
+                Jim_ListAppendElement(interp, optListObj, interp->stackTrace);
+
+                errorCode = Jim_GetGlobalVariableStr(interp, "errorCode", JIM_NONE);
+                if (errorCode) {
+                    Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorcode", -1));
+                    Jim_ListAppendElement(interp, optListObj, errorCode);
+                }
+            }
+            if (Jim_SetVariable(interp, argv[2], optListObj) != JIM_OK) {
+                return JIM_ERR;
+            }
+        }
+    }
+    Jim_SetResultInt(interp, exitCode);
+    return JIM_OK;
+}
+
+#ifdef JIM_REFERENCES
+
+/* [ref] */
+static int Jim_RefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 3 && argc != 4) {
+        Jim_WrongNumArgs(interp, 1, argv, "string tag ?finalizer?");
+        return JIM_ERR;
+    }
+    if (argc == 3) {
+        Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2], NULL));
+    }
+    else {
+        Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2], argv[3]));
+    }
+    return JIM_OK;
+}
+
+/* [getref] */
+static int Jim_GetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Reference *refPtr;
+
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "reference");
+        return JIM_ERR;
+    }
+    if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL)
+        return JIM_ERR;
+    Jim_SetResult(interp, refPtr->objPtr);
+    return JIM_OK;
+}
+
+/* [setref] */
+static int Jim_SetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Reference *refPtr;
+
+    if (argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "reference newValue");
+        return JIM_ERR;
+    }
+    if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL)
+        return JIM_ERR;
+    Jim_IncrRefCount(argv[2]);
+    Jim_DecrRefCount(interp, refPtr->objPtr);
+    refPtr->objPtr = argv[2];
+    Jim_SetResult(interp, argv[2]);
+    return JIM_OK;
+}
+
+/* [collect] */
+static int Jim_CollectCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 1) {
+        Jim_WrongNumArgs(interp, 1, argv, "");
+        return JIM_ERR;
+    }
+    Jim_SetResultInt(interp, Jim_Collect(interp));
+
+    /* Free all the freed objects. */
+    while (interp->freeList) {
+        Jim_Obj *nextObjPtr = interp->freeList->nextObjPtr;
+        Jim_Free(interp->freeList);
+        interp->freeList = nextObjPtr;
+    }
+
+    return JIM_OK;
+}
+
+/* [finalize] reference ?newValue? */
+static int Jim_FinalizeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "reference ?finalizerProc?");
+        return JIM_ERR;
+    }
+    if (argc == 2) {
+        Jim_Obj *cmdNamePtr;
+
+        if (Jim_GetFinalizer(interp, argv[1], &cmdNamePtr) != JIM_OK)
+            return JIM_ERR;
+        if (cmdNamePtr != NULL) /* otherwise the null string is returned. */
+            Jim_SetResult(interp, cmdNamePtr);
+    }
+    else {
+        if (Jim_SetFinalizer(interp, argv[1], argv[2]) != JIM_OK)
+            return JIM_ERR;
+        Jim_SetResult(interp, argv[2]);
+    }
+    return JIM_OK;
+}
+
+/* [info references] */
+static int JimInfoReferences(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *listObjPtr;
+    Jim_HashTableIterator *htiter;
+    Jim_HashEntry *he;
+
+    listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+    htiter = Jim_GetHashTableIterator(&interp->references);
+    while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+        char buf[JIM_REFERENCE_SPACE];
+        Jim_Reference *refPtr = he->u.val;
+        const jim_wide *refId = he->key;
+
+        JimFormatReference(buf, refPtr, *refId);
+        Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, buf, -1));
+    }
+    Jim_FreeHashTableIterator(htiter);
+    Jim_SetResult(interp, listObjPtr);
+    return JIM_OK;
+}
+#endif
+
+/* [rename] */
+static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *oldName, *newName;
+
+    if (argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "oldName newName");
+        return JIM_ERR;
+    }
+
+    if (JimValidName(interp, "new procedure", argv[2])) {
+        return JIM_ERR;
+    }
+
+    oldName = Jim_String(argv[1]);
+    newName = Jim_String(argv[2]);
+    return Jim_RenameCommand(interp, oldName, newName);
+}
+
+int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj)
+{
+    int i;
+    int len;
+    Jim_Obj *resultObj;
+    Jim_Obj *dictObj;
+    Jim_Obj **dictValuesObj;
+
+    if (Jim_DictKeysVector(interp, objPtr, NULL, 0, &dictObj, JIM_ERRMSG) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    /* XXX: Could make the exact-match case much more efficient here.
+     *      See JimCommandsList()
+     */
+    if (Jim_DictPairs(interp, dictObj, &dictValuesObj, &len) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    /* Only return the matching values */
+    resultObj = Jim_NewListObj(interp, NULL, 0);
+
+    for (i = 0; i < len; i += 2) {
+        if (patternObj == NULL || Jim_StringMatchObj(interp, patternObj, dictValuesObj[i], 0)) {
+            Jim_ListAppendElement(interp, resultObj, dictValuesObj[i]);
+        }
+    }
+    Jim_Free(dictValuesObj);
+
+    Jim_SetResult(interp, resultObj);
+    return JIM_OK;
+}
+
+int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+    if (SetDictFromAny(interp, objPtr) != JIM_OK) {
+        return -1;
+    }
+    return ((Jim_HashTable *)objPtr->internalRep.ptr)->used;
+}
+
+/* [dict] */
+static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr;
+    int option;
+    static const char * const options[] = {
+        "create", "get", "set", "unset", "exists", "keys", "merge", "size", "with", NULL
+    };
+    enum
+    {
+        OPT_CREATE, OPT_GET, OPT_SET, OPT_UNSET, OPT_EXIST, OPT_KEYS, OPT_MERGE, OPT_SIZE, OPT_WITH,
+    };
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "subcommand ?arguments ...?");
+        return JIM_ERR;
+    }
+
+    if (Jim_GetEnum(interp, argv[1], options, &option, "subcommand", JIM_ERRMSG) != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    switch (option) {
+        case OPT_GET:
+            if (argc < 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "varName ?key ...?");
+                return JIM_ERR;
+            }
+            if (Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr,
+                    JIM_ERRMSG) != JIM_OK) {
+                return JIM_ERR;
+            }
+            Jim_SetResult(interp, objPtr);
+            return JIM_OK;
+
+        case OPT_SET:
+            if (argc < 5) {
+                Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...? value");
+                return JIM_ERR;
+            }
+            return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG);
+
+        case OPT_EXIST:
+            if (argc < 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "varName ?key ...?");
+                return JIM_ERR;
+            }
+            Jim_SetResultBool(interp, Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3,
+                    &objPtr, JIM_ERRMSG) == JIM_OK);
+            return JIM_OK;
+
+        case OPT_UNSET:
+            if (argc < 4) {
+                Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...?");
+                return JIM_ERR;
+            }
+            return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_NONE);
+
+        case OPT_KEYS:
+            if (argc != 3 && argc != 4) {
+                Jim_WrongNumArgs(interp, 2, argv, "dictVar ?pattern?");
+                return JIM_ERR;
+            }
+            return Jim_DictKeys(interp, argv[2], argc == 4 ? argv[3] : NULL);
+
+        case OPT_SIZE: {
+            int size;
+
+            if (argc != 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "dictVar");
+                return JIM_ERR;
+            }
+
+            size = Jim_DictSize(interp, argv[2]);
+            if (size < 0) {
+                return JIM_ERR;
+            }
+            Jim_SetResultInt(interp, size);
+            return JIM_OK;
+        }
+
+        case OPT_MERGE:
+            if (argc == 2) {
+                return JIM_OK;
+            }
+            else if (argv[2]->typePtr != &dictObjType && SetDictFromAny(interp, argv[2]) != JIM_OK) {
+                return JIM_ERR;
+            }
+            else {
+                return Jim_EvalPrefix(interp, "dict merge", argc - 2, argv + 2);
+            }
+
+        case OPT_WITH:
+            if (argc < 4) {
+                Jim_WrongNumArgs(interp, 2, argv, "dictVar ?key ...? script");
+                return JIM_ERR;
+            }
+            else if (Jim_GetVariable(interp, argv[2], JIM_ERRMSG) == NULL) {
+                return JIM_ERR;
+            }
+            else {
+                return Jim_EvalPrefix(interp, "dict with", argc - 2, argv + 2);
+            }
+
+        case OPT_CREATE:
+            if (argc % 2) {
+                Jim_WrongNumArgs(interp, 2, argv, "?key value ...?");
+                return JIM_ERR;
+            }
+            objPtr = Jim_NewDictObj(interp, argv + 2, argc - 2);
+            Jim_SetResult(interp, objPtr);
+            return JIM_OK;
+
+        default:
+            abort();
+    }
+}
+
+/* [subst] */
+static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    static const char * const options[] = {
+        "-nobackslashes", "-nocommands", "-novariables", NULL
+    };
+    enum
+    { OPT_NOBACKSLASHES, OPT_NOCOMMANDS, OPT_NOVARIABLES };
+    int i;
+    int flags = JIM_SUBST_FLAG;
+    Jim_Obj *objPtr;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "?options? string");
+        return JIM_ERR;
+    }
+    for (i = 1; i < (argc - 1); i++) {
+        int option;
+
+        if (Jim_GetEnum(interp, argv[i], options, &option, NULL,
+                JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+            return JIM_ERR;
+        }
+        switch (option) {
+            case OPT_NOBACKSLASHES:
+                flags |= JIM_SUBST_NOESC;
+                break;
+            case OPT_NOCOMMANDS:
+                flags |= JIM_SUBST_NOCMD;
+                break;
+            case OPT_NOVARIABLES:
+                flags |= JIM_SUBST_NOVAR;
+                break;
+        }
+    }
+    if (Jim_SubstObj(interp, argv[argc - 1], &objPtr, flags) != JIM_OK) {
+        return JIM_ERR;
+    }
+    Jim_SetResult(interp, objPtr);
+    return JIM_OK;
+}
+
+/* [info] */
+static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int cmd;
+    Jim_Obj *objPtr;
+    int mode = 0;
+
+    static const char * const commands[] = {
+        "body", "commands", "procs", "channels", "exists", "globals", "level", "frame", "locals",
+        "vars", "version", "patchlevel", "complete", "args", "hostname",
+        "script", "source", "stacktrace", "nameofexecutable", "returncodes",
+        "references", NULL
+    };
+    enum
+    { INFO_BODY, INFO_COMMANDS, INFO_PROCS, INFO_CHANNELS, INFO_EXISTS, INFO_GLOBALS, INFO_LEVEL,
+        INFO_FRAME, INFO_LOCALS, INFO_VARS, INFO_VERSION, INFO_PATCHLEVEL, INFO_COMPLETE, INFO_ARGS,
+        INFO_HOSTNAME, INFO_SCRIPT, INFO_SOURCE, INFO_STACKTRACE, INFO_NAMEOFEXECUTABLE,
+        INFO_RETURNCODES, INFO_REFERENCES,
+    };
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "subcommand ?args ...?");
+        return JIM_ERR;
+    }
+    if (Jim_GetEnum(interp, argv[1], commands, &cmd, "subcommand", JIM_ERRMSG | JIM_ENUM_ABBREV)
+        != JIM_OK) {
+        return JIM_ERR;
+    }
+
+    /* Test for the the most common commands first, just in case it makes a difference */
+    switch (cmd) {
+        case INFO_EXISTS:{
+                if (argc != 3) {
+                    Jim_WrongNumArgs(interp, 2, argv, "varName");
+                    return JIM_ERR;
+                }
+                Jim_SetResultBool(interp, Jim_GetVariable(interp, argv[2], 0) != NULL);
+                break;
+            }
+
+        case INFO_CHANNELS:
+#ifndef jim_ext_aio
+            Jim_SetResultString(interp, "aio not enabled", -1);
+            return JIM_ERR;
+#endif
+        case INFO_COMMANDS:
+        case INFO_PROCS:
+            if (argc != 2 && argc != 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
+                return JIM_ERR;
+            }
+            Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL,
+                    (cmd - INFO_COMMANDS)));
+            break;
+
+        case INFO_VARS:
+            mode++;             /* JIM_VARLIST_VARS */
+        case INFO_LOCALS:
+            mode++;             /* JIM_VARLIST_LOCALS */
+        case INFO_GLOBALS:
+            /* mode 0 => JIM_VARLIST_GLOBALS */
+            if (argc != 2 && argc != 3) {
+                Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
+                return JIM_ERR;
+            }
+            Jim_SetResult(interp, JimVariablesList(interp, argc == 3 ? argv[2] : NULL, mode));
+            break;
+
+        case INFO_SCRIPT:
+            if (argc != 2) {
+                Jim_WrongNumArgs(interp, 2, argv, "");
+                return JIM_ERR;
+            }
+            Jim_SetResult(interp, Jim_GetScript(interp, interp->currentScriptObj)->fileNameObj);
+            break;
+
+        case INFO_SOURCE:{
+                int line;
+                Jim_Obj *resObjPtr;
+                Jim_Obj *fileNameObj;
+
+                if (argc != 3) {
+                    Jim_WrongNumArgs(interp, 2, argv, "source");
+                    return JIM_ERR;
+                }
+                if (argv[2]->typePtr == &sourceObjType) {
+                    fileNameObj = argv[2]->internalRep.sourceValue.fileNameObj;
+                    line = argv[2]->internalRep.sourceValue.lineNumber;
+                }
+                else if (argv[2]->typePtr == &scriptObjType) {
+                    ScriptObj *script = Jim_GetScript(interp, argv[2]);
+                    fileNameObj = script->fileNameObj;
+                    line = script->line;
+                }
+                else {
+                    fileNameObj = interp->emptyObj;
+                    line = 1;
+                }
+                resObjPtr = Jim_NewListObj(interp, NULL, 0);
+                Jim_ListAppendElement(interp, resObjPtr, fileNameObj);
+                Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line));
+                Jim_SetResult(interp, resObjPtr);
+                break;
+            }
+
+        case INFO_STACKTRACE:
+            Jim_SetResult(interp, interp->stackTrace);
+            break;
+
+        case INFO_LEVEL:
+        case INFO_FRAME:
+            switch (argc) {
+                case 2:
+                    Jim_SetResultInt(interp, interp->framePtr->level);
+                    break;
+
+                case 3:
+                    if (JimInfoLevel(interp, argv[2], &objPtr, cmd == INFO_LEVEL) != JIM_OK) {
+                        return JIM_ERR;
+                    }
+                    Jim_SetResult(interp, objPtr);
+                    break;
+
+                default:
+                    Jim_WrongNumArgs(interp, 2, argv, "?levelNum?");
+                    return JIM_ERR;
+            }
+            break;
+
+        case INFO_BODY:
+        case INFO_ARGS:{
+                Jim_Cmd *cmdPtr;
+
+                if (argc != 3) {
+                    Jim_WrongNumArgs(interp, 2, argv, "procname");
+                    return JIM_ERR;
+                }
+                if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) {
+                    return JIM_ERR;
+                }
+                if (!cmdPtr->isproc) {
+                    Jim_SetResultFormatted(interp, "command \"%#s\" is not a procedure", argv[2]);
+                    return JIM_ERR;
+                }
+                Jim_SetResult(interp,
+                    cmd == INFO_BODY ? cmdPtr->u.proc.bodyObjPtr : cmdPtr->u.proc.argListObjPtr);
+                break;
+            }
+
+        case INFO_VERSION:
+        case INFO_PATCHLEVEL:{
+                char buf[(JIM_INTEGER_SPACE * 2) + 1];
+
+                sprintf(buf, "%d.%d", JIM_VERSION / 100, JIM_VERSION % 100);
+                Jim_SetResultString(interp, buf, -1);
+                break;
+            }
+
+        case INFO_COMPLETE:
+            if (argc != 3 && argc != 4) {
+                Jim_WrongNumArgs(interp, 2, argv, "script ?missing?");
+                return JIM_ERR;
+            }
+            else {
+                int len;
+                const char *s = Jim_GetString(argv[2], &len);
+                char missing;
+
+                Jim_SetResultBool(interp, Jim_ScriptIsComplete(s, len, &missing));
+                if (missing != ' ' && argc == 4) {
+                    Jim_SetVariable(interp, argv[3], Jim_NewStringObj(interp, &missing, 1));
+                }
+            }
+            break;
+
+        case INFO_HOSTNAME:
+            /* Redirect to os.gethostname if it exists */
+            return Jim_Eval(interp, "os.gethostname");
+
+        case INFO_NAMEOFEXECUTABLE:
+            /* Redirect to Tcl proc */
+            return Jim_Eval(interp, "{info nameofexecutable}");
+
+        case INFO_RETURNCODES:
+            if (argc == 2) {
+                int i;
+                Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+                for (i = 0; jimReturnCodes[i]; i++) {
+                    Jim_ListAppendElement(interp, listObjPtr, Jim_NewIntObj(interp, i));
+                    Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp,
+                            jimReturnCodes[i], -1));
+                }
+
+                Jim_SetResult(interp, listObjPtr);
+            }
+            else if (argc == 3) {
+                long code;
+                const char *name;
+
+                if (Jim_GetLong(interp, argv[2], &code) != JIM_OK) {
+                    return JIM_ERR;
+                }
+                name = Jim_ReturnCode(code);
+                if (*name == '?') {
+                    Jim_SetResultInt(interp, code);
+                }
+                else {
+                    Jim_SetResultString(interp, name, -1);
+                }
+            }
+            else {
+                Jim_WrongNumArgs(interp, 2, argv, "?code?");
+                return JIM_ERR;
+            }
+            break;
+        case INFO_REFERENCES:
+#ifdef JIM_REFERENCES
+            return JimInfoReferences(interp, argc, argv);
+#else
+            Jim_SetResultString(interp, "not supported", -1);
+            return JIM_ERR;
+#endif
+    }
+    return JIM_OK;
+}
+
+/* [exists] */
+static int Jim_ExistsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr;
+
+    static const char * const options[] = {
+        "-command", "-proc", "-var", NULL
+    };
+    enum
+    {
+        OPT_COMMAND, OPT_PROC, OPT_VAR
+    };
+    int option;
+
+    if (argc == 2) {
+        option = OPT_VAR;
+        objPtr = argv[1];
+    }
+    else if (argc == 3) {
+        if (Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+            return JIM_ERR;
+        }
+        objPtr = argv[2];
+    }
+    else {
+        Jim_WrongNumArgs(interp, 1, argv, "?option? name");
+        return JIM_ERR;
+    }
+
+    /* Test for the the most common commands first, just in case it makes a difference */
+    switch (option) {
+        case OPT_VAR:
+            Jim_SetResultBool(interp, Jim_GetVariable(interp, objPtr, 0) != NULL);
+            break;
+
+        case OPT_COMMAND:
+        case OPT_PROC: {
+            Jim_Cmd *cmd = Jim_GetCommand(interp, objPtr, JIM_NONE);
+            Jim_SetResultBool(interp, cmd != NULL && (option == OPT_COMMAND || cmd->isproc));
+            break;
+        }
+    }
+    return JIM_OK;
+}
+
+/* [split] */
+static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *str, *splitChars, *noMatchStart;
+    int splitLen, strLen;
+    Jim_Obj *resObjPtr;
+    int c;
+    int len;
+
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "string ?splitChars?");
+        return JIM_ERR;
+    }
+
+    str = Jim_GetString(argv[1], &len);
+    if (len == 0) {
+        return JIM_OK;
+    }
+    strLen = Jim_Utf8Length(interp, argv[1]);
+
+    /* Init */
+    if (argc == 2) {
+        splitChars = " \n\t\r";
+        splitLen = 4;
+    }
+    else {
+        splitChars = Jim_String(argv[2]);
+        splitLen = Jim_Utf8Length(interp, argv[2]);
+    }
+
+    noMatchStart = str;
+    resObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+    /* Split */
+    if (splitLen) {
+        Jim_Obj *objPtr;
+        while (strLen--) {
+            const char *sc = splitChars;
+            int scLen = splitLen;
+            int sl = utf8_tounicode(str, &c);
+            while (scLen--) {
+                int pc;
+                sc += utf8_tounicode(sc, &pc);
+                if (c == pc) {
+                    objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart));
+                    Jim_ListAppendElement(interp, resObjPtr, objPtr);
+                    noMatchStart = str + sl;
+                    break;
+                }
+            }
+            str += sl;
+        }
+        objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart));
+        Jim_ListAppendElement(interp, resObjPtr, objPtr);
+    }
+    else {
+        /* This handles the special case of splitchars eq {}
+         * Optimise by sharing common (ASCII) characters
+         */
+        Jim_Obj **commonObj = NULL;
+#define NUM_COMMON (128 - 9)
+        while (strLen--) {
+            int n = utf8_tounicode(str, &c);
+#ifdef JIM_OPTIMIZATION
+            if (c >= 9 && c < 128) {
+                /* Common ASCII char. Note that 9 is the tab character */
+                c -= 9;
+                if (!commonObj) {
+                    commonObj = Jim_Alloc(sizeof(*commonObj) * NUM_COMMON);
+                    memset(commonObj, 0, sizeof(*commonObj) * NUM_COMMON);
+                }
+                if (!commonObj[c]) {
+                    commonObj[c] = Jim_NewStringObj(interp, str, 1);
+                }
+                Jim_ListAppendElement(interp, resObjPtr, commonObj[c]);
+                str++;
+                continue;
+            }
+#endif
+            Jim_ListAppendElement(interp, resObjPtr, Jim_NewStringObjUtf8(interp, str, 1));
+            str += n;
+        }
+        Jim_Free(commonObj);
+    }
+
+    Jim_SetResult(interp, resObjPtr);
+    return JIM_OK;
+}
+
+/* [join] */
+static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *joinStr;
+    int joinStrLen, i, listLen;
+    Jim_Obj *resObjPtr;
+
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?");
+        return JIM_ERR;
+    }
+    /* Init */
+    if (argc == 2) {
+        joinStr = " ";
+        joinStrLen = 1;
+    }
+    else {
+        joinStr = Jim_GetString(argv[2], &joinStrLen);
+    }
+    listLen = Jim_ListLength(interp, argv[1]);
+    resObjPtr = Jim_NewStringObj(interp, NULL, 0);
+    /* Split */
+    for (i = 0; i < listLen; i++) {
+        Jim_Obj *objPtr = 0;
+
+        Jim_ListIndex(interp, argv[1], i, &objPtr, JIM_NONE);
+        Jim_AppendObj(interp, resObjPtr, objPtr);
+        if (i + 1 != listLen) {
+            Jim_AppendString(interp, resObjPtr, joinStr, joinStrLen);
+        }
+    }
+    Jim_SetResult(interp, resObjPtr);
+    return JIM_OK;
+}
+
+/* [format] */
+static int Jim_FormatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr;
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "formatString ?arg arg ...?");
+        return JIM_ERR;
+    }
+    objPtr = Jim_FormatString(interp, argv[1], argc - 2, argv + 2);
+    if (objPtr == NULL)
+        return JIM_ERR;
+    Jim_SetResult(interp, objPtr);
+    return JIM_OK;
+}
+
+/* [scan] */
+static int Jim_ScanCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *listPtr, **outVec;
+    int outc, i;
+
+    if (argc < 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "string format ?varName varName ...?");
+        return JIM_ERR;
+    }
+    if (argv[2]->typePtr != &scanFmtStringObjType)
+        SetScanFmtFromAny(interp, argv[2]);
+    if (FormatGetError(argv[2]) != 0) {
+        Jim_SetResultString(interp, FormatGetError(argv[2]), -1);
+        return JIM_ERR;
+    }
+    if (argc > 3) {
+        int maxPos = FormatGetMaxPos(argv[2]);
+        int count = FormatGetCnvCount(argv[2]);
+
+        if (maxPos > argc - 3) {
+            Jim_SetResultString(interp, "\"%n$\" argument index out of range", -1);
+            return JIM_ERR;
+        }
+        else if (count > argc - 3) {
+            Jim_SetResultString(interp, "different numbers of variable names and "
+                "field specifiers", -1);
+            return JIM_ERR;
+        }
+        else if (count < argc - 3) {
+            Jim_SetResultString(interp, "variable is not assigned by any "
+                "conversion specifiers", -1);
+            return JIM_ERR;
+        }
+    }
+    listPtr = Jim_ScanString(interp, argv[1], argv[2], JIM_ERRMSG);
+    if (listPtr == 0)
+        return JIM_ERR;
+    if (argc > 3) {
+        int rc = JIM_OK;
+        int count = 0;
+
+        if (listPtr != 0 && listPtr != (Jim_Obj *)EOF) {
+            int len = Jim_ListLength(interp, listPtr);
+
+            if (len != 0) {
+                JimListGetElements(interp, listPtr, &outc, &outVec);
+                for (i = 0; i < outc; ++i) {
+                    if (Jim_Length(outVec[i]) > 0) {
+                        ++count;
+                        if (Jim_SetVariable(interp, argv[3 + i], outVec[i]) != JIM_OK) {
+                            rc = JIM_ERR;
+                        }
+                    }
+                }
+            }
+            Jim_FreeNewObj(interp, listPtr);
+        }
+        else {
+            count = -1;
+        }
+        if (rc == JIM_OK) {
+            Jim_SetResultInt(interp, count);
+        }
+        return rc;
+    }
+    else {
+        if (listPtr == (Jim_Obj *)EOF) {
+            Jim_SetResult(interp, Jim_NewListObj(interp, 0, 0));
+            return JIM_OK;
+        }
+        Jim_SetResult(interp, listPtr);
+    }
+    return JIM_OK;
+}
+
+/* [error] */
+static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    if (argc != 2 && argc != 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "message ?stacktrace?");
+        return JIM_ERR;
+    }
+    Jim_SetResult(interp, argv[1]);
+    if (argc == 3) {
+        JimSetStackTrace(interp, argv[2]);
+        return JIM_ERR;
+    }
+    interp->addStackTrace++;
+    return JIM_ERR;
+}
+
+/* [lrange] */
+static int Jim_LrangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr;
+
+    if (argc != 4) {
+        Jim_WrongNumArgs(interp, 1, argv, "list first last");
+        return JIM_ERR;
+    }
+    if ((objPtr = Jim_ListRange(interp, argv[1], argv[2], argv[3])) == NULL)
+        return JIM_ERR;
+    Jim_SetResult(interp, objPtr);
+    return JIM_OK;
+}
+
+/* [lrepeat] */
+static int Jim_LrepeatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *objPtr;
+    long count;
+
+    if (argc < 2 || Jim_GetLong(interp, argv[1], &count) != JIM_OK || count < 0) {
+        Jim_WrongNumArgs(interp, 1, argv, "count ?value ...?");
+        return JIM_ERR;
+    }
+
+    if (count == 0 || argc == 2) {
+        return JIM_OK;
+    }
+
+    argc -= 2;
+    argv += 2;
+
+    objPtr = Jim_NewListObj(interp, argv, argc);
+    while (--count) {
+        int i;
+
+        for (i = 0; i < argc; i++) {
+            ListAppendElement(objPtr, argv[i]);
+        }
+    }
+
+    Jim_SetResult(interp, objPtr);
+    return JIM_OK;
+}
+
+char **Jim_GetEnviron(void)
+{
+#if defined(HAVE__NSGETENVIRON)
+    return *_NSGetEnviron();
+#else
+    #if !defined(NO_ENVIRON_EXTERN)
+    extern char **environ;
+    #endif
+
+    return environ;
+#endif
+}
+
+void Jim_SetEnviron(char **env)
+{
+#if defined(HAVE__NSGETENVIRON)
+    *_NSGetEnviron() = env;
+#else
+    #if !defined(NO_ENVIRON_EXTERN)
+    extern char **environ;
+    #endif
+
+    environ = env;
+#endif
+}
+
+/* [env] */
+static int Jim_EnvCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    const char *key;
+    const char *val;
+
+    if (argc == 1) {
+        char **e = Jim_GetEnviron();
+
+        int i;
+        Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+        for (i = 0; e[i]; i++) {
+            const char *equals = strchr(e[i], '=');
+
+            if (equals) {
+                Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, e[i],
+                        equals - e[i]));
+                Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, equals + 1, -1));
+            }
+        }
+
+        Jim_SetResult(interp, listObjPtr);
+        return JIM_OK;
+    }
+
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "varName ?default?");
+        return JIM_ERR;
+    }
+    key = Jim_String(argv[1]);
+    val = getenv(key);
+    if (val == NULL) {
+        if (argc < 3) {
+            Jim_SetResultFormatted(interp, "environment variable \"%#s\" does not exist", argv[1]);
+            return JIM_ERR;
+        }
+        val = Jim_String(argv[2]);
+    }
+    Jim_SetResult(interp, Jim_NewStringObj(interp, val, -1));
+    return JIM_OK;
+}
+
+/* [source] */
+static int Jim_SourceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    int retval;
+
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "fileName");
+        return JIM_ERR;
+    }
+    retval = Jim_EvalFile(interp, Jim_String(argv[1]));
+    if (retval == JIM_RETURN)
+        return JIM_OK;
+    return retval;
+}
+
+/* [lreverse] */
+static int Jim_LreverseCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *revObjPtr, **ele;
+    int len;
+
+    if (argc != 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "list");
+        return JIM_ERR;
+    }
+    JimListGetElements(interp, argv[1], &len, &ele);
+    len--;
+    revObjPtr = Jim_NewListObj(interp, NULL, 0);
+    while (len >= 0)
+        ListAppendElement(revObjPtr, ele[len--]);
+    Jim_SetResult(interp, revObjPtr);
+    return JIM_OK;
+}
+
+static int JimRangeLen(jim_wide start, jim_wide end, jim_wide step)
+{
+    jim_wide len;
+
+    if (step == 0)
+        return -1;
+    if (start == end)
+        return 0;
+    else if (step > 0 && start > end)
+        return -1;
+    else if (step < 0 && end > start)
+        return -1;
+    len = end - start;
+    if (len < 0)
+        len = -len;             /* abs(len) */
+    if (step < 0)
+        step = -step;           /* abs(step) */
+    len = 1 + ((len - 1) / step);
+    /* We can truncate safely to INT_MAX, the range command
+     * will always return an error for a such long range
+     * because Tcl lists can't be so long. */
+    if (len > INT_MAX)
+        len = INT_MAX;
+    return (int)((len < 0) ? -1 : len);
+}
+
+/* [range] */
+static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    jim_wide start = 0, end, step = 1;
+    int len, i;
+    Jim_Obj *objPtr;
+
+    if (argc < 2 || argc > 4) {
+        Jim_WrongNumArgs(interp, 1, argv, "?start? end ?step?");
+        return JIM_ERR;
+    }
+    if (argc == 2) {
+        if (Jim_GetWide(interp, argv[1], &end) != JIM_OK)
+            return JIM_ERR;
+    }
+    else {
+        if (Jim_GetWide(interp, argv[1], &start) != JIM_OK ||
+            Jim_GetWide(interp, argv[2], &end) != JIM_OK)
+            return JIM_ERR;
+        if (argc == 4 && Jim_GetWide(interp, argv[3], &step) != JIM_OK)
+            return JIM_ERR;
+    }
+    if ((len = JimRangeLen(start, end, step)) == -1) {
+        Jim_SetResultString(interp, "Invalid (infinite?) range specified", -1);
+        return JIM_ERR;
+    }
+    objPtr = Jim_NewListObj(interp, NULL, 0);
+    for (i = 0; i < len; i++)
+        ListAppendElement(objPtr, Jim_NewIntObj(interp, start + i * step));
+    Jim_SetResult(interp, objPtr);
+    return JIM_OK;
+}
+
+/* [rand] */
+static int Jim_RandCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    jim_wide min = 0, max = 0, len, maxMul;
+
+    if (argc < 1 || argc > 3) {
+        Jim_WrongNumArgs(interp, 1, argv, "?min? max");
+        return JIM_ERR;
+    }
+    if (argc == 1) {
+        max = JIM_WIDE_MAX;
+    } else if (argc == 2) {
+        if (Jim_GetWide(interp, argv[1], &max) != JIM_OK)
+            return JIM_ERR;
+    } else if (argc == 3) {
+        if (Jim_GetWide(interp, argv[1], &min) != JIM_OK ||
+            Jim_GetWide(interp, argv[2], &max) != JIM_OK)
+            return JIM_ERR;
+    }
+    len = max-min;
+    if (len < 0) {
+        Jim_SetResultString(interp, "Invalid arguments (max < min)", -1);
+        return JIM_ERR;
+    }
+    maxMul = JIM_WIDE_MAX - (len ? (JIM_WIDE_MAX%len) : 0);
+    while (1) {
+        jim_wide r;
+
+        JimRandomBytes(interp, &r, sizeof(jim_wide));
+        if (r < 0 || r >= maxMul) continue;
+        r = (len == 0) ? 0 : r%len;
+        Jim_SetResultInt(interp, min+r);
+        return JIM_OK;
+    }
+}
+
+static const struct {
+    const char *name;
+    Jim_CmdProc cmdProc;
+} Jim_CoreCommandsTable[] = {
+    {"set", Jim_SetCoreCommand},
+    {"unset", Jim_UnsetCoreCommand},
+    {"puts", Jim_PutsCoreCommand},
+    {"+", Jim_AddCoreCommand},
+    {"*", Jim_MulCoreCommand},
+    {"-", Jim_SubCoreCommand},
+    {"/", Jim_DivCoreCommand},
+    {"incr", Jim_IncrCoreCommand},
+    {"while", Jim_WhileCoreCommand},
+    {"loop", Jim_LoopCoreCommand},
+    {"for", Jim_ForCoreCommand},
+    {"foreach", Jim_ForeachCoreCommand},
+    {"lmap", Jim_LmapCoreCommand},
+    {"if", Jim_IfCoreCommand},
+    {"switch", Jim_SwitchCoreCommand},
+    {"list", Jim_ListCoreCommand},
+    {"lindex", Jim_LindexCoreCommand},
+    {"lset", Jim_LsetCoreCommand},
+    {"lsearch", Jim_LsearchCoreCommand},
+    {"llength", Jim_LlengthCoreCommand},
+    {"lappend", Jim_LappendCoreCommand},
+    {"linsert", Jim_LinsertCoreCommand},
+    {"lreplace", Jim_LreplaceCoreCommand},
+    {"lsort", Jim_LsortCoreCommand},
+    {"append", Jim_AppendCoreCommand},
+    {"debug", Jim_DebugCoreCommand},
+    {"eval", Jim_EvalCoreCommand},
+    {"uplevel", Jim_UplevelCoreCommand},
+    {"expr", Jim_ExprCoreCommand},
+    {"break", Jim_BreakCoreCommand},
+    {"continue", Jim_ContinueCoreCommand},
+    {"proc", Jim_ProcCoreCommand},
+    {"concat", Jim_ConcatCoreCommand},
+    {"return", Jim_ReturnCoreCommand},
+    {"upvar", Jim_UpvarCoreCommand},
+    {"global", Jim_GlobalCoreCommand},
+    {"string", Jim_StringCoreCommand},
+    {"time", Jim_TimeCoreCommand},
+    {"exit", Jim_ExitCoreCommand},
+    {"catch", Jim_CatchCoreCommand},
+#ifdef JIM_REFERENCES
+    {"ref", Jim_RefCoreCommand},
+    {"getref", Jim_GetrefCoreCommand},
+    {"setref", Jim_SetrefCoreCommand},
+    {"finalize", Jim_FinalizeCoreCommand},
+    {"collect", Jim_CollectCoreCommand},
+#endif
+    {"rename", Jim_RenameCoreCommand},
+    {"dict", Jim_DictCoreCommand},
+    {"subst", Jim_SubstCoreCommand},
+    {"info", Jim_InfoCoreCommand},
+    {"exists", Jim_ExistsCoreCommand},
+    {"split", Jim_SplitCoreCommand},
+    {"join", Jim_JoinCoreCommand},
+    {"format", Jim_FormatCoreCommand},
+    {"scan", Jim_ScanCoreCommand},
+    {"error", Jim_ErrorCoreCommand},
+    {"lrange", Jim_LrangeCoreCommand},
+    {"lrepeat", Jim_LrepeatCoreCommand},
+    {"env", Jim_EnvCoreCommand},
+    {"source", Jim_SourceCoreCommand},
+    {"lreverse", Jim_LreverseCoreCommand},
+    {"range", Jim_RangeCoreCommand},
+    {"rand", Jim_RandCoreCommand},
+    {"tailcall", Jim_TailcallCoreCommand},
+    {"local", Jim_LocalCoreCommand},
+    {"upcall", Jim_UpcallCoreCommand},
+    {NULL, NULL},
+};
+
+void Jim_RegisterCoreCommands(Jim_Interp *interp)
+{
+    int i = 0;
+
+    while (Jim_CoreCommandsTable[i].name != NULL) {
+        Jim_CreateCommand(interp,
+            Jim_CoreCommandsTable[i].name, Jim_CoreCommandsTable[i].cmdProc, NULL, NULL);
+        i++;
+    }
+}
+
+/* -----------------------------------------------------------------------------
+ * Interactive prompt
+ * ---------------------------------------------------------------------------*/
+void Jim_MakeErrorMessage(Jim_Interp *interp)
+{
+    Jim_Obj *argv[2];
+
+    argv[0] = Jim_NewStringObj(interp, "errorInfo", -1);
+    argv[1] = interp->result;
+
+    Jim_EvalObjVector(interp, 2, argv);
+}
+
+static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
+    const char *prefix, const char *const *tablePtr, const char *name)
+{
+    int count;
+    char **tablePtrSorted;
+    int i;
+
+    for (count = 0; tablePtr[count]; count++) {
+    }
+
+    if (name == NULL) {
+        name = "option";
+    }
+
+    Jim_SetResultFormatted(interp, "%s%s \"%s\": must be ", badtype, name, arg);
+    tablePtrSorted = Jim_Alloc(sizeof(char *) * count);
+    memcpy(tablePtrSorted, tablePtr, sizeof(char *) * count);
+    qsort(tablePtrSorted, count, sizeof(char *), qsortCompareStringPointers);
+    for (i = 0; i < count; i++) {
+        if (i + 1 == count && count > 1) {
+            Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1);
+        }
+        Jim_AppendStrings(interp, Jim_GetResult(interp), prefix, tablePtrSorted[i], NULL);
+        if (i + 1 != count) {
+            Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1);
+        }
+    }
+    Jim_Free(tablePtrSorted);
+}
+
+int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
+    const char *const *tablePtr, int *indexPtr, const char *name, int flags)
+{
+    const char *bad = "bad ";
+    const char *const *entryPtr = NULL;
+    int i;
+    int match = -1;
+    int arglen;
+    const char *arg = Jim_GetString(objPtr, &arglen);
+
+    *indexPtr = -1;
+
+    for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) {
+        if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) {
+            /* Found an exact match */
+            *indexPtr = i;
+            return JIM_OK;
+        }
+        if (flags & JIM_ENUM_ABBREV) {
+            /* Accept an unambiguous abbreviation.
+             * Note that '-' doesnt' consitute a valid abbreviation
+             */
+            if (strncmp(arg, *entryPtr, arglen) == 0) {
+                if (*arg == '-' && arglen == 1) {
+                    break;
+                }
+                if (match >= 0) {
+                    bad = "ambiguous ";
+                    goto ambiguous;
+                }
+                match = i;
+            }
+        }
+    }
+
+    /* If we had an unambiguous partial match */
+    if (match >= 0) {
+        *indexPtr = match;
+        return JIM_OK;
+    }
+
+  ambiguous:
+    if (flags & JIM_ERRMSG) {
+        JimSetFailedEnumResult(interp, arg, bad, "", tablePtr, name);
+    }
+    return JIM_ERR;
+}
+
+int Jim_FindByName(const char *name, const char * const array[], size_t len)
+{
+    int i;
+
+    for (i = 0; i < (int)len; i++) {
+        if (array[i] && strcmp(array[i], name) == 0) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+int Jim_IsDict(Jim_Obj *objPtr)
+{
+    return objPtr->typePtr == &dictObjType;
+}
+
+int Jim_IsList(Jim_Obj *objPtr)
+{
+    return objPtr->typePtr == &listObjType;
+}
+
+/**
+ * Very simple printf-like formatting, designed for error messages.
+ *
+ * The format may contain up to 5 '%s' or '%#s', corresponding to variable arguments.
+ * The resulting string is created and set as the result.
+ *
+ * Each '%s' should correspond to a regular string parameter.
+ * Each '%#s' should correspond to a (Jim_Obj *) parameter.
+ * Any other printf specifier is not allowed (but %% is allowed for the % character).
+ *
+ * e.g. Jim_SetResultFormatted(interp, "Bad option \"%#s\" in proc \"%#s\"", optionObjPtr, procNamePtr);
+ *
+ * Note: We take advantage of the fact that printf has the same behaviour for both %s and %#s
+ */
+void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...)
+{
+    /* Initial space needed */
+    int len = strlen(format);
+    int extra = 0;
+    int n = 0;
+    const char *params[5];
+    char *buf;
+    va_list args;
+    int i;
+
+    va_start(args, format);
+
+    for (i = 0; i < len && n < 5; i++) {
+        int l;
+
+        if (strncmp(format + i, "%s", 2) == 0) {
+            params[n] = va_arg(args, char *);
+
+            l = strlen(params[n]);
+        }
+        else if (strncmp(format + i, "%#s", 3) == 0) {
+            Jim_Obj *objPtr = va_arg(args, Jim_Obj *);
+
+            params[n] = Jim_GetString(objPtr, &l);
+        }
+        else {
+            if (format[i] == '%') {
+                i++;
+            }
+            continue;
+        }
+        n++;
+        extra += l;
+    }
+
+    len += extra;
+    buf = Jim_Alloc(len + 1);
+    len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]);
+
+    Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
+}
+
+/* stubs */
+#ifndef jim_ext_package
+int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
+{
+    return JIM_OK;
+}
+#endif
+#ifndef jim_ext_aio
+FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *fhObj)
+{
+    Jim_SetResultString(interp, "aio not enabled", -1);
+    return NULL;
+}
+#endif
+
+
+/*
+ * Local Variables: ***
+ * c-basic-offset: 4 ***
+ * tab-width: 4 ***
+ * End: ***
+ */
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim.h b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim.h
new file mode 100755
index 0000000..fdc9db9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jim.h
@@ -0,0 +1,917 @@
+/* Jim - A small embeddable Tcl interpreter
+ *
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
+ * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
+ * Copyright 2008 oharboe - �yvind Harboe - oyvind.harboe@zylin.com
+ * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
+ * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
+ * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ *
+ *--- Inline Header File Documentation ---
+ *    [By Duane Ellis, openocd@duaneellis.com, 8/18/8]
+ *
+ * Belief is "Jim" would greatly benifit if Jim Internals where
+ * documented in some way - form whatever, and perhaps - the package:
+ * 'doxygen' is the correct approach to do that.
+ *
+ *   Details, see: http://www.stack.nl/~dimitri/doxygen/
+ *
+ * To that end please follow these guide lines:
+ *
+ *    (A) Document the PUBLIC api in the .H file.
+ *
+ *    (B) Document JIM Internals, in the .C file.
+ *
+ *    (C) Remember JIM is embedded in other packages, to that end do
+ *    not assume that your way of documenting is the right way, Jim's
+ *    public documentation should be agnostic, such that it is some
+ *    what agreeable with the "package" that is embedding JIM inside
+ *    of it's own doxygen documentation.
+ *
+ *    (D) Use minimal Doxygen tags.
+ *
+ * This will be an "ongoing work in progress" for some time.
+ **/
+
+#ifndef __JIM__H
+#define __JIM__H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <time.h>
+#include <limits.h>
+#include <stdio.h>  /* for the FILE typedef definition */
+#include <stdlib.h> /* In order to export the Jim_Free() macro */
+#include <stdarg.h> /* In order to get type va_list */
+
+/* -----------------------------------------------------------------------------
+ * System configuration
+ * autoconf (configure) will set these
+ * ---------------------------------------------------------------------------*/
+#include <jim-win32compat.h>
+
+#ifndef HAVE_NO_AUTOCONF
+#include <jim-config.h>
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Compiler specific fixes.
+ * ---------------------------------------------------------------------------*/
+
+/* Long Long type and related issues */
+#ifndef jim_wide
+#  ifdef HAVE_LONG_LONG
+#    define jim_wide long long
+#    ifndef LLONG_MAX
+#      define LLONG_MAX    9223372036854775807LL
+#    endif
+#    ifndef LLONG_MIN
+#      define LLONG_MIN    (-LLONG_MAX - 1LL)
+#    endif
+#    define JIM_WIDE_MIN LLONG_MIN
+#    define JIM_WIDE_MAX LLONG_MAX
+#  else
+#    define jim_wide long
+#    define JIM_WIDE_MIN LONG_MIN
+#    define JIM_WIDE_MAX LONG_MAX
+#  endif
+
+/* -----------------------------------------------------------------------------
+ * LIBC specific fixes
+ * ---------------------------------------------------------------------------*/
+
+#  ifdef HAVE_LONG_LONG
+#    define JIM_WIDE_MODIFIER "lld"
+#  else
+#    define JIM_WIDE_MODIFIER "ld"
+#    define strtoull strtoul
+#  endif
+#endif
+
+#define UCHAR(c) ((unsigned char)(c))
+
+/* -----------------------------------------------------------------------------
+ * Exported defines
+ * ---------------------------------------------------------------------------*/
+
+/* Jim version numbering: every version of jim is marked with a
+ * successive integer number. This is version 0. The first
+ * stable version will be 1, then 2, 3, and so on. */
+#define JIM_VERSION 72
+
+#define JIM_OK 0
+#define JIM_ERR 1
+#define JIM_RETURN 2
+#define JIM_BREAK 3
+#define JIM_CONTINUE 4
+#define JIM_SIGNAL 5
+#define JIM_EXIT 6
+/* The following are internal codes and should never been seen/used */
+#define JIM_EVAL 7
+
+#define JIM_MAX_NESTING_DEPTH 1000 /* default max nesting depth */
+
+/* Some function get an integer argument with flags to change
+ * the behaviour. */
+#define JIM_NONE 0    /* no flags set */
+#define JIM_ERRMSG 1    /* set an error message in the interpreter. */
+
+#define JIM_UNSHARED 4 /* Flag to Jim_GetVariable() */
+
+/* Flags for Jim_SubstObj() */
+#define JIM_SUBST_NOVAR 1 /* don't perform variables substitutions */
+#define JIM_SUBST_NOCMD 2 /* don't perform command substitutions */
+#define JIM_SUBST_NOESC 4 /* don't perform escapes substitutions */
+#define JIM_SUBST_FLAG 128 /* flag to indicate that this is a real substition object */
+
+/* Unused arguments generate annoying warnings... */
+#define JIM_NOTUSED(V) ((void) V)
+
+/* Flags for Jim_GetEnum() */
+#define JIM_ENUM_ABBREV 2    /* Allow unambiguous abbreviation */
+
+/* Flags used by API calls getting a 'nocase' argument. */
+#define JIM_CASESENS    0   /* case sensitive */
+#define JIM_NOCASE      1   /* no case */
+
+/* Filesystem related */
+#define JIM_PATH_LEN 1024
+
+/* Newline, some embedded system may need -DJIM_CRLF */
+#ifdef JIM_CRLF
+#define JIM_NL "\r\n"
+#else
+#define JIM_NL "\n"
+#endif
+
+#define JIM_LIBPATH "auto_path"
+#define JIM_INTERACTIVE "tcl_interactive"
+
+/* -----------------------------------------------------------------------------
+ * Stack
+ * ---------------------------------------------------------------------------*/
+
+typedef struct Jim_Stack {
+    int len;
+    int maxlen;
+    void **vector;
+} Jim_Stack;
+
+/* -----------------------------------------------------------------------------
+ * Hash table
+ * ---------------------------------------------------------------------------*/
+
+typedef struct Jim_HashEntry {
+    const void *key;
+    union {
+        void *val;
+        int intval;
+    } u;
+    struct Jim_HashEntry *next;
+} Jim_HashEntry;
+
+typedef struct Jim_HashTableType {
+    unsigned int (*hashFunction)(const void *key);
+    const void *(*keyDup)(void *privdata, const void *key);
+    void *(*valDup)(void *privdata, const void *obj);
+    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
+    void (*keyDestructor)(void *privdata, const void *key);
+    void (*valDestructor)(void *privdata, void *obj);
+} Jim_HashTableType;
+
+typedef struct Jim_HashTable {
+    Jim_HashEntry **table;
+    const Jim_HashTableType *type;
+    unsigned int size;
+    unsigned int sizemask;
+    unsigned int used;
+    unsigned int collisions;
+    void *privdata;
+} Jim_HashTable;
+
+typedef struct Jim_HashTableIterator {
+    Jim_HashTable *ht;
+    int index;
+    Jim_HashEntry *entry, *nextEntry;
+} Jim_HashTableIterator;
+
+/* This is the initial size of every hash table */
+#define JIM_HT_INITIAL_SIZE     16
+
+/* ------------------------------- Macros ------------------------------------*/
+#define Jim_FreeEntryVal(ht, entry) \
+    if ((ht)->type->valDestructor) \
+        (ht)->type->valDestructor((ht)->privdata, (entry)->u.val)
+
+#define Jim_SetHashVal(ht, entry, _val_) do { \
+    if ((ht)->type->valDup) \
+        entry->u.val = (ht)->type->valDup((ht)->privdata, _val_); \
+    else \
+        entry->u.val = (_val_); \
+} while(0)
+
+#define Jim_FreeEntryKey(ht, entry) \
+    if ((ht)->type->keyDestructor) \
+        (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
+
+#define Jim_SetHashKey(ht, entry, _key_) do { \
+    if ((ht)->type->keyDup) \
+        entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \
+    else \
+        entry->key = (_key_); \
+} while(0)
+
+#define Jim_CompareHashKeys(ht, key1, key2) \
+    (((ht)->type->keyCompare) ? \
+        (ht)->type->keyCompare((ht)->privdata, key1, key2) : \
+        (key1) == (key2))
+
+#define Jim_HashKey(ht, key) (ht)->type->hashFunction(key)
+
+#define Jim_GetHashEntryKey(he) ((he)->key)
+#define Jim_GetHashEntryVal(he) ((he)->val)
+#define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
+#define Jim_GetHashTableSize(ht) ((ht)->size)
+#define Jim_GetHashTableUsed(ht) ((ht)->used)
+
+/* -----------------------------------------------------------------------------
+ * Jim_Obj structure
+ * ---------------------------------------------------------------------------*/
+
+/* -----------------------------------------------------------------------------
+ * Jim object. This is mostly the same as Tcl_Obj itself,
+ * with the addition of the 'prev' and 'next' pointers.
+ * In Jim all the objects are stored into a linked list for GC purposes,
+ * so that it's possible to access every object living in a given interpreter
+ * sequentially. When an object is freed, it's moved into a different
+ * linked list, used as object pool.
+ *
+ * The refcount of a freed object is always -1.
+ * ---------------------------------------------------------------------------*/
+typedef struct Jim_Obj {
+    int refCount; /* reference count */
+    char *bytes; /* string representation buffer. NULL = no string repr. */
+    int length; /* number of bytes in 'bytes', not including the numterm. */
+    const struct Jim_ObjType *typePtr; /* object type. */
+    /* Internal representation union */
+    union {
+        /* integer number type */
+        jim_wide wideValue;
+        /* hashed object type value */
+        int hashValue;
+        /* index type */
+        int indexValue;
+        /* return code type */
+        int returnCode;
+        /* double number type */
+        double doubleValue;
+        /* Generic pointer */
+        void *ptr;
+        /* Generic two pointers value */
+        struct {
+            void *ptr1;
+            void *ptr2;
+        } twoPtrValue;
+        /* Variable object */
+        struct {
+            unsigned jim_wide callFrameId;
+            struct Jim_Var *varPtr;
+        } varValue;
+        /* Command object */
+        struct {
+            unsigned jim_wide procEpoch;
+            struct Jim_Cmd *cmdPtr;
+        } cmdValue;
+        /* List object */
+        struct {
+            struct Jim_Obj **ele;    /* Elements vector */
+            int len;        /* Length */
+            int maxLen;        /* Allocated 'ele' length */
+        } listValue;
+        /* String type */
+        struct {
+            int maxLength;
+            int charLength;     /* utf-8 char length. -1 if unknown */
+        } strValue;
+        /* Reference type */
+        struct {
+            jim_wide id;
+            struct Jim_Reference *refPtr;
+        } refValue;
+        /* Source type */
+        struct {
+            struct Jim_Obj *fileNameObj;
+            int lineNumber;
+        } sourceValue;
+        /* Dict substitution type */
+        struct {
+            struct Jim_Obj *varNameObjPtr;
+            struct Jim_Obj *indexObjPtr;
+        } dictSubstValue;
+        /* tagged binary type */
+        struct {
+            unsigned char *data;
+            size_t         len;
+        } binaryValue;
+        /* Regular expression pattern */
+        struct {
+            unsigned flags;
+            void *compre;       /* really an allocated (regex_t *) */
+        } regexpValue;
+        struct {
+            int line;
+            int argc;
+        } scriptLineValue;
+    } internalRep;
+    /* This are 8 or 16 bytes more for every object
+     * but this is required for efficient garbage collection
+     * of Jim references. */
+    struct Jim_Obj *prevObjPtr; /* pointer to the prev object. */
+    struct Jim_Obj *nextObjPtr; /* pointer to the next object. */
+} Jim_Obj;
+
+/* Jim_Obj related macros */
+#define Jim_IncrRefCount(objPtr) \
+    ++(objPtr)->refCount
+#define Jim_DecrRefCount(interp, objPtr) \
+    if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr)
+#define Jim_IsShared(objPtr) \
+    ((objPtr)->refCount > 1)
+
+/* This macro is used when we allocate a new object using
+ * Jim_New...Obj(), but for some error we need to destroy it.
+ * Instead to use Jim_IncrRefCount() + Jim_DecrRefCount() we
+ * can just call Jim_FreeNewObj. To call Jim_Free directly
+ * seems too raw, the object handling may change and we want
+ * that Jim_FreeNewObj() can be called only against objects
+ * that are belived to have refcount == 0. */
+#define Jim_FreeNewObj Jim_FreeObj
+
+/* Free the internal representation of the object. */
+#define Jim_FreeIntRep(i,o) \
+    if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \
+        (o)->typePtr->freeIntRepProc(i, o)
+
+/* Get the internal representation pointer */
+#define Jim_GetIntRepPtr(o) (o)->internalRep.ptr
+
+/* Set the internal representation pointer */
+#define Jim_SetIntRepPtr(o, p) \
+    (o)->internalRep.ptr = (p)
+
+/* The object type structure.
+ * There are four methods.
+ *
+ * - FreeIntRep is used to free the internal representation of the object.
+ *   Can be NULL if there is nothing to free.
+ * - DupIntRep is used to duplicate the internal representation of the object.
+ *   If NULL, when an object is duplicated, the internalRep union is
+ *   directly copied from an object to another.
+ *   Note that it's up to the caller to free the old internal repr of the
+ *   object before to call the Dup method.
+ * - UpdateString is used to create the string from the internal repr.
+ * - setFromAny is used to convert the current object into one of this type.
+ */
+
+struct Jim_Interp;
+
+typedef void (Jim_FreeInternalRepProc)(struct Jim_Interp *interp,
+        struct Jim_Obj *objPtr);
+typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp,
+        struct Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr);
+
+typedef struct Jim_ObjType {
+    const char *name; /* The name of the type. */
+    Jim_FreeInternalRepProc *freeIntRepProc;
+    Jim_DupInternalRepProc *dupIntRepProc;
+    Jim_UpdateStringProc *updateStringProc;
+    int flags;
+} Jim_ObjType;
+
+/* Jim_ObjType flags */
+#define JIM_TYPE_NONE 0        /* No flags */
+#define JIM_TYPE_REFERENCES 1    /* The object may contain referneces. */
+
+/* Starting from 1 << 20 flags are reserved for private uses of
+ * different calls. This way the same 'flags' argument may be used
+ * to pass both global flags and private flags. */
+#define JIM_PRIV_FLAG_SHIFT 20
+
+/* -----------------------------------------------------------------------------
+ * Call frame, vars, commands structures
+ * ---------------------------------------------------------------------------*/
+
+/* Call frame */
+typedef struct Jim_CallFrame {
+    unsigned jim_wide id; /* Call Frame ID. Used for caching. */
+    int level; /* Level of this call frame. 0 = global */
+    struct Jim_HashTable vars; /* Where local vars are stored */
+    struct Jim_HashTable *staticVars; /* pointer to procedure static vars */
+    struct Jim_CallFrame *parentCallFrame;
+    Jim_Obj *const *argv; /* object vector of the current procedure call. */
+    int argc; /* number of args of the current procedure call. */
+    Jim_Obj *procArgsObjPtr; /* arglist object of the running procedure */
+    Jim_Obj *procBodyObjPtr; /* body object of the running procedure */
+    struct Jim_CallFrame *nextFramePtr;
+    Jim_Obj *fileNameObj;       /* file and line of caller of this proc (if available) */
+    int line;
+} Jim_CallFrame;
+
+/* The var structure. It just holds the pointer of the referenced
+ * object. If linkFramePtr is not NULL the variable is a link
+ * to a variable of name store on objPtr living on the given callframe
+ * (this happens when the [global] or [upvar] command is used).
+ * The interp in order to always know how to free the Jim_Obj associated
+ * with a given variable because In Jim objects memory managment is
+ * bound to interpreters. */
+typedef struct Jim_Var {
+    Jim_Obj *objPtr;
+    struct Jim_CallFrame *linkFramePtr;
+} Jim_Var;
+
+/* The cmd structure. */
+typedef int (*Jim_CmdProc)(struct Jim_Interp *interp, int argc,
+    Jim_Obj *const *argv);
+typedef void (*Jim_DelCmdProc)(struct Jim_Interp *interp, void *privData);
+
+
+
+/* A command is implemented in C if funcPtr is != NULL, otherwise
+ * it's a Tcl procedure with the arglist and body represented by the
+ * two objects referenced by arglistObjPtr and bodyoObjPtr. */
+typedef struct Jim_Cmd {
+    int inUse;           /* Reference count */
+    int isproc;          /* Is this a procedure? */
+    union {
+        struct {
+            /* native (C) command */
+            Jim_CmdProc cmdProc; /* The command implementation */
+            Jim_DelCmdProc delProc; /* Called when the command is deleted if != NULL */
+            void *privData; /* command-private data available via Jim_CmdPrivData() */
+        } native;
+        struct {
+            /* Tcl procedure */
+            Jim_Obj *argListObjPtr;
+            Jim_Obj *bodyObjPtr;
+            Jim_HashTable *staticVars;  /* Static vars hash table. NULL if no statics. */
+            struct Jim_Cmd *prevCmd;    /* Previous command defn if proc created 'local' */
+            int argListLen;             /* Length of argListObjPtr */
+            int reqArity;               /* Number of required parameters */
+            int optArity;               /* Number of optional parameters */
+            int argsPos;                /* Position of 'args', if specified, or -1 */
+            int upcall;                 /* True if proc is currently in upcall */
+            struct Jim_ProcArg {
+                Jim_Obj *nameObjPtr;    /* Name of this arg */
+                Jim_Obj *defaultObjPtr; /* Default value, (or rename for $args) */
+            } *arglist;
+        } proc;
+    } u;
+} Jim_Cmd;
+
+/* Pseudo Random Number Generator State structure */
+typedef struct Jim_PrngState {
+    unsigned char sbox[256];
+    unsigned int i, j;
+} Jim_PrngState;
+
+/* -----------------------------------------------------------------------------
+ * Jim interpreter structure.
+ * Fields similar to the real Tcl interpreter structure have the same names.
+ * ---------------------------------------------------------------------------*/
+typedef struct Jim_Interp {
+    Jim_Obj *result; /* object returned by the last command called. */
+    int errorLine; /* Error line where an error occurred. */
+    Jim_Obj *errorFileNameObj; /* Error file where an error occurred. */
+    int addStackTrace; /* > 0 If a level should be added to the stack trace */
+    int maxNestingDepth; /* Used for infinite loop detection. */
+    int returnCode; /* Completion code to return on JIM_RETURN. */
+    int returnLevel; /* Current level of 'return -level' */
+    int exitCode; /* Code to return to the OS on JIM_EXIT. */
+    long id; /* Hold unique id for various purposes */
+    int signal_level; /* A nesting level of catch -signal */
+    jim_wide sigmask;  /* Bit mask of caught signals, or 0 if none */
+    int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask); /* Set a result for the sigmask */
+    Jim_CallFrame *framePtr; /* Pointer to the current call frame */
+    Jim_CallFrame *topFramePtr; /* toplevel/global frame pointer. */
+    struct Jim_HashTable commands; /* Commands hash table */
+    unsigned jim_wide procEpoch; /* Incremented every time the result
+                of procedures names lookup caching
+                may no longer be valid. */
+    unsigned jim_wide callFrameEpoch; /* Incremented every time a new
+                callframe is created. This id is used for the
+                'ID' field contained in the Jim_CallFrame
+                structure. */
+    int local; /* If 'local' is in effect, newly defined procs keep a reference to the old defn */
+    Jim_Obj *liveList; /* Linked list of all the live objects. */
+    Jim_Obj *freeList; /* Linked list of all the unused objects. */
+    Jim_Obj *currentScriptObj; /* Script currently in execution. */
+    Jim_Obj *emptyObj; /* Shared empty string object. */
+    Jim_Obj *trueObj; /* Shared true int object. */
+    Jim_Obj *falseObj; /* Shared false int object. */
+    unsigned jim_wide referenceNextId; /* Next id for reference. */
+    struct Jim_HashTable references; /* References hash table. */
+    jim_wide lastCollectId; /* reference max Id of the last GC
+                execution. It's set to -1 while the collection
+                is running as sentinel to avoid to recursive
+                calls via the [collect] command inside
+                finalizers. */
+    time_t lastCollectTime; /* unix time of the last GC execution */
+    Jim_Obj *stackTrace; /* Stack trace object. */
+    Jim_Obj *errorProc; /* Name of last procedure which returned an error */
+    Jim_Obj *unknown; /* Unknown command cache */
+    int unknown_called; /* The unknown command has been invoked */
+    int errorFlag; /* Set if an error occurred during execution. */
+    void *cmdPrivData; /* Used to pass the private data pointer to
+                  a command. It is set to what the user specified
+                  via Jim_CreateCommand(). */
+
+    struct Jim_CallFrame *freeFramesList; /* list of CallFrame structures. */
+    struct Jim_HashTable assocData; /* per-interp storage for use by packages */
+    Jim_PrngState *prngState; /* per interpreter Random Number Gen. state. */
+    struct Jim_HashTable packages; /* Provided packages hash table */
+    Jim_Stack *localProcs; /* procs to be destroyed on end of evaluation */
+    Jim_Stack *loadHandles; /* handles of loaded modules [load] */
+} Jim_Interp;
+
+/* Currently provided as macro that performs the increment.
+ * At some point may be a real function doing more work.
+ * The proc epoch is used in order to know when a command lookup
+ * cached can no longer considered valid. */
+#define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++
+#define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
+#define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
+/* Note: Using trueObj and falseObj here makes some things slower...*/
+#define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b)
+#define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj)
+#define Jim_GetResult(i) ((i)->result)
+#define Jim_CmdPrivData(i) ((i)->cmdPrivData)
+#define Jim_String(o) Jim_GetString((o), NULL)
+
+/* Note that 'o' is expanded only one time inside this macro,
+ * so it's safe to use side effects. */
+#define Jim_SetResult(i,o) do {     \
+    Jim_Obj *_resultObjPtr_ = (o);    \
+    Jim_IncrRefCount(_resultObjPtr_); \
+    Jim_DecrRefCount(i,(i)->result);  \
+    (i)->result = _resultObjPtr_;     \
+} while(0)
+
+/* Use this for filehandles, etc. which need a unique id */
+#define Jim_GetId(i) (++(i)->id)
+
+/* Reference structure. The interpreter pointer is held within privdata member in HashTable */
+#define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference
+                                  string representation must be fixed length. */
+typedef struct Jim_Reference {
+    Jim_Obj *objPtr;
+    Jim_Obj *finalizerCmdNamePtr;
+    char tag[JIM_REFERENCE_TAGLEN+1];
+} Jim_Reference;
+
+/* -----------------------------------------------------------------------------
+ * Exported API prototypes.
+ * ---------------------------------------------------------------------------*/
+
+/* Macros that are common for extensions and core. */
+#define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
+
+/* The core includes real prototypes, extensions instead
+ * include a global function pointer for every function exported.
+ * Once the extension calls Jim_InitExtension(), the global
+ * functon pointers are set to the value of the STUB table
+ * contained in the Jim_Interp structure.
+ *
+ * This makes Jim able to load extensions even if it is statically
+ * linked itself, and to load extensions compiled with different
+ * versions of Jim (as long as the API is still compatible.) */
+
+/* Macros are common for core and extensions */
+#define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
+
+#define JIM_EXPORT
+
+/* Memory allocation */
+JIM_EXPORT void *Jim_Alloc (int size);
+JIM_EXPORT void *Jim_Realloc(void *ptr, int size);
+JIM_EXPORT void Jim_Free (void *ptr);
+JIM_EXPORT char * Jim_StrDup (const char *s);
+JIM_EXPORT char *Jim_StrDupLen(const char *s, int l);
+
+/* environment */
+JIM_EXPORT char **Jim_GetEnviron(void);
+JIM_EXPORT void Jim_SetEnviron(char **env);
+
+/* evaluation */
+JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);
+/* in C code, you can do this and get better error messages */
+/*   Jim_EvalSource( interp, __FILE__, __LINE__ , "some tcl commands"); */
+JIM_EXPORT int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script);
+/* Backwards compatibility */
+#define Jim_Eval_Named(I, S, F, L) Jim_EvalSource((I), (F), (L), (S))
+
+JIM_EXPORT int Jim_EvalGlobal(Jim_Interp *interp, const char *script);
+JIM_EXPORT int Jim_EvalFile(Jim_Interp *interp, const char *filename);
+JIM_EXPORT int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename);
+JIM_EXPORT int Jim_EvalObj (Jim_Interp *interp, Jim_Obj *scriptObjPtr);
+JIM_EXPORT int Jim_EvalObjVector (Jim_Interp *interp, int objc,
+        Jim_Obj *const *objv);
+JIM_EXPORT int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix,
+        int objc, Jim_Obj *const *objv);
+#define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
+JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr,
+        Jim_Obj **resObjPtrPtr, int flags);
+
+/* stack */
+JIM_EXPORT void Jim_InitStack(Jim_Stack *stack);
+JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack);
+JIM_EXPORT int Jim_StackLen(Jim_Stack *stack);
+JIM_EXPORT void Jim_StackPush(Jim_Stack *stack, void *element);
+JIM_EXPORT void * Jim_StackPop(Jim_Stack *stack);
+JIM_EXPORT void * Jim_StackPeek(Jim_Stack *stack);
+JIM_EXPORT void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr));
+
+/* hash table */
+JIM_EXPORT int Jim_InitHashTable (Jim_HashTable *ht,
+        const Jim_HashTableType *type, void *privdata);
+JIM_EXPORT int Jim_ExpandHashTable (Jim_HashTable *ht,
+        unsigned int size);
+JIM_EXPORT int Jim_AddHashEntry (Jim_HashTable *ht, const void *key,
+        void *val);
+JIM_EXPORT int Jim_ReplaceHashEntry (Jim_HashTable *ht,
+        const void *key, void *val);
+JIM_EXPORT int Jim_DeleteHashEntry (Jim_HashTable *ht,
+        const void *key);
+JIM_EXPORT int Jim_FreeHashTable (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashEntry * Jim_FindHashEntry (Jim_HashTable *ht,
+        const void *key);
+JIM_EXPORT int Jim_ResizeHashTable (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashTableIterator *Jim_GetHashTableIterator
+        (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashEntry * Jim_NextHashEntry
+        (Jim_HashTableIterator *iter);
+
+/* objects */
+JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp);
+JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr);
+JIM_EXPORT void Jim_InitStringRep (Jim_Obj *objPtr, const char *bytes,
+        int length);
+JIM_EXPORT Jim_Obj * Jim_DuplicateObj (Jim_Interp *interp,
+        Jim_Obj *objPtr);
+JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr,
+        int *lenPtr);
+JIM_EXPORT int Jim_Length(Jim_Obj *objPtr);
+
+/* string object */
+JIM_EXPORT Jim_Obj * Jim_NewStringObj (Jim_Interp *interp,
+        const char *s, int len);
+JIM_EXPORT Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp,
+        const char *s, int charlen);
+JIM_EXPORT Jim_Obj * Jim_NewStringObjNoAlloc (Jim_Interp *interp,
+        char *s, int len);
+JIM_EXPORT void Jim_AppendString (Jim_Interp *interp, Jim_Obj *objPtr,
+        const char *str, int len);
+JIM_EXPORT void Jim_AppendObj (Jim_Interp *interp, Jim_Obj *objPtr,
+        Jim_Obj *appendObjPtr);
+JIM_EXPORT void Jim_AppendStrings (Jim_Interp *interp,
+        Jim_Obj *objPtr, ...);
+JIM_EXPORT int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr);
+JIM_EXPORT int Jim_StringMatchObj (Jim_Interp *interp, Jim_Obj *patternObjPtr,
+        Jim_Obj *objPtr, int nocase);
+JIM_EXPORT Jim_Obj * Jim_StringRangeObj (Jim_Interp *interp,
+        Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr,
+        Jim_Obj *lastObjPtr);
+JIM_EXPORT Jim_Obj * Jim_FormatString (Jim_Interp *interp,
+        Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv);
+JIM_EXPORT Jim_Obj * Jim_ScanString (Jim_Interp *interp, Jim_Obj *strObjPtr,
+        Jim_Obj *fmtObjPtr, int flags);
+JIM_EXPORT int Jim_CompareStringImmediate (Jim_Interp *interp,
+        Jim_Obj *objPtr, const char *str);
+JIM_EXPORT int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr,
+        Jim_Obj *secondObjPtr, int nocase);
+JIM_EXPORT int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr);
+
+/* reference object */
+JIM_EXPORT Jim_Obj * Jim_NewReference (Jim_Interp *interp,
+        Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr);
+JIM_EXPORT Jim_Reference * Jim_GetReference (Jim_Interp *interp,
+        Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr);
+JIM_EXPORT int Jim_GetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr);
+
+/* interpreter */
+JIM_EXPORT Jim_Interp * Jim_CreateInterp (void);
+JIM_EXPORT void Jim_FreeInterp (Jim_Interp *i);
+JIM_EXPORT int Jim_GetExitCode (Jim_Interp *interp);
+JIM_EXPORT const char *Jim_ReturnCode(int code);
+JIM_EXPORT void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...);
+
+/* commands */
+JIM_EXPORT void Jim_RegisterCoreCommands (Jim_Interp *interp);
+JIM_EXPORT int Jim_CreateCommand (Jim_Interp *interp,
+        const char *cmdName, Jim_CmdProc cmdProc, void *privData,
+         Jim_DelCmdProc delProc);
+JIM_EXPORT int Jim_DeleteCommand (Jim_Interp *interp,
+        const char *cmdName);
+JIM_EXPORT int Jim_RenameCommand (Jim_Interp *interp,
+        const char *oldName, const char *newName);
+JIM_EXPORT Jim_Cmd * Jim_GetCommand (Jim_Interp *interp,
+        Jim_Obj *objPtr, int flags);
+JIM_EXPORT int Jim_SetVariable (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr);
+JIM_EXPORT int Jim_SetVariableStr (Jim_Interp *interp,
+        const char *name, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetGlobalVariableStr (Jim_Interp *interp,
+        const char *name, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetVariableStrWithStr (Jim_Interp *interp,
+        const char *name, const char *val);
+JIM_EXPORT int Jim_SetVariableLink (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr,
+        Jim_CallFrame *targetCallFrame);
+JIM_EXPORT Jim_Obj * Jim_GetVariable (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetGlobalVariable (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetVariableStr (Jim_Interp *interp,
+        const char *name, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetGlobalVariableStr (Jim_Interp *interp,
+        const char *name, int flags);
+JIM_EXPORT int Jim_UnsetVariable (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, int flags);
+
+/* call frame */
+JIM_EXPORT Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp,
+        Jim_Obj *levelObjPtr);
+
+/* garbage collection */
+JIM_EXPORT int Jim_Collect (Jim_Interp *interp);
+JIM_EXPORT void Jim_CollectIfNeeded (Jim_Interp *interp);
+
+/* index object */
+JIM_EXPORT int Jim_GetIndex (Jim_Interp *interp, Jim_Obj *objPtr,
+        int *indexPtr);
+
+/* list object */
+JIM_EXPORT Jim_Obj * Jim_NewListObj (Jim_Interp *interp,
+        Jim_Obj *const *elements, int len);
+JIM_EXPORT void Jim_ListInsertElements (Jim_Interp *interp,
+        Jim_Obj *listPtr, int listindex, int objc, Jim_Obj *const *objVec);
+JIM_EXPORT void Jim_ListAppendElement (Jim_Interp *interp,
+        Jim_Obj *listPtr, Jim_Obj *objPtr);
+JIM_EXPORT void Jim_ListAppendList (Jim_Interp *interp,
+        Jim_Obj *listPtr, Jim_Obj *appendListPtr);
+JIM_EXPORT int Jim_ListLength (Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_ListIndex (Jim_Interp *interp, Jim_Obj *listPrt,
+        int listindex, Jim_Obj **objPtrPtr, int seterr);
+JIM_EXPORT int Jim_SetListIndex (Jim_Interp *interp,
+        Jim_Obj *varNamePtr, Jim_Obj *const *indexv, int indexc,
+        Jim_Obj *newObjPtr);
+JIM_EXPORT Jim_Obj * Jim_ConcatObj (Jim_Interp *interp, int objc,
+        Jim_Obj *const *objv);
+
+/* dict object */
+JIM_EXPORT Jim_Obj * Jim_NewDictObj (Jim_Interp *interp,
+        Jim_Obj *const *elements, int len);
+JIM_EXPORT int Jim_DictKey (Jim_Interp *interp, Jim_Obj *dictPtr,
+        Jim_Obj *keyPtr, Jim_Obj **objPtrPtr, int flags);
+JIM_EXPORT int Jim_DictKeysVector (Jim_Interp *interp,
+        Jim_Obj *dictPtr, Jim_Obj *const *keyv, int keyc,
+        Jim_Obj **objPtrPtr, int flags);
+JIM_EXPORT int Jim_SetDictKeysVector (Jim_Interp *interp,
+        Jim_Obj *varNamePtr, Jim_Obj *const *keyv, int keyc,
+        Jim_Obj *newObjPtr, int flags);
+JIM_EXPORT int Jim_DictPairs(Jim_Interp *interp,
+        Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len);
+JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
+        Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr);
+JIM_EXPORT int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj);
+JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr);
+
+/* return code object */
+JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr,
+        int *intPtr);
+
+/* expression object */
+JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp,
+        Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr);
+JIM_EXPORT int Jim_GetBoolFromExpr (Jim_Interp *interp,
+        Jim_Obj *exprObjPtr, int *boolPtr);
+
+/* integer object */
+JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr,
+        jim_wide *widePtr);
+JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr,
+        long *longPtr);
+#define Jim_NewWideObj  Jim_NewIntObj
+JIM_EXPORT Jim_Obj * Jim_NewIntObj (Jim_Interp *interp,
+        jim_wide wideValue);
+
+/* double object */
+JIM_EXPORT int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
+        double *doublePtr);
+JIM_EXPORT void Jim_SetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
+        double doubleValue);
+JIM_EXPORT Jim_Obj * Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue);
+
+/* shared strings */
+JIM_EXPORT const char * Jim_GetSharedString (Jim_Interp *interp,
+        const char *str);
+JIM_EXPORT void Jim_ReleaseSharedString (Jim_Interp *interp,
+        const char *str);
+
+/* commands utilities */
+JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc,
+        Jim_Obj *const *argv, const char *msg);
+JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr,
+        const char * const *tablePtr, int *indexPtr, const char *name, int flags);
+JIM_EXPORT int Jim_ScriptIsComplete (const char *s, int len,
+        char *stateCharPtr);
+/**
+ * Find a matching name in the array of the given length.
+ *
+ * NULL entries are ignored.
+ *
+ * Returns the matching index if found, or -1 if not.
+ */
+JIM_EXPORT int Jim_FindByName(const char *name, const char * const array[], size_t len);
+
+/* package utilities */
+typedef void (Jim_InterpDeleteProc)(Jim_Interp *interp, void *data);
+JIM_EXPORT void * Jim_GetAssocData(Jim_Interp *interp, const char *key);
+JIM_EXPORT int Jim_SetAssocData(Jim_Interp *interp, const char *key,
+        Jim_InterpDeleteProc *delProc, void *data);
+JIM_EXPORT int Jim_DeleteAssocData(Jim_Interp *interp, const char *key);
+
+/* Packages C API */
+/* jim-package.c */
+JIM_EXPORT int Jim_PackageProvide (Jim_Interp *interp,
+        const char *name, const char *ver, int flags);
+JIM_EXPORT int Jim_PackageRequire (Jim_Interp *interp,
+        const char *name, int flags);
+
+/* error messages */
+JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp);
+
+/* interactive mode */
+JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp);
+
+/* Misc */
+JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
+JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base);
+
+/* jim-load.c */
+JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName);
+JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp);
+
+/* jim-aio.c */
+JIM_EXPORT FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command);
+
+
+/* type inspection - avoid where possible */
+JIM_EXPORT int Jim_IsDict(Jim_Obj *objPtr);
+JIM_EXPORT int Jim_IsList(Jim_Obj *objPtr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __JIM__H */
+
+/*
+ * Local Variables: ***
+ * c-basic-offset: 4 ***
+ * tab-width: 4 ***
+ * End: ***
+ */
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jimautoconf.h.in b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jimautoconf.h.in
new file mode 100755
index 0000000..f4eb0e5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jimautoconf.h.in
@@ -0,0 +1,145 @@
+/* jimautoconf.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the `backtrace' function. */
+#undef HAVE_BACKTRACE
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Have the dlopen function */
+#undef HAVE_DLOPEN
+
+/* Define to 1 if you have the `fork' function. */
+#undef HAVE_FORK
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `geteuid' function. */
+#undef HAVE_GETEUID
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#undef HAVE_INET_NTOP
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if the system has the type `long long'. */
+#undef HAVE_LONG_LONG
+
+/* Define to 1 if you have the `lstat' function. */
+#undef HAVE_LSTAT
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `mkstemp' function. */
+#undef HAVE_MKSTEMP
+
+/* Define to 1 if you have the `opendir' function. */
+#undef HAVE_OPENDIR
+
+/* Define to 1 if you have the `pipe' function. */
+#undef HAVE_PIPE
+
+/* Have libreadline */
+#undef HAVE_READLINE
+
+/* Define to 1 if you have the `readlink' function. */
+#undef HAVE_READLINK
+
+/* Define to 1 if you have the `realpath' function. */
+#undef HAVE_REALPATH
+
+/* Define to 1 if you have the `regcomp' function. */
+#undef HAVE_REGCOMP
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the `sleep' function. */
+#undef HAVE_SLEEP
+
+/* Have libsqlite */
+#undef HAVE_SQLITE
+
+/* Have libsqlite3 */
+#undef HAVE_SQLITE3
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strptime' function. */
+#undef HAVE_STRPTIME
+
+/* Define to 1 if you have the `sysinfo' function. */
+#undef HAVE_SYSINFO
+
+/* Define to 1 if you have the `syslog' function. */
+#undef HAVE_SYSLOG
+
+/* Define to 1 if you have the `sys_siglist' function. */
+#undef HAVE_SYS_SIGLIST
+
+/* Define to 1 if you have the `sys_signame' function. */
+#undef HAVE_SYS_SIGNAME
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#undef HAVE_SYS_UN_H
+
+/* Define to 1 if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define to 1 if you have the `ualarm' function. */
+#undef HAVE_UALARM
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `usleep' function. */
+#undef HAVE_USLEEP
+
+/* Define to 1 if you have the `vfork' function. */
+#undef HAVE_VFORK
+
+/* Define to 1 if you have the `waitpid' function. */
+#undef HAVE_WAITPID
+
+/* No need to declare extern 'environ'. */
+#undef NO_ENVIRON_EXTERN
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jimregexp.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jimregexp.c
new file mode 100755
index 0000000..c652ad4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jimregexp.c
@@ -0,0 +1,1756 @@
+/*
+ * regcomp and regexec -- regsub and regerror are elsewhere
+ *
+ *	Copyright (c) 1986 by University of Toronto.
+ *	Written by Henry Spencer.  Not derived from licensed software.
+ *
+ *	Permission is granted to anyone to use this software for any
+ *	purpose on any computer system, and to redistribute it freely,
+ *	subject to the following restrictions:
+ *
+ *	1. The author is not responsible for the consequences of use of
+ *		this software, no matter how awful, even if they arise
+ *		from defects in it.
+ *
+ *	2. The origin of this software must not be misrepresented, either
+ *		by explicit claim or by omission.
+ *
+ *	3. Altered versions must be plainly marked as such, and must not
+ *		be misrepresented as being the original software.
+ *** THIS IS AN ALTERED VERSION.  It was altered by John Gilmore,
+ *** hoptoad!gnu, on 27 Dec 1986, to add \n as an alternative to |
+ *** to assist in implementing egrep.
+ *** THIS IS AN ALTERED VERSION.  It was altered by John Gilmore,
+ *** hoptoad!gnu, on 27 Dec 1986, to add \< and \> for word-matching
+ *** as in BSD grep and ex.
+ *** THIS IS AN ALTERED VERSION.  It was altered by John Gilmore,
+ *** hoptoad!gnu, on 28 Dec 1986, to optimize characters quoted with \.
+ *** THIS IS AN ALTERED VERSION.  It was altered by James A. Woods,
+ *** ames!jaw, on 19 June 1987, to quash a regcomp() redundancy.
+ *** THIS IS AN ALTERED VERSION.  It was altered by Christopher Seiwald
+ *** seiwald@vix.com, on 28 August 1993, for use in jam.  Regmagic.h
+ *** was moved into regexp.h, and the include of regexp.h now uses "'s
+ *** to avoid conflicting with the system regexp.h.  Const, bless its
+ *** soul, was removed so it can compile everywhere.  The declaration
+ *** of strchr() was in conflict on AIX, so it was removed (as it is
+ *** happily defined in string.h).
+ *** THIS IS AN ALTERED VERSION.  It was altered by Christopher Seiwald
+ *** seiwald@perforce.com, on 20 January 2000, to use function prototypes.
+ *** THIS IS AN ALTERED VERSION.  It was altered by Christopher Seiwald
+ *** seiwald@perforce.com, on 05 November 2002, to const string literals.
+ *
+ *   THIS IS AN ALTERED VERSION.  It was altered by Steve Bennett <steveb@workware.net.au>
+ *   on 16 October 2010, to remove static state and add better Tcl ARE compatibility.
+ *   This includes counted repetitions, UTF-8 support, character classes,
+ *   shorthand character classes, increased number of parentheses to 100,
+ *   backslash escape sequences. It also removes \n as an alternative to |.
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions.  Serious changes in
+ * regular-expression syntax might require a total rethink.
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "jimregexp.h"
+#include "utf8.h"
+
+#if !defined(HAVE_REGCOMP) || defined(JIM_REGEXP)
+
+/*
+ * Structure for regexp "program".  This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology).  Each node is an opcode
+ * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
+ * all nodes except BRANCH implement concatenation; a "next" pointer with
+ * a BRANCH on both ends of it is connecting two alternatives.  (Here we
+ * have one of the subtle syntax dependencies:  an individual BRANCH (as
+ * opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence.)  The operand of some types of node is
+ * a literal string; for others, it is a node leading into a sub-FSM.  In
+ * particular, the operand of a BRANCH node is the first node of the branch.
+ * (NB this is *not* a tree structure:  the tail of the branch connects
+ * to the thing following the set of BRANCHes.)  The opcodes are:
+ */
+
+/* This *MUST* be less than (255-20)/2=117 */
+#define REG_MAX_PAREN 100
+
+/* definition	number	opnd?	meaning */
+#define	END	0	/* no	End of program. */
+#define	BOL	1	/* no	Match "" at beginning of line. */
+#define	EOL	2	/* no	Match "" at end of line. */
+#define	ANY	3	/* no	Match any one character. */
+#define	ANYOF	4	/* str	Match any character in this string. */
+#define	ANYBUT	5	/* str	Match any character not in this string. */
+#define	BRANCH	6	/* node	Match this alternative, or the next... */
+#define	BACK	7	/* no	Match "", "next" ptr points backward. */
+#define	EXACTLY	8	/* str	Match this string. */
+#define	NOTHING	9	/* no	Match empty string. */
+#define	REP		10	/* max,min	Match this (simple) thing [min,max] times. */
+#define	REPMIN	11	/* max,min	Match this (simple) thing [min,max] times, mininal match. */
+#define	REPX	12	/* max,min	Match this (complex) thing [min,max] times. */
+#define	REPXMIN	13	/* max,min	Match this (complex) thing [min,max] times, minimal match. */
+
+#define	WORDA	15	/* no	Match "" at wordchar, where prev is nonword */
+#define	WORDZ	16	/* no	Match "" at nonwordchar, where prev is word */
+#define	OPEN	20	/* no	Mark this point in input as start of #n. */
+			/*	OPEN+1 is number 1, etc. */
+#define	CLOSE	(OPEN+REG_MAX_PAREN)	/* no	Analogous to OPEN. */
+#define	CLOSE_END	(CLOSE+REG_MAX_PAREN)
+
+/*
+ * The first byte of the regexp internal "program" is actually this magic
+ * number; the start node begins in the second byte.
+ */
+#define	REG_MAGIC	0xFADED00D
+
+/*
+ * Opcode notes:
+ *
+ * BRANCH	The set of branches constituting a single choice are hooked
+ *		together with their "next" pointers, since precedence prevents
+ *		anything being concatenated to any individual branch.  The
+ *		"next" pointer of the last BRANCH in a choice points to the
+ *		thing following the whole choice.  This is also where the
+ *		final "next" pointer of each individual branch points; each
+ *		branch starts with the operand node of a BRANCH node.
+ *
+ * BACK		Normal "next" pointers all implicitly point forward; BACK
+ *		exists to make loop structures possible.
+ *
+ * STAR,PLUS	'?', and complex '*' and '+', are implemented as circular
+ *		BRANCH structures using BACK.  Simple cases (one character
+ *		per match) are implemented with STAR and PLUS for speed
+ *		and to minimize recursive plunges.
+ *
+ * OPEN,CLOSE	...are numbered at compile time.
+ */
+
+/*
+ * A node is one char of opcode followed by two chars of "next" pointer.
+ * "Next" pointers are stored as two 8-bit pieces, high order first.  The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node.  (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "next" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ */
+#define	OP(preg, p)	(preg->program[p])
+#define	NEXT(preg, p)	(preg->program[p + 1])
+#define	OPERAND(p)	((p) + 2)
+
+/*
+ * See regmagic.h for one further detail of program structure.
+ */
+
+
+/*
+ * Utility definitions.
+ */
+
+#define	FAIL(R,M)	{ (R)->err = (M); return (M); }
+#define	ISMULT(c)	((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
+#define	META	"^$.[()|?{+*"
+
+/*
+ * Flags to be passed up and down.
+ */
+#define	HASWIDTH	01	/* Known never to match null string. */
+#define	SIMPLE		02	/* Simple enough to be STAR/PLUS operand. */
+#define	SPSTART		04	/* Starts with * or +. */
+#define	WORST		0	/* Worst case. */
+
+#define MAX_REP_COUNT 1000000
+
+/*
+ * Forward declarations for regcomp()'s friends.
+ */
+static int reg(regex_t *preg, int paren /* Parenthesized? */, int *flagp );
+static int regpiece(regex_t *preg, int *flagp );
+static int regbranch(regex_t *preg, int *flagp );
+static int regatom(regex_t *preg, int *flagp );
+static int regnode(regex_t *preg, int op );
+static int regnext(regex_t *preg, int p );
+static void regc(regex_t *preg, int b );
+static int reginsert(regex_t *preg, int op, int size, int opnd );
+static void regtail_(regex_t *preg, int p, int val, int line );
+static void regoptail(regex_t *preg, int p, int val );
+#define regtail(PREG, P, VAL) regtail_(PREG, P, VAL, __LINE__)
+
+static int reg_range_find(const int *string, int c);
+static const char *str_find(const char *string, int c, int nocase);
+static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase);
+
+/*#define DEBUG*/
+#ifdef DEBUG
+int regnarrate = 0;
+static void regdump(regex_t *preg);
+static const char *regprop( int op );
+#endif
+
+
+/**
+ * Returns the length of the null-terminated integer sequence.
+ */
+static int str_int_len(const int *seq)
+{
+	int n = 0;
+	while (*seq++) {
+		n++;
+	}
+	return n;
+}
+
+/*
+ - regcomp - compile a regular expression into internal code
+ *
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code.  So we cheat:  we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it.  (Note that it has to be in
+ * one piece because free() must be able to free it all.)
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp.
+ */
+int regcomp(regex_t *preg, const char *exp, int cflags)
+{
+	int scan;
+	int longest;
+	unsigned len;
+	int flags;
+
+#ifdef DEBUG
+	fprintf(stderr, "Compiling: '%s'\n", exp);
+#endif
+	memset(preg, 0, sizeof(*preg));
+
+	if (exp == NULL)
+		FAIL(preg, REG_ERR_NULL_ARGUMENT);
+
+	/* First pass: determine size, legality. */
+	preg->cflags = cflags;
+	preg->regparse = exp;
+	/* XXX: For now, start unallocated */
+	preg->program = NULL;
+	preg->proglen = 0;
+
+#if 1
+	/* Allocate space. */
+	preg->proglen = (strlen(exp) + 1) * 5;
+	preg->program = malloc(preg->proglen * sizeof(int));
+	if (preg->program == NULL)
+		FAIL(preg, REG_ERR_NOMEM);
+#endif
+
+	/* Note that since we store a magic value as the first item in the program,
+	 * program offsets will never be 0
+	 */
+	regc(preg, REG_MAGIC);
+	if (reg(preg, 0, &flags) == 0) {
+		return preg->err;
+	}
+
+	/* Small enough for pointer-storage convention? */
+	if (preg->re_nsub >= REG_MAX_PAREN)		/* Probably could be 65535L. */
+		FAIL(preg,REG_ERR_TOO_BIG);
+
+	/* Dig out information for optimizations. */
+	preg->regstart = 0;	/* Worst-case defaults. */
+	preg->reganch = 0;
+	preg->regmust = 0;
+	preg->regmlen = 0;
+	scan = 1;			/* First BRANCH. */
+	if (OP(preg, regnext(preg, scan)) == END) {		/* Only one top-level choice. */
+		scan = OPERAND(scan);
+
+		/* Starting-point info. */
+		if (OP(preg, scan) == EXACTLY) {
+			preg->regstart = preg->program[OPERAND(scan)];
+		}
+		else if (OP(preg, scan) == BOL)
+			preg->reganch++;
+
+		/*
+		 * If there's something expensive in the r.e., find the
+		 * longest literal string that must appear and make it the
+		 * regmust.  Resolve ties in favor of later strings, since
+		 * the regstart check works with the beginning of the r.e.
+		 * and avoiding duplication strengthens checking.  Not a
+		 * strong reason, but sufficient in the absence of others.
+		 */
+		if (flags&SPSTART) {
+			longest = 0;
+			len = 0;
+			for (; scan != 0; scan = regnext(preg, scan)) {
+				if (OP(preg, scan) == EXACTLY) {
+					int plen = str_int_len(preg->program + OPERAND(scan));
+					if (plen >= len) {
+						longest = OPERAND(scan);
+						len = plen;
+					}
+				}
+			}
+			preg->regmust = longest;
+			preg->regmlen = len;
+		}
+	}
+
+#ifdef DEBUG
+	regdump(preg);
+#endif
+
+	return 0;
+}
+
+/*
+ - reg - regular expression, i.e. main body or parenthesized thing
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+static int reg(regex_t *preg, int paren /* Parenthesized? */, int *flagp )
+{
+	int ret;
+	int br;
+	int ender;
+	int parno = 0;
+	int flags;
+
+	*flagp = HASWIDTH;	/* Tentatively. */
+
+	/* Make an OPEN node, if parenthesized. */
+	if (paren) {
+		parno = ++preg->re_nsub;
+		ret = regnode(preg, OPEN+parno);
+	} else
+		ret = 0;
+
+	/* Pick up the branches, linking them together. */
+	br = regbranch(preg, &flags);
+	if (br == 0)
+		return 0;
+	if (ret != 0)
+		regtail(preg, ret, br);	/* OPEN -> first. */
+	else
+		ret = br;
+	if (!(flags&HASWIDTH))
+		*flagp &= ~HASWIDTH;
+	*flagp |= flags&SPSTART;
+	while (*preg->regparse == '|') {
+		preg->regparse++;
+		br = regbranch(preg, &flags);
+		if (br == 0)
+			return 0;
+		regtail(preg, ret, br);	/* BRANCH -> BRANCH. */
+		if (!(flags&HASWIDTH))
+			*flagp &= ~HASWIDTH;
+		*flagp |= flags&SPSTART;
+	}
+
+	/* Make a closing node, and hook it on the end. */
+	ender = regnode(preg, (paren) ? CLOSE+parno : END);
+	regtail(preg, ret, ender);
+
+	/* Hook the tails of the branches to the closing node. */
+	for (br = ret; br != 0; br = regnext(preg, br))
+		regoptail(preg, br, ender);
+
+	/* Check for proper termination. */
+	if (paren && *preg->regparse++ != ')') {
+		preg->err = REG_ERR_UNMATCHED_PAREN;
+		return 0;
+	} else if (!paren && *preg->regparse != '\0') {
+		if (*preg->regparse == ')') {
+			preg->err = REG_ERR_UNMATCHED_PAREN;
+			return 0;
+		} else {
+			preg->err = REG_ERR_JUNK_ON_END;
+			return 0;
+		}
+	}
+
+	return(ret);
+}
+
+/*
+ - regbranch - one alternative of an | operator
+ *
+ * Implements the concatenation operator.
+ */
+static int regbranch(regex_t *preg, int *flagp )
+{
+	int ret;
+	int chain;
+	int latest;
+	int flags;
+
+	*flagp = WORST;		/* Tentatively. */
+
+	ret = regnode(preg, BRANCH);
+	chain = 0;
+	while (*preg->regparse != '\0' && *preg->regparse != ')' &&
+	       *preg->regparse != '|') {
+		latest = regpiece(preg, &flags);
+		if (latest == 0)
+			return 0;
+		*flagp |= flags&HASWIDTH;
+		if (chain == 0) {/* First piece. */
+			*flagp |= flags&SPSTART;
+		}
+		else {
+			regtail(preg, chain, latest);
+		}
+		chain = latest;
+	}
+	if (chain == 0)	/* Loop ran zero times. */
+		(void) regnode(preg, NOTHING);
+
+	return(ret);
+}
+
+/*
+ - regpiece - something followed by possible [*+?]
+ *
+ * Note that the branching code sequences used for ? and the general cases
+ * of * and + are somewhat optimized:  they use the same NOTHING node as
+ * both the endmarker for their branch list and the body of the last branch.
+ * It might seem that this node could be dispensed with entirely, but the
+ * endmarker role is not redundant.
+ */
+static int regpiece(regex_t *preg, int *flagp)
+{
+	int ret;
+	char op;
+	int next;
+	int flags;
+	int chain = 0;
+	int min;
+	int max;
+
+	ret = regatom(preg, &flags);
+	if (ret == 0)
+		return 0;
+
+	op = *preg->regparse;
+	if (!ISMULT(op)) {
+		*flagp = flags;
+		return(ret);
+	}
+
+	if (!(flags&HASWIDTH) && op != '?') {
+		preg->err = REG_ERR_OPERAND_COULD_BE_EMPTY;
+		return 0;
+	}
+
+	/* Handle braces (counted repetition) by expansion */
+	if (op == '{') {
+		char *end;
+
+		min = strtoul(preg->regparse + 1, &end, 10);
+		if (end == preg->regparse + 1) {
+			preg->err = REG_ERR_BAD_COUNT;
+			return 0;
+		}
+		if (*end == '}') {
+			max = min;
+		}
+		else {
+			preg->regparse = end;
+			max = strtoul(preg->regparse + 1, &end, 10);
+			if (*end != '}') {
+				preg->err = REG_ERR_UNMATCHED_BRACES;
+				return 0;
+			}
+		}
+		if (end == preg->regparse + 1) {
+			max = MAX_REP_COUNT;
+		}
+		else if (max < min || max >= 100) {
+			preg->err = REG_ERR_BAD_COUNT;
+			return 0;
+		}
+		if (min >= 100) {
+			preg->err = REG_ERR_BAD_COUNT;
+			return 0;
+		}
+
+		preg->regparse = strchr(preg->regparse, '}');
+	}
+	else {
+		min = (op == '+');
+		max = (op == '?' ? 1 : MAX_REP_COUNT);
+	}
+
+	if (preg->regparse[1] == '?') {
+		preg->regparse++;
+		next = reginsert(preg, flags & SIMPLE ? REPMIN : REPXMIN, 5, ret);
+	}
+	else {
+		next = reginsert(preg, flags & SIMPLE ? REP: REPX, 5, ret);
+	}
+	preg->program[ret + 2] = max;
+	preg->program[ret + 3] = min;
+	preg->program[ret + 4] = 0;
+
+	*flagp = (min) ? (WORST|HASWIDTH) : (WORST|SPSTART);
+
+	if (!(flags & SIMPLE)) {
+		int back = regnode(preg, BACK);
+		regtail(preg, back, ret);
+		regtail(preg, next, back);
+	}
+
+	preg->regparse++;
+	if (ISMULT(*preg->regparse)) {
+		preg->err = REG_ERR_NESTED_COUNT;
+		return 0;
+	}
+
+	return chain ? chain : ret;
+}
+
+/**
+ * Add all characters in the inclusive range between lower and upper.
+ *
+ * Handles a swapped range (upper < lower).
+ */
+static void reg_addrange(regex_t *preg, int lower, int upper)
+{
+	if (lower > upper) {
+		reg_addrange(preg, upper, lower);
+	}
+	/* Add a range as length, start */
+	regc(preg, upper - lower + 1);
+	regc(preg, lower);
+}
+
+/**
+ * Add a null-terminated literal string as a set of ranges.
+ */
+static void reg_addrange_str(regex_t *preg, const char *str)
+{
+	while (*str) {
+		reg_addrange(preg, *str, *str);
+		str++;
+	}
+}
+
+/**
+ * Extracts the next unicode char from utf8.
+ *
+ * If 'upper' is set, converts the char to uppercase.
+ */
+static int reg_utf8_tounicode_case(const char *s, int *uc, int upper)
+{
+	int l = utf8_tounicode(s, uc);
+	if (upper) {
+		*uc = utf8_upper(*uc);
+	}
+	return l;
+}
+
+/**
+ * Converts a hex digit to decimal.
+ *
+ * Returns -1 for an invalid hex digit.
+ */
+static int hexdigitval(int c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	if (c >= 'A' && c <= 'F')
+		return c - 'A' + 10;
+	return -1;
+}
+
+/**
+ * Parses up to 'n' hex digits at 's' and stores the result in *uc.
+ *
+ * Returns the number of hex digits parsed.
+ * If there are no hex digits, returns 0 and stores nothing.
+ */
+static int parse_hex(const char *s, int n, int *uc)
+{
+	int val = 0;
+	int k;
+
+	for (k = 0; k < n; k++) {
+		int c = hexdigitval(*s++);
+		if (c == -1) {
+			break;
+		}
+		val = (val << 4) | c;
+	}
+	if (k) {
+		*uc = val;
+	}
+	return k;
+}
+
+/**
+ * Call for chars after a backlash to decode the escape sequence.
+ *
+ * Stores the result in *ch.
+ *
+ * Returns the number of bytes consumed.
+ */
+static int reg_decode_escape(const char *s, int *ch)
+{
+	int n;
+	const char *s0 = s;
+
+	*ch = *s++;
+
+	switch (*ch) {
+		case 'b': *ch = '\b'; break;
+		case 'e': *ch = 27; break;
+		case 'f': *ch = '\f'; break;
+		case 'n': *ch = '\n'; break;
+		case 'r': *ch = '\r'; break;
+		case 't': *ch = '\t'; break;
+		case 'v': *ch = '\v'; break;
+		case 'u':
+			if ((n = parse_hex(s, 4, ch)) > 0) {
+				s += n;
+			}
+			break;
+		case 'x':
+			if ((n = parse_hex(s, 2, ch)) > 0) {
+				s += n;
+			}
+			break;
+		case '\0':
+			s--;
+			*ch = '\\';
+			break;
+	}
+	return s - s0;
+}
+
+/*
+ - regatom - the lowest level
+ *
+ * Optimization:  gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run.  Backslashed characters are exceptions, each becoming a
+ * separate node; the code is simpler that way and it's not worth fixing.
+ */
+static int regatom(regex_t *preg, int *flagp)
+{
+	int ret;
+	int flags;
+	int nocase = (preg->cflags & REG_ICASE);
+
+	int ch;
+	int n = reg_utf8_tounicode_case(preg->regparse, &ch, nocase);
+
+	*flagp = WORST;		/* Tentatively. */
+
+	preg->regparse += n;
+	switch (ch) {
+	/* FIXME: these chars only have meaning at beg/end of pat? */
+	case '^':
+		ret = regnode(preg, BOL);
+		break;
+	case '$':
+		ret = regnode(preg, EOL);
+		break;
+	case '.':
+		ret = regnode(preg, ANY);
+		*flagp |= HASWIDTH|SIMPLE;
+		break;
+	case '[': {
+			const char *pattern = preg->regparse;
+
+			if (*pattern == '^') {	/* Complement of range. */
+				ret = regnode(preg, ANYBUT);
+				pattern++;
+			} else
+				ret = regnode(preg, ANYOF);
+
+			/* Special case. If the first char is ']' or '-', it is part of the set */
+			if (*pattern == ']' || *pattern == '-') {
+				reg_addrange(preg, *pattern, *pattern);
+				pattern++;
+			}
+
+			while (*pattern && *pattern != ']') {
+				/* Is this a range? a-z */
+				int start;
+				int end;
+
+				pattern += reg_utf8_tounicode_case(pattern, &start, nocase);
+				if (start == '\\') {
+					pattern += reg_decode_escape(pattern, &start);
+					if (start == 0) {
+						preg->err = REG_ERR_NULL_CHAR;
+						return 0;
+					}
+				}
+				if (pattern[0] == '-' && pattern[1]) {
+					/* skip '-' */
+					pattern += utf8_tounicode(pattern, &end);
+					pattern += reg_utf8_tounicode_case(pattern, &end, nocase);
+					if (end == '\\') {
+						pattern += reg_decode_escape(pattern, &end);
+						if (end == 0) {
+							preg->err = REG_ERR_NULL_CHAR;
+							return 0;
+						}
+					}
+
+					reg_addrange(preg, start, end);
+					continue;
+				}
+				if (start == '[') {
+					if (strncmp(pattern, ":alpha:]", 8) == 0) {
+						if ((preg->cflags & REG_ICASE) == 0) {
+							reg_addrange(preg, 'a', 'z');
+						}
+						reg_addrange(preg, 'A', 'Z');
+						pattern += 8;
+						continue;
+					}
+					if (strncmp(pattern, ":alnum:]", 8) == 0) {
+						if ((preg->cflags & REG_ICASE) == 0) {
+							reg_addrange(preg, 'a', 'z');
+						}
+						reg_addrange(preg, 'A', 'Z');
+						reg_addrange(preg, '0', '9');
+						pattern += 8;
+						continue;
+					}
+					if (strncmp(pattern, ":space:]", 8) == 0) {
+						reg_addrange_str(preg, " \t\r\n\f\v");
+						pattern += 8;
+						continue;
+					}
+				}
+				/* Not a range, so just add the char */
+				reg_addrange(preg, start, start);
+			}
+			regc(preg, '\0');
+
+			if (*pattern) {
+				pattern++;
+			}
+			preg->regparse = pattern;
+
+			*flagp |= HASWIDTH|SIMPLE;
+		}
+		break;
+	case '(':
+		ret = reg(preg, 1, &flags);
+		if (ret == 0)
+			return 0;
+		*flagp |= flags&(HASWIDTH|SPSTART);
+		break;
+	case '\0':
+	case '|':
+	case ')':
+		preg->err = REG_ERR_INTERNAL;
+		return 0;	/* Supposed to be caught earlier. */
+	case '?':
+	case '+':
+	case '*':
+	case '{':
+		preg->err = REG_ERR_COUNT_FOLLOWS_NOTHING;
+		return 0;
+	case '\\':
+		switch (*preg->regparse++) {
+		case '\0':
+			preg->err = REG_ERR_TRAILING_BACKSLASH;
+			return 0;
+		case '<':
+		case 'm':
+			ret = regnode(preg, WORDA);
+			break;
+		case '>':
+		case 'M':
+			ret = regnode(preg, WORDZ);
+			break;
+		case 'd':
+			ret = regnode(preg, ANYOF);
+			reg_addrange(preg, '0', '9');
+			regc(preg, '\0');
+			*flagp |= HASWIDTH|SIMPLE;
+			break;
+		case 'w':
+			ret = regnode(preg, ANYOF);
+			if ((preg->cflags & REG_ICASE) == 0) {
+				reg_addrange(preg, 'a', 'z');
+			}
+			reg_addrange(preg, 'A', 'Z');
+			reg_addrange(preg, '0', '9');
+			reg_addrange(preg, '_', '_');
+			regc(preg, '\0');
+			*flagp |= HASWIDTH|SIMPLE;
+			break;
+		case 's':
+			ret = regnode(preg, ANYOF);
+			reg_addrange_str(preg," \t\r\n\f\v");
+			regc(preg, '\0');
+			*flagp |= HASWIDTH|SIMPLE;
+			break;
+		/* FIXME: Someday handle \1, \2, ... */
+		default:
+			/* Handle general quoted chars in exact-match routine */
+			/* Back up to include the backslash */
+			preg->regparse--;
+			goto de_fault;
+		}
+		break;
+	de_fault:
+	default: {
+			/*
+			 * Encode a string of characters to be matched exactly.
+			 */
+			int added = 0;
+
+			/* Back up to pick up the first char of interest */
+			preg->regparse -= n;
+
+			ret = regnode(preg, EXACTLY);
+
+			/* Note that a META operator such as ? or * consumes the
+			 * preceding char.
+			 * Thus we must be careful to look ahead by 2 and add the
+			 * last char as it's own EXACTLY if necessary
+			 */
+
+			/* Until end of string or a META char is reached */
+			while (*preg->regparse && strchr(META, *preg->regparse) == NULL) {
+				n = reg_utf8_tounicode_case(preg->regparse, &ch, (preg->cflags & REG_ICASE));
+				if (ch == '\\' && preg->regparse[n]) {
+					/* Non-trailing backslash.
+					 * Is this a special escape, or a regular escape?
+					 */
+					if (strchr("<>mMwds", preg->regparse[n])) {
+						/* A special escape. All done with EXACTLY */
+						break;
+					}
+					/* Decode it. Note that we add the length for the escape
+					 * sequence to the length for the backlash so we can skip
+					 * the entire sequence, or not as required.
+					 */
+					n += reg_decode_escape(preg->regparse + n, &ch);
+					if (ch == 0) {
+						preg->err = REG_ERR_NULL_CHAR;
+						return 0;
+					}
+				}
+
+				/* Now we have one char 'ch' of length 'n'.
+				 * Check to see if the following char is a MULT
+				 */
+
+				if (ISMULT(preg->regparse[n])) {
+					/* Yes. But do we already have some EXACTLY chars? */
+					if (added) {
+						/* Yes, so return what we have and pick up the current char next time around */
+						break;
+					}
+					/* No, so add this single char and finish */
+					regc(preg, ch);
+					added++;
+					preg->regparse += n;
+					break;
+				}
+
+				/* No, so just add this char normally */
+				regc(preg, ch);
+				added++;
+				preg->regparse += n;
+			}
+			regc(preg, '\0');
+
+			*flagp |= HASWIDTH;
+			if (added == 1)
+				*flagp |= SIMPLE;
+			break;
+		}
+		break;
+	}
+
+	return(ret);
+}
+
+static void reg_grow(regex_t *preg, int n)
+{
+	if (preg->p + n >= preg->proglen) {
+		preg->proglen = (preg->p + n) * 2;
+		preg->program = realloc(preg->program, preg->proglen * sizeof(int));
+	}
+}
+
+/*
+ - regnode - emit a node
+ */
+/* Location. */
+static int regnode(regex_t *preg, int op)
+{
+	reg_grow(preg, 2);
+
+	preg->program[preg->p++] = op;
+	preg->program[preg->p++] = 0;
+
+	/* Return the start of the node */
+	return preg->p - 2;
+}
+
+/*
+ - regc - emit (if appropriate) a byte of code
+ */
+static void regc(regex_t *preg, int b )
+{
+	reg_grow(preg, 1);
+	preg->program[preg->p++] = b;
+}
+
+/*
+ - reginsert - insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ * Returns the new location of the original operand.
+ */
+static int reginsert(regex_t *preg, int op, int size, int opnd )
+{
+	reg_grow(preg, size);
+
+	/* Move everything from opnd up */
+	memmove(preg->program + opnd + size, preg->program + opnd, sizeof(int) * (preg->p - opnd));
+	/* Zero out the new space */
+	memset(preg->program + opnd, 0, sizeof(int) * size);
+
+	preg->program[opnd] = op;
+
+	preg->p += size;
+
+	return opnd + size;
+}
+
+/*
+ - regtail - set the next-pointer at the end of a node chain
+ */
+static void regtail_(regex_t *preg, int p, int val, int line )
+{
+	int scan;
+	int temp;
+	int offset;
+
+	/* Find last node. */
+	scan = p;
+	for (;;) {
+		temp = regnext(preg, scan);
+		if (temp == 0)
+			break;
+		scan = temp;
+	}
+
+	if (OP(preg, scan) == BACK)
+		offset = scan - val;
+	else
+		offset = val - scan;
+
+	preg->program[scan + 1] = offset;
+}
+
+/*
+ - regoptail - regtail on operand of first argument; nop if operandless
+ */
+
+static void regoptail(regex_t *preg, int p, int val )
+{
+	/* "Operandless" and "op != BRANCH" are synonymous in practice. */
+	if (p != 0 && OP(preg, p) == BRANCH) {
+		regtail(preg, OPERAND(p), val);
+	}
+}
+
+/*
+ * regexec and friends
+ */
+
+/*
+ * Forwards.
+ */
+static int regtry(regex_t *preg, const char *string );
+static int regmatch(regex_t *preg, int prog);
+static int regrepeat(regex_t *preg, int p, int max);
+
+/*
+ - regexec - match a regexp against a string
+ */
+int regexec(regex_t  *preg,  const  char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
+{
+	const char *s;
+	int scan;
+
+	/* Be paranoid... */
+	if (preg == NULL || preg->program == NULL || string == NULL) {
+		return REG_ERR_NULL_ARGUMENT;
+	}
+
+	/* Check validity of program. */
+	if (*preg->program != REG_MAGIC) {
+		return REG_ERR_CORRUPTED;
+	}
+
+#ifdef DEBUG
+	fprintf(stderr, "regexec: %s\n", string);
+	regdump(preg);
+#endif
+
+	preg->eflags = eflags;
+	preg->pmatch = pmatch;
+	preg->nmatch = nmatch;
+	preg->start = string;	/* All offsets are computed from here */
+
+	/* Must clear out the embedded repeat counts */
+	for (scan = OPERAND(1); scan != 0; scan = regnext(preg, scan)) {
+		switch (OP(preg, scan)) {
+		case REP:
+		case REPMIN:
+		case REPX:
+		case REPXMIN:
+			preg->program[scan + 4] = 0;
+			break;
+		}
+	}
+
+	/* If there is a "must appear" string, look for it. */
+	if (preg->regmust != 0) {
+		s = string;
+		while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) {
+			if (prefix_cmp(preg->program + preg->regmust, preg->regmlen, s, preg->cflags & REG_ICASE) >= 0) {
+				break;
+			}
+			s++;
+		}
+		if (s == NULL)	/* Not present. */
+			return REG_NOMATCH;
+	}
+
+	/* Mark beginning of line for ^ . */
+	preg->regbol = string;
+
+	/* Simplest case:  anchored match need be tried only once (maybe per line). */
+	if (preg->reganch) {
+		if (eflags & REG_NOTBOL) {
+			/* This is an anchored search, but not an BOL, so possibly skip to the next line */
+			goto nextline;
+		}
+		while (1) {
+			int ret = regtry(preg, string);
+			if (ret) {
+				return REG_NOERROR;
+			}
+			if (*string) {
+nextline:
+				if (preg->cflags & REG_NEWLINE) {
+					/* Try the next anchor? */
+					string = strchr(string, '\n');
+					if (string) {
+						preg->regbol = ++string;
+						continue;
+					}
+				}
+			}
+			return REG_NOMATCH;
+		}
+	}
+
+	/* Messy cases:  unanchored match. */
+	s = string;
+	if (preg->regstart != '\0') {
+		/* We know what char it must start with. */
+		while ((s = str_find(s, preg->regstart, preg->cflags & REG_ICASE)) != NULL) {
+			if (regtry(preg, s))
+				return REG_NOERROR;
+			s++;
+		}
+	}
+	else
+		/* We don't -- general case. */
+		while (1) {
+			if (regtry(preg, s))
+				return REG_NOERROR;
+			if (*s == '\0') {
+				break;
+			}
+			s += utf8_charlen(*s);
+		}
+
+	/* Failure. */
+	return REG_NOMATCH;
+}
+
+/*
+ - regtry - try match at specific point
+ */
+			/* 0 failure, 1 success */
+static int regtry( regex_t *preg, const char *string )
+{
+	int i;
+
+	preg->reginput = string;
+
+	for (i = 0; i < preg->nmatch; i++) {
+		preg->pmatch[i].rm_so = -1;
+		preg->pmatch[i].rm_eo = -1;
+	}
+	if (regmatch(preg, 1)) {
+		preg->pmatch[0].rm_so = string - preg->start;
+		preg->pmatch[0].rm_eo = preg->reginput - preg->start;
+		return(1);
+	} else
+		return(0);
+}
+
+/**
+ * Returns bytes matched if 'pattern' is a prefix of 'string'.
+ *
+ * If 'nocase' is non-zero, does a case-insensitive match.
+ *
+ * Returns -1 on not found.
+ */
+static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase)
+{
+	const char *s = string;
+	while (proglen && *s) {
+		int ch;
+		int n = reg_utf8_tounicode_case(s, &ch, nocase);
+		if (ch != *prog) {
+			return -1;
+		}
+		prog++;
+		s += n;
+		proglen--;
+	}
+	if (proglen == 0) {
+		return s - string;
+	}
+	return -1;
+}
+
+/**
+ * Searchs for 'c' in the range 'range'.
+ *
+ * Returns 1 if found, or 0 if not.
+ */
+static int reg_range_find(const int *range, int c)
+{
+	while (*range) {
+		/*printf("Checking %d in range [%d,%d]\n", c, range[1], (range[0] + range[1] - 1));*/
+		if (c >= range[1] && c <= (range[0] + range[1] - 1)) {
+			return 1;
+		}
+		range += 2;
+	}
+	return 0;
+}
+
+/**
+ * Search for the character 'c' in the utf-8 string 'string'.
+ *
+ * If 'nocase' is set, the 'string' is assumed to be uppercase
+ * and 'c' is converted to uppercase before matching.
+ *
+ * Returns the byte position in the string where the 'c' was found, or
+ * NULL if not found.
+ */
+static const char *str_find(const char *string, int c, int nocase)
+{
+	if (nocase) {
+		/* The "string" should already be converted to uppercase */
+		c = utf8_upper(c);
+	}
+	while (*string) {
+		int ch;
+		int n = reg_utf8_tounicode_case(string, &ch, nocase);
+		if (c == ch) {
+			return string;
+		}
+		string += n;
+	}
+	return NULL;
+}
+
+/**
+ * Returns true if 'ch' is an end-of-line char.
+ *
+ * In REG_NEWLINE mode, \n is considered EOL in
+ * addition to \0
+ */
+static int reg_iseol(regex_t *preg, int ch)
+{
+	if (preg->cflags & REG_NEWLINE) {
+		return ch == '\0' || ch == '\n';
+	}
+	else {
+		return ch == '\0';
+	}
+}
+
+static int regmatchsimplerepeat(regex_t *preg, int scan, int matchmin)
+{
+	int nextch = '\0';
+	const char *save;
+	int no;
+	int c;
+
+	int max = preg->program[scan + 2];
+	int min = preg->program[scan + 3];
+	int next = regnext(preg, scan);
+
+	/*
+	 * Lookahead to avoid useless match attempts
+	 * when we know what character comes next.
+	 */
+	if (OP(preg, next) == EXACTLY) {
+		nextch = preg->program[OPERAND(next)];
+	}
+	save = preg->reginput;
+	no = regrepeat(preg, scan + 5, max);
+	if (no < min) {
+		return 0;
+	}
+	if (matchmin) {
+		/* from min up to no */
+		max = no;
+		no = min;
+	}
+	/* else from no down to min */
+	while (1) {
+		if (matchmin) {
+			if (no > max) {
+				break;
+			}
+		}
+		else {
+			if (no < min) {
+				break;
+			}
+		}
+		preg->reginput = save + utf8_index(save, no);
+		reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
+		/* If it could work, try it. */
+		if (reg_iseol(preg, nextch) || c == nextch) {
+			if (regmatch(preg, next)) {
+				return(1);
+			}
+		}
+		if (matchmin) {
+			/* Couldn't or didn't, add one more */
+			no++;
+		}
+		else {
+			/* Couldn't or didn't -- back up. */
+			no--;
+		}
+	}
+	return(0);
+}
+
+static int regmatchrepeat(regex_t *preg, int scan, int matchmin)
+{
+	int *scanpt = preg->program + scan;
+
+	int max = scanpt[2];
+	int min = scanpt[3];
+
+	/* Have we reached min? */
+	if (scanpt[4] < min) {
+		/* No, so get another one */
+		scanpt[4]++;
+		if (regmatch(preg, scan + 5)) {
+			return 1;
+		}
+		scanpt[4]--;
+		return 0;
+	}
+	if (scanpt[4] > max) {
+		return 0;
+	}
+
+	if (matchmin) {
+		/* minimal, so try other branch first */
+		if (regmatch(preg, regnext(preg, scan))) {
+			return 1;
+		}
+		/* No, so try one more */
+		scanpt[4]++;
+		if (regmatch(preg, scan + 5)) {
+			return 1;
+		}
+		scanpt[4]--;
+		return 0;
+	}
+	/* maximal, so try this branch again */
+	if (scanpt[4] < max) {
+		scanpt[4]++;
+		if (regmatch(preg, scan + 5)) {
+			return 1;
+		}
+		scanpt[4]--;
+	}
+	/* At this point we are at max with no match. Try the other branch */
+	return regmatch(preg, regnext(preg, scan));
+}
+
+/*
+ - regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple:  check to see whether the current
+ * node matches, call self recursively to see whether the rest matches,
+ * and then act accordingly.  In practice we make some effort to avoid
+ * recursion, in particular by going through "ordinary" nodes (that don't
+ * need to know whether the rest of the match failed) by a loop instead of
+ * by recursion.
+ */
+/* 0 failure, 1 success */
+static int regmatch(regex_t *preg, int prog)
+{
+	int scan;	/* Current node. */
+	int next;		/* Next node. */
+
+	scan = prog;
+
+#ifdef DEBUG
+	if (scan != 0 && regnarrate)
+		fprintf(stderr, "%s(\n", regprop(scan));
+#endif
+	while (scan != 0) {
+		int n;
+		int c;
+#ifdef DEBUG
+		if (regnarrate) {
+			fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan)));	/* Where, what. */
+		}
+#endif
+		next = regnext(preg, scan);
+		n = reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
+
+		switch (OP(preg, scan)) {
+		case BOL:
+			if (preg->reginput != preg->regbol)
+				return(0);
+			break;
+		case EOL:
+			if (!reg_iseol(preg, c)) {
+				return(0);
+			}
+			break;
+		case WORDA:
+			/* Must be looking at a letter, digit, or _ */
+			if ((!isalnum(UCHAR(c))) && c != '_')
+				return(0);
+			/* Prev must be BOL or nonword */
+			if (preg->reginput > preg->regbol &&
+				(isalnum(UCHAR(preg->reginput[-1])) || preg->reginput[-1] == '_'))
+				return(0);
+			break;
+		case WORDZ:
+			/* Can't match at BOL */
+			if (preg->reginput > preg->regbol) {
+				/* Current must be EOL or nonword */
+				if (reg_iseol(preg, c) || !isalnum(UCHAR(c)) || c != '_') {
+					c = preg->reginput[-1];
+					/* Previous must be word */
+					if (isalnum(UCHAR(c)) || c == '_') {
+						break;
+					}
+				}
+			}
+			/* No */
+			return(0);
+
+		case ANY:
+			if (reg_iseol(preg, c))
+				return 0;
+			preg->reginput += n;
+			break;
+		case EXACTLY: {
+				int opnd;
+				int len;
+				int slen;
+
+				opnd = OPERAND(scan);
+				len = str_int_len(preg->program + opnd);
+
+				slen = prefix_cmp(preg->program + opnd, len, preg->reginput, preg->cflags & REG_ICASE);
+				if (slen < 0) {
+					return(0);
+				}
+				preg->reginput += slen;
+			}
+			break;
+		case ANYOF:
+			if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) == 0) {
+				return(0);
+			}
+			preg->reginput += n;
+			break;
+		case ANYBUT:
+			if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) != 0) {
+				return(0);
+			}
+			preg->reginput += n;
+			break;
+		case NOTHING:
+			break;
+		case BACK:
+			break;
+		case BRANCH: {
+				const char *save;
+
+				if (OP(preg, next) != BRANCH)		/* No choice. */
+					next = OPERAND(scan);	/* Avoid recursion. */
+				else {
+					do {
+						save = preg->reginput;
+						if (regmatch(preg, OPERAND(scan))) {
+							return(1);
+						}
+						preg->reginput = save;
+						scan = regnext(preg, scan);
+					} while (scan != 0 && OP(preg, scan) == BRANCH);
+					return(0);
+					/* NOTREACHED */
+				}
+			}
+			break;
+		case REP:
+		case REPMIN:
+			return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN);
+
+		case REPX:
+		case REPXMIN:
+			return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN);
+
+		case END:
+			return(1);	/* Success! */
+			break;
+		default:
+			if (OP(preg, scan) >= OPEN+1 && OP(preg, scan) < CLOSE_END) {
+				const char *save;
+
+				save = preg->reginput;
+
+				if (regmatch(preg, next)) {
+					int no;
+					/*
+					 * Don't set startp if some later
+					 * invocation of the same parentheses
+					 * already has.
+					 */
+					if (OP(preg, scan) < CLOSE) {
+						no = OP(preg, scan) - OPEN;
+						if (no < preg->nmatch && preg->pmatch[no].rm_so == -1) {
+							preg->pmatch[no].rm_so = save - preg->start;
+						}
+					}
+					else {
+						no = OP(preg, scan) - CLOSE;
+						if (no < preg->nmatch && preg->pmatch[no].rm_eo == -1) {
+							preg->pmatch[no].rm_eo = save - preg->start;
+						}
+					}
+					return(1);
+				} else
+					return(0);
+			}
+			return REG_ERR_INTERNAL;
+		}
+
+		scan = next;
+	}
+
+	/*
+	 * We get here only if there's trouble -- normally "case END" is
+	 * the terminating point.
+	 */
+	return REG_ERR_INTERNAL;
+}
+
+/*
+ - regrepeat - repeatedly match something simple, report how many
+ */
+static int regrepeat(regex_t *preg, int p, int max)
+{
+	int count = 0;
+	const char *scan;
+	int opnd;
+	int ch;
+	int n;
+
+	scan = preg->reginput;
+	opnd = OPERAND(p);
+	switch (OP(preg, p)) {
+	case ANY:
+		/* No need to handle utf8 specially here */
+		while (!reg_iseol(preg, *scan) && count < max) {
+			count++;
+			scan++;
+		}
+		break;
+	case EXACTLY:
+		while (count < max) {
+			n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+			if (preg->program[opnd] != ch) {
+				break;
+			}
+			count++;
+			scan += n;
+		}
+		break;
+	case ANYOF:
+		while (count < max) {
+			n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+			if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) == 0) {
+				break;
+			}
+			count++;
+			scan += n;
+		}
+		break;
+	case ANYBUT:
+		while (count < max) {
+			n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+			if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) != 0) {
+				break;
+			}
+			count++;
+			scan += n;
+		}
+		break;
+	default:		/* Oh dear.  Called inappropriately. */
+		preg->err = REG_ERR_INTERNAL;
+		count = 0;	/* Best compromise. */
+		break;
+	}
+	preg->reginput = scan;
+
+	return(count);
+}
+
+/*
+ - regnext - dig the "next" pointer out of a node
+ */
+static int regnext(regex_t *preg, int p )
+{
+	int offset;
+
+	offset = NEXT(preg, p);
+
+	if (offset == 0)
+		return 0;
+
+	if (OP(preg, p) == BACK)
+		return(p-offset);
+	else
+		return(p+offset);
+}
+
+#if defined(DEBUG) && !defined(JIM_BOOTSTRAP)
+
+/*
+ - regdump - dump a regexp onto stdout in vaguely comprehensible form
+ */
+static void regdump(regex_t *preg)
+{
+	int s;
+	int op = EXACTLY;	/* Arbitrary non-END op. */
+	int next;
+	char buf[4];
+
+	int i;
+	for (i = 1; i < preg->p; i++) {
+		printf("%02x ", preg->program[i]);
+		if (i % 16 == 15) {
+			printf("\n");
+		}
+	}
+	printf("\n");
+
+	s = 1;
+	while (op != END && s < preg->p) {	/* While that wasn't END last time... */
+		op = OP(preg, s);
+		printf("%3d: %s", s, regprop(op));	/* Where, what. */
+		next = regnext(preg, s);
+		if (next == 0)		/* Next ptr. */
+			printf("(0)");
+		else
+			printf("(%d)", next);
+		s += 2;
+		if (op == REP || op == REPMIN || op == REPX || op == REPXMIN) {
+			int max = preg->program[s];
+			int min = preg->program[s + 1];
+			if (max == 65535) {
+				printf("{%d,*}", min);
+			}
+			else {
+				printf("{%d,%d}", min, max);
+			}
+			printf(" %d", preg->program[s + 2]);
+			s += 3;
+		}
+		else if (op == ANYOF || op == ANYBUT) {
+			/* set of ranges */
+
+			while (preg->program[s]) {
+				int len = preg->program[s++];
+				int first = preg->program[s++];
+				buf[utf8_fromunicode(buf, first)] = 0;
+				printf("%s", buf);
+				if (len > 1) {
+					buf[utf8_fromunicode(buf, first + len - 1)] = 0;
+					printf("-%s", buf);
+				}
+			}
+			s++;
+		}
+		else if (op == EXACTLY) {
+			/* Literal string, where present. */
+
+			while (preg->program[s]) {
+				buf[utf8_fromunicode(buf, preg->program[s])] = 0;
+				printf("%s", buf);
+				s++;
+			}
+			s++;
+		}
+		putchar('\n');
+	}
+
+	if (op == END) {
+		/* Header fields of interest. */
+		if (preg->regstart) {
+			buf[utf8_fromunicode(buf, preg->regstart)] = 0;
+			printf("start '%s' ", buf);
+		}
+		if (preg->reganch)
+			printf("anchored ");
+		if (preg->regmust != 0) {
+			int i;
+			printf("must have:");
+			for (i = 0; i < preg->regmlen; i++) {
+				putchar(preg->program[preg->regmust + i]);
+			}
+			putchar('\n');
+		}
+	}
+	printf("\n");
+}
+
+/*
+ - regprop - printable representation of opcode
+ */
+static const char *regprop( int op )
+{
+	static char buf[50];
+
+	switch (op) {
+	case BOL:
+		return "BOL";
+	case EOL:
+		return "EOL";
+	case ANY:
+		return "ANY";
+	case ANYOF:
+		return "ANYOF";
+	case ANYBUT:
+		return "ANYBUT";
+	case BRANCH:
+		return "BRANCH";
+	case EXACTLY:
+		return "EXACTLY";
+	case NOTHING:
+		return "NOTHING";
+	case BACK:
+		return "BACK";
+	case END:
+		return "END";
+	case REP:
+		return "REP";
+	case REPMIN:
+		return "REPMIN";
+	case REPX:
+		return "REPX";
+	case REPXMIN:
+		return "REPXMIN";
+	case WORDA:
+		return "WORDA";
+	case WORDZ:
+		return "WORDZ";
+	default:
+		if (op >= OPEN && op < CLOSE) {
+			snprintf(buf, sizeof(buf), "OPEN%d", op-OPEN);
+		}
+		else if (op >= CLOSE && op < CLOSE_END) {
+			snprintf(buf, sizeof(buf), "CLOSE%d", op-CLOSE);
+		}
+		else {
+			snprintf(buf, sizeof(buf), "?%d?\n", op);
+		}
+		return(buf);
+	}
+}
+#endif /* JIM_BOOTSTRAP */
+
+size_t regerror(int errcode, const regex_t *preg, char *errbuf,  size_t errbuf_size)
+{
+	static const char *error_strings[] = {
+		"success",
+		"no match",
+		"bad pattern",
+		"null argument",
+		"unknown error",
+		"too big",
+		"out of memory",
+		"too many ()",
+		"parentheses () not balanced",
+		"braces {} not balanced",
+		"invalid repetition count(s)",
+		"extra characters",
+		"*+ of empty atom",
+		"nested count",
+		"internal error",
+		"count follows nothing",
+		"trailing backslash",
+		"corrupted program",
+		"contains null char",
+	};
+	const char *err;
+
+	if (errcode < 0 || errcode >= REG_ERR_NUM) {
+		err = "Bad error code";
+	}
+	else {
+		err = error_strings[errcode];
+	}
+
+	return snprintf(errbuf, errbuf_size, "%s", err);
+}
+
+void regfree(regex_t *preg)
+{
+	free(preg->program);
+}
+
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jimregexp.h b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jimregexp.h
new file mode 100755
index 0000000..79a87e5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jimregexp.h
@@ -0,0 +1,117 @@
+#ifndef JIMREGEXP_H
+#define JIMREGEXP_H
+
+#ifndef _JIMAUTOCONF_H
+#error Need jimautoconf.h
+#endif
+
+#if defined(HAVE_REGCOMP) && !defined(JIM_REGEXP)
+/* Use POSIX regex */
+#include <regex.h>
+
+#else
+
+#include <stdlib.h>
+
+/*
+ * Definitions etc. for regexp(3) routines.
+ *
+ * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof],
+ * not the System V one.
+ *
+ * 11/04/02 (seiwald) - const-ing for string literals
+ */
+
+typedef struct {
+	int rm_so;
+	int rm_eo;
+} regmatch_t;
+
+/*
+ * The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases.  They are:
+ *
+ * regstart	char that must begin a match; '\0' if none obvious
+ * reganch	is the match anchored (at beginning-of-line only)?
+ * regmust	string (pointer into program) that match must include, or NULL
+ * regmlen	length of regmust string
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot.  Regmust permits fast rejection
+ * of lines that cannot possibly match.  The regmust tests are costly enough
+ * that regcomp() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup).  Regmlen is
+ * supplied because the test in regexec() needs it and regcomp() is computing
+ * it anyway.
+ */
+
+typedef struct regexp {
+	/* -- public -- */
+	int re_nsub;		/* number of parenthesized subexpressions */
+
+	/* -- private -- */
+	int cflags;			/* Flags used when compiling */
+	int err;			/* Any error which occurred during compile */
+	int regstart;		/* Internal use only. */
+	int reganch;		/* Internal use only. */
+	int regmust;		/* Internal use only. */
+	int regmlen;		/* Internal use only. */
+	int *program;		/* Allocated */
+
+	/* working state - compile */
+	const char *regparse;		/* Input-scan pointer. */
+	int p;				/* Current output pos in program */
+	int proglen;		/* Allocated program size */
+
+	/* working state - exec */
+	int eflags;				/* Flags used when executing */
+	const char *start;		/* Initial string pointer. */
+	const char *reginput;	/* Current input pointer. */
+	const char *regbol;		/* Beginning of input, for ^ check. */
+
+	/* Input to regexec() */
+	regmatch_t *pmatch;		/* submatches will be stored here */
+	int nmatch;				/* size of pmatch[] */
+} regexp;
+
+typedef regexp regex_t;
+
+#define REG_EXTENDED 0
+#define REG_NEWLINE 1
+#define REG_ICASE 2
+
+#define REG_NOTBOL 16
+
+enum {
+	REG_NOERROR,      /* Success.  */
+	REG_NOMATCH,      /* Didn't find a match (for regexec).  */
+	REG_BADPAT,		  /* >= REG_BADPAT is an error */
+	REG_ERR_NULL_ARGUMENT,
+	REG_ERR_UNKNOWN,
+	REG_ERR_TOO_BIG,
+	REG_ERR_NOMEM,
+	REG_ERR_TOO_MANY_PAREN,
+	REG_ERR_UNMATCHED_PAREN,
+	REG_ERR_UNMATCHED_BRACES,
+	REG_ERR_BAD_COUNT,
+	REG_ERR_JUNK_ON_END,
+	REG_ERR_OPERAND_COULD_BE_EMPTY,
+	REG_ERR_NESTED_COUNT,
+	REG_ERR_INTERNAL,
+	REG_ERR_COUNT_FOLLOWS_NOTHING,
+	REG_ERR_TRAILING_BACKSLASH,
+	REG_ERR_CORRUPTED,
+	REG_ERR_NULL_CHAR,
+	REG_ERR_NUM
+};
+
+int regcomp(regex_t *preg, const char *regex, int cflags);
+int regexec(regex_t  *preg,  const  char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
+size_t regerror(int errcode, const regex_t *preg, char *errbuf,  size_t errbuf_size);
+void regfree(regex_t *preg);
+
+#endif
+
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jimsh.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jimsh.c
new file mode 100755
index 0000000..2c94468
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/jimsh.c
@@ -0,0 +1,111 @@
+
+/* Jimsh - An interactive shell for Jim
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2009 Steve Bennett <steveb@workware.net.au>
+ *
+ * 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
+ *
+ * A copy of the license is also included in the source distribution
+ * of Jim, as a TXT file name called LICENSE.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+
+/* From initjimsh.tcl */
+extern int Jim_initjimshInit(Jim_Interp *interp);
+
+static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[])
+{
+    int n;
+    Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
+    /* Populate argv global var */
+    for (n = 0; n < argc; n++) {
+        Jim_Obj *obj = Jim_NewStringObj(interp, argv[n], -1);
+
+        Jim_ListAppendElement(interp, listObj, obj);
+    }
+
+    Jim_SetVariableStr(interp, "argv", listObj);
+    Jim_SetVariableStr(interp, "argc", Jim_NewIntObj(interp, argc));
+}
+
+int main(int argc, char *const argv[])
+{
+    int retcode;
+    Jim_Interp *interp;
+
+    if (argc > 1 && strcmp(argv[1], "--version") == 0) {
+        printf("%d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
+        return 0;
+    }
+
+    /* Create and initialize the interpreter */
+    interp = Jim_CreateInterp();
+    Jim_RegisterCoreCommands(interp);
+
+    /* Register static extensions */
+    if (Jim_InitStaticExtensions(interp) != JIM_OK) {
+        Jim_MakeErrorMessage(interp);
+        fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
+    }
+
+    Jim_SetVariableStrWithStr(interp, "jim_argv0", argv[0]);
+    Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0");
+    retcode = Jim_initjimshInit(interp);
+
+    if (argc == 1) {
+        if (retcode == JIM_ERR) {
+            Jim_MakeErrorMessage(interp);
+            fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
+        }
+        if (retcode != JIM_EXIT) {
+            JimSetArgv(interp, 0, NULL);
+            retcode = Jim_InteractivePrompt(interp);
+        }
+    }
+    else {
+        if (argc > 2 && strcmp(argv[1], "-e") == 0) {
+            JimSetArgv(interp, argc - 3, argv + 3);
+            retcode = Jim_Eval(interp, argv[2]);
+            if (retcode != JIM_ERR) {
+                printf("%s\n", Jim_String(Jim_GetResult(interp)));
+            }
+        }
+        else {
+            Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1));
+            JimSetArgv(interp, argc - 2, argv + 2);
+            retcode = Jim_EvalFile(interp, argv[1]);
+        }
+        if (retcode == JIM_ERR) {
+            Jim_MakeErrorMessage(interp);
+            fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
+        }
+    }
+    if (retcode == JIM_EXIT) {
+        retcode = Jim_GetExitCode(interp);
+    }
+    else if (retcode == JIM_ERR) {
+        retcode = 1;
+    }
+    else {
+        retcode = 0;
+    }
+    Jim_FreeInterp(interp);
+    return retcode;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/linenoise.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/linenoise.c
new file mode 100755
index 0000000..4065d06
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/linenoise.c
@@ -0,0 +1,1379 @@
+/* linenoise.c -- guerrilla line editing library against the idea that a
+ * line editing lib needs to be 20,000 lines of C code.
+ *
+ * You can find the latest source code at:
+ *
+ *   http://github.com/antirez/linenoise
+ *
+ * Does a number of crazy assumptions that happen to be true in 99.9999% of
+ * the 2010 UNIX computers around.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  *  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *  *  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * References:
+ * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+ * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
+ *
+ * Todo list:
+ * - Win32 support
+ * - Save and load history containing newlines
+ *
+ * Bloat:
+ * - Completion?
+ *
+ * List of escape sequences used by this program, we do everything just
+ * a few sequences. In order to be so cheap we may have some
+ * flickering effect with some slow terminal, but the lesser sequences
+ * the more compatible.
+ *
+ * CHA (Cursor Horizontal Absolute)
+ *    Sequence: ESC [ n G
+ *    Effect: moves cursor to column n (1 based)
+ *
+ * EL (Erase Line)
+ *    Sequence: ESC [ n K
+ *    Effect: if n is 0 or missing, clear from cursor to end of line
+ *    Effect: if n is 1, clear from beginning of line to cursor
+ *    Effect: if n is 2, clear entire line
+ *
+ * CUF (CUrsor Forward)
+ *    Sequence: ESC [ n C
+ *    Effect: moves cursor forward of n chars
+ *
+ * The following are used to clear the screen: ESC [ H ESC [ 2 J
+ * This is actually composed of two sequences:
+ *
+ * cursorhome
+ *    Sequence: ESC [ H
+ *    Effect: moves the cursor to upper left corner
+ *
+ * ED2 (Clear entire screen)
+ *    Sequence: ESC [ 2 J
+ *    Effect: clear the whole screen
+ *
+ * == For highlighting control characters, we also use the following two ==
+ * SO (enter StandOut)
+ *    Sequence: ESC [ 7 m
+ *    Effect: Uses some standout mode such as reverse video
+ *
+ * SE (Standout End)
+ *    Sequence: ESC [ 0 m
+ *    Effect: Exit standout mode
+ *
+ * == Only used if TIOCGWINSZ fails ==
+ * DSR/CPR (Report cursor position)
+ *    Sequence: ESC [ 6 n
+ *    Effect: reports current cursor position as ESC [ NNN ; MMM R
+ */
+
+#ifdef __MINGW32__
+#include <windows.h>
+#include <fcntl.h>
+#define USE_WINCONSOLE
+#else
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#define USE_TERMIOS
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "linenoise.h"
+
+#include "jim-config.h"
+#ifdef JIM_UTF8
+#define USE_UTF8
+#endif
+#include "utf8.h"
+
+#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
+#define LINENOISE_MAX_LINE 4096
+
+#define ctrl(C) ((C) - '@')
+
+/* Use -ve numbers here to co-exist with normal unicode chars */
+enum {
+    SPECIAL_NONE,
+    SPECIAL_UP = -20,
+    SPECIAL_DOWN = -21,
+    SPECIAL_LEFT = -22,
+    SPECIAL_RIGHT = -23,
+    SPECIAL_DELETE = -24,
+    SPECIAL_HOME = -25,
+    SPECIAL_END = -26,
+};
+
+static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
+static int history_len = 0;
+static char **history = NULL;
+
+/* Structure to contain the status of the current (being edited) line */
+struct current {
+    char *buf;  /* Current buffer. Always null terminated */
+    int bufmax; /* Size of the buffer, including space for the null termination */
+    int len;    /* Number of bytes in 'buf' */
+    int chars;  /* Number of chars in 'buf' (utf-8 chars) */
+    int pos;    /* Cursor position, measured in chars */
+    int cols;   /* Size of the window, in chars */
+    const char *prompt;
+#if defined(USE_TERMIOS)
+    int fd;     /* Terminal fd */
+#elif defined(USE_WINCONSOLE)
+    HANDLE outh; /* Console output handle */
+    HANDLE inh; /* Console input handle */
+    int rows;   /* Screen rows */
+    int x;      /* Current column during output */
+    int y;      /* Current row */
+#endif
+};
+
+static int fd_read(struct current *current);
+static int getWindowSize(struct current *current);
+
+void linenoiseHistoryFree(void) {
+    if (history) {
+        int j;
+
+        for (j = 0; j < history_len; j++)
+            free(history[j]);
+        free(history);
+        history = NULL;
+    }
+}
+
+#if defined(USE_TERMIOS)
+static void linenoiseAtExit(void);
+static struct termios orig_termios; /* in order to restore at exit */
+static int rawmode = 0; /* for atexit() function to check if restore is needed*/
+static int atexit_registered = 0; /* register atexit just 1 time */
+
+static const char *unsupported_term[] = {"dumb","cons25",NULL};
+
+static int isUnsupportedTerm(void) {
+    char *term = getenv("TERM");
+
+    if (term) {
+        int j;
+        for (j = 0; unsupported_term[j]; j++) {
+            if (strcasecmp(term, unsupported_term[j]) == 0) {
+                return 1;
+            }
+        }
+    }
+    return 0;
+}
+
+static int enableRawMode(struct current *current) {
+    struct termios raw;
+
+    current->fd = STDIN_FILENO;
+
+    if (!isatty(current->fd) || isUnsupportedTerm() ||
+        tcgetattr(current->fd, &orig_termios) == -1) {
+fatal:
+        errno = ENOTTY;
+        return -1;
+    }
+
+    if (!atexit_registered) {
+        atexit(linenoiseAtExit);
+        atexit_registered = 1;
+    }
+
+    raw = orig_termios;  /* modify the original mode */
+    /* input modes: no break, no CR to NL, no parity check, no strip char,
+     * no start/stop output control. */
+    raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+    /* output modes - disable post processing */
+    raw.c_oflag &= ~(OPOST);
+    /* control modes - set 8 bit chars */
+    raw.c_cflag |= (CS8);
+    /* local modes - choing off, canonical off, no extended functions,
+     * no signal chars (^Z,^C) */
+    raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+    /* control chars - set return condition: min number of bytes and timer.
+     * We want read to return every single byte, without timeout. */
+    raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
+
+    /* put terminal in raw mode after flushing */
+    if (tcsetattr(current->fd,TCSADRAIN,&raw) < 0) {
+        goto fatal;
+    }
+    rawmode = 1;
+
+    current->cols = 0;
+    return 0;
+}
+
+static void disableRawMode(struct current *current) {
+    /* Don't even check the return value as it's too late. */
+    if (rawmode && tcsetattr(current->fd,TCSADRAIN,&orig_termios) != -1)
+        rawmode = 0;
+}
+
+/* At exit we'll try to fix the terminal to the initial conditions. */
+static void linenoiseAtExit(void) {
+    if (rawmode) {
+        tcsetattr(STDIN_FILENO, TCSADRAIN, &orig_termios);
+    }
+    linenoiseHistoryFree();
+}
+
+/* gcc/glibc insists that we care about the return code of write! */
+#define IGNORE_RC(EXPR) if (EXPR) {}
+
+/* This is fdprintf() on some systems, but use a different
+ * name to avoid conflicts
+ */
+static void fd_printf(int fd, const char *format, ...)
+{
+    va_list args;
+    char buf[64];
+    int n;
+
+    va_start(args, format);
+    n = vsnprintf(buf, sizeof(buf), format, args);
+    va_end(args);
+    IGNORE_RC(write(fd, buf, n));
+}
+
+static void clearScreen(struct current *current)
+{
+    fd_printf(current->fd, "\x1b[H\x1b[2J");
+}
+
+static void cursorToLeft(struct current *current)
+{
+    fd_printf(current->fd, "\x1b[1G");
+}
+
+static int outputChars(struct current *current, const char *buf, int len)
+{
+    return write(current->fd, buf, len);
+}
+
+static void outputControlChar(struct current *current, char ch)
+{
+    fd_printf(current->fd, "\033[7m^%c\033[0m", ch);
+}
+
+static void eraseEol(struct current *current)
+{
+    fd_printf(current->fd, "\x1b[0K");
+}
+
+static void setCursorPos(struct current *current, int x)
+{
+    fd_printf(current->fd, "\x1b[1G\x1b[%dC", x);
+}
+
+/**
+ * Reads a char from 'fd', waiting at most 'timeout' milliseconds.
+ *
+ * A timeout of -1 means to wait forever.
+ *
+ * Returns -1 if no char is received within the time or an error occurs.
+ */
+static int fd_read_char(int fd, int timeout)
+{
+    struct pollfd p;
+    unsigned char c;
+
+    p.fd = fd;
+    p.events = POLLIN;
+
+    if (poll(&p, 1, timeout) == 0) {
+        /* timeout */
+        return -1;
+    }
+    if (read(fd, &c, 1) != 1) {
+        return -1;
+    }
+    return c;
+}
+
+/**
+ * Reads a complete utf-8 character
+ * and returns the unicode value, or -1 on error.
+ */
+static int fd_read(struct current *current)
+{
+#ifdef USE_UTF8
+    char buf[4];
+    int n;
+    int i;
+    int c;
+
+    if (read(current->fd, &buf[0], 1) != 1) {
+        return -1;
+    }
+    n = utf8_charlen(buf[0]);
+    if (n < 1 || n > 3) {
+        return -1;
+    }
+    for (i = 1; i < n; i++) {
+        if (read(current->fd, &buf[i], 1) != 1) {
+            return -1;
+        }
+    }
+    buf[n] = 0;
+    /* decode and return the character */
+    utf8_tounicode(buf, &c);
+    return c;
+#else
+    return fd_read_char(current->fd, -1);
+#endif
+}
+
+static int getWindowSize(struct current *current)
+{
+    struct winsize ws;
+
+    if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && ws.ws_col != 0) {
+        current->cols = ws.ws_col;
+        return 0;
+    }
+
+    /* Failed to query the window size. Perhaps we are on a serial terminal.
+     * Try to query the width by sending the cursor as far to the right
+     * and reading back the cursor position.
+     * Note that this is only done once per call to linenoise rather than
+     * every time the line is refreshed for efficiency reasons.
+     */
+    if (current->cols == 0) {
+        current->cols = 80;
+
+        /* Move cursor far right and report cursor position */
+        fd_printf(current->fd, "\x1b[999G" "\x1b[6n");
+
+        /* Parse the response: ESC [ rows ; cols R */
+        if (fd_read_char(current->fd, 100) == 0x1b && fd_read_char(current->fd, 100) == '[') {
+            int n = 0;
+            while (1) {
+                int ch = fd_read_char(current->fd, 100);
+                if (ch == ';') {
+                    /* Ignore rows */
+                    n = 0;
+                }
+                else if (ch == 'R') {
+                    /* Got cols */
+                    if (n != 0 && n < 1000) {
+                        current->cols = n;
+                    }
+                    break;
+                }
+                else if (ch >= 0 && ch <= '9') {
+                    n = n * 10 + ch - '0';
+                }
+                else {
+                    break;
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+/**
+ * If escape (27) was received, reads subsequent
+ * chars to determine if this is a known special key.
+ *
+ * Returns SPECIAL_NONE if unrecognised, or -1 if EOF.
+ *
+ * If no additional char is received within a short time,
+ * 27 is returned.
+ */
+static int check_special(int fd)
+{
+    int c = fd_read_char(fd, 50);
+    int c2;
+
+    if (c < 0) {
+        return 27;
+    }
+
+    c2 = fd_read_char(fd, 50);
+    if (c2 < 0) {
+        return c2;
+    }
+    if (c == '[' || c == 'O') {
+        /* Potential arrow key */
+        switch (c2) {
+            case 'A':
+                return SPECIAL_UP;
+            case 'B':
+                return SPECIAL_DOWN;
+            case 'C':
+                return SPECIAL_RIGHT;
+            case 'D':
+                return SPECIAL_LEFT;
+            case 'F':
+                return SPECIAL_END;
+            case 'H':
+                return SPECIAL_HOME;
+        }
+    }
+    if (c == '[' && c2 >= '1' && c2 <= '6') {
+        /* extended escape */
+        int c3 = fd_read_char(fd, 50);
+        if (c2 == '3' && c3 == '~') {
+            /* delete char under cursor */
+            return SPECIAL_DELETE;
+        }
+        while (c3 != -1 && c3 != '~') {
+            /* .e.g \e[12~ or '\e[11;2~   discard the complete sequence */
+            c3 = fd_read_char(fd, 50);
+        }
+    }
+
+    return SPECIAL_NONE;
+}
+#elif defined(USE_WINCONSOLE)
+
+static DWORD orig_consolemode = 0;
+
+static int enableRawMode(struct current *current) {
+    DWORD n;
+    INPUT_RECORD irec;
+
+    current->outh = GetStdHandle(STD_OUTPUT_HANDLE);
+    current->inh = GetStdHandle(STD_INPUT_HANDLE);
+
+    if (!PeekConsoleInput(current->inh, &irec, 1, &n)) {
+        return -1;
+    }
+    if (getWindowSize(current) != 0) {
+        return -1;
+    }
+    if (GetConsoleMode(current->inh, &orig_consolemode)) {
+        SetConsoleMode(current->inh, ENABLE_PROCESSED_INPUT);
+    }
+    return 0;
+}
+
+static void disableRawMode(struct current *current)
+{
+    SetConsoleMode(current->inh, orig_consolemode);
+}
+
+static void clearScreen(struct current *current)
+{
+    COORD topleft = { 0, 0 };
+    DWORD n;
+
+    FillConsoleOutputCharacter(current->outh, ' ',
+        current->cols * current->rows, topleft, &n);
+    FillConsoleOutputAttribute(current->outh,
+        FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN,
+        current->cols * current->rows, topleft, &n);
+    SetConsoleCursorPosition(current->outh, topleft);
+}
+
+static void cursorToLeft(struct current *current)
+{
+    COORD pos = { 0, current->y };
+    DWORD n;
+
+    FillConsoleOutputAttribute(current->outh,
+        FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN, current->cols, pos, &n);
+    current->x = 0;
+}
+
+static int outputChars(struct current *current, const char *buf, int len)
+{
+    COORD pos = { current->x, current->y };
+    WriteConsoleOutputCharacter(current->outh, buf, len, pos, 0);
+    current->x += len;
+    return 0;
+}
+
+static void outputControlChar(struct current *current, char ch)
+{
+    COORD pos = { current->x, current->y };
+    DWORD n;
+
+    FillConsoleOutputAttribute(current->outh, BACKGROUND_INTENSITY, 2, pos, &n);
+    outputChars(current, "^", 1);
+    outputChars(current, &ch, 1);
+}
+
+static void eraseEol(struct current *current)
+{
+    COORD pos = { current->x, current->y };
+    DWORD n;
+
+    FillConsoleOutputCharacter(current->outh, ' ', current->cols - current->x, pos, &n);
+}
+
+static void setCursorPos(struct current *current, int x)
+{
+    COORD pos = { x, current->y };
+
+    SetConsoleCursorPosition(current->outh, pos);
+    current->x = x;
+}
+
+static int fd_read(struct current *current)
+{
+    while (1) {
+        INPUT_RECORD irec;
+        DWORD n;
+        if (WaitForSingleObject(current->inh, INFINITE) != WAIT_OBJECT_0) {
+            break;
+        }
+        if (!ReadConsoleInput (current->inh, &irec, 1, &n)) {
+            break;
+        }
+        if (irec.EventType == KEY_EVENT && irec.Event.KeyEvent.bKeyDown) {
+            KEY_EVENT_RECORD *k = &irec.Event.KeyEvent;
+            if (k->dwControlKeyState & ENHANCED_KEY) {
+                switch (k->wVirtualKeyCode) {
+                 case VK_LEFT:
+                    return SPECIAL_LEFT;
+                 case VK_RIGHT:
+                    return SPECIAL_RIGHT;
+                 case VK_UP:
+                    return SPECIAL_UP;
+                 case VK_DOWN:
+                    return SPECIAL_DOWN;
+                 case VK_DELETE:
+                    return SPECIAL_DELETE;
+                 case VK_HOME:
+                    return SPECIAL_HOME;
+                 case VK_END:
+                    return SPECIAL_END;
+                }
+            }
+            /* Note that control characters are already translated in AsciiChar */
+            else {
+#ifdef USE_UTF8
+                return k->uChar.UnicodeChar;
+#else
+                return k->uChar.AsciiChar;
+#endif
+            }
+        }
+    }
+    return -1;
+}
+
+static int getWindowSize(struct current *current)
+{
+    CONSOLE_SCREEN_BUFFER_INFO info;
+    if (!GetConsoleScreenBufferInfo(current->outh, &info)) {
+        return -1;
+    }
+    current->cols = info.dwSize.X;
+    current->rows = info.dwSize.Y;
+    if (current->cols <= 0 || current->rows <= 0) {
+        current->cols = 80;
+        return -1;
+    }
+    current->y = info.dwCursorPosition.Y;
+    current->x = info.dwCursorPosition.X;
+    return 0;
+}
+#endif
+
+static int utf8_getchars(char *buf, int c)
+{
+#ifdef USE_UTF8
+    return utf8_fromunicode(buf, c);
+#else
+    *buf = c;
+    return 1;
+#endif
+}
+
+/**
+ * Returns the unicode character at the given offset,
+ * or -1 if none.
+ */
+static int get_char(struct current *current, int pos)
+{
+    if (pos >= 0 && pos < current->chars) {
+        int c;
+        int i = utf8_index(current->buf, pos);
+        (void)utf8_tounicode(current->buf + i, &c);
+        return c;
+    }
+    return -1;
+}
+
+static void refreshLine(const char *prompt, struct current *current)
+{
+    int plen;
+    int pchars;
+    int backup = 0;
+    int i;
+    const char *buf = current->buf;
+    int chars = current->chars;
+    int pos = current->pos;
+    int b;
+    int ch;
+    int n;
+
+    /* Should intercept SIGWINCH. For now, just get the size every time */
+    getWindowSize(current);
+
+    plen = strlen(prompt);
+    pchars = utf8_strlen(prompt, plen);
+
+    /* Account for a line which is too long to fit in the window.
+     * Note that control chars require an extra column
+     */
+
+    /* How many cols are required to the left of 'pos'?
+     * The prompt, plus one extra for each control char
+     */
+    n = pchars + utf8_strlen(buf, current->len);
+    b = 0;
+    for (i = 0; i < pos; i++) {
+        b += utf8_tounicode(buf + b, &ch);
+        if (ch < ' ') {
+            n++;
+        }
+    }
+
+    /* If too many are need, strip chars off the front of 'buf'
+     * until it fits. Note that if the current char is a control character,
+     * we need one extra col.
+     */
+    if (current->pos < current->chars && get_char(current, current->pos) < ' ') {
+        n++;
+    }
+
+    while (n >= current->cols) {
+        b = utf8_tounicode(buf, &ch);
+        if (ch < ' ') {
+            n--;
+        }
+        n--;
+        buf += b;
+        pos--;
+        chars--;
+    }
+
+    /* Cursor to left edge, then the prompt */
+    cursorToLeft(current);
+    outputChars(current, prompt, plen);
+
+    /* Now the current buffer content */
+
+    /* Need special handling for control characters.
+     * If we hit 'cols', stop.
+     */
+    b = 0; /* unwritted bytes */
+    n = 0; /* How many control chars were written */
+    for (i = 0; i < chars; i++) {
+        int ch;
+        int w = utf8_tounicode(buf + b, &ch);
+        if (ch < ' ') {
+            n++;
+        }
+        if (pchars + i + n >= current->cols) {
+            break;
+        }
+        if (ch < ' ') {
+            /* A control character, so write the buffer so far */
+            outputChars(current, buf, b);
+            buf += b + w;
+            b = 0;
+            outputControlChar(current, ch + '@');
+            if (i < pos) {
+                backup++;
+            }
+        }
+        else {
+            b += w;
+        }
+    }
+    outputChars(current, buf, b);
+
+    /* Erase to right, move cursor to original position */
+    eraseEol(current);
+    setCursorPos(current, pos + pchars + backup);
+}
+
+static void set_current(struct current *current, const char *str)
+{
+    strncpy(current->buf, str, current->bufmax);
+    current->buf[current->bufmax - 1] = 0;
+    current->len = strlen(current->buf);
+    current->pos = current->chars = utf8_strlen(current->buf, current->len);
+}
+
+static int has_room(struct current *current, int bytes)
+{
+    return current->len + bytes < current->bufmax - 1;
+}
+
+/**
+ * Removes the char at 'pos'.
+ *
+ * Returns 1 if the line needs to be refreshed, 2 if not
+ * and 0 if nothing was removed
+ */
+static int remove_char(struct current *current, int pos)
+{
+    if (pos >= 0 && pos < current->chars) {
+        int p1, p2;
+        int ret = 1;
+        p1 = utf8_index(current->buf, pos);
+        p2 = p1 + utf8_index(current->buf + p1, 1);
+
+#ifdef USE_TERMIOS
+        /* optimise remove char in the case of removing the last char */
+        if (current->pos == pos + 1 && current->pos == current->chars) {
+            if (current->buf[pos] >= ' ' && utf8_strlen(current->prompt, -1) + utf8_strlen(current->buf, current->len) < current->cols - 1) {
+                ret = 2;
+                fd_printf(current->fd, "\b \b");
+            }
+        }
+#endif
+
+        /* Move the null char too */
+        memmove(current->buf + p1, current->buf + p2, current->len - p2 + 1);
+        current->len -= (p2 - p1);
+        current->chars--;
+
+        if (current->pos > pos) {
+            current->pos--;
+        }
+        return ret;
+    }
+    return 0;
+}
+
+/**
+ * Insert 'ch' at position 'pos'
+ *
+ * Returns 1 if the line needs to be refreshed, 2 if not
+ * and 0 if nothing was inserted (no room)
+ */
+static int insert_char(struct current *current, int pos, int ch)
+{
+    char buf[3];
+    int n = utf8_getchars(buf, ch);
+
+    if (has_room(current, n) && pos >= 0 && pos <= current->chars) {
+        int p1, p2;
+        int ret = 1;
+        p1 = utf8_index(current->buf, pos);
+        p2 = p1 + n;
+
+#ifdef USE_TERMIOS
+        /* optimise the case where adding a single char to the end and no scrolling is needed */
+        if (current->pos == pos && current->chars == pos) {
+            if (ch >= ' ' && utf8_strlen(current->prompt, -1) + utf8_strlen(current->buf, current->len) < current->cols - 1) {
+                IGNORE_RC(write(current->fd, buf, n));
+                ret = 2;
+            }
+        }
+#endif
+
+        memmove(current->buf + p2, current->buf + p1, current->len - p1);
+        memcpy(current->buf + p1, buf, n);
+        current->len += n;
+
+        current->chars++;
+        if (current->pos >= pos) {
+            current->pos++;
+        }
+        return ret;
+    }
+    return 0;
+}
+
+/**
+ * Returns 0 if no chars were removed or non-zero otherwise.
+ */
+static int remove_chars(struct current *current, int pos, int n)
+{
+    int removed = 0;
+    while (n-- && remove_char(current, pos)) {
+        removed++;
+    }
+    return removed;
+}
+
+#ifndef NO_COMPLETION
+static linenoiseCompletionCallback *completionCallback = NULL;
+
+static void beep() {
+#ifdef USE_TERMIOS
+    fprintf(stderr, "\x7");
+    fflush(stderr);
+#endif
+}
+
+static void freeCompletions(linenoiseCompletions *lc) {
+    size_t i;
+    for (i = 0; i < lc->len; i++)
+        free(lc->cvec[i]);
+    free(lc->cvec);
+}
+
+static int completeLine(struct current *current) {
+    linenoiseCompletions lc = { 0, NULL };
+    int c = 0;
+
+    completionCallback(current->buf,&lc);
+    if (lc.len == 0) {
+        beep();
+    } else {
+        size_t stop = 0, i = 0;
+
+        while(!stop) {
+            /* Show completion or original buffer */
+            if (i < lc.len) {
+                struct current tmp = *current;
+                tmp.buf = lc.cvec[i];
+                tmp.pos = tmp.len = strlen(tmp.buf);
+                tmp.chars = utf8_strlen(tmp.buf, tmp.len);
+                refreshLine(current->prompt, &tmp);
+            } else {
+                refreshLine(current->prompt, current);
+            }
+
+            c = fd_read(current);
+            if (c == -1) {
+                break;
+            }
+
+            switch(c) {
+                case '\t': /* tab */
+                    i = (i+1) % (lc.len+1);
+                    if (i == lc.len) beep();
+                    break;
+                case 27: /* escape */
+                    /* Re-show original buffer */
+                    if (i < lc.len) {
+                        refreshLine(current->prompt, current);
+                    }
+                    stop = 1;
+                    break;
+                default:
+                    /* Update buffer and return */
+                    if (i < lc.len) {
+                        set_current(current,lc.cvec[i]);
+                    }
+                    stop = 1;
+                    break;
+            }
+        }
+    }
+
+    freeCompletions(&lc);
+    return c; /* Return last read character */
+}
+
+/* Register a callback function to be called for tab-completion. */
+void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
+    completionCallback = fn;
+}
+
+void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
+    lc->cvec = (char **)realloc(lc->cvec,sizeof(char*)*(lc->len+1));
+    lc->cvec[lc->len++] = strdup(str);
+}
+
+#endif
+
+static int linenoisePrompt(struct current *current) {
+    int history_index = 0;
+
+    /* The latest history entry is always our current buffer, that
+     * initially is just an empty string. */
+    linenoiseHistoryAdd("");
+
+    set_current(current, "");
+    refreshLine(current->prompt, current);
+
+    while(1) {
+        int dir = -1;
+        int c = fd_read(current);
+
+#ifndef NO_COMPLETION
+        /* Only autocomplete when the callback is set. It returns < 0 when
+         * there was an error reading from fd. Otherwise it will return the
+         * character that should be handled next. */
+        if (c == 9 && completionCallback != NULL) {
+            c = completeLine(current);
+            /* Return on errors */
+            if (c < 0) return current->len;
+            /* Read next character when 0 */
+            if (c == 0) continue;
+        }
+#endif
+
+process_char:
+        if (c == -1) return current->len;
+#ifdef USE_TERMIOS
+        if (c == 27) {   /* escape sequence */
+            c = check_special(current->fd);
+        }
+#endif
+        switch(c) {
+        case '\r':    /* enter */
+            history_len--;
+            free(history[history_len]);
+            return current->len;
+        case ctrl('C'):     /* ctrl-c */
+            errno = EAGAIN;
+            return -1;
+        case 127:   /* backspace */
+        case ctrl('H'):
+            if (remove_char(current, current->pos - 1) == 1) {
+                refreshLine(current->prompt, current);
+            }
+            break;
+        case ctrl('D'):     /* ctrl-d */
+            if (current->len == 0) {
+                /* Empty line, so EOF */
+                history_len--;
+                free(history[history_len]);
+                return -1;
+            }
+            /* Otherwise delete char to right of cursor */
+            if (remove_char(current, current->pos)) {
+                refreshLine(current->prompt, current);
+            }
+            break;
+        case ctrl('W'):    /* ctrl-w */
+            /* eat any spaces on the left */
+            {
+                int pos = current->pos;
+                while (pos > 0 && get_char(current, pos - 1) == ' ') {
+                    pos--;
+                }
+
+                /* now eat any non-spaces on the left */
+                while (pos > 0 && get_char(current, pos - 1) != ' ') {
+                    pos--;
+                }
+
+                if (remove_chars(current, pos, current->pos - pos)) {
+                    refreshLine(current->prompt, current);
+                }
+            }
+            break;
+        case ctrl('R'):    /* ctrl-r */
+            {
+                /* Display the reverse-i-search prompt and process chars */
+                char rbuf[50];
+                char rprompt[80];
+                int rchars = 0;
+                int rlen = 0;
+                int searchpos = history_len - 1;
+
+                rbuf[0] = 0;
+                while (1) {
+                    int n = 0;
+                    const char *p = NULL;
+                    int skipsame = 0;
+                    int searchdir = -1;
+
+                    snprintf(rprompt, sizeof(rprompt), "(reverse-i-search)'%s': ", rbuf);
+                    refreshLine(rprompt, current);
+                    c = fd_read(current);
+                    if (c == ctrl('H') || c == 127) {
+                        if (rchars) {
+                            int p = utf8_index(rbuf, --rchars);
+                            rbuf[p] = 0;
+                            rlen = strlen(rbuf);
+                        }
+                        continue;
+                    }
+#ifdef USE_TERMIOS
+                    if (c == 27) {
+                        c = check_special(current->fd);
+                    }
+#endif
+                    if (c == ctrl('P') || c == SPECIAL_UP) {
+                        /* Search for the previous (earlier) match */
+                        if (searchpos > 0) {
+                            searchpos--;
+                        }
+                        skipsame = 1;
+                    }
+                    else if (c == ctrl('N') || c == SPECIAL_DOWN) {
+                        /* Search for the next (later) match */
+                        if (searchpos < history_len) {
+                            searchpos++;
+                        }
+                        searchdir = 1;
+                        skipsame = 1;
+                    }
+                    else if (c >= ' ') {
+                        if (rlen >= (int)sizeof(rbuf) + 3) {
+                            continue;
+                        }
+
+                        n = utf8_getchars(rbuf + rlen, c);
+                        rlen += n;
+                        rchars++;
+                        rbuf[rlen] = 0;
+
+                        /* Adding a new char resets the search location */
+                        searchpos = history_len - 1;
+                    }
+                    else {
+                        /* Exit from incremental search mode */
+                        break;
+                    }
+
+                    /* Now search through the history for a match */
+                    for (; searchpos >= 0 && searchpos < history_len; searchpos += searchdir) {
+                        p = strstr(history[searchpos], rbuf);
+                        if (p) {
+                            /* Found a match */
+                            if (skipsame && strcmp(history[searchpos], current->buf) == 0) {
+                                /* But it is identical, so skip it */
+                                continue;
+                            }
+                            /* Copy the matching line and set the cursor position */
+                            set_current(current,history[searchpos]);
+                            current->pos = utf8_strlen(history[searchpos], p - history[searchpos]);
+                            break;
+                        }
+                    }
+                    if (!p && n) {
+                        /* No match, so don't add it */
+                        rchars--;
+                        rlen -= n;
+                        rbuf[rlen] = 0;
+                    }
+                }
+                if (c == ctrl('G') || c == ctrl('C')) {
+                    /* ctrl-g terminates the search with no effect */
+                    set_current(current, "");
+                    c = 0;
+                }
+                else if (c == ctrl('J')) {
+                    /* ctrl-j terminates the search leaving the buffer in place */
+                    c = 0;
+                }
+                /* Go process the char normally */
+                refreshLine(current->prompt, current);
+                goto process_char;
+            }
+            break;
+        case ctrl('T'):    /* ctrl-t */
+            if (current->pos > 0 && current->pos < current->chars) {
+                c = get_char(current, current->pos);
+                remove_char(current, current->pos);
+                insert_char(current, current->pos - 1, c);
+                refreshLine(current->prompt, current);
+            }
+            break;
+        case ctrl('V'):    /* ctrl-v */
+            if (has_room(current, 3)) {
+                /* Insert the ^V first */
+                if (insert_char(current, current->pos, c)) {
+                    refreshLine(current->prompt, current);
+                    /* Now wait for the next char. Can insert anything except \0 */
+                    c = fd_read(current);
+
+                    /* Remove the ^V first */
+                    remove_char(current, current->pos - 1);
+                    if (c != -1) {
+                        /* Insert the actual char */
+                        insert_char(current, current->pos, c);
+                    }
+                    refreshLine(current->prompt, current);
+                }
+            }
+            break;
+        case ctrl('B'):
+        case SPECIAL_LEFT:
+            if (current->pos > 0) {
+                current->pos--;
+                refreshLine(current->prompt, current);
+            }
+            break;
+        case ctrl('F'):
+        case SPECIAL_RIGHT:
+            if (current->pos < current->chars) {
+                current->pos++;
+                refreshLine(current->prompt, current);
+            }
+            break;
+        case ctrl('P'):
+        case SPECIAL_UP:
+            dir = 1;
+        case ctrl('N'):
+        case SPECIAL_DOWN:
+            if (history_len > 1) {
+                /* Update the current history entry before to
+                 * overwrite it with tne next one. */
+                free(history[history_len-1-history_index]);
+                history[history_len-1-history_index] = strdup(current->buf);
+                /* Show the new entry */
+                history_index += dir;
+                if (history_index < 0) {
+                    history_index = 0;
+                    break;
+                } else if (history_index >= history_len) {
+                    history_index = history_len-1;
+                    break;
+                }
+                set_current(current, history[history_len-1-history_index]);
+                refreshLine(current->prompt, current);
+            }
+            break;
+
+        case SPECIAL_DELETE:
+            if (remove_char(current, current->pos) == 1) {
+                refreshLine(current->prompt, current);
+            }
+            break;
+        case SPECIAL_HOME:
+            current->pos = 0;
+            refreshLine(current->prompt, current);
+            break;
+        case SPECIAL_END:
+            current->pos = current->chars;
+            refreshLine(current->prompt, current);
+            break;
+        default:
+            /* Only tab is allowed without ^V */
+            if (c == '\t' || c >= ' ') {
+                if (insert_char(current, current->pos, c) == 1) {
+                    refreshLine(current->prompt, current);
+                }
+            }
+            break;
+        case ctrl('U'): /* Ctrl+u, delete to beginning of line. */
+            if (remove_chars(current, 0, current->pos)) {
+                refreshLine(current->prompt, current);
+            }
+            break;
+        case ctrl('K'): /* Ctrl+k, delete from current to end of line. */
+            if (remove_chars(current, current->pos, current->chars - current->pos)) {
+                refreshLine(current->prompt, current);
+            }
+            break;
+        case ctrl('A'): /* Ctrl+a, go to the start of the line */
+            current->pos = 0;
+            refreshLine(current->prompt, current);
+            break;
+        case ctrl('E'): /* ctrl+e, go to the end of the line */
+            current->pos = current->chars;
+            refreshLine(current->prompt, current);
+            break;
+        case ctrl('L'): /* Ctrl+L, clear screen */
+            /* clear screen */
+            clearScreen(current);
+            /* Force recalc of window size for serial terminals */
+            current->cols = 0;
+            refreshLine(current->prompt, current);
+            break;
+        }
+    }
+    return current->len;
+}
+
+char *linenoise(const char *prompt)
+{
+    int count;
+    struct current current;
+    char buf[LINENOISE_MAX_LINE];
+
+    if (enableRawMode(&current) == -1) {
+	printf("%s", prompt);
+        fflush(stdout);
+        if (fgets(buf, sizeof(buf), stdin) == NULL) {
+		return NULL;
+        }
+        count = strlen(buf);
+        if (count && buf[count-1] == '\n') {
+            count--;
+            buf[count] = '\0';
+        }
+    }
+    else
+    {
+        current.buf = buf;
+        current.bufmax = sizeof(buf);
+        current.len = 0;
+        current.chars = 0;
+        current.pos = 0;
+        current.prompt = prompt;
+
+        count = linenoisePrompt(&current);
+        disableRawMode(&current);
+        printf("\n");
+        if (count == -1) {
+            return NULL;
+        }
+    }
+    return strdup(buf);
+}
+
+/* Using a circular buffer is smarter, but a bit more complex to handle. */
+int linenoiseHistoryAdd(const char *line) {
+    char *linecopy;
+
+    if (history_max_len == 0) return 0;
+    if (history == NULL) {
+        history = (char**)malloc(sizeof(char*)*history_max_len);
+        if (history == NULL) return 0;
+        memset(history,0,(sizeof(char*)*history_max_len));
+    }
+    linecopy = strdup(line);
+    if (!linecopy) return 0;
+    if (history_len == history_max_len) {
+        free(history[0]);
+        memmove(history,history+1,sizeof(char*)*(history_max_len-1));
+        history_len--;
+    }
+    history[history_len] = linecopy;
+    history_len++;
+    return 1;
+}
+
+int linenoiseHistorySetMaxLen(int len) {
+    char **newHistory;
+
+    if (len < 1) return 0;
+    if (history) {
+        int tocopy = history_len;
+
+        newHistory = (char**)malloc(sizeof(char*)*len);
+        if (newHistory == NULL) return 0;
+        if (len < tocopy) tocopy = len;
+        memcpy(newHistory,history+(history_max_len-tocopy), sizeof(char*)*tocopy);
+        free(history);
+        history = newHistory;
+    }
+    history_max_len = len;
+    if (history_len > history_max_len)
+        history_len = history_max_len;
+    return 1;
+}
+
+/* Save the history in the specified file. On success 0 is returned
+ * otherwise -1 is returned. */
+int linenoiseHistorySave(const char *filename) {
+    FILE *fp = fopen(filename,"w");
+    int j;
+
+    if (fp == NULL) return -1;
+    for (j = 0; j < history_len; j++) {
+        const char *str = history[j];
+        /* Need to encode backslash, nl and cr */
+        while (*str) {
+            if (*str == '\\') {
+                fputs("\\\\", fp);
+            }
+            else if (*str == '\n') {
+                fputs("\\n", fp);
+            }
+            else if (*str == '\r') {
+                fputs("\\r", fp);
+            }
+            else {
+                fputc(*str, fp);
+            }
+            str++;
+        }
+        fputc('\n', fp);
+    }
+
+    fclose(fp);
+    return 0;
+}
+
+/* Load the history from the specified file. If the file does not exist
+ * zero is returned and no operation is performed.
+ *
+ * If the file exists and the operation succeeded 0 is returned, otherwise
+ * on error -1 is returned. */
+int linenoiseHistoryLoad(const char *filename) {
+    FILE *fp = fopen(filename,"r");
+    char buf[LINENOISE_MAX_LINE];
+
+    if (fp == NULL) return -1;
+
+    while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
+        char *src, *dest;
+
+        /* Decode backslash escaped values */
+        for (src = dest = buf; *src; src++) {
+            char ch = *src;
+
+            if (ch == '\\') {
+                src++;
+                if (*src == 'n') {
+                    ch = '\n';
+                }
+                else if (*src == 'r') {
+                    ch = '\r';
+                } else {
+                    ch = *src;
+                }
+            }
+            *dest++ = ch;
+        }
+        /* Remove trailing newline */
+        if (dest != buf && (dest[-1] == '\n' || dest[-1] == '\r')) {
+            dest--;
+        }
+        *dest = 0;
+
+        linenoiseHistoryAdd(buf);
+    }
+    fclose(fp);
+    return 0;
+}
+
+/* Provide access to the history buffer.
+ *
+ * If 'len' is not NULL, the length is stored in *len.
+ */
+char **linenoiseHistory(int *len) {
+    if (len) {
+        *len = history_len;
+    }
+    return history;
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/linenoise.h b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/linenoise.h
new file mode 100755
index 0000000..dcf22f7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/linenoise.h
@@ -0,0 +1,62 @@
+/* linenoise.h -- guerrilla line editing library against the idea that a
+ * line editing lib needs to be 20,000 lines of C code.
+ *
+ * See linenoise.c for more information.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  *  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *  *  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LINENOISE_H
+#define __LINENOISE_H
+
+/* Currently never enable completion */
+#define NO_COMPLETION
+
+#ifndef NO_COMPLETION
+typedef struct linenoiseCompletions {
+  size_t len;
+  char **cvec;
+} linenoiseCompletions;
+
+typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
+void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
+void linenoiseAddCompletion(linenoiseCompletions *, const char *);
+#endif
+
+char *linenoise(const char *prompt);
+int linenoiseHistoryAdd(const char *line);
+int linenoiseHistorySetMaxLen(int len);
+int linenoiseHistorySave(const char *filename);
+int linenoiseHistoryLoad(const char *filename);
+void linenoiseHistoryFree(void);
+char **linenoiseHistory(int *len);
+
+#endif /* __LINENOISE_H */
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/make-bootstrap-jim b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/make-bootstrap-jim
new file mode 100755
index 0000000..cc2cd5d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/make-bootstrap-jim
@@ -0,0 +1,104 @@
+#!/bin/sh
+
+# This script writes to stdout, a single source file (e.g. jimsh0.c)
+# which can be compiled to provide a bootstrap version of jimsh.
+# e.g. cc -o jimsh0 jimsh0.c
+
+makeext()
+{
+	source="$1"
+	basename=`basename "$source" .tcl`
+cat <<EOF
+int Jim_${basename}Init(Jim_Interp *interp)
+{
+	if (Jim_PackageProvide(interp, "$basename", "1.0", JIM_ERRMSG))
+		return JIM_ERR;
+
+	return Jim_EvalSource(interp, "$source", 1,
+EOF
+
+# Note: Keep newlines so that line numbers match in error messages
+sed -e 's/^[ 	]*#.*//' -e 's@\\@\\\\@g' -e 's@"@\\"@g' -e 's@^\(.*\)$@"\1\\n"@' $source
+
+echo ");"
+echo "}"
+}
+
+makeloadexts()
+{
+cat <<EOF
+int Jim_InitStaticExtensions(Jim_Interp *interp)
+EOF
+    echo "{"
+    for ext in $*; do
+        echo "extern int Jim_${ext}Init(Jim_Interp *);"
+    done
+    for ext in $*; do
+        echo "Jim_${ext}Init(interp);"
+    done
+    echo "return JIM_OK;"
+    echo "}"
+}
+
+cexts="aio readdir regexp file exec clock array"
+tclexts="bootstrap initjimsh glob stdlib tclcompat"
+
+# Note ordering
+allexts="bootstrap aio readdir glob regexp file exec clock array stdlib tclcompat"
+
+echo "/* This is single source file, bootstrap version of Jim Tcl. See http://jim.berlios.de/ */"
+
+# define some core features
+for i in _GNU_SOURCE JIM_TCL_COMPAT JIM_REFERENCES JIM_ANSIC JIM_REGEXP HAVE_NO_AUTOCONF _JIMAUTOCONF_H; do
+	echo "#define $i"
+done
+echo '#define TCL_LIBRARY "."'
+# and extensions
+for i in $allexts; do
+	echo "#define jim_ext_$i"
+done
+
+# Can we make a bootstrap jimsh work even on mingw32?
+cat <<EOF
+#if defined(__MINGW32__)
+#define TCL_PLATFORM_OS "mingw"
+#define TCL_PLATFORM_PLATFORM "windows"
+#define TCL_PLATFORM_PATH_SEPARATOR ";"
+#define HAVE_MKDIR_ONE_ARG
+#define HAVE_SYSTEM
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#else
+#define TCL_PLATFORM_OS "unknown"
+#define TCL_PLATFORM_PLATFORM "unix"
+#define TCL_PLATFORM_PATH_SEPARATOR ":"
+#define HAVE_VFORK
+#define HAVE_WAITPID
+#endif
+EOF
+
+outputsource()
+{
+        sed -e '/#include.*jim/d' -e '/#include.*utf8/d' \
+                -e '/^#.*if.*JIM_BOOTSTRAP/,/^#endif.*JIM_BOOTSTRAP/d' \
+                -e 's/\/\*.*\*\///' -e '/^[ 	]*\/\*/,/\*\//d' $1
+}
+
+# Now output header files, removing references to jim header files
+for i in utf8.h jim.h jim-subcmd.h jimregexp.h ; do
+	outputsource $i
+done
+
+# Now extension source code
+for i in $tclexts; do
+	makeext $i.tcl
+done
+for i in $cexts; do
+	outputsource jim-$i.c
+done
+makeloadexts $allexts
+
+# And finally the core source code
+for i in jim.c jim-subcmd.c utf8.c jim-interactive.c jim-format.c jimregexp.c jimsh.c; do
+	outputsource $i
+done
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/make-c-ext.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/make-c-ext.tcl
new file mode 100755
index 0000000..fd1a056
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/make-c-ext.tcl
@@ -0,0 +1,38 @@
+#!/usr/bin/env tclsh
+
+# Usage: make-c-ext.tcl source.tcl >jim-source.c
+
+# Converts a Tcl source file into C source suitable
+# for loading as a static extension.
+
+lassign $argv source
+
+if {![string match *.tcl $source]} {
+	error "Source $source is not a .tcl file"
+}
+
+# Read the Tcl source and convert to C
+# Note that no lines are removed in order to preserve line numbering
+set sourcelines {}
+set f [open $source]
+while {[gets $f buf] >= 0} {
+	# Remove comment lines
+	regsub {^[ \t]*#.*$} $buf "" buf
+	# Escape quotes and backlashes
+	set buf [string map [list \\ \\\\ \" \\"] $buf]
+	lappend sourcelines \"$buf\\n\"
+}
+close $f
+
+lappend lines {/* autogenerated - do not edit */}
+lappend lines {#include <jim.h>}
+set basename [file tail $source]
+set pkgname [file rootname $basename]
+
+lappend lines "int Jim_${pkgname}Init(Jim_Interp *interp)"
+lappend lines "\{"
+lappend lines "\tif (Jim_PackageProvide(interp, \"$pkgname\", \"1.0\", JIM_ERRMSG)) return JIM_ERR;"
+lappend lines "\treturn Jim_EvalSource(interp, \"$basename\", 1, [join $sourcelines \n]);"
+lappend lines "\}"
+
+puts [join $lines \n]
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/make-index b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/make-index
new file mode 100755
index 0000000..8dba920
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/make-index
@@ -0,0 +1,70 @@
+#!/usr/bin/env tclsh
+# vim:se syn=tcl:
+
+set filename [lindex $argv 0]
+set f [open $filename]
+
+# Read the file looking for command definitions
+set lines {}
+set commands {}
+array set cdict {}
+set c 0
+
+while {[gets $f buf] >= 0} {
+	if {[string match "~~*" $buf]} {
+		if {[string match "*:*" $prev]} {
+			incr c
+			set target cmd_$c
+			set lines [linsert $lines end-1 "\[\[$target\]\]"]
+		} else {
+			set target _$prev
+		}
+		foreach cmd [split $prev ":,"] {
+			set cmd [string trim $cmd]
+			if {[regexp {^[a-z.]+$} $cmd]} {
+				lappend commands [list $cmd $target]
+				set cdict($cmd) $target
+			}
+		}
+	}
+	lappend lines $buf
+	set prev $buf
+}
+close $f
+
+# Build the command index in the list: $index
+lappend index {[frame="none",grid="none"]}
+lappend index {|=========================}
+set i 0
+set row {}
+foreach command [lsort $commands] {
+	lassign $command cmd target
+
+	append row "|<<$target,*`$cmd`*>> "
+	incr i
+	if {$i % 8 == 0} {
+		lappend index $row
+		set row {}
+	}
+}
+while {$i % 8 != 0} {
+	incr i
+	append row "| "
+}
+lappend index $row
+lappend index {|=========================}
+
+# Map all `cmd` to <<$target,`cmd`>>
+set mapping {}
+foreach c [array names cdict] {
+	lappend mapping `$c` <<$cdict($c),*`$c`*>>
+	lappend mapping "`$c " "<<$cdict($c),*`$c`*>> `"
+}
+
+# And the command index
+lappend mapping @INSERTINDEX@ [join $index \n]
+
+# Output the result
+foreach line $lines {
+	puts [string map $mapping $line]
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/make-load-static-exts.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/make-load-static-exts.tcl
new file mode 100755
index 0000000..9185e77
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/make-load-static-exts.tcl
@@ -0,0 +1,48 @@
+#!/usr/bin/env tclsh
+
+# Usage: make-load-static-exts extname ... >load-static-exts.c
+
+# Creates load-static-exts.c based on the configured static extensions
+
+# There are some dependencies on static extensions which require
+# a certain load order. Do this by setting priorities and sorting.
+
+array set pri {
+    stdlib 0
+    readdir 1
+    glob 2
+    oo 1
+    tree 2
+    pack 1
+    binary 2
+}
+
+foreach i $argv {
+    set p 1
+    if {[info exists pri($i)]} {
+        set p $pri($i)
+    }
+    lappend exts [list $p $i]
+}
+set exts [lsort $exts]
+
+puts {
+/* autogenerated - do not edit */
+#include "jim.h"
+#include "jimautoconf.h"
+int Jim_InitStaticExtensions(Jim_Interp *interp)
+}
+puts \{
+
+foreach e $exts {
+    set ext [lindex $e 1]
+    puts "\textern int Jim_${ext}Init(Jim_Interp *);"
+}
+foreach e $exts {
+    set ext [lindex $e 1]
+    puts "\tJim_${ext}Init(interp);"
+}
+
+puts "\treturn JIM_OK;"
+
+puts \}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/parse-unidata.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/parse-unidata.tcl
new file mode 100755
index 0000000..4b5ec3a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/parse-unidata.tcl
@@ -0,0 +1,64 @@
+#!/usr/bin/env tclsh
+
+# Generate UTF-8 case mapping tables
+#
+# (c) 2010 Steve Bennett <steveb@workware.net.au>
+#
+# See LICENCE for licence details.
+#/
+
+# Parse the unicode data from: http://unicode.org/Public/UNIDATA/UnicodeData.txt
+# to generate case mapping tables
+
+set f [open [lindex $argv 0]]
+set extoff 0
+puts "static const struct casemap unicode_case_mapping\[\] = \{"
+while {[gets $f buf] >= 0} {
+	foreach {code name class x x x x x x x x x upper lower} [split $buf ";"] break
+	set code 0x$code
+	if {$code <= 0x7f} {
+		continue
+	}
+	if {$code > 0xffff} {
+		break
+	}
+	if {$class ne "Lu" && $class ne "Ll"} {
+		continue
+	}
+	if {$upper eq ""} {
+		set upper $code
+	} else {
+		set upper 0x$upper
+	}
+	if {$lower eq ""} {
+		set lower $code
+	} else {
+		set lower 0x$lower
+	}
+	if {$upper == $code && $lower == $code} {
+		continue
+	}
+	set l [expr {$lower - $code}]
+	set u [expr {$upper - $code}]
+	if {abs($u) > 127 || abs($l) > 127} {
+		# Can't encode both in one byte, so use indirection
+		lappend jumptable $code $lower $upper
+		set l -128
+		set u $extoff
+		incr extoff
+		if {$extoff > 0xff} {
+			error "Too many entries in the offset table!"
+		}
+	}
+	set entry [string tolower "$code, $l, $u"]
+	puts "    { $entry },"
+}
+close $f
+puts "\};\n"
+
+# Now the jump table
+puts "static const struct caseextmap unicode_extmap\[\] = \{"
+foreach {c l u} $jumptable {
+	puts "    { $l, $u },"
+}
+puts "\};\n"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/regtest.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/regtest.tcl
new file mode 100755
index 0000000..de796d9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/regtest.tcl
@@ -0,0 +1,158 @@
+# REGTEST 1
+# 27Jan2005 - SIGSEGV for bug on Jim_DuplicateObj().
+
+for {set i 0} {$i < 100} {incr i} {
+    set a "x"
+    lappend a n
+}
+puts "TEST 1 PASSED"
+
+# REGTEST 2
+# 29Jan2005 - SEGFAULT parsing script composed of just one comment.
+eval {#foobar}
+puts "TEST 2 PASSED"
+
+# REGTEST 3
+# 29Jan2005 - "Error in Expression" with correct expression
+set x 5
+expr {$x-5}
+puts "TEST 3 PASSED"
+
+# REGTEST 4
+# 29Jan2005 - SIGSEGV when run this code, due to expr's bug.
+proc fibonacci {x} {
+    if {$x <= 1} {
+    expr 1
+    } else {
+    expr {[fibonacci [expr {$x-1}]] + [fibonacci [expr {$x-2}]]}
+    }
+}
+fibonacci 6
+puts "TEST 4 PASSED"
+
+# REGTEST 5
+# 06Mar2005 - This looped forever...
+for {set i 0} {$i < 10} {incr i} {continue}
+puts "TEST 5 PASSED"
+
+# REGTEST 6
+# 07Mar2005 - Unset create variable + dict is using dict syntax sugar at
+#             currently non-existing variable
+catch {unset thisvardoesnotexists(thiskeytoo)}
+if {[catch {set thisvardoesnotexists}] == 0} {
+  puts "TEST 6 FAILED - unset created dict for non-existing variable"
+  break
+}
+puts "TEST 6 PASSED"
+
+# REGTEST 7
+# 04Nov2008 - variable parsing does not eat last brace
+set a 1
+list ${a}
+puts "TEST 7 PASSED"
+
+# REGTEST 8
+# 04Nov2008 - string toupper/tolower do not convert to string rep
+string tolower [list a]
+string toupper [list a]
+puts "TEST 8 PASSED"
+
+# REGTEST 9
+# 04Nov2008 - crash on exit when replacing Tcl proc with C command.
+# Requires the clock extension to be built as a loadable module.
+proc clock {args} {}
+catch {package require clock}
+# Note, crash on exit, so don't say we passed!
+
+# REGTEST 10
+# 05Nov2008 - incorrect lazy expression evaluation with unary not
+expr {1 || !0}
+puts "TEST 10 PASSED"
+
+# REGTEST 11
+# 14 Feb 2010 - access static variable in deleted proc
+proc a {} {{x 1}} { rename a ""; incr x }
+a
+puts "TEST 11 PASSED"
+
+# REGTEST 12
+# 13 Sep 2010 - reference with invalid tag
+set a b[ref value "tag name"]
+getref [string range $a 1 end]
+puts "TEST 12 PASSED"
+
+# REGTEST 13
+# 14 Sep 2010 - parse list with trailing backslash
+set x "switch -0 \$on \\"
+lindex $x 1
+puts "TEST 13 PASSED"
+
+# REGTEST 14
+# 14 Sep 2010 - command expands to nothing
+eval "{*}{}"
+puts "TEST 14 PASSED"
+
+# REGTEST 15
+# 24 Feb 2010 - bad reference counting of the stack trace in 'error'
+proc a {msg stack} {
+    tailcall error $msg $stack
+}
+catch {fail} msg opts
+catch {a $msg $opts(-errorinfo)}
+
+# REGTEST 16
+# 24 Feb 2010 - rename the current proc
+# Leaves unfreed objects on the stack
+proc a {} { rename a newa}
+a
+
+# REGTEST 17
+# 26 Nov 2010 - crashes on invalid dict sugar
+catch {eval {$x(}}
+puts "TEST 17 PASSED"
+
+# REGTEST 18
+# 12 Apr 2011 - crashes on unset for loop var
+catch {
+    for {set i 0} {$i < 5} {incr i} {unset i}
+}
+puts "TEST 18 PASSED"
+
+# REGTEST 19
+# 25 May 2011 - crashes with double colon
+catch {
+    expr {5 ne ::}
+}
+puts "TEST 19 PASSED"
+
+# REGTEST 20
+# 26 May 2011 - infinite recursion
+proc a {} { global ::blah; set ::blah test }
+a
+puts "TEST 20 PASSED"
+
+# REGTEST 21
+# 26 May 2011 - infinite loop with null byte in subst
+subst "abc\0def"
+puts "TEST 21 PASSED"
+
+# REGTEST 22
+# 21 June 2011 - crashes on lappend to to value with script rep
+set x rand
+eval $x
+lappend x b
+puts "TEST 22 PASSED"
+
+# REGTEST 23
+# 27 July 2011 - unfreed objects on exit
+catch {
+    set x abc
+    subst $x
+    regexp $x $x
+}
+# Actually, the test passes if no objects leaked on exit
+puts "TEST 23 PASSED"
+
+# TAKE THE FOLLOWING puts AS LAST LINE
+
+puts "--- ALL TESTS PASSED ---"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/rlprompt.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/rlprompt.tcl
new file mode 100755
index 0000000..cdd78d4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/rlprompt.tcl
@@ -0,0 +1,45 @@
+# Readline-based interactive shell for Jim
+# Copyright(C) 2005 Salvatore Sanfilippo <antirez@invece.org>
+#
+# In order to automatically have readline-editing features
+# put this in your $HOME/.jimrc
+#
+# if {$jim_interactive} {
+#    if {[catch {package require rlprompt}] == 0} {
+#       rlprompt.shell
+#    }
+# }
+package require readline
+
+proc rlprompt.shell {} {
+    puts "Readline shell loaded"
+    puts "Welcome to Jim [info version]!"
+    set prompt ". "
+    set buf ""
+    while 1 {
+        set line [readline.readline $prompt]
+
+        if {[string length $line] == 0} {
+            continue
+        }
+        if {$buf eq ""} {
+            set buf $line
+        } else {
+            append buf \n $line
+        }
+        if {![info complete $buf]} {
+            set prompt "> "
+            continue
+        }
+        readline.addhistory $buf
+
+        catch {
+            uplevel #0 $buf
+        } error
+        if {$error ne ""} {
+            puts $error
+        }
+        set buf ""
+        set prompt ". "
+    }
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/stdlib.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/stdlib.tcl
new file mode 100755
index 0000000..3abeb3e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/stdlib.tcl
@@ -0,0 +1,150 @@
+# Create a single word alias (proc) for one or more words
+# e.g. alias x info exists
+# if {[x var]} ...
+proc alias {name args} {
+	set prefix $args
+	proc $name args prefix {
+		tailcall {*}$prefix {*}$args
+	}
+}
+
+# Creates an anonymous procedure
+proc lambda {arglist args} {
+	set name [ref {} function lambda.finalizer]
+	tailcall proc $name $arglist {*}$args
+}
+
+proc lambda.finalizer {name val} {
+	rename $name {}
+}
+
+# Like alias, but creates and returns an anonyous procedure
+proc curry {args} {
+	set prefix $args
+	lambda args prefix {
+		tailcall {*}$prefix {*}$args
+	}
+}
+
+# Returns the given argument.
+# Useful with 'local' as follows:
+#   proc a {} {...}
+#   local function a 
+#
+#   set x [lambda ...]
+#   local function $x
+#
+proc function {value} {
+	return $value
+}
+
+# Tcl 8.5 lassign
+proc lassign {list args} {
+	# in case the list is empty...
+	lappend list {}
+	uplevel 1 [list foreach $args $list break]
+	lrange $list [llength $args] end-1
+}
+
+# Returns a list of proc filename line ...
+# with 3 entries for each stack frame (proc),
+# (deepest level first)
+proc stacktrace {} {
+	set trace {}
+	foreach level [range 1 [info level]] {
+		lassign [info frame -$level] p f l
+		lappend trace $p $f $l
+	}
+	return $trace
+}
+
+# Returns a human-readable version of a stack trace
+proc stackdump {stacktrace} {
+	set result {}
+	set count 0
+	foreach {l f p} [lreverse $stacktrace] {
+		if {$count} {
+			append result \n
+		}
+		incr count
+		if {$p ne ""} {
+			append result "in procedure '$p' "
+			if {$f ne ""} {
+				append result "called "
+			}
+		}
+		if {$f ne ""} {
+			append result "at file \"$f\", line $l"
+		}
+	}
+	return $result
+}
+
+# Sort of replacement for $::errorInfo
+# Usage: errorInfo error ?stacktrace?
+proc errorInfo {msg {stacktrace ""}} {
+	if {$stacktrace eq ""} {
+		set stacktrace [info stacktrace]
+	}
+	lassign $stacktrace p f l
+	if {$f ne ""} {
+		set result "Runtime Error: $f:$l: "
+	}
+	append result "$msg\n"
+	append result [stackdump $stacktrace]
+
+	# Remove the trailing newline
+	string trim $result
+}
+
+# Finds the current executable by searching along the path
+# Returns the empty string if not found.
+proc {info nameofexecutable} {} {
+	if {[info exists ::jim_argv0]} {
+		if {[string match "*/*" $::jim_argv0]} {
+			return [file join [pwd] $::jim_argv0]
+		}
+		foreach path [split [env PATH ""] $::tcl_platform(pathSeparator)] {
+			set exec [file join [pwd] $path $::jim_argv0]
+			if {[file executable $exec]} {
+				return $exec
+			}
+		}
+	}
+	return ""
+}
+
+# Script-based implementation of 'dict with'
+proc {dict with} {dictVar args script} {
+	upvar $dictVar dict
+	set keys {}
+	foreach {n v} [dict get $dict {*}$args] {
+		upvar $n var_$n
+		set var_$n $v
+		lappend keys $n
+	}
+	catch {uplevel 1 $script} msg opts
+	if {[info exists dict] && [dict exists $dict {*}$args]} {
+		foreach n $keys {
+			if {[info exists var_$n]} {
+				dict set dict {*}$args $n [set var_$n]
+			} else {
+				dict unset dict {*}$args $n
+			}
+		}
+	}
+	return {*}$opts $msg
+}
+
+# Script-based implementation of 'dict merge'
+# This won't get called in the trivial case of no args
+proc {dict merge} {dict args} {
+	foreach d $args {
+		# Check for a valid dict
+		dict size $d
+		foreach {k v} $d {
+			dict set dict $k $v
+		}
+	}
+	return $dict
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/tcl.license.terms b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/tcl.license.terms
new file mode 100755
index 0000000..f1dcaa5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/tcl.license.terms
@@ -0,0 +1,40 @@
+This software is copyrighted by the Regents of the University of
+California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
+Corporation and other parties.  The following terms apply to all files
+associated with the software unless explicitly disclaimed in
+individual files.
+
+The authors hereby grant permission to use, copy, modify, distribute,
+and license this software and its documentation for any purpose, provided
+that existing copyright notices are retained in all copies and that this
+notice is included verbatim in any distributions. No written agreement,
+license, or royalty fee is required for any of the authorized uses.
+Modifications to this software may be copyrighted by their authors
+and need not follow the licensing terms described here, provided that
+the new terms are clearly indicated on the first page of each file where
+they apply.
+
+IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
+IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+MODIFICATIONS.
+
+GOVERNMENT USE: If you are acquiring this software on behalf of the
+U.S. government, the Government shall have only "Restricted Rights"
+in the software and related documentation as defined in the Federal 
+Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
+are acquiring the software on behalf of the Department of Defense, the
+software shall be classified as "Commercial Computer Software" and the
+Government shall have only "Restricted Rights" as defined in Clause
+252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
+authors grant the U.S. Government and others acting in its behalf
+permission to use and distribute the software in accordance with the
+terms specified in this license. 
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/tclcompat.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/tclcompat.tcl
new file mode 100755
index 0000000..8e5b128
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/tclcompat.tcl
@@ -0,0 +1,279 @@
+# (c) 2008 Steve Bennett <steveb@workware.net.au>
+#
+# Loads some Tcl-compatible features.
+# I/O commands, case, lassign, parray, errorInfo, ::tcl_platform, ::env
+# try, throw, file copy, file delete -force
+
+# Set up the ::env array
+set env [env]
+
+if {[info commands stdout] ne ""} {
+	# Tcl-compatible I/O commands
+	foreach p {gets flush close eof seek tell} {
+		proc $p {chan args} {p} {
+			tailcall $chan $p {*}$args
+		}
+	}
+	unset p
+
+	# puts is complicated by -nonewline
+	#
+	proc puts {{-nonewline {}} {chan stdout} msg} {
+		if {${-nonewline} ni {-nonewline {}}} {
+			tailcall ${-nonewline} puts $msg
+		}
+		tailcall $chan puts {*}${-nonewline} $msg
+	}
+
+	# read is complicated by -nonewline
+	#
+	# read chan ?maxchars?
+	# read -nonewline chan
+	proc read {{-nonewline {}} chan} {
+		if {${-nonewline} ni {-nonewline {}}} {
+			tailcall ${-nonewline} read {*}${chan}
+		}
+		tailcall $chan read {*}${-nonewline}
+	}
+
+	proc fconfigure {f args} {
+		foreach {n v} $args {
+			switch -glob -- $n {
+				-bl* {
+					$f ndelay $v
+				}
+				-bu* {
+					$f buffering $v
+				}
+				-tr* {
+					# Just ignore -translation
+				}
+				default {
+					return -code error "fconfigure: unknown option $n"
+				}
+			}
+		}
+	}
+}
+
+# case var ?in? pattern action ?pattern action ...?
+proc case {var args} {
+	# Skip dummy parameter
+	if {[lindex $args 0] eq "in"} {
+		set args [lrange $args 1 end]
+	}
+
+	# Check for single arg form
+	if {[llength $args] == 1} {
+		set args [lindex $args 0]
+	}
+
+	# Check for odd number of args
+	if {[llength $args] % 2 != 0} {
+		return -code error "extra case pattern with no body"
+	}
+
+	# Internal function to match a value agains a list of patterns
+	local proc case.checker {value pattern} {
+		string match $pattern $value
+	}
+
+	foreach {value action} $args {
+		if {$value eq "default"} {
+			set do_action $action
+			continue
+		} elseif {[lsearch -bool -command case.checker $value $var]} {
+			set do_action $action
+			break
+		}
+	}
+
+	if {[info exists do_action]} {
+		set rc [catch [list uplevel 1 $do_action] result opts]
+		if {$rc} {
+			incr opts(-level)
+		}
+		return {*}$opts $result
+	}
+}
+
+# fileevent isn't needed in Jim, but provide it for compatibility
+proc fileevent {args} {
+	tailcall {*}$args
+}
+
+# Second, option argument is a glob pattern
+# Third, optional argument is a "putter" function
+# 
+proc parray {arrayname {pattern *} {puts puts}} {
+	upvar $arrayname a
+
+	set max 0
+	foreach name [array names a $pattern]] {
+		if {[string length $name] > $max} {
+			set max [string length $name]
+		}
+	}
+	incr max [string length $arrayname]
+	incr max 2
+	foreach name [lsort [array names a $pattern]] {
+		$puts [format "%-${max}s = %s" $arrayname\($name\) $a($name)]
+	}
+}
+
+# Implements 'file copy' - single file mode only
+proc {file copy} {{force {}} source target} {
+	try {
+		if {$force ni {{} -force}} {
+			error "bad option \"$force\": should be -force"
+		}
+
+		set in [open $source]
+
+		if {$force eq "" && [file exists $target]} {
+			$in close
+			error "error copying \"$source\" to \"$target\": file already exists"
+		}
+		set out [open $target w]
+		$in copyto $out
+		$out close
+	} on error {msg opts} {
+		incr opts(-level)
+		return {*}$opts $msg
+	} finally {
+		catch {$in close}
+	}
+}
+
+# 'open "|..." ?mode?" will invoke this wrapper around exec/pipe
+# Note that we return a lambda which also provides the 'pid' command
+proc popen {cmd {mode r}} {
+	lassign [socket pipe] r w
+	try {
+		if {[string match "w*" $mode]} {
+			lappend cmd <@$r &
+			set pids [exec {*}$cmd]
+			$r close
+			set f $w
+		} else {
+			lappend cmd >@$w &
+			set pids [exec {*}$cmd]
+			$w close
+			set f $r
+		}
+		lambda {cmd args} {f pids} {
+			if {$cmd eq "pid"} {
+				return $pids
+			}
+			if {$cmd eq "close"} {
+				$f close
+				# And wait for the child processes to complete
+				foreach p $pids { os.wait $p }
+				return
+			}
+			tailcall $f $cmd {*}$args
+		}
+	} on error {error opts} {
+		$r close
+		$w close
+		error $error
+	}
+}
+
+# A wrapper around 'pid' which can return the pids for 'popen'
+local proc pid {{chan {}}} {
+	if {$chan eq ""} {
+		tailcall upcall pid
+	}
+	if {[catch {$chan tell}]} {
+		return -code error "can not find channel named \"$chan\""
+	}
+	if {[catch {$chan pid} pids]} {
+		return ""
+	}
+	return $pids
+}
+
+# try/on/finally conceptually similar to Tcl 8.6
+#
+# Usage: try ?catchopts? script ?onclause ...? ?finallyclause?
+#
+# Where:
+#   onclause is:       on codes {?resultvar? ?optsvar?} script
+#
+#   codes is: a list of return codes (ok, error, etc. or integers), or * for any
+#
+#   finallyclause is:  finally script
+#
+#
+# Where onclause is: on codes {?resultvar? ?optsvar?}
+proc try {args} {
+	set catchopts {}
+	while {[string match -* [lindex $args 0]]} {
+		set args [lassign $args opt]
+		if {$opt eq "--"} {
+			break
+		}
+		lappend catchopts $opt
+	}
+	if {[llength $args] == 0} {
+		return -code error {wrong # args: should be "try ?options? script ?argument ...?"}
+	}
+	set args [lassign $args script]
+	set code [catch -eval {*}$catchopts [list uplevel 1 $script] msg opts]
+
+	set handled 0
+
+	foreach {on codes vars script} $args {
+		switch -- $on \
+			on {
+				if {!$handled && ($codes eq "*" || [info returncode $code] in $codes)} {
+					lassign $vars msgvar optsvar
+					if {$msgvar ne ""} {
+						upvar $msgvar hmsg
+						set hmsg $msg
+					}
+					if {$optsvar ne ""} {
+						upvar $optsvar hopts
+						set hopts $opts
+					}
+					# Override any body result
+					set code [catch [list uplevel 1 $script] msg opts]
+					incr handled
+				}
+			} \
+			finally {
+				set finalcode [catch [list uplevel 1 $codes] finalmsg finalopts]
+				if {$finalcode} {
+					# Override any body or handler result
+					set code $finalcode
+					set msg $finalmsg
+					set opts $finalopts
+				}
+				break
+			} \
+			default {
+				return -code error "try: expected 'on' or 'finally', got '$on'"
+			}
+	}
+
+	if {$code} {
+		incr opts(-level)
+		return {*}$opts $msg
+	}
+	return $msg
+}
+
+# Generates an exception with the given code (ok, error, etc. or an integer)
+# and the given message
+proc throw {code {msg ""}} {
+	return -code $code $msg
+}
+
+# Helper for "file delete -force"
+proc {file delete force} {path} {
+	foreach e [readdir $path] {
+		file delete -force $path/$e
+	}
+	file delete $path
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/tree.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/tree.tcl
new file mode 100755
index 0000000..01fc167
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/tree.tcl
@@ -0,0 +1,219 @@
+# Conceptually compatible with tcllib ::struct::tree
+# but uses an object based interface.
+# To mimic tcllib, do:
+#   rename [tree] mytree
+
+package require oo
+
+# set pt [tree]
+#
+#   Create a tree
+#   This automatically creates a node named "root"
+#
+# $pt destroy
+#
+#   Destroy the tree and all it's nodes
+#
+# $pt set <nodename> <key> <value>
+#
+#   Set the value for the given key
+#
+# $pt lappend <nodename> <key> <value> ...
+#
+#   Append to the (list) value(s) for the given key, or set if not yet set
+#
+# $pt keyexists <nodename> <key>
+#
+#   Returns 1 if the given key exists
+#
+# $pt get <nodename> <key>
+#
+#   Returns the value associated with the given key
+# 
+# $pt getall <nodename>
+#
+#   Returns the entire attribute dictionary associated with the given key
+# 
+# $pt depth <nodename>
+#
+#   Returns the depth of the given node. The depth of "root" is 0.
+#
+# $pt parent <nodename>
+#
+#   Returns the name of the parent node, or "" for the root node.
+# 
+# $pt numchildren <nodename>
+#
+#   Returns the number of child nodes.
+# 
+# $pt children <nodename>
+#
+#   Returns a list of the child nodes.
+# 
+# $pt next <nodename>
+#
+#   Returns the next sibling node, or "" if none.
+# 
+# $pt insert <nodename> ?index?
+#
+#   Add a new child node to the given node.
+#   THe default index is "end"
+#   Returns the name of the newly added node
+#
+# $pt walk <nodename> dfs|bfs {actionvar nodevar} <code>
+#
+#   Walks the tree starting from the given node, either breadth first (bfs)
+#   depth first (dfs).
+#   The value "enter" or "exit" is stored in variable $actionvar
+#   The name of each node is stored in $nodevar.
+#   The script $code is evaluated twice for each node, on entry and exit.
+#
+# $pt dump
+#
+#   Dumps the tree contents to stdout
+
+#------------------------------------------
+# Internal implementation.
+# The tree class has 4 instance variables.
+# - tree is a dictionary. key=node, value=node value dictionary
+# - parent is a dictionary. key=node, value=parent of this node
+# - children is a dictionary. key=node, value=list of child nodes for this node
+# - nodeid is an integer which increments to give each node a unique id
+
+# Construct a tree with a single root node with no parent and no children
+class tree {
+	tree {root {}}
+	parents {root {}}
+	children {root {}}
+	nodeid 0
+}
+
+# Simply walk up the tree to get the depth
+tree method depth {node} {
+	set depth 0
+	while {$node ne "root"} {
+		incr depth
+		set node [dict get $parents $node]
+	}
+	return $depth
+}
+
+tree method parent {node} {
+	dict get $parents $node
+}
+
+tree method children {node} {
+	dict get $children $node
+}
+
+tree method numchildren {node} {
+	llength [dict get $children $node]
+}
+
+tree method next {node} {
+	# My siblings are my parents children
+	set siblings [dict get $children [dict get $parents $node]]
+	# Find me
+	set i [lsearch $siblings $node]
+	incr i
+	lindex $siblings $i
+}
+
+tree method set {node key value} {
+	dict set tree $node $key $value
+	return $value
+}
+
+tree method get {node key} {
+	dict get $tree $node $key
+}
+
+tree method keyexists {node key} {
+	dict exists $tree $node $key
+}
+
+tree method getall {node} {
+	dict get $tree $node
+}
+
+tree method insert {node {index end}} {
+
+	# Make a new node and add it to the tree
+	set childname node[incr nodeid]
+	dict set tree $childname {}
+
+	# The new node has no children
+	dict set children $childname {}
+
+	# Set the parent
+	dict set parents $childname $node
+
+	# And add it as a child
+	set nodes [dict get $children $node]
+	dict set children $node [linsert $nodes $index $childname]
+
+	return $childname
+}
+
+tree method lappend {node key args} {
+	if {[dict exists $tree $node $key]} {
+		set result [dict get $tree $node $key]
+	}
+	lappend result {*}$args
+	dict set tree $node $key $result
+	return $result
+}
+
+# $tree walk node bfs|dfs {action loopvar} <code>
+#
+tree method walk {node type vars code} {
+	# set up vars
+	lassign $vars actionvar namevar
+
+	set n $node
+
+	if {$type ne "child"} {
+		upvar 2 $namevar name $actionvar action
+
+		# Enter this node
+		set name $node
+		set action enter
+
+		uplevel 2 $code
+	}
+
+	if {$type eq "dfs"} {
+		# Depth-first so do the children
+		foreach child [$self children $n] {
+			uplevel 2 [list $self walk $child $type $vars $code]
+		}
+	} elseif {$type ne "none"} {
+		# Breadth-first so do the children to one level only
+		foreach child [$self children $n] {
+			uplevel 2 [list $self walk $child none $vars $code]
+		}
+
+		# Now our grandchildren
+		foreach child [$self children $n] {
+			uplevel 2 [list $self walk $child child $vars $code]
+		}
+	}
+
+	if {$type ne "child"} {
+		# Exit this node
+		set name $node
+		set action exit
+
+		uplevel 2 $code
+	}
+}
+
+tree method dump {} {
+	$self walk root dfs {action n} {
+		set indent [string repeat "  " [$self depth $n]]
+		if {$action eq "enter"} {
+			puts "$indent$n ([$self getall $n])"
+		}
+	}
+	puts ""
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/utf8.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/utf8.c
new file mode 100755
index 0000000..a81b3de
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/utf8.c
@@ -0,0 +1,192 @@
+/**
+ * UTF-8 utility functions
+ *
+ * (c) 2010 Steve Bennett <steveb@workware.net.au>
+ *
+ * See LICENCE for licence details.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include "utf8.h"
+
+/* This one is always implemented */
+int utf8_fromunicode(char *p, unsigned short uc)
+{
+    if (uc <= 0x7f) {
+        *p = uc;
+        return 1;
+    }
+    else if (uc <= 0x7ff) {
+        *p++ = 0xc0 | ((uc & 0x7c0) >> 6);
+        *p = 0x80 | (uc & 0x3f);
+        return 2;
+    }
+    else {
+        *p++ = 0xe0 | ((uc & 0xf000) >> 12);
+        *p++ = 0x80 | ((uc & 0xfc0) >> 6);
+        *p = 0x80 | (uc & 0x3f);
+        return 3;
+    }
+}
+
+#if defined(JIM_UTF8) && !defined(JIM_BOOTSTRAP)
+int utf8_charlen(int c)
+{
+    if ((c & 0x80) == 0) {
+        return 1;
+    }
+    if ((c & 0xe0) == 0xc0) {
+        return 2;
+    }
+    if ((c & 0xf0) == 0xe0) {
+        return 3;
+    }
+    if ((c & 0xf8) == 0xf0) {
+        return 4;
+    }
+    /* Invalid sequence */
+    return -1;
+}
+
+int utf8_strlen(const char *str, int bytelen)
+{
+    int charlen = 0;
+    if (bytelen < 0) {
+        bytelen = strlen(str);
+    }
+    while (bytelen) {
+        int c;
+        int l = utf8_tounicode(str, &c);
+        charlen++;
+        str += l;
+        bytelen -= l;
+    }
+    return charlen;
+}
+
+int utf8_index(const char *str, int index)
+{
+    const char *s = str;
+    while (index--) {
+        int c;
+        s += utf8_tounicode(s, &c);
+    }
+    return s - str;
+}
+
+int utf8_charequal(const char *s1, const char *s2)
+{
+    int c1, c2;
+
+    utf8_tounicode(s1, &c1);
+    utf8_tounicode(s2, &c2);
+
+    return c1 == c2;
+}
+
+int utf8_prev_len(const char *str, int len)
+{
+    int n = 1;
+
+    assert(len > 0);
+
+    /* Look up to len chars backward for a start-of-char byte */
+    while (--len) {
+        if ((str[-n] & 0x80) == 0) {
+            /* Start of a 1-byte char */
+            break;
+        }
+        if ((str[-n] & 0xc0) == 0xc0) {
+            /* Start of a multi-byte char */
+            break;
+        }
+        n++;
+    }
+    return n;
+}
+
+int utf8_tounicode(const char *str, int *uc)
+{
+    unsigned const char *s = (unsigned const char *)str;
+
+    if (s[0] < 0xc0) {
+        *uc = s[0];
+        return 1;
+    }
+    if (s[0] < 0xe0) {
+        if ((s[1] & 0xc0) == 0x80) {
+            *uc = ((s[0] & ~0xc0) << 6) | (s[1] & ~0x80);
+            return 2;
+        }
+    }
+    else if (s[0] < 0xf0) {
+        if (((str[1] & 0xc0) == 0x80) && ((str[2] & 0xc0) == 0x80)) {
+            *uc = ((s[0] & ~0xe0) << 12) | ((s[1] & ~0x80) << 6) | (s[2] & ~0x80);
+            return 3;
+        }
+    }
+
+    /* Invalid sequence, so just return the byte */
+    *uc = *s;
+    return 1;
+}
+
+struct casemap {
+    unsigned short code;    /* code point */
+    signed char lowerdelta; /* add for lowercase, or if -128 use the ext table */
+    signed char upperdelta; /* add for uppercase, or offset into the ext table */
+};
+
+/* Extended table for codepoints where |delta| > 127 */
+struct caseextmap {
+    unsigned short lower;
+    unsigned short upper;
+};
+
+/* Generated mapping tables */
+#include "_unicode_mapping.c"
+
+#define NUMCASEMAP sizeof(unicode_case_mapping) / sizeof(*unicode_case_mapping)
+
+static int cmp_casemap(const void *key, const void *cm)
+{
+    return *(int *)key - (int)((const struct casemap *)cm)->code;
+}
+
+static int utf8_map_case(int uc, int upper)
+{
+    const struct casemap *cm = bsearch(&uc, unicode_case_mapping, NUMCASEMAP, sizeof(*unicode_case_mapping), cmp_casemap);
+
+    if (cm) {
+        if (cm->lowerdelta == -128) {
+            uc = upper ? unicode_extmap[cm->upperdelta].upper : unicode_extmap[cm->upperdelta].lower;
+        }
+        else {
+            uc += upper ? cm->upperdelta : cm->lowerdelta;
+        }
+    }
+    return uc;
+}
+
+int utf8_upper(int uc)
+{
+    if (isascii(uc)) {
+        return toupper(uc);
+    }
+    return utf8_map_case(uc, 1);
+}
+
+int utf8_lower(int uc)
+{
+    if (isascii(uc)) {
+        return tolower(uc);
+    }
+
+    return utf8_map_case(uc, 0);
+}
+
+#endif /* JIM_BOOTSTRAP */
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/utf8.h b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/utf8.h
new file mode 100755
index 0000000..9ada93f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/jim/utf8.h
@@ -0,0 +1,110 @@
+#ifndef UTF8_UTIL_H
+#define UTF8_UTIL_H
+/**
+ * UTF-8 utility functions
+ *
+ * (c) 2010 Steve Bennett <steveb@workware.net.au>
+ *
+ * See LICENCE for licence details.
+ */
+#include <jim-config.h>
+
+/**
+ * Converts the given unicode codepoint (0 - 0xffff) to utf-8
+ * and stores the result at 'p'.
+ *
+ * Returns the number of utf-8 characters (1-3).
+ */
+int utf8_fromunicode(char *p, unsigned short uc);
+
+#ifndef JIM_UTF8
+#include <ctype.h>
+
+/* No utf-8 support. 1 byte = 1 char */
+#define utf8_strlen(S, B) ((B) < 0 ? strlen(S) : (B))
+#define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
+#define utf8_upper(C) toupper(C)
+#define utf8_lower(C) tolower(C)
+#define utf8_index(C, I) (I)
+#define utf8_charlen(C) 1
+#define utf8_prev_len(S, L) 1
+
+#else
+#if !defined(JIM_BOOTSTRAP)
+/**
+ * Returns the length of the utf-8 sequence starting with 'c'.
+ *
+ * Returns 1-4, or -1 if this is not a valid start byte.
+ *
+ * Note that charlen=4 is not supported by the rest of the API.
+ */
+int utf8_charlen(int c);
+
+/**
+ * Returns the number of characters in the utf-8
+ * string of the given byte length.
+ *
+ * Any bytes which are not part of an valid utf-8
+ * sequence are treated as individual characters.
+ *
+ * The string *must* be null terminated.
+ *
+ * Does not support unicode code points > \uffff
+ */
+int utf8_strlen(const char *str, int bytelen);
+
+/**
+ * Returns the byte index of the given character in the utf-8 string.
+ *
+ * The string *must* be null terminated.
+ *
+ * This will return the byte length of a utf-8 string
+ * if given the char length.
+ */
+int utf8_index(const char *str, int charindex);
+
+/**
+ * Returns the unicode codepoint corresponding to the
+ * utf-8 sequence 'str'.
+ *
+ * Stores the result in *uc and returns the number of bytes
+ * consumed.
+ *
+ * If 'str' is null terminated, then an invalid utf-8 sequence
+ * at the end of the string will be returned as individual bytes.
+ *
+ * If it is not null terminated, the length *must* be checked first.
+ *
+ * Does not support unicode code points > \uffff
+ */
+int utf8_tounicode(const char *str, int *uc);
+
+/**
+ * Returns the number of bytes before 'str' that the previous
+ * utf-8 character sequence starts (which may be the middle of a sequence).
+ *
+ * Looks back at most 'len' bytes backwards, which must be > 0.
+ * If no start char is found, returns -len
+ */
+int utf8_prev_len(const char *str, int len);
+
+/**
+ * Returns the upper-case variant of the given unicode codepoint.
+ *
+ * Does not support unicode code points > \uffff
+ */
+int utf8_upper(int uc);
+
+/**
+ * Returns the lower-case variant of the given unicode codepoint.
+ *
+ * NOTE: Use utf8_upper() in preference for case-insensitive matching.
+ *
+ * Does not support unicode code points > \uffff
+ */
+int utf8_lower(int uc);
+#endif /* JIM_BOOTSTRAP */
+
+#endif
+
+#endif
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/make_string.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/make_string.tcl
new file mode 100755
index 0000000..5a1b5ff
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/make_string.tcl
@@ -0,0 +1,31 @@
+#!/usr/bin/env tclsh
+
+# (c) Josua Dietze 2012
+#
+# Usage: make_string.tcl source.tcl >jim-source.c
+
+# Converts a Tcl source file into C source suitable
+# for using as an embedded script.
+
+set source [lindex $argv 0]
+
+if {![string match *.tcl $source]} {
+	error "Source $source is not a .tcl file"
+}
+
+# Read the Tcl source and convert to C macro
+set sourcelines {}
+set f [open $source]
+while {[gets $f buf] >= 0} {
+	# Remove comment lines
+	regsub {^[ \t]*#.*$} $buf "" buf
+	# Remove leading whitespaces
+	set buf [string trimleft $buf]
+	# Escape quotes and backlashes
+	set buf [string map [list \\ \\\\ \" \\"] $buf]
+	if [string length $buf] {
+		lappend sourcelines "$buf\\n"
+	}
+}
+close $f
+puts "#define RAW \"[join $sourcelines ""]\""
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb-modeswitch-upstart.conf b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb-modeswitch-upstart.conf
new file mode 100755
index 0000000..570ca65
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb-modeswitch-upstart.conf
@@ -0,0 +1,5 @@
+start on usb-modeswitch-upstart
+task
+script
+	exec /usr/sbin/usb_modeswitch_dispatcher --switch-upstart $UMS_PARAM
+end script
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.1 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.1
new file mode 100755
index 0000000..fecac7c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.1
@@ -0,0 +1,172 @@
+.TH "USB_MODESWITCH" "1"
+.SH "NAME"
+usb_modeswitch - control the mode of 'multi-state' USB devices
+.SH "SYNOPSIS"
+.PP
+\fBusb_modeswitch\fR [\fB\-heWQDIvpVPmM23rwKdHSOBGTNALnsRiuagft\fP] [\fB\-c \fIfilename\fP]
+.SH "DESCRIPTION"
+.PP
+Several new USB devices have their proprietary Windows drivers onboard,
+most of them WWAN and WLAN  dongles. When plugged in for the first time,
+they act like a flash storage and start installing the Windows driver from
+there. If the driver is already installed, it makes the storage device
+disappear and a new device, mainly composite with modem ports, shows up.
+.PP
+On Linux, in most cases the drivers are available as kernel modules,
+such as "usbserial" or "option". However, the device initially binds to
+"usb-storage" by default. \fBusb_modeswitch\fR can then send a provided bulk
+message (most likely a mass storage command) to the device; this message
+has to be determined by analyzing the actions of the Windows driver.
+.PP
+In some cases, USB control commands are used for switching. These cases are
+handled by custom functions, and no bulk message needs to be provided.
+.PP
+Usually, the program is distributed with a set of configurations for many
+known devices, which allows a fully automatic handling of a device upon
+insertion, made possible by combining usb_modeswitch with the wrapper script
+\fBusb_modeswitch_dispatcher\fR which is launched by the udev daemon.
+.PP
+Note that \fBusb_modeswitch\fR itself has no specific Linux dependencies.
+
+.SH "OPTIONS"
+.PP
+This program follows the usual GNU command line syntax,
+with long options starting with two dashes ('--').  A summary of
+options is included below.
+.IP "\fB-h\fP \fB\-\-help\fP         " 10
+Show summary of options.
+.IP "\fB-e\fP \fB\-\-version\fP         " 10
+Print version information and exit
+.IP "\fB-v\fP \fB\-\-default-vendor NUM\fP         " 10
+Vendor ID to look for (mandatory), usually given as hex number (example: 0x12d1).
+Each USB device is identified by a number
+officialy assigned to the vendor by the USB association and a number for the
+respective model (product ID) chosen by the vendor
+.IP "\fB-p\fP \fB\-\-default-product NUM\fP         " 10
+Product ID to look for (mandatory)
+.IP "\fB-V\fP \fB\-\-target-vendor NUM\fP         " 10
+Target vendor ID. When given will be searched for and detected initially
+for information purposes. If success checking (option \-s) is active,
+providing target IDs (vendor/product) or target class is recommended
+.IP "\fB-j\fP \fB\-\-find-mbim\fP         " 10
+Return configuration number with MBIM interface and exit.
+.IP "\fB-P\fP \fB\-\-target-product NUM\fP         " 10
+Target product ID
+.IP "\fB-b\fP \fB\-\-bus-num NUM\fP         " 10
+.IP "\fB-g\fP \fB\-\-device-num NUM\fP         " 10
+If bus and device number are provided, the handling of a specific device on
+a specific USB port is guaranteed, in contrast to using only the USB ID. This
+is important if there are multiple similar devices on a system
+.IP "\fB-C\fP \fB\-\-target-class NUM\fP         " 10
+Target Device Class according to the USB specification. Some devices keep
+their original vendor/product ID after successful switching. To prevent
+them from being treated again, the device class can be checked.
+For unswitched devices it is always 8 (storage class), for switched
+modems it is often 0xff (vendor specific). In composite modes,
+the class of the first interface is watched
+.IP "\fB-m\fP \fB\-\-message-endpoint NUM\fP         " 10
+A specific endpoint to use for data transfers. Only for testing purposes; usually
+endpoints are determined from the device attributes
+.IP "\fB-M\fP \fB\-\-message-content STRING\fP         " 10
+A bulk message to send as a switching command. Provided as a hexadecimal string
+.IP "\fB-2, -3\fP  \fB\-\-message-content2, \-\-message-content3 STRING\fP         " 10
+Additional bulk messages to send as switching commands. Provided as hexadecimal strings.
+When used with mass storage commands, setting \fB\-\-need-response\fR is
+strongly advised to comply with specifications and to avoid likely errors
+.IP "\fB-w\fP \fB\-\-release-delay NUM\fP         " 10
+After issuing all bulk messages, wait for NUM milliseconds before releasing the interface.
+Required for some modems on older systems (especially after an EJECT message)
+.IP "\fB-n\fP \fB\-\-need-response\fP         " 10
+Obsolete. CSW is always attempted to being read after mass storage transfers. No downside
+.IP "\fB-r\fP \fB\-\-response-endpoint NUM\fP         " 10
+Try to read the response to a storage command from there. Only for testing purposes;
+usually endpoints are determined from the device attributes
+.IP "\fB-K\fP \fB\-\-std-eject\fP         " 10
+Apply the standard SCSI sequence of "Allow Medium Removal" and
+"Eject". Implies \fB-n\fP. One 'Message' can be added with \fB-M\fP
+that will be transmitted after the eject sequence. Used by many modems
+.IP "\fB-d\fP \fB\-\-detach-only\fP         " 10
+Just detach the current driver. This is sufficient for some early
+devices to switch successfully. Otherwise this feature can
+be used as a 'scalpel' for special cases, like separating the
+driver from individual interfaces
+.IP "\fB-H\fP \fB\-\-huawei-mode\fP         " 10
+Send a special control message used by older Huawei devices
+.IP "\fB-J\fP \fB\-\-huawei-new-mode\fP         " 10
+Send a specific bulk message used by all newer Huawei devices
+.IP "\fB-S\fP \fB\-\-sierra-mode\fP         " 10
+Send a special control message used by Sierra devices
+.IP "\fB-G\fP \fB\-\-gct-mode\fP         " 10
+Send a special control message used by GCT chipsets
+.IP "\fB-T\fP \fB\-\-kobil-mode\fP         " 10
+Send a special control message used by Kobil devices
+.IP "\fB-N\fP \fB\-\-sequans-mode\fP         " 10
+Send a special control message used by Sequans chipset
+.IP "\fB-A\fP \fB\-\-mobileaction-mode\fP         " 10
+Send a special control message used by the MobileAction device
+.IP "\fB-B\fP \fB\-\-qisda-mode\fP         " 10
+Send a special control message used by Qisda devices
+.IP "\fB-E\fP \fB\-\-quanta-mode\fP         " 10
+Send a special control message used by Quanta devices
+.IP "\fB-F\fP \fB\-\-pantech-mode NUM\fP         " 10
+Send a special control message used by Pantech devices.
+Value NUM will be used in control message as 'wValue'
+.IP "\fB-Z\fP \fB\-\-blackberry-mode\fP         " 10
+Send a special control message used by some newer Blackberry devices
+.IP "\fB-S\fP \fB\-\-option-mode\fP         " 10
+Send a special control message used by all Option devices
+.IP "\fB-O\fP \fB\-\-sony-mode\fP         " 10
+Apply a special sequence used by Sony Ericsson devices. Implies option \--check-success
+.IP "\fB-L\fP \fB\-\-cisco-mode\fP         " 10
+Send a sequence of bulk messages used by Cisco devices
+.IP "\fB-R\fP \fB\-\-reset-usb\fP         " 10
+Send a USB reset command to the device. Can be combined with any switching
+method or stand alone. It is always done as the last step of all device
+interactions.
+Few devices need it to complete the switching; apart from that it may be
+useful during testing
+.IP "\fB-c\fP \fB\-\-config-file FILENAME\fP         " 10
+Use a specific config file. If any ID or switching options are given as
+command line parameters, this option is ignored.
+In that case all mandatory parameters have to be provided on
+the command line
+.IP "\fB-f\fP \fB\-\-long-config STRING\fP         " 10
+Provide device details in config file syntax as a multiline string
+on the command line
+.IP "\fB-t\fP \fB\-\-stdinput\fP         " 10
+Read the device details in config file syntax from standard input, e.g. redirected from
+a command pipe (multiline text)
+.IP "\fB-Q\fP \fB\-\-quiet\fP         " 10
+Don't show progress or error messages 
+.IP "\fB-W\fP \fB\-\-verbose\fP         " 10
+Print all settings before running and show libusb debug messages 
+.IP "\fB-D\fP \fB\-\-sysmode\fP         " 10
+Changes the behaviour of the program slightly. A success message including the
+effective target device ID is put out and a syslog notice is issued. Mainly for
+integration with a wrapper script
+.IP "\fB-s\fP \fB\-\-check-success NUM\fP         " 10
+After switching, keep checking for the result up to max. NUM seconds. If target IDs
+or target class were provided, their appearance indicates certain success. Otherwise
+the disconnection of the original device is rated as likely proof
+.IP "\fB-I\fP \fB\-\-inquire\fP         " 10
+Obsolete. Formerly obtained SCSI attributes, now ignored
+.IP "\fB-i\fP \fB\-\-interface NUM\fP         " 10
+Select initial USB interface (default: 0). Only for testing purposes
+.IP "\fB-u\fP \fB\-\-configuration NUM\fP         " 10
+Select USB configuration (applied after any other possible switching actions)
+.IP "\fB-a\fP \fB\-\-altsetting NUM\fP         " 10
+Select alternative USB interface setting (applied after switching). Mainly
+for testing
+.SH "AUTHOR"
+.PP
+This manual page was originally written by Didier Raboud (didier@raboud.com) for
+the \fBDebian\fP system. Additions made by Josua Dietze. Permission is
+granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 or any
+later version published by the Free Software Foundation.
+
+.PP
+The complete text of the current GNU General Public
+License can be found in http://www.gnu.org/licenses/gpl.txt
+
+.\" last edited 2016-01-11 for version 2.3.0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.c
new file mode 100755
index 0000000..ba5be82
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.c
@@ -0,0 +1,2095 @@
+/*
+  Mode switching tool for controlling mode of 'multi-state' USB devices
+  Version 2.4.0, 2016/06/12
+
+  Copyright (C) 2007 - 2016 Josua Dietze (mail to "usb_admin" at the domain
+  of the home page; or write a personal message through the forum to "Josh".
+  NO SUPPORT VIA E-MAIL - please use the forum for that)
+
+  Major contributions:
+
+  Command line parsing, decent usage/config output/handling, bugfixes and advanced
+  options added by:
+    Joakim Wennergren
+
+  TargetClass parameter implementation to support new Option devices/firmware:
+    Paul Hardwick (http://www.pharscape.org)
+
+  Created with initial help from:
+    "usbsnoop2libusb.pl" by Timo Lindfors (http://iki.fi/lindi/usb/usbsnoop2libusb.pl)
+
+  Config file parsing code borrowed from:
+    Guillaume Dargaud (http://www.gdargaud.net/Hack/SourceCode.html)
+
+  Hexstr2bin function borrowed from:
+    Jouni Malinen (http://hostap.epitest.fi/wpa_supplicant, from "common.c")
+
+  Other contributions: see README
+
+  Device information contributors are named in the "device_reference.txt" file. See
+  homepage.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details:
+
+  http://www.gnu.org/licenses/gpl.txt
+
+*/
+
+/* Recommended tab size: 4 */
+
+#define VERSION "2.4.0"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "usb_modeswitch.h"
+
+
+// Little helpers
+
+int usb_bulk_io(struct libusb_device_handle *handle, int ep, unsigned char *bytes,
+		int size, int timeout)
+{
+	int actual_length;
+	int r;
+//	usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout);
+	r = libusb_bulk_transfer(handle, ep & 0xff, bytes, size,
+		&actual_length, timeout);
+
+	/* if we timed out but did transfer some data, report as successful short
+	 * read. FIXME: is this how libusb-0.1 works? */
+	if (r == 0 || (r == LIBUSB_ERROR_TIMEOUT && actual_length > 0))
+		return actual_length;
+
+	return r;
+}
+
+
+static int usb_interrupt_io(libusb_device_handle *handle, int ep, unsigned char *bytes,
+		int size, int timeout)
+{
+	int actual_length;
+	int r;
+//	usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout);
+	r = libusb_interrupt_transfer(handle, ep & 0xff, bytes, size,
+		&actual_length, timeout);
+
+	/* if we timed out but did transfer some data, report as successful short
+	 * read. FIXME: is this how libusb-0.1 works? */
+	if (r == 0 || (r == LIBUSB_ERROR_TIMEOUT && actual_length > 0))
+		return actual_length;
+
+	return (r);
+}
+
+
+#define LINE_DIM 1024
+#define MSG_DIM 11
+#define MAXLINES 50
+#define BUF_SIZE 4096
+#define DESCR_MAX 129
+
+#define SEARCH_DEFAULT 0
+#define SEARCH_TARGET 1
+#define SEARCH_BUSDEV 2
+
+#define SWITCH_CONFIG_MAXTRIES   5
+
+#define SHOW_PROGRESS if (show_progress) fprintf
+
+char *TempPP=NULL;
+
+static struct libusb_context *ctx = NULL;
+static struct libusb_device *dev = NULL;
+static struct libusb_device_handle *devh = NULL;
+static struct libusb_config_descriptor *active_config = NULL;
+
+int DefaultVendor=0, DefaultProduct=0, TargetVendor=0, TargetProduct=-1, TargetClass=0;
+int MessageEndpoint=0, ResponseEndpoint=0, ReleaseDelay=0;
+int targetDeviceCount=0, searchMode;
+int devnum=-1, busnum=-1;
+
+unsigned int ModeMap = 0;
+#define DETACHONLY_MODE		0x00000001
+#define HUAWEI_MODE			0x00000002
+#define SIERRA_MODE			0x00000004
+#define SONY_MODE			0x00000008
+#define GCT_MODE			0x00000010
+#define KOBIL_MODE			0x00000020
+#define SEQUANS_MODE		0x00000040
+#define MOBILEACTION_MODE	0x00000080
+#define CISCO_MODE			0x00000100
+#define QISDA_MODE			0x00000200
+#define QUANTA_MODE			0x00000400
+#define BLACKBERRY_MODE		0x00000800
+#define PANTECH_MODE		0x00001000
+#define HUAWEINEW_MODE		0x00002000
+#define OPTION_MODE			0x00004000
+
+
+int PantechMode=0;
+char verbose=0, show_progress=1, ResetUSB=0, CheckSuccess=0, config_read=0;
+char NoDriverLoading=0, sysmode=0, mbim=0;
+char StandardEject=0;
+
+char MessageContent[LINE_DIM];
+char MessageContent2[LINE_DIM];
+char MessageContent3[LINE_DIM];
+char TargetProductList[LINE_DIM];
+char DefaultProductList[5];
+unsigned char ByteString[LINE_DIM/2];
+unsigned char buffer[BUF_SIZE];
+char **Messages = NULL;
+
+FILE *output;
+
+
+/* Settable Interface and Configuration (for debugging mostly) (jmw) */
+int Interface = -1, Configuration = 0, AltSetting = -1;
+
+
+static struct option long_options[] = {
+	{"help",				no_argument, 0, 'h'},
+	{"version",				no_argument, 0, 'e'},
+	{"default-vendor",		required_argument, 0, 'v'},
+	{"default-product",		required_argument, 0, 'p'},
+	{"target-vendor",		required_argument, 0, 'V'},
+	{"target-product",		required_argument, 0, 'P'},
+	{"target-class",		required_argument, 0, 'C'},
+	{"message-endpoint",	required_argument, 0, 'm'},
+	{"message-content",		required_argument, 0, 'M'},
+	{"message-content2",	required_argument, 0, '2'},
+	{"message-content3",	required_argument, 0, '3'},
+	{"release-delay",		required_argument, 0, 'w'},
+	{"response-endpoint",	required_argument, 0, 'r'},
+	{"bus-num",				required_argument, 0, 'b'},
+	{"device-num",			required_argument, 0, 'g'},
+	{"detach-only",			no_argument, 0, 'd'},
+	{"huawei-mode",			no_argument, 0, 'H'},
+	{"huawei-new-mode",		no_argument, 0, 'J'},
+	{"sierra-mode",			no_argument, 0, 'S'},
+	{"sony-mode",			no_argument, 0, 'O'},
+	{"qisda-mode",			no_argument, 0, 'B'},
+	{"quanta-mode",			no_argument, 0, 'E'},
+	{"kobil-mode",			no_argument, 0, 'T'},
+	{"gct-mode",			no_argument, 0, 'G'},
+	{"sequans-mode",		no_argument, 0, 'N'},
+	{"mobileaction-mode",	no_argument, 0, 'A'},
+	{"cisco-mode",	        no_argument, 0, 'L'},
+	{"blackberry-mode",		no_argument, 0, 'Z'},
+	{"option-mode",			no_argument, 0, 'U'},
+	{"pantech-mode",		required_argument, 0, 'F'},
+	{"std-eject",			no_argument, 0, 'K'},
+	{"need-response",		no_argument, 0, 'n'},
+	{"reset-usb",			no_argument, 0, 'R'},
+	{"config-file",			required_argument, 0, 'c'},
+	{"verbose",				no_argument, 0, 'W'},
+	{"quiet",				no_argument, 0, 'Q'},
+	{"sysmode",				no_argument, 0, 'D'},
+	{"inquire",				no_argument, 0, 'I'},
+	{"stdinput",			no_argument, 0, 't'},
+	{"find-mbim",			no_argument, 0, 'j'},
+	{"long-config",			required_argument, 0, 'f'},
+	{"check-success",		required_argument, 0, 's'},
+	{"interface",			required_argument, 0, 'i'},
+	{"configuration",		required_argument, 0, 'u'},
+	{"altsetting",			required_argument, 0, 'a'},
+	{0, 0, 0, 0}
+};
+
+
+void readConfigFile(const char *configFilename)
+{
+	ParseParamHex(configFilename, TargetVendor);
+	ParseParamHex(configFilename, TargetProduct);
+	ParseParamString(configFilename, TargetProductList);
+	ParseParamHex(configFilename, TargetClass);
+	ParseParamHex(configFilename, DefaultVendor);
+	ParseParamHex(configFilename, DefaultProduct);
+	ParseParamBoolMap(configFilename, DetachStorageOnly, ModeMap, DETACHONLY_MODE);
+	ParseParamBoolMap(configFilename, HuaweiMode, ModeMap, HUAWEI_MODE);
+	ParseParamBoolMap(configFilename, HuaweiNewMode, ModeMap, HUAWEINEW_MODE);
+	ParseParamBoolMap(configFilename, SierraMode, ModeMap, SIERRA_MODE);
+	ParseParamBoolMap(configFilename, SonyMode, ModeMap, SONY_MODE);
+	ParseParamBoolMap(configFilename, GCTMode, ModeMap, GCT_MODE);
+	ParseParamBoolMap(configFilename, KobilMode, ModeMap, KOBIL_MODE);
+	ParseParamBoolMap(configFilename, SequansMode, ModeMap, SEQUANS_MODE);
+	ParseParamBoolMap(configFilename, MobileActionMode, ModeMap, MOBILEACTION_MODE);
+	ParseParamBoolMap(configFilename, CiscoMode, ModeMap, CISCO_MODE);
+	ParseParamBoolMap(configFilename, QisdaMode, ModeMap, QISDA_MODE);
+	ParseParamBoolMap(configFilename, QuantaMode, ModeMap, QUANTA_MODE);
+	ParseParamBoolMap(configFilename, OptionMode, ModeMap, OPTION_MODE);
+	ParseParamBoolMap(configFilename, BlackberryMode, ModeMap, BLACKBERRY_MODE);
+	ParseParamInt(configFilename, PantechMode);
+	if (PantechMode)
+		ModeMap |= PANTECH_MODE;
+	ParseParamBool(configFilename, StandardEject);
+	ParseParamBool(configFilename, NoDriverLoading);
+	ParseParamHex(configFilename, MessageEndpoint);
+	ParseParamString(configFilename, MessageContent);
+	ParseParamString(configFilename, MessageContent2);
+	ParseParamString(configFilename, MessageContent3);
+	ParseParamInt(configFilename, ReleaseDelay);
+	ParseParamHex(configFilename, ResponseEndpoint);
+	ParseParamHex(configFilename, ResetUSB);
+	ParseParamInt(configFilename, CheckSuccess);
+	ParseParamHex(configFilename, Interface);
+	ParseParamHex(configFilename, Configuration);
+	ParseParamHex(configFilename, AltSetting);
+
+	/* TargetProductList has priority over TargetProduct */
+	if (TargetProduct != -1 && TargetProductList[0] != '\0') {
+		TargetProduct = -1;
+		SHOW_PROGRESS(output,"Warning: TargetProductList overrides TargetProduct!\n");
+	}
+
+	config_read = 1;
+}
+
+
+void printConfig()
+{
+	if ( DefaultVendor )
+		fprintf (output,"DefaultVendor=  0x%04x\n",	DefaultVendor);
+	if ( DefaultProduct )
+		fprintf (output,"DefaultProduct= 0x%04x\n",	DefaultProduct);
+	if ( TargetVendor )
+		fprintf (output,"TargetVendor=   0x%04x\n",	TargetVendor);
+	if ( TargetProduct > -1 )
+		fprintf (output,"TargetProduct=  0x%04x\n",	TargetProduct);
+	if ( TargetClass )
+		fprintf (output,"TargetClass=    0x%02x\n",	TargetClass);
+	if ( strlen(TargetProductList) )
+		fprintf (output,"TargetProductList=\"%s\"\n", TargetProductList);
+	if (StandardEject)
+		fprintf (output,"\nStandardEject=1\n");
+	if (ModeMap & DETACHONLY_MODE)
+		fprintf (output,"\nDetachStorageOnly=1\n");
+	if (ModeMap & HUAWEI_MODE)
+		fprintf (output,"HuaweiMode=1\n");
+	if (ModeMap & HUAWEINEW_MODE)
+		fprintf (output,"HuaweiNewMode=1\n");
+	if (ModeMap & SIERRA_MODE)
+		fprintf (output,"SierraMode=1\n");
+	if (ModeMap & SONY_MODE)
+		fprintf (output,"SonyMode=1\n");
+	if (ModeMap & QISDA_MODE)
+		fprintf (output,"QisdaMode=1\n");
+	if (ModeMap & QUANTA_MODE)
+		fprintf (output,"QuantaMode=1\n");
+	if (ModeMap & GCT_MODE)
+		fprintf (output,"GCTMode=1\n");
+	if (ModeMap & KOBIL_MODE)
+		fprintf (output,"KobilMode=1\n");
+	if (ModeMap & SEQUANS_MODE)
+		fprintf (output,"SequansMode=1\n");
+	if (ModeMap & MOBILEACTION_MODE)
+		fprintf (output,"MobileActionMode=1\n");
+	if (ModeMap & CISCO_MODE)
+		fprintf (output,"CiscoMode=1\n");
+	if (ModeMap & BLACKBERRY_MODE)
+		fprintf (output,"BlackberryMode=1\n");
+	if (ModeMap & OPTION_MODE)
+		fprintf (output,"OptionMode=1\n");
+	if (ModeMap & PANTECH_MODE)
+		fprintf (output,"PantechMode=1\n");
+	if ( MessageEndpoint )
+		fprintf (output,"MessageEndpoint=0x%02x\n",	MessageEndpoint);
+	if ( strlen(MessageContent) )
+		fprintf (output,"MessageContent=\"%s\"\n",	MessageContent);
+	if ( strlen(MessageContent2) )
+		fprintf (output,"MessageContent2=\"%s\"\n",	MessageContent2);
+	if ( strlen(MessageContent3) )
+		fprintf (output,"MessageContent3=\"%s\"\n",	MessageContent3);
+	if ( ResponseEndpoint )
+		fprintf (output,"ResponseEndpoint=0x%02x\n",	ResponseEndpoint);
+	if ( Interface > -1 )
+		fprintf (output,"Interface=0x%02x\n",			Interface);
+	if ( Configuration > 0 )
+		fprintf (output,"Configuration=0x%02x\n",	Configuration);
+	if ( AltSetting > -1 )
+		fprintf (output,"AltSetting=0x%02x\n",	AltSetting);
+	if ( CheckSuccess )
+		fprintf (output,"Success check enabled, max. wait time %d seconds\n", CheckSuccess);
+	if ( sysmode )
+		fprintf (output,"System integration mode enabled\n");
+}
+
+
+int readArguments(int argc, char **argv)
+{
+	int c, option_index = 0, count=0;
+	char *longConfig = NULL;
+	if (argc==1)
+	{
+		printHelp();
+		printVersion();
+		exit(1);
+	}
+
+	while (1)
+	{
+		c = getopt_long (argc, argv, "hejWQDndKHJSOBEGTNALZUF:RItv:p:V:P:C:m:M:2:3:w:r:c:i:u:a:s:f:b:g:",
+					long_options, &option_index);
+
+		/* Detect the end of the options. */
+		if (c == -1)
+			break;
+		count++;
+		switch (c)
+		{
+			case 'R': ResetUSB = 1; break;
+			case 'v': DefaultVendor = strtol(optarg, NULL, 16); break;
+			case 'p': DefaultProduct = strtol(optarg, NULL, 16); break;
+			case 'V': TargetVendor = strtol(optarg, NULL, 16); break;
+			case 'P': TargetProduct = strtol(optarg, NULL, 16); break;
+			case 'C': TargetClass = strtol(optarg, NULL, 16); break;
+			case 'm': MessageEndpoint = strtol(optarg, NULL, 16); break;
+			case 'M': strncpy(MessageContent, optarg, LINE_DIM); break;
+			case '2': strncpy(MessageContent2, optarg, LINE_DIM); break;
+			case '3': strncpy(MessageContent3, optarg, LINE_DIM); break;
+			case 'w': ReleaseDelay = strtol(optarg, NULL, 10); break;
+			case 'n': break;
+			case 'r': ResponseEndpoint = strtol(optarg, NULL, 16); break;
+			case 'K': StandardEject = 1; break;
+			case 'd': ModeMap = ModeMap + DETACHONLY_MODE; break;
+			case 'H': ModeMap = ModeMap + HUAWEI_MODE; break;
+			case 'J': ModeMap = ModeMap + HUAWEINEW_MODE; break;
+			case 'S': ModeMap = ModeMap + SIERRA_MODE; break;
+			case 'O': ModeMap = ModeMap + SONY_MODE; break;; break;
+			case 'B': ModeMap = ModeMap + QISDA_MODE; break;
+			case 'E': ModeMap = ModeMap + QUANTA_MODE; break;
+			case 'G': ModeMap = ModeMap + GCT_MODE; break;
+			case 'T': ModeMap = ModeMap + KOBIL_MODE; break;
+			case 'N': ModeMap = ModeMap + SEQUANS_MODE; break;
+			case 'A': ModeMap = ModeMap + MOBILEACTION_MODE; break;
+			case 'L': ModeMap = ModeMap + CISCO_MODE; break;
+			case 'Z': ModeMap = ModeMap + BLACKBERRY_MODE; break;
+			case 'U': ModeMap = ModeMap + OPTION_MODE; break;
+			case 'F': ModeMap = ModeMap + PANTECH_MODE;
+						PantechMode = strtol(optarg, NULL, 10); break;
+			case 'c': readConfigFile(optarg); break;
+			case 't': readConfigFile("stdin"); break;
+			case 'W': verbose = 1; show_progress = 1; count--; break;
+			case 'Q': show_progress = 0; verbose = 0; count--; break;
+			case 'D': sysmode = 1; count--; break;
+			case 's': CheckSuccess = strtol(optarg, NULL, 10); count--; break;
+			case 'I': break;
+			case 'b': busnum = strtol(optarg, NULL, 10); break;
+			case 'g': devnum = strtol(optarg, NULL, 10); break;
+
+			case 'i': Interface = strtol(optarg, NULL, 16); break;
+			case 'u': Configuration = strtol(optarg, NULL, 16); break;
+			case 'a': AltSetting = strtol(optarg, NULL, 16); break;
+			case 'j': mbim = 1; break;
+
+			case 'f':
+				longConfig = malloc(strlen(optarg)+5);
+				strcpy(longConfig,"##\n");
+				strcat(longConfig,optarg);
+				strcat(longConfig,"\n");
+				readConfigFile(longConfig);
+				free(longConfig);
+				break;
+
+			case 'e':
+				printVersion();
+				exit(0);
+				break;
+			case 'h':
+				printVersion();
+				printHelp();
+				exit(0);
+				break;
+
+			default: /* Unsupported - error message has already been printed */
+				fprintf (output,"\n");
+				printHelp();
+				exit(1);
+		}
+	}
+	return count;
+}
+
+
+int main(int argc, char **argv)
+{
+	int ret=0, numDefaults=0, sonySuccess=0, i;
+	int currentConfigVal=0, defaultClass=0, interfaceClass=0;
+	struct libusb_device_descriptor descriptor;
+	enum libusb_error libusbError;
+
+	/* Make sure we have empty strings even if not set by config */
+	TargetProductList[0] = '\0';
+	MessageContent[0] = '\0';
+	MessageContent2[0] = '\0';
+	MessageContent3[0] = '\0';
+	DefaultProductList[0] = '\0';
+
+	/* Useful for debugging during boot */
+//	output=fopen("/dev/console", "w");
+	output=stdout;
+
+	signal(SIGTERM, release_usb_device);
+
+	/*
+	 * Parameter parsing, USB preparation/diagnosis, plausibility checks
+	 */
+
+	/* Check command arguments, use params instead of config file when given */
+	switch (readArguments(argc, argv)) {
+		case 0:						/* no argument or -W, -q or -s */
+			break;
+		default:					/* one or more arguments except -W, -q or -s */
+			if (!config_read)		/* if arguments contain -c, the config file was already processed */
+				if (verbose) fprintf(output,"Take all parameters from the command line\n\n");
+	}
+
+	if (verbose) {
+		printVersion();
+		printConfig();
+		fprintf(output,"\n");
+	}
+
+	/* Some sanity checks. The default IDs are mandatory */
+	if (!(DefaultVendor && DefaultProduct)) {
+		SHOW_PROGRESS(output,"No default vendor/product ID given. Abort\n\n");
+		exit(1);
+	}
+
+	if (strlen(MessageContent)) {
+		if (strlen(MessageContent) % 2 != 0) {
+			fprintf(stderr, "Error: MessageContent hex string has uneven length. Abort\n\n");
+			exit(1);
+		}
+		if ( hexstr2bin(MessageContent, ByteString, strlen(MessageContent)/2) == -1) {
+			fprintf(stderr, "Error: MessageContent %s\n is not a hex string. Abort\n\n",
+					MessageContent);
+
+			exit(1);
+		}
+	}
+
+	if (devnum == -1) {
+		searchMode = SEARCH_DEFAULT;
+	} else {
+		SHOW_PROGRESS(output,"Use given bus/device number: %03d/%03d ...\n", busnum, devnum);
+		searchMode = SEARCH_BUSDEV;
+	}
+
+	if (show_progress)
+		if (CheckSuccess && !(TargetVendor || TargetProduct > -1 || TargetProductList[0] != '\0')
+				 && !TargetClass)
+
+			fprintf(output,"Note: No target parameter given; success check limited\n");
+
+	if (TargetProduct > -1 && TargetProductList[0] == '\0') {
+		sprintf(TargetProductList,"%04x",TargetProduct);
+		TargetProduct = -1;
+	}
+
+	/* libusb initialization */
+	if ((libusbError = libusb_init(&ctx)) != LIBUSB_SUCCESS) {
+		//fprintf(stderr, "Error: Failed to initialize libusb. %s (%d)\n\n",
+				//libusb_error_name(libusbError), libusbError);
+		exit(1);
+	}
+
+	if (verbose)
+		libusb_set_debug(ctx, 3);
+
+	if (mbim) {
+		printf("%d\n", findMBIMConfig(DefaultVendor, DefaultProduct, searchMode) );
+		exit(0);
+	}
+
+	/* Count existing target devices, remember for success check */
+	if (searchMode != SEARCH_BUSDEV && (TargetVendor || TargetClass)) {
+		SHOW_PROGRESS(output,"Look for target devices ...\n");
+		search_devices(&targetDeviceCount, TargetVendor, TargetProductList, TargetClass, 0,
+				SEARCH_TARGET);
+
+		if (targetDeviceCount) {
+			SHOW_PROGRESS(output," Found devices in target mode or class (%d)\n", targetDeviceCount);
+		} else
+			SHOW_PROGRESS(output," No devices in target mode or class found\n");
+	}
+
+	/* Count default devices, get the last one found */
+	SHOW_PROGRESS(output,"Look for default devices ...\n");
+
+	sprintf(DefaultProductList,"%04x",DefaultProduct);
+	dev = search_devices(&numDefaults, DefaultVendor, DefaultProductList, TargetClass,
+		Configuration, searchMode);
+
+	if (numDefaults) {
+		SHOW_PROGRESS(output," Found devices in default mode (%d)\n", numDefaults);
+	} else {
+		SHOW_PROGRESS(output," No devices in default mode found. Nothing to do. Bye!\n\n");
+		close_all();
+		exit(0);
+	}
+
+	if (dev == NULL) {
+		SHOW_PROGRESS(output," No bus/device match. Is device connected? Abort\n\n");
+		close_all();
+		exit(0);
+	} else {
+		if (devnum == -1) {
+			devnum = libusb_get_device_address(dev);
+			busnum = libusb_get_bus_number(dev);
+			SHOW_PROGRESS(output,"Access device %03d on bus %03d\n", devnum, busnum);
+		}
+		libusb_open(dev, &devh);
+		if (devh == NULL) {
+			SHOW_PROGRESS(output,"Error opening the device. Abort\n\n");
+			abortExit();
+		}
+	}
+
+	/* Get current configuration of default device, note value if Configuration
+	 * parameter is set. Also sets active_config
+	 */
+	currentConfigVal = get_current_config_value(dev);
+	if (Configuration > -1) {
+		SHOW_PROGRESS(output,"Current configuration number is %d\n", currentConfigVal);
+	} else
+		currentConfigVal = 0;
+
+	libusb_get_device_descriptor(dev, &descriptor);
+	defaultClass = descriptor.bDeviceClass;
+	if (Interface == -1)
+		Interface = active_config->interface[0].altsetting[0].bInterfaceNumber;
+	SHOW_PROGRESS(output,"Use interface number %d\n", Interface);
+
+	/* Get class of default device/interface */
+	interfaceClass = get_interface_class();
+
+	/* Check or get endpoints and alloc message list if needed*/
+	if (strlen(MessageContent) || StandardEject || ModeMap & CISCO_MODE
+				|| ModeMap & HUAWEINEW_MODE || ModeMap & OPTION_MODE) {
+
+		Messages = (char**) calloc(MSG_DIM, sizeof(char*));
+		for (i = 0; i < MSG_DIM; i++) {
+			Messages[i] = (char*) calloc(LINE_DIM, sizeof(char));
+			Messages[i][0] = '\0';
+		}
+
+		if (!MessageEndpoint)
+			MessageEndpoint = find_first_bulk_endpoint(LIBUSB_ENDPOINT_OUT);
+		if (!ResponseEndpoint)
+			ResponseEndpoint = find_first_bulk_endpoint(LIBUSB_ENDPOINT_IN);
+		if (!MessageEndpoint) {
+			fprintf(stderr,"Error: message endpoint not given or found. Abort\n\n");
+			abortExit();
+		}
+		if (!ResponseEndpoint) {
+			fprintf(stderr,"Error: response endpoint not given or found. Abort\n\n");
+			abortExit();
+		}
+		SHOW_PROGRESS(output,"Use endpoints 0x%02x (out) and 0x%02x (in)\n", MessageEndpoint,
+				ResponseEndpoint);
+
+	}
+
+	if (interfaceClass == -1) {
+		fprintf(stderr, "Error: Could not get class of interface %d. Does it exist? Abort\n\n",Interface);
+		abortExit();
+	}
+
+	if (defaultClass == 0 || defaultClass == 0xef)
+		defaultClass = interfaceClass;
+	else
+		if (interfaceClass == LIBUSB_CLASS_MASS_STORAGE && defaultClass != LIBUSB_CLASS_MASS_STORAGE
+				&& defaultClass != LIBUSB_CLASS_VENDOR_SPEC) {
+
+			/* Unexpected default class combined with differing interface class */
+			SHOW_PROGRESS(output,"Bogus Class/InterfaceClass: 0x%02x/0x08\n", defaultClass);
+			defaultClass = 8;
+		}
+
+	if (strlen(MessageContent) && strncmp("55534243",MessageContent,8) == 0)
+		if (defaultClass != 8) {
+			fprintf(stderr, "Error: can't use storage command in MessageContent with interface %d;\n"
+				"       interface class is %d, expected 8. Abort\n\n", Interface, defaultClass);
+			abortExit();
+		}
+
+	if (show_progress) {
+		fprintf(output,"\nUSB description data (for identification)\n");
+		deviceDescription();
+	}
+
+	/* Special modes are exclusive, so check for illegal combinations.
+	 * More than one bit set?
+	 */
+	if ( ModeMap & (ModeMap-1) ) {
+		fprintf(output,"Multiple special modes selected; check configuration. Abort\n\n");
+		abortExit();
+	}
+
+	if ((strlen(MessageContent) || StandardEject) && ModeMap ) {
+		MessageContent[0] = '\0';
+		StandardEject = 0;
+		fprintf(output,"Warning: MessageContent/StandardEject ignored; can't combine with special mode\n");
+	}
+
+	if (StandardEject && (strlen(MessageContent2) || strlen(MessageContent3))) {
+		fprintf(output,"Warning: MessageContent2/3 ignored; only one allowed with StandardEject\n");
+	}
+
+	if ( !ModeMap && !strlen(MessageContent) && AltSetting == -1 && !Configuration && !StandardEject )
+		SHOW_PROGRESS(output,"Warning: no switching method given. See documentation\n");
+
+	/*
+	 * The switching actions
+	 */
+
+	if (sysmode) {
+		openlog("usb_modeswitch", 0, LOG_SYSLOG);
+		syslog(LOG_NOTICE, "switch device %04x:%04x on %03d/%03d", DefaultVendor, DefaultProduct,
+				busnum, devnum);
+
+	}
+
+	if (ModeMap & DETACHONLY_MODE) {
+		SHOW_PROGRESS(output,"Detach storage driver as switching method ...\n");
+		ret = detachDriver();
+		if (ret == 2)
+			SHOW_PROGRESS(output," You may want to remove the storage driver manually\n");
+	}
+
+	if(ModeMap & HUAWEI_MODE) {
+		switchHuaweiMode();
+	}
+	if(ModeMap & SIERRA_MODE) {
+		switchSierraMode();
+	}
+	if(ModeMap & GCT_MODE) {
+		detachDriver();
+		switchGCTMode();
+	}
+	if(ModeMap & QISDA_MODE) {
+		switchQisdaMode();
+	}
+	if(ModeMap & KOBIL_MODE) {
+		detachDriver();
+		switchKobilMode();
+	}
+	if(ModeMap & QUANTA_MODE) {
+		switchQuantaMode();
+	}
+	if(ModeMap & SEQUANS_MODE) {
+		switchSequansMode();
+	}
+	if(ModeMap & MOBILEACTION_MODE) {
+		switchActionMode();
+	}
+	if(ModeMap & CISCO_MODE) {
+		detachDriver();
+		switchCiscoMode();
+	}
+	if(ModeMap & BLACKBERRY_MODE) {
+		detachDriver();
+	    switchBlackberryMode();
+	}
+	if(ModeMap & PANTECH_MODE) {
+		detachDriver();
+		if (PantechMode > 1)
+			switchPantechMode();
+		else
+			SHOW_PROGRESS(output,"Waiting for auto-switch of Pantech modem ...\n");
+	}
+	if(ModeMap & SONY_MODE) {
+		if (CheckSuccess)
+			SHOW_PROGRESS(output,"Note: CheckSuccess ignored; Sony mode does separate checks\n");
+		CheckSuccess = 0; /* separate and implied success control */
+		sonySuccess = switchSonyMode();
+	}
+
+	if (StandardEject) {
+		SHOW_PROGRESS(output,"Sending standard EJECT sequence\n");
+		detachDriver();
+
+		strcpy(Messages[0],"5553424387654321000000000000061e000000000000000000000000000000");
+		strcpy(Messages[1],"5553424397654321000000000000061b000000020000000000000000000000");
+		strcpy(Messages[2],"5553424387654321000000000001061e000000000000000000000000000000");
+		strcpy(Messages[3],"5553424397654321000000000001061b000000020000000000000000000000");
+		if (MessageContent[0] != '\0')
+			strcpy(Messages[4], MessageContent);
+
+		switchSendMessage();
+	} else if (ModeMap & HUAWEINEW_MODE) {
+		SHOW_PROGRESS(output,"Using standard Huawei switching message\n");
+		detachDriver();
+		strcpy(Messages[0],"55534243123456780000000000000011062000000101000100000000000000");
+		switchSendMessage();
+	} else if (ModeMap & OPTION_MODE) {
+		SHOW_PROGRESS(output,"Using standard Option switching message\n");
+		detachDriver();
+//		strcpy(MessageContent,"55534243123456780100000080000601000000000000000000000000000000");
+		strcpy(Messages[0],"55534243123456780000000000000601000000000000000000000000000000");
+		switchSendMessage();
+	} else if (strlen(MessageContent)) {
+		detachDriver();
+		strcpy(Messages[0],MessageContent);
+		switchSendMessage();
+	}
+
+	if (Configuration > 0) {
+		if (currentConfigVal != Configuration) {
+			if (switchConfiguration()) {
+				currentConfigVal = get_current_config_value(dev);
+				if (currentConfigVal == Configuration) {
+					SHOW_PROGRESS(output,"The configuration was set successfully\n");
+				} else {
+					SHOW_PROGRESS(output,"Changing the configuration has failed\n");
+				}
+			}
+		} else {
+			SHOW_PROGRESS(output,"Target configuration %d found. Do nothing\n", currentConfigVal);
+		}
+	}
+
+	if (AltSetting != -1) {
+		switchAltSetting();
+	}
+
+	/* No "removal" check if these are set */
+	if ((Configuration > 0 || AltSetting > -1) && !ResetUSB) {
+		libusb_close(devh);
+		devh = NULL;
+	}
+
+	if (ResetUSB) {
+		resetUSB();
+		devh = NULL;
+	}
+
+	if (searchMode == SEARCH_BUSDEV && sysmode) {
+		printf("ok:busdev\n");
+		close_all();
+		exit(0);
+	}
+
+	if (CheckSuccess) {
+		if (checkSuccess()) {
+			if (sysmode) {
+				if (NoDriverLoading)
+					printf("ok:\n");
+				else
+					if (TargetProduct < 1)
+						printf("ok:no_data\n");
+					else
+						printf("ok:%04x:%04x\n", TargetVendor, TargetProduct);
+			}
+		} else
+			if (sysmode)
+				printf("fail:\n");
+	} else {
+		if (ModeMap & SONY_MODE)
+			if (sonySuccess) {
+				if (sysmode) {
+					syslog(LOG_NOTICE, "switched S.E. MD400 to modem mode");
+					printf("ok:\n"); /* ACM device, no driver action */
+				}
+				SHOW_PROGRESS(output,"-> device should be stable now. Bye!\n\n");
+			} else {
+				if (sysmode)
+					printf("fail:\n");
+				SHOW_PROGRESS(output,"-> switching was probably not completed. Bye!\n\n");
+			}
+		else
+			SHOW_PROGRESS(output,"-> Run lsusb to note any changes. Bye!\n\n");
+	}
+	close_all();
+	exit(0);
+}
+
+
+/* Get descriptor strings if available (identification details) */
+void deviceDescription ()
+{
+	char imanufact[DESCR_MAX], iproduct[DESCR_MAX], iserial[DESCR_MAX];
+	int ret=0;
+	char* c;
+	memset (imanufact, ' ', DESCR_MAX);
+	memset (iproduct, ' ', DESCR_MAX);
+	memset (iserial, ' ', DESCR_MAX);
+
+	struct libusb_device_descriptor descriptor;
+	libusb_get_device_descriptor(dev, &descriptor);
+
+	int iManufacturer = descriptor.iManufacturer;
+	int iProduct = descriptor.iProduct;
+	int iSerialNumber = descriptor.iSerialNumber;
+
+	if (iManufacturer) {
+		ret = libusb_get_string_descriptor_ascii(devh, iManufacturer, (unsigned char *)imanufact, DESCR_MAX);
+		if (ret < 0) {
+			fprintf(stderr, "Error: could not get description string \"manufacturer\"\n");
+			strcpy(imanufact, "read error");
+		}
+	} else
+		strcpy(imanufact, "not provided");
+	c = strstr(imanufact, "    ");
+	if (c)
+		memset((void*)c, '\0', 1);
+
+	if (iProduct) {
+		ret = libusb_get_string_descriptor_ascii(devh, iProduct, (unsigned char *)iproduct, DESCR_MAX);
+		if (ret < 0) {
+			fprintf(stderr, "Error: could not get description string \"product\"\n");
+			strcpy(iproduct, "read error");
+		}
+	} else
+		strcpy(iproduct, "not provided");
+	c = strstr(iproduct, "    ");
+	if (c)
+		memset((void*)c, '\0', 1);
+
+	if (iSerialNumber) {
+		ret = libusb_get_string_descriptor_ascii(devh, iSerialNumber, (unsigned char *)iserial, DESCR_MAX);
+		if (ret < 0) {
+			fprintf(stderr, "Error: could not get description string \"serial number\"\n");
+			strcpy(iserial, "read error");
+		}
+	} else
+		strcpy(iserial, "not provided");
+	c = strstr(iserial, "    ");
+	if (c)
+		memset((void*)c, '\0', 1);
+	fprintf(output,"-------------------------\n");
+	fprintf(output,"Manufacturer: %s\n", imanufact);
+	fprintf(output,"     Product: %s\n", iproduct);
+	fprintf(output,"  Serial No.: %s\n", iserial);
+	fprintf(output,"-------------------------\n");
+}
+
+
+/* Auxiliary function used by the wrapper */
+int findMBIMConfig(int vendor, int product, int mode)
+{
+	struct libusb_device **devs;
+	int resultConfig=0;
+	int i=0, j;
+
+	if (libusb_get_device_list(ctx, &devs) < 0) {
+		perror("Libusb could not access USB. Abort");
+		return 0;
+	}
+
+	SHOW_PROGRESS(output,"Search USB devices ...\n");
+	while ((dev = devs[i++]) != NULL) {
+		struct libusb_device_descriptor descriptor;
+		libusb_get_device_descriptor(dev, &descriptor);
+
+		if (mode == SEARCH_BUSDEV) {
+			if ((libusb_get_bus_number(dev) != busnum) ||
+				(libusb_get_device_address(dev) != devnum)) {
+				continue;
+			} else {
+				if (descriptor.idVendor != vendor)
+					continue;
+				if (product != descriptor.idProduct)
+					continue;
+			}
+		}
+		SHOW_PROGRESS(output,"Found device, search for MBIM configuration...\n");
+
+		// No check if there is only one configuration
+		if (descriptor.bNumConfigurations < 2)
+			return -1;
+
+		// Checking all interfaces of all configurations
+		for (j=0; j<descriptor.bNumConfigurations; j++) {
+			struct libusb_config_descriptor *config;
+
+			libusb_get_config_descriptor(dev, j, &config);
+			resultConfig = config->bConfigurationValue;
+			for (i=0; i<config->bNumInterfaces; i++) {
+				if ( config->interface[i].altsetting[0].bInterfaceClass == 2 )
+					if ( config->interface[i].altsetting[0].bInterfaceSubClass == 0x0e ) {
+						// found MBIM interface in this configuration
+						libusb_free_config_descriptor(config);
+						return resultConfig;
+					}
+			}
+			libusb_free_config_descriptor(config);
+		}
+		return -1;
+	}
+	return 0;
+}
+
+
+void resetUSB ()
+{
+	int success;
+	int bpoint = 0;
+
+	if (!devh) {
+		fprintf(output,"Device handle empty, skip USB reset\n");
+		return;
+	}
+	if (show_progress) {
+		fprintf(output,"Reset USB device ");
+		fflush(output);
+	}
+	sleep( 1 );
+	do {
+		success = libusb_reset_device(devh);
+		if ( ((bpoint % 10) == 0) && show_progress ) {
+			fprintf(output,".");
+			fflush(output);
+		}
+		bpoint++;
+		if (bpoint > 100)
+			success = 1;
+	} while (success < 0);
+
+	if ( success ) {
+		SHOW_PROGRESS(output,"\n Device reset failed.\n");
+	} else
+		SHOW_PROGRESS(output,"\n Device was reset\n");
+}
+
+
+int switchSendMessage ()
+{
+	const char* cmdHead = "55534243";
+	int ret, i;
+/*	char* msg[3];
+	msg[0] = MessageContent;
+	msg[1] = MessageContent2;
+	msg[2] = MessageContent3;
+*/
+	SHOW_PROGRESS(output,"Set up interface %d\n", Interface);
+	ret = libusb_claim_interface(devh, Interface);
+	if (ret != 0) {
+		SHOW_PROGRESS(output," Could not claim interface (error %d). Skip message sending\n", ret);
+		return 0;
+	}
+	libusb_clear_halt(devh, MessageEndpoint);
+	SHOW_PROGRESS(output,"Use endpoint 0x%02x for message sending ...\n", MessageEndpoint);
+	if (show_progress)
+		fflush(stdout);
+
+	for (i=0; i<MSG_DIM; i++) {
+		if ( strlen(Messages[i]) == 0)
+			break;
+
+		if ( sendMessage(Messages[i], i+1) )
+			goto skip;
+
+		if ( strstr(Messages[i],cmdHead) != NULL ) {
+			// UFI command
+			SHOW_PROGRESS(output,"Read the response to message %d (CSW) ...\n", i+1);
+			ret = read_bulk(ResponseEndpoint, ByteString, 13);
+			if (ret >= 0)
+				SHOW_PROGRESS(output,", status %d",ByteString[12]);
+		} else {
+			// Other bulk transfer
+			SHOW_PROGRESS(output,"Read the response to message %d ...\n", i+1);
+			ret = read_bulk(ResponseEndpoint, ByteString, strlen(Messages[i])/2 );
+		}
+		SHOW_PROGRESS(output,"\n");
+		if (ret < 0)
+			goto skip;
+	}
+
+	SHOW_PROGRESS(output,"Reset response endpoint 0x%02x\n", ResponseEndpoint);
+	ret = libusb_clear_halt(devh, ResponseEndpoint);
+	if (ret)
+		SHOW_PROGRESS(output," Could not reset endpoint (probably harmless): %d\n", ret);
+	SHOW_PROGRESS(output,"Reset message endpoint 0x%02x\n", MessageEndpoint);
+	ret = libusb_clear_halt(devh, MessageEndpoint);
+	if (ret)
+		SHOW_PROGRESS(output," Could not reset endpoint (probably harmless): %d\n", ret);
+	usleep(50000);
+
+	if (ReleaseDelay) {
+		SHOW_PROGRESS(output,"Wait for %d ms before releasing interface ...\n", ReleaseDelay);
+		usleep(ReleaseDelay*1000);
+	}
+	ret = libusb_release_interface(devh, Interface);
+	if (ret)
+		goto skip;
+	return 1;
+
+skip:
+	SHOW_PROGRESS(output," Device is gone, skip any further commands\n");
+	libusb_close(devh);
+	devh = NULL;
+	return 2;
+}
+
+
+int switchConfiguration ()
+{
+	int ret, count = SWITCH_CONFIG_MAXTRIES;
+
+	SHOW_PROGRESS(output,"Change configuration to %i ...\n", Configuration);
+	while (((ret = libusb_set_configuration(devh, Configuration)) < 0) && --count) {
+		SHOW_PROGRESS(output," Device is busy, try to detach kernel driver\n");
+		detachDriver();
+	}
+	if (ret < 0 ) {
+		SHOW_PROGRESS(output," Changing the configuration failed (error %d). Try to continue\n", ret);
+		return 0;
+	} else {
+		SHOW_PROGRESS(output," OK, configuration set\n");
+		return 1;
+	}
+}
+
+
+int switchAltSetting ()
+{
+	int ret;
+	SHOW_PROGRESS(output,"Change to alt setting %i ...\n", AltSetting);
+	ret = libusb_claim_interface(devh, Interface);
+	if (ret < 0) {
+		SHOW_PROGRESS(output," Could not claim interface (error %d). Skip AltSetting\n", ret);
+		return 0;
+	}
+	ret = libusb_set_interface_alt_setting(devh, Interface, AltSetting);
+	libusb_release_interface(devh, Interface);
+	if (ret < 0) {
+		SHOW_PROGRESS(output," Change to alt setting returned error %d. Try to continue\n", ret);
+		return 0;
+	} else
+		return 1;
+}
+
+
+void switchHuaweiMode ()
+{
+	int ret;
+	SHOW_PROGRESS(output,"Send old Huawei control message ...\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
+			LIBUSB_REQUEST_SET_FEATURE, 00000001, 0, buffer, 0, 1000);
+
+	if (ret != 0) {
+		fprintf(stderr, "Error: Huawei control message failed (error %d). Abort\n\n", ret);
+		exit(0);
+	}
+}
+
+
+void switchSierraMode ()
+{
+	int ret;
+	SHOW_PROGRESS(output,"Send Sierra control message\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
+		LIBUSB_REQUEST_SET_INTERFACE, 00000001, 0, buffer, 0, 1000);
+	if (ret == LIBUSB_ERROR_PIPE) {
+		SHOW_PROGRESS(output," communication with device stopped. May have switched modes anyway\n");
+	    return;
+	}
+	if (ret < 0) {
+		fprintf(stderr, "Error: Sierra control message failed (error %d). Abort\n\n", ret);
+	    exit(0);
+	}
+}
+
+
+void switchGCTMode ()
+{
+	int ret;
+	ret = libusb_claim_interface(devh, Interface);
+	if (ret != 0) {
+		SHOW_PROGRESS(output," Could not claim interface (error %d). Skip GCT sequence\n", ret);
+		return;
+	}
+	SHOW_PROGRESS(output,"Send GCT control message 1 ...\n type (should be 161/0xA1): %d",
+			LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN);
+
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN,
+			0xa0, 0, Interface, buffer, 1, 1000);
+
+	if (ret < 0) {
+		SHOW_PROGRESS(output," GCT control message 1 failed (error %d), continue anyway ...\n", ret);
+	}
+	SHOW_PROGRESS(output,"Send GCT control message 2 ...\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN,
+			0xfe, 0, Interface, buffer, 1, 1000);
+
+	if (ret < 0) {
+		SHOW_PROGRESS(output," GCT control message 2 failed (error %d). Abort\n\n", ret);
+	}
+	libusb_release_interface(devh, Interface);
+	if (ret < 0)
+		exit(0);
+}
+
+
+void switchKobilMode() {
+	int ret;
+	SHOW_PROGRESS(output,"Send Kobil control message ...\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
+			0x88, 0, 0, buffer, 8, 1000);
+
+	if (ret < 0) {
+		fprintf(stderr, "Error: Kobil control message failed (error %d). Abort\n\n", ret);
+		exit(0);
+	}
+}
+
+
+void switchQisdaMode () {
+	int ret;
+	SHOW_PROGRESS(output,"Sending Qisda control message ...\n");
+	memcpy(buffer, "\x05\x8c\x04\x08\xa0\xee\x20\x00\x5c\x01\x04\x08\x98\xcd\xea\xbf", 16);
+	ret = libusb_control_transfer(devh, 0x40, 0x04, 0, 0, buffer, 16, 1000);
+	if (ret < 0) {
+		fprintf(stderr, "Error: Qisda control message failed (error %d). Abort\n\n", ret);
+		exit(0);
+	}
+}
+
+
+void switchQuantaMode() {
+	int ret;
+	SHOW_PROGRESS(output,"Send Quanta control message ...\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
+			0xff, 0, 0, buffer, 0, 1000);
+
+	if (ret < 0) {
+		SHOW_PROGRESS(output,"Error: Quanta control message failed (error %d). Abort\n\n", ret);
+		exit(0);
+	}
+}
+
+
+void switchBlackberryMode ()
+{
+	int ret;
+	SHOW_PROGRESS(output,"Send Blackberry control message 1 ...\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
+			0xb1, 0x0000, 0, buffer, 8, 1000);
+
+	if (ret != 8) {
+		fprintf(stderr, "Error: Blackberry control message 1 failed (result %d)\n", ret);
+	}
+	SHOW_PROGRESS(output,"Send Blackberry control message 2 ...\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
+			0xa9, 0x000e, 0, buffer, 2, 1000);
+
+	if (ret != 2) {
+		fprintf(stderr, "Error: Blackberry control message 2 failed (result %d). Abort\n\n", ret);
+		exit(0);
+	}
+}
+
+
+void switchPantechMode()
+{
+	int ret;
+	SHOW_PROGRESS(output,"Send Pantech control message, wValue %d ...\n", PantechMode);
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
+			0x70, PantechMode, 0, buffer, 0, 1000);
+
+	if (ret < 0) {
+		SHOW_PROGRESS(output," Error: Pantech control message failed (error %d). Abort\n\n", ret);
+		exit(0);
+	}
+}
+
+
+#define EP_OUT 0x02
+#define EP_IN 0x81
+#define SIZE 0x08
+
+#define MOBILE_ACTION_READLOOP1 63
+#define MOBILE_ACTION_READLOOP2 73
+
+/* The code here is statically derived from sniffing (and confirmed working).
+ * However I bet it could be simplified significantly.
+ */
+
+void switchActionMode ()
+{
+	int ret, i;
+	SHOW_PROGRESS(output,"Send MobileAction control sequence ...\n");
+	memcpy(buffer, "\xb0\x04\x00\x00\x02\x90\x26\x86", SIZE);
+	libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
+			0x09, 0x0300, 0, buffer, SIZE, 1000);
+
+	memcpy(buffer, "\xb0\x04\x00\x00\x02\x90\x26\x86", SIZE);
+	libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
+			0x09, 0x0300, 0, buffer, SIZE, 1000);
+
+	usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	memcpy(buffer, "\x37\x01\xfe\xdb\xc1\x33\x1f\x83", SIZE);
+	usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
+	usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	memcpy(buffer, "\x37\x0e\xb5\x9d\x3b\x8a\x91\x51", SIZE);
+	usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
+	usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	memcpy(buffer, "\x34\x87\xba\x0d\xfc\x8a\x91\x51", SIZE);
+	usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
+	for (i=0; i < MOBILE_ACTION_READLOOP1; i++) {
+		usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	}
+	memcpy(buffer, "\x37\x01\xfe\xdb\xc1\x33\x1f\x83", SIZE);
+	usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
+	usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	memcpy(buffer, "\x37\x0e\xb5\x9d\x3b\x8a\x91\x51", SIZE);
+	usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
+	usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	memcpy(buffer, "\x34\x87\xba\x0d\xfc\x8a\x91\x51", SIZE);
+	usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
+	for (i=0; i < MOBILE_ACTION_READLOOP2; i++) {
+		usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	}
+	memcpy(buffer, "\x33\x04\xfe\x00\xf4\x6c\x1f\xf0", SIZE);
+	usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
+	usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	memcpy(buffer, "\x32\x07\xfe\xf0\x29\xb9\x3a\xf0", SIZE);
+	ret = usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000);
+	usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000);
+	if (ret < 0) {
+		SHOW_PROGRESS(output," MobileAction control sequence did not complete\n"
+			" Last error was %d\n",ret);
+	} else {
+		SHOW_PROGRESS(output," MobileAction control sequence complete\n");
+	}
+}
+
+
+#define SQN_SET_DEVICE_MODE_REQUEST		0x0b
+#define SQN_GET_DEVICE_MODE_REQUEST		0x0a
+
+#define SQN_DEFAULT_DEVICE_MODE			0x00
+#define SQN_MASS_STORAGE_MODE			0x01
+#define SQN_CUSTOM_DEVICE_MODE			0x02
+
+void switchSequansMode()
+{
+
+	int ret;
+	SHOW_PROGRESS(output,"Send Sequans control message\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE
+			| LIBUSB_ENDPOINT_OUT, SQN_SET_DEVICE_MODE_REQUEST, SQN_CUSTOM_DEVICE_MODE,
+			0, buffer, 0, 1000);
+
+	if (ret < 0) {
+		fprintf(stderr, "Error: Sequans request failed (error %d). Abort\n\n", ret);
+	    exit(0);
+	}
+}
+
+
+void switchCiscoMode()
+{
+	int ret, i, j;
+
+	strcpy(Messages[0],"55534243f83bcd810002000080000afd000000030000000100000000000000");
+	strcpy(Messages[1],"55534243984300820002000080000afd000000070000000100000000000000");
+	strcpy(Messages[2],"55534243984300820000000000000afd000100071000000000000000000000");
+	strcpy(Messages[3],"55534243984300820002000080000afd000200230000000100000000000000");
+	strcpy(Messages[4],"55534243984300820000000000000afd000300238200000000000000000000");
+	strcpy(Messages[5],"55534243984300820002000080000afd000200260000000100000000000000");
+	strcpy(Messages[6],"55534243984300820000000000000afd00030026c800000000000000000000");
+	strcpy(Messages[7],"55534243d84c04820002000080000afd000010730000000100000000000000");
+	strcpy(Messages[8],"55534243d84c04820002000080000afd000200240000000100000000000000");
+	strcpy(Messages[9],"55534243d84c04820000000000000afd000300241300000000000000000000");
+	strcpy(Messages[10],"55534243d84c04820000000000000afd000110732400000000000000000000");
+
+	SHOW_PROGRESS(output,"Set up Cisco interface %d\n", Interface);
+	ret = libusb_claim_interface(devh, Interface);
+	if (ret < 0) {
+		SHOW_PROGRESS(output," Could not claim interface (error %d). Abort\n", ret);
+		abortExit();
+	}
+//	libusb_clear_halt(devh, MessageEndpoint);
+	if (show_progress)
+		fflush(output);
+
+//	ret = read_bulk(ResponseEndpoint, ByteString, 13);
+//	SHOW_PROGRESS(output," Extra response (CSW) read, result %d\n",ret);
+
+	for (i=0; i<11; i++) {
+		if ( sendMessage(Messages[i], i+1) )
+			goto skip;
+
+		for (j=1; j<4; j++) {
+
+			SHOW_PROGRESS(output," Read the CSW for bulk message %d (attempt %d) ...\n",i+1,j);
+			ret = read_bulk(ResponseEndpoint, ByteString, 13);
+			SHOW_PROGRESS(output,"\n");
+
+			if (ret < 0)
+				goto skip;
+			if (ret == 13)
+				break;
+		}
+	}
+	libusb_clear_halt(devh, MessageEndpoint);
+	libusb_clear_halt(devh, ResponseEndpoint);
+
+	ReleaseDelay = 2000;
+	SHOW_PROGRESS(output,"Wait for %d ms before releasing interface ...\n", ReleaseDelay);
+	usleep(ReleaseDelay*1000);
+
+	ret = libusb_release_interface(devh, Interface);
+	if (ret < 0)
+		goto skip;
+	return;
+
+skip:
+	SHOW_PROGRESS(output,"Device returned error %d, skip further commands\n", ret);
+	libusb_close(devh);
+	devh = NULL;
+}
+
+
+int switchSonyMode ()
+{
+	int ret, i, found;
+	detachDriver();
+
+	if (CheckSuccess) {
+		CheckSuccess = 0;
+	}
+
+	SHOW_PROGRESS(output,"Send Sony control message\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE
+			| LIBUSB_ENDPOINT_IN, 0x11, 2, 0, buffer, 3, 100);
+
+	if (ret < 0) {
+		fprintf(stderr, "Error: Sony control message failed (error %d). Abort\n\n", ret);
+		exit(0);
+	} else
+		SHOW_PROGRESS(output," OK, control message sent, wait for device to return ...\n");
+
+	libusb_close(devh);
+	devh = NULL;
+
+	/* Now waiting for the device to reappear */
+	devnum=-1;
+	busnum=-1;
+	i=0;
+	dev = 0;
+	while ( dev == 0 && i < 30 ) {
+		if ( i > 5 ) {
+			dev = search_devices(&found, DefaultVendor, DefaultProductList, TargetClass,
+					0, SEARCH_TARGET);
+		}
+		if ( dev != 0 )
+			break;
+		sleep(1);
+		if (show_progress) {
+			fprintf(output,"#");
+			fflush(stdout);
+		}
+		i++;
+	}
+	SHOW_PROGRESS(output,"\n After %d seconds:",i);
+	if ( dev ) {
+		SHOW_PROGRESS(output," device came back, proceed\n");
+		libusb_open(dev, &devh);
+		if (devh == 0) {
+			fprintf(stderr, "Error: could not get handle on device\n");
+			return 0;
+		}
+	} else {
+		SHOW_PROGRESS(output," device still gone, abort\n");
+		return 0;
+	}
+	sleep(1);
+
+	SHOW_PROGRESS(output,"Send Sony control message again ...\n");
+	ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE
+			| LIBUSB_ENDPOINT_IN, 0x11, 2, 0, buffer, 3, 100);
+
+	if (ret < 0) {
+		fprintf(stderr, "Error: Sony control message (2) failed (error %d)\n", ret);
+		return 0;
+	}
+	SHOW_PROGRESS(output," OK, control message sent\n");
+	return 1;
+}
+
+
+/* Detach driver
+ */
+int detachDriver()
+{
+
+	int ret;
+	SHOW_PROGRESS(output,"Looking for active driver ...\n");
+	ret = libusb_kernel_driver_active(devh, 0);
+	if (ret == LIBUSB_ERROR_NOT_SUPPORTED) {
+		fprintf(output," Can't do driver detection on this platform.\n");
+		return 2;
+	}
+	if (ret < 0) {
+		fprintf(output," Driver check failed with error %d. Try to continue\n", ret);
+		return 2;
+	}
+	if (ret == 0) {
+		SHOW_PROGRESS(output," No active driver found. Detached before or never attached\n");
+		return 1;
+	}
+
+	ret = libusb_detach_kernel_driver(devh, Interface);
+	if (ret == LIBUSB_ERROR_NOT_SUPPORTED) {
+		fprintf(output," Can't do driver detaching on this platform.\n");
+		return 2;
+	}
+	if (ret == 0) {
+		SHOW_PROGRESS(output," OK, driver detached\n");
+	} else
+		SHOW_PROGRESS(output," Driver detach failed (error %d). Try to continue\n", ret);
+	return 1;
+}
+
+
+int sendMessage(char* message, int count)
+{
+	int ret, message_length;
+
+	if (strlen(message) % 2 != 0) {
+		fprintf(stderr, "Error: MessageContent %d hex string has uneven length. Skipping ...\n", count);
+		return 1;
+	}
+	message_length = strlen(message) / 2;
+	if ( hexstr2bin(message, ByteString, message_length) == -1) {
+		fprintf(stderr, "Error: MessageContent %d %s\n is not a hex string. Skipping ...\n",
+				count, MessageContent);
+
+		return 1;
+	}
+	SHOW_PROGRESS(output,"Trying to send message %d to endpoint 0x%02x ...\n", count, MessageEndpoint);
+	fflush(output);
+	ret = write_bulk(MessageEndpoint, ByteString, message_length);
+	if (ret == LIBUSB_ERROR_NO_DEVICE)
+		return 1;
+
+	return 0;
+}
+
+
+int checkSuccess()
+{
+	int ret, i;
+	int newTargetCount, success=0;
+
+	SHOW_PROGRESS(output,"\nCheck for mode switch (max. %d times, once per second) ...\n", CheckSuccess);
+	sleep(1);
+
+	/* If target parameters are given, don't check for vanished device
+	 * Changed for Cisco AM10 where a new device is added while the install
+	 * storage device stays active
+	 */
+	if ((TargetVendor || TargetClass) && devh) {
+		libusb_close(devh);
+		devh = NULL;
+	}
+
+	/* if target ID is not given but target class is, assign default as target;
+	 * it will be needed for sysmode output
+	 */
+	if (!TargetVendor && TargetClass) {
+		TargetVendor = DefaultVendor;
+		TargetProduct = DefaultProduct;
+	}
+
+	/* devh is 0 if device vanished during command transmission or if target params were given
+	 */
+	if (devh)
+		for (i=0; i < CheckSuccess; i++) {
+
+			/* Test if default device still can be accessed; positive result does
+			 * not necessarily mean failure
+			 */
+			SHOW_PROGRESS(output," Wait for original device to vanish ...\n");
+
+			ret = libusb_claim_interface(devh, Interface);
+			libusb_release_interface(devh, Interface);
+			if (ret < 0) {
+				SHOW_PROGRESS(output," Original device can't be accessed anymore. Good.\n");
+				libusb_close(devh);
+				devh = NULL;
+				break;
+			}
+			if (i == CheckSuccess-1) {
+				SHOW_PROGRESS(output," Original device still present after the timeout\n\n"
+						"Mode switch most likely failed. Bye!\n\n");
+			} else
+				sleep(1);
+		}
+
+	if ( TargetVendor && (TargetProduct > -1 || TargetProductList[0] != '\0') ) {
+
+		/* Recount target devices (compare with previous count) if target data is given.
+		 * Target device on the same bus with higher device number is returned,
+		 * description is read for syslog message
+		 */
+		for (i=i; i < CheckSuccess; i++) {
+			SHOW_PROGRESS(output," Search for target devices ...\n");
+			dev = search_devices(&newTargetCount, TargetVendor, TargetProductList,
+					TargetClass, 0, SEARCH_TARGET);
+
+			if (dev && (newTargetCount > targetDeviceCount)) {
+				if (verbose) {
+					libusb_open(dev, &devh);
+					fprintf(output,"\nFound target device %03d on bus %03d\n",
+							libusb_get_device_address(dev), libusb_get_bus_number(dev));
+
+					fprintf(output,"\nTarget device description data\n");
+					deviceDescription();
+					libusb_close(devh);
+					devh = NULL;
+				}
+				SHOW_PROGRESS(output," Found correct target device\n\n"
+						"Mode switch succeeded. Bye!\n\n");
+
+				success = 2;
+				break;
+			}
+			if (i == CheckSuccess-1) {
+				SHOW_PROGRESS(output," No new devices in target mode or class found\n\n"
+						"Mode switch has failed. Bye!\n\n");
+			} else
+				sleep(1);
+		}
+	} else
+		/* No target data given, rely on the vanished device */
+		if (!devh) {
+			SHOW_PROGRESS(output," (For a better success check provide target IDs or class)\n");
+			SHOW_PROGRESS(output," Original device vanished after switching\n\n"
+					"Mode switch most likely succeeded. Bye!\n\n");
+			success = 1;
+		}
+
+	switch (success) {
+		case 3: 
+			if (sysmode)
+				syslog(LOG_NOTICE, "switched to new device, but hit libusb1 bug");
+			TargetProduct = -1;
+			success = 1;
+			break;
+		case 2: 
+			if (sysmode)
+				syslog(LOG_NOTICE, "switched to %04x:%04x on %03d/%03d", TargetVendor,
+						TargetProduct, busnum, devnum);
+
+			success = 1;
+			break;
+		case 1:
+			if (sysmode)
+				syslog(LOG_NOTICE, "device seems to have switched");
+		default:
+			;
+	}
+	if (sysmode)
+		closelog();
+
+	return success;
+
+}
+
+
+int write_bulk(int endpoint, unsigned char *message, int length)
+{
+	int ret = usb_bulk_io(devh, endpoint, message, length, 3000);
+	if (ret >= 0 ) {
+		SHOW_PROGRESS(output," OK, message successfully sent\n");
+	} else
+		if (ret == LIBUSB_ERROR_NO_DEVICE) {
+			SHOW_PROGRESS(output," Device seems to have vanished right after sending. Good.\n");
+		} else
+			SHOW_PROGRESS(output," Sending the message returned error %d. Try to continue\n", ret);
+	return ret;
+
+}
+
+
+int read_bulk(int endpoint, unsigned char *buffer, int length)
+{
+	int ret = usb_bulk_io(devh, endpoint, buffer, length, 3000);
+	if (ret >= 0 ) {
+		SHOW_PROGRESS(output," Response successfully read (%d bytes)", ret);
+	} else
+		if (ret == LIBUSB_ERROR_NO_DEVICE) {
+			SHOW_PROGRESS(output," Device seems to have vanished after reading. Good.");
+		} else
+			SHOW_PROGRESS(output," Response reading failed (error %d)", ret);
+	return ret;
+
+}
+
+
+void release_usb_device(int __attribute__((unused)) dummy)
+{
+	SHOW_PROGRESS(output,"Program cancelled by system. Bye!\n\n");
+	if (devh)
+		libusb_release_interface(devh, Interface);
+	close_all();
+	exit(0);
+
+}
+
+
+/* Iterates over busses and devices, counts the ones which match the given
+ * parameters and returns the last one of them
+*/
+struct libusb_device* search_devices( int *numFound, int vendor, char* productList,
+		int targetClass, int configuration, int mode)
+{
+	char *listcopy=NULL, *token;
+	unsigned char buffer[2];
+	int devClass, product;
+	struct libusb_device* right_dev = NULL;
+//	struct libusb_device_handle *testdevh;
+	struct libusb_device **devs;
+	int i=0;
+
+	/* only target class given, target vendor and product assumed unchanged */
+	if ( targetClass && !(vendor || strlen(productList)) ) {
+		vendor = DefaultVendor;
+		productList = DefaultProductList;
+	}
+	*numFound = 0;
+
+	/* Sanity check */
+	if (!vendor || productList == '\0')
+		return NULL;
+
+	listcopy = malloc(strlen(productList)+1);
+
+	if (libusb_get_device_list(ctx, &devs) < 0) {
+		perror("Libusb failed to get USB access!");
+		return 0;
+	}
+
+	while ((dev = devs[i++]) != NULL) {
+		struct libusb_device_descriptor descriptor;
+		libusb_get_device_descriptor(dev, &descriptor);
+
+		if (mode == SEARCH_BUSDEV) {
+			if ((libusb_get_bus_number(dev) != busnum) ||
+				(libusb_get_device_address(dev) != devnum))
+				continue;
+			else
+				SHOW_PROGRESS(output," bus/device number matched\n");
+		}
+
+		if (verbose)
+			fprintf (output,"  found USB ID %04x:%04x\n",
+					descriptor.idVendor, descriptor.idProduct);
+		if (descriptor.idVendor != vendor)
+			continue;
+		if (verbose)
+			fprintf (output,"   vendor ID matched\n");
+
+		strcpy(listcopy, productList);
+		token = strtok(listcopy, ",");
+		while (token != NULL) {
+			if (strlen(token) != 4) {
+				SHOW_PROGRESS(output,"Error: entry in product ID list has wrong length: %s. "
+						"Ignored\n", token);
+
+				goto NextToken;
+			}
+			if ( hexstr2bin(token, buffer, strlen(token)/2) == -1) {
+				SHOW_PROGRESS(output,"Error: entry in product ID list is not a hex string: %s. "
+						"Ignored\n", token);
+
+				goto NextToken;
+			}
+			product = 0;
+			product += (unsigned char)buffer[0];
+			product <<= 8;
+			product += (unsigned char)buffer[1];
+			if (product == descriptor.idProduct) {
+				SHOW_PROGRESS(output,"   product ID matched\n");
+
+				if (targetClass != 0) {
+					// TargetClass is set, check class of first interface
+					struct libusb_device_descriptor descriptor;
+					libusb_get_device_descriptor(dev, &descriptor);
+					devClass = descriptor.bDeviceClass;
+					struct libusb_config_descriptor *config;
+					libusb_get_config_descriptor(dev, 0, &config);
+					int ifaceClass = config->interface[0].altsetting[0].bInterfaceClass;
+					libusb_free_config_descriptor(config);
+					if (devClass == 0)
+						devClass = ifaceClass;
+					else
+						/* Check for some quirky devices */
+						if (devClass != ifaceClass)
+							devClass = ifaceClass;
+					if (devClass == targetClass) {
+						if (verbose)
+							fprintf (output,"   target class %02x matches\n", targetClass);
+						if (mode == SEARCH_TARGET) {
+							(*numFound)++;
+							right_dev = dev;
+							if (verbose)
+								fprintf (output,"   count device\n");
+						} else
+							if (verbose)
+								fprintf (output,"   device not counted, target class reached\n");
+					} else {
+						if (verbose)
+							fprintf (output,"   device class %02x not matching target\n", devClass);
+						if (mode == SEARCH_DEFAULT || mode == SEARCH_BUSDEV) {
+							(*numFound)++;
+							right_dev = dev;
+							if (verbose)
+								fprintf (output,"   count device\n");
+						}
+					}
+				} else if (configuration > 0) {
+					// Configuration parameter is set, check device configuration
+					int testconfig = get_current_config_value(dev);
+					if (testconfig != configuration) {
+						if (verbose)
+							fprintf (output,"   device configuration %d not matching target\n",
+									testconfig);
+
+						(*numFound)++;
+						right_dev = dev;
+						if (verbose)
+							fprintf (output,"   count device\n");
+					} else
+						if (verbose)
+							fprintf (output,"   device not counted, target configuration reached\n");
+				} else {
+					// Neither TargetClass nor Configuration are set
+					(*numFound)++;
+					right_dev = dev;
+					if (mode == SEARCH_BUSDEV)
+						break;
+				}
+			}
+
+			NextToken:
+			token = strtok(NULL, ",");
+		}
+	}
+	if (listcopy != NULL)
+		free(listcopy);
+	return right_dev;
+}
+
+
+/* Autodetect bulk endpoints (ab) */
+
+int find_first_bulk_endpoint(int direction)
+{
+	int i, j;
+	const struct libusb_interface_descriptor *alt;
+	const struct libusb_endpoint_descriptor *ep;
+
+	for (j=0; j < active_config->bNumInterfaces; j++) {
+		alt = &(active_config->interface[j].altsetting[0]);
+		if (alt->bInterfaceNumber == Interface) {
+			for (i=0; i < alt->bNumEndpoints; i++) {
+				ep = &(alt->endpoint[i]);
+				if ( ( (ep->bmAttributes & LIBUSB_ENDPOINT_ADDRESS_MASK) == LIBUSB_TRANSFER_TYPE_BULK)
+						&& ( (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == direction ) ) {
+
+					return ep->bEndpointAddress;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+
+int get_current_config_value()
+{
+	SHOW_PROGRESS(output,"Get the current device configuration ...\n");
+	if (active_config != NULL) {
+		libusb_free_config_descriptor(active_config);
+		active_config = NULL;
+	}
+	int ret = libusb_get_active_config_descriptor(dev, &active_config);
+	if (ret < 0) {
+		SHOW_PROGRESS(output," Determining the active configuration failed (error %d). Abort\n", ret);
+		abortExit();
+	}
+	return active_config->bConfigurationValue;
+}
+
+
+int get_interface_class()
+{
+	int i;
+	for (i=0; i < active_config->bNumInterfaces; i++) {
+		if (active_config->interface[i].altsetting[0].bInterfaceNumber == Interface)
+			return active_config->interface[i].altsetting[0].bInterfaceClass;
+	}
+	return -1;
+}
+
+
+/* Parameter parsing */
+
+char* ReadParseParam(const char* FileName, char *VariableName)
+{
+	static int numLines = 0;
+	static char* ConfigBuffer[MAXLINES];
+	char *VarName, *Comment=NULL, *Equal=NULL;
+	char *FirstQuote, *LastQuote, *P1, *P2;
+	int Line=0;
+	unsigned Len=0, Pos=0;
+	char Str[LINE_DIM], *token, *configPos;
+	FILE *file = NULL;
+
+	// Reading and storing input during the first call
+	if (numLines==0) {
+		if (strncmp(FileName,"##",2) == 0) {
+			if (verbose) fprintf(output,"\nRead long config from command line\n");
+			// "Embedded" configuration data
+			configPos = (char*)FileName;
+			token = strtok(configPos, "\n");
+			strncpy(Str,token,LINE_DIM-1);
+		} else {
+			if (strcmp(FileName, "stdin")==0) {
+				if (verbose) fprintf(output,"\nRead long config from stdin\n");
+				file = stdin;
+			} else {
+				if (verbose) fprintf(output,"\nRead config file: %s\n", FileName);
+				file=fopen(FileName, "r");
+			}
+			if (file==NULL) {
+				fprintf(stderr, "Error: Could not find file %s. Abort\n\n", FileName);
+				abortExit();
+			} else {
+				token = fgets(Str, LINE_DIM-1, file);
+			}
+		}
+		while (token != NULL && numLines < MAXLINES) {
+//			Line++;
+			Len=strlen(Str);
+			if (Len==0)
+				goto NextLine;
+			if (Str[Len-1]=='\n' or Str[Len-1]=='\r')
+				Str[--Len]='\0';
+			Equal = strchr (Str, '=');			// search for equal sign
+			Pos = strcspn (Str, ";#!");			// search for comment
+			Comment = (Pos==Len) ? NULL : Str+Pos;
+			if (Equal==NULL or ( Comment!=NULL and Comment<=Equal))
+				goto NextLine;	// Comment or irrelevant, don't save
+			Len=strlen(Str)+1;
+			ConfigBuffer[numLines] = malloc(Len*sizeof(char));
+			strcpy(ConfigBuffer[numLines],Str);
+			numLines++;
+		NextLine:
+			if (file == NULL) {
+				token = strtok(NULL, "\n");
+				if (token != NULL)
+					strncpy(Str,token,LINE_DIM-1);
+			} else
+				token = fgets(Str, LINE_DIM-1, file);
+		}
+		if (file != NULL)
+			fclose(file);
+	}
+
+	// Now checking for parameters
+	Line=0;
+	while (Line < numLines) {
+		strcpy(Str,ConfigBuffer[Line]);
+		Equal = strchr (Str, '=');			// search for equal sign
+		*Equal++ = '\0';
+
+		// String
+		FirstQuote=strchr (Equal, '"');		// search for double quote char
+		LastQuote=strrchr (Equal, '"');
+		if (FirstQuote!=NULL) {
+			if (LastQuote==NULL) {
+				fprintf(stderr, "Error reading parameters from file %s - "
+						"Missing end quote:\n%s\n", FileName, Str);
+
+				goto Next;
+			}
+			*FirstQuote=*LastQuote='\0';
+			Equal=FirstQuote+1;
+		}
+
+		// removes leading/trailing spaces
+		Pos=strspn (Str, " \t");
+		if (Pos==strlen(Str)) {
+			fprintf(stderr, "Error reading parameters from file %s - "
+					"Missing variable name:\n%s\n", FileName, Str);
+
+			goto Next;
+		}
+		while ((P1=strrchr(Str, ' '))!=NULL or (P2=strrchr(Str, '\t'))!=NULL)
+			if (P1!=NULL) *P1='\0';
+			else if (P2!=NULL) *P2='\0';
+		VarName=Str+Pos;
+
+		Pos=strspn (Equal, " \t");
+		if (Pos==strlen(Equal)) {
+			fprintf(stderr, "Error reading parameter from file %s - "
+					"Missing value:\n%s\n", FileName, Str);
+
+			goto Next;
+		}
+		Equal+=Pos;
+
+		if (strcmp(VarName, VariableName)==0) {		// Found it
+			return Equal;
+		}
+	Next:
+		Line++;
+	}
+
+	return NULL;
+}
+
+
+int hex2num(char c)
+{
+	if (c >= '0' && c <= '9')
+	return c - '0';
+	if (c >= 'a' && c <= 'f')
+	return c - 'a' + 10;
+	if (c >= 'A' && c <= 'F')
+	return c - 'A' + 10;
+	return -1;
+}
+
+
+int hex2byte(const char *hex)
+{
+	int a, b;
+	a = hex2num(*hex++);
+	if (a < 0)
+		return -1;
+	b = hex2num(*hex++);
+	if (b < 0)
+		return -1;
+	return (a << 4) | b;
+}
+
+
+int hexstr2bin(const char *hex, unsigned char *buffer, int len)
+{
+	int i;
+	int a;
+	const char *ipos = hex;
+	unsigned char *opos = buffer;
+
+	for (i = 0; i < len; i++) {
+	a = hex2byte(ipos);
+	if (a < 0)
+		return -1;
+	*opos++ = (unsigned char) a;
+	ipos += 2;
+	}
+	return 0;
+}
+
+
+void close_all()
+{
+	int i;
+	if (Messages) {
+		for ( i = 0; i < MSG_DIM; i++ ) {
+			free(Messages[i]);
+		}
+		free(Messages);
+	}
+	if (active_config)
+		libusb_free_config_descriptor(active_config);
+	if (devh)
+		libusb_close(devh);
+	// libusb_exit will crash on Raspbian 7, crude protection
+#ifndef __ARMEL__
+	libusb_exit(NULL);
+#endif
+	if (sysmode)
+		closelog();
+}
+
+
+void abortExit()
+{
+	close_all();
+	exit(1);
+}
+
+
+void printVersion()
+{
+	char* version = VERSION;
+	fprintf(output,"\n * usb_modeswitch: handle USB devices with multiple modes\n"
+		" * Version %s (C) Josua Dietze 2016\n"
+		" * Based on libusb1/libusbx\n\n"
+		" ! PLEASE REPORT NEW CONFIGURATIONS !\n\n", version);
+}
+
+
+void printHelp()
+{
+	fprintf(output,"\nUsage: usb_modeswitch [<params>] [-c filename]\n\n"
+	" -h, --help                    this help\n"
+	" -e, --version                 print version information and exit\n"
+	" -j, --find-mbim               return config no. with MBIM interface, exit\n\n"
+	" -v, --default-vendor NUM      vendor ID of original mode (mandatory)\n"
+	" -p, --default-product NUM     product ID of original mode (mandatory)\n"
+	" -V, --target-vendor NUM       target mode vendor ID (optional)\n"
+	" -P, --target-product NUM      target mode product ID (optional)\n"
+	" -C, --target-class NUM        target mode device class (optional)\n"
+	" -b, --bus-num NUM             system bus number of device (for hard ID)\n"
+	" -g, --device-num NUM          system device number (for hard ID)\n"
+	" -m, --message-endpoint NUM    direct the message transfer there (optional)\n"
+	" -M, --message-content <msg>   message to send (hex number as string)\n"
+	" -2 <msg>, -3 <msg>            additional messages to send (-n recommended)\n"
+	" -w, --release-delay NUM       wait NUM ms before releasing the interface\n"
+	" -n, --need-response           obsolete, no effect (always on)\n"
+	" -r, --response-endpoint NUM   read response from there (optional)\n"
+	" -K, --std-eject               send standard EJECT sequence\n"
+	" -d, --detach-only             detach the active driver, no further action\n"
+	" -H, --huawei-mode             apply a special procedure\n"
+	" -J, --huawei-new-mode         apply a special procedure\n"
+	" -S, --sierra-mode             apply a special procedure\n"
+	" -O, --sony-mode               apply a special procedure\n"
+	" -G, --gct-mode                apply a special procedure\n"
+	" -N, --sequans-mode            apply a special procedure\n"
+	" -A, --mobileaction-mode       apply a special procedure\n"
+	" -T, --kobil-mode              apply a special procedure\n"
+	" -L, --cisco-mode              apply a special procedure\n"
+	" -B, --qisda-mode              apply a special procedure\n"
+	" -E, --quanta-mode             apply a special procedure\n"
+	" -F, --pantech-mode NUM        apply a special procedure, pass NUM through\n"
+	" -Z, --blackberry-mode         apply a special procedure\n"
+	" -U, --option-mode             apply a special procedure\n"
+	" -R, --reset-usb               reset the device after all other actions\n"
+	" -Q, --quiet                   don't show progress or error messages\n"
+	" -W, --verbose                 print all settings and debug output\n"
+	" -D, --sysmode                 specific result and syslog message\n"
+	" -s, --success <seconds>       switching result check with timeout\n"
+	" -I, --inquire                 obsolete, no effect\n\n"
+	" -c, --config-file <filename>  load long configuration from file\n\n"
+	" -t, --stdinput                read long configuration from stdin\n\n"
+	" -f, --long-config <text>      get long configuration from string\n\n"
+	" -i, --interface NUM           select initial USB interface (default 0)\n"
+	" -u, --configuration NUM       select USB configuration\n"
+	" -a, --altsetting NUM          select alternative USB interface setting\n\n");
+}
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.conf b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.conf
new file mode 100755
index 0000000..7c68993
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.conf
@@ -0,0 +1,31 @@
+# Configuration for the usb_modeswitch package, a mode switching tool for
+# USB devices providing multiple states or modes
+#
+# Evaluated by the wrapper script /usr/sbin/usb_modeswitch_dispatcher
+#
+# To enable an option, set it to "1", "yes" or "true" (case doesn't matter)
+# Everything else counts as "disable"
+
+
+# Disable automatic mode switching globally (e.g. to access the original
+# install storage)
+
+DisableSwitching=0
+
+# Disable check for MBIM module presence and configuration globally (to aid
+# special embedded environments)
+
+DisableMBIMGlobal=0
+
+# Enable logging (results in a extensive report file in /var/log, named
+# "usb_modeswitch_<interface-name>" and probably others
+
+EnableLogging=0
+
+
+# Optional increase of "delay_use" for the usb-storage driver; there are hints
+# that a recent kernel default change to 1 sec. may lead to problems, particu-
+# larly with USB 3.0 ports. Set this to at least 3 (seconds) in that case.
+# Does nothing if the current system value is same or higher
+
+#SetStorageDelay=4
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_002a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_002a
new file mode 100755
index 0000000..9813a20
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_002a
@@ -0,0 +1,4 @@
+# HP LaserJet Professional P1102
+TargetClass=0x07
+MessageContent="555342431234567800000000000006d0000000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_521d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_521d
new file mode 100755
index 0000000..609c7a1
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_521d
@@ -0,0 +1,2 @@
+# HP hs3110
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_531d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_531d
new file mode 100755
index 0000000..8b5a348
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_531d
@@ -0,0 +1,2 @@
+# HP hs3120
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_541d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_541d
new file mode 100755
index 0000000..ecb0c48
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_541d
@@ -0,0 +1,2 @@
+# HP hs3114
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_581d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_581d
new file mode 100755
index 0000000..b2f662d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_581d
@@ -0,0 +1,2 @@
+# HP hs4112
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_631d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_631d
new file mode 100755
index 0000000..ff2dcc7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_631d
@@ -0,0 +1,2 @@
+# HP lt4225
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_641d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_641d
new file mode 100755
index 0000000..131c9d7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_641d
@@ -0,0 +1,2 @@
+# HP lt4226
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_681d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_681d
new file mode 100755
index 0000000..60b7f75
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_681d
@@ -0,0 +1,2 @@
+# HP lt4227
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_911d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_911d
new file mode 100755
index 0000000..b9a6a13
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_911d
@@ -0,0 +1,2 @@
+# HP lt4211
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_931d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_931d
new file mode 100755
index 0000000..08a3290
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_931d
@@ -0,0 +1,2 @@
+# HP lt4110
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_9a1d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_9a1d
new file mode 100755
index 0000000..d3b8b9d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/03f0_9a1d
@@ -0,0 +1,2 @@
+# HP lt4114
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_1000
new file mode 100755
index 0000000..089c437
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_1000
@@ -0,0 +1,4 @@
+# Quanta MU-Q101
+TargetVendor=0x0408
+TargetProduct=0xea02
+MessageContent="55534243123456780002000000000a2a000000003300000100000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea17 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea17
new file mode 100755
index 0000000..562377a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea17
@@ -0,0 +1,4 @@
+# Quanta 1KR / USB-lte 7410
+TargetVendor=0x0408
+TargetProduct=0xea16
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea25 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea25
new file mode 100755
index 0000000..9274941
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea25
@@ -0,0 +1,4 @@
+# Quanta 1K3 LTE
+TargetVendor=0x0408
+TargetProduct=0xea26
+QuantaMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea43 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea43
new file mode 100755
index 0000000..5c580e8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_ea43
@@ -0,0 +1,4 @@
+# Quanta MobileGenie 4G LTE, Quanta 1K6
+TargetVendor=0x0408
+TargetProductList="ea47,ea49,ea4d"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f000
new file mode 100755
index 0000000..3e38133
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f000
@@ -0,0 +1,4 @@
+# MU-Q110
+TargetVendor=0x0408
+TargetProduct=0xea03
+QuantaMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f000_uMa=Yota b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f000_uMa=Yota
new file mode 100755
index 0000000..0b18e44
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f000_uMa=Yota
@@ -0,0 +1,4 @@
+# Yota Router (Quanta 1QDLZZZ0ST2)
+TargetVendor=0x0408
+TargetProduct=0xd009
+MessageContent="5553424312345678000000000000061b004600000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f001
new file mode 100755
index 0000000..3cb57a0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0408_f001
@@ -0,0 +1,4 @@
+# SpeedUp SU-8500U
+TargetVendor=0x0408
+TargetProduct=0xea03
+QuantaMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_060c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_060c
new file mode 100755
index 0000000..be0b8dc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_060c
@@ -0,0 +1,4 @@
+# Nokia CS-10
+TargetVendor=0x0421
+TargetProduct=0x060e
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0610 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0610
new file mode 100755
index 0000000..b2710ad
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0610
@@ -0,0 +1,4 @@
+# Nokia CS-15
+TargetVendor=0x0421
+TargetProduct=0x0612
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0618 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0618
new file mode 100755
index 0000000..80afec0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0618
@@ -0,0 +1,4 @@
+# Nokia CS-12
+TargetVendor=0x0421
+TargetProduct=0x0619
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_061d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_061d
new file mode 100755
index 0000000..98818a2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_061d
@@ -0,0 +1,4 @@
+# Nokia CS-11
+TargetVendor=0x0421
+TargetProduct=0x061e
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0622 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0622
new file mode 100755
index 0000000..465f145
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0622
@@ -0,0 +1,4 @@
+# Nokia CS-17
+TargetVendor=0x0421
+TargetProduct=0x0623
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0627 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0627
new file mode 100755
index 0000000..882893b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0627
@@ -0,0 +1,4 @@
+# Nokia CS-18
+TargetVendor=0x0421
+TargetProductList="0612,0629"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_062c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_062c
new file mode 100755
index 0000000..eb5dbde
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_062c
@@ -0,0 +1,4 @@
+# Nokia CS-19
+TargetVendor=0x0421
+TargetProductList="062d,062f"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0632 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0632
new file mode 100755
index 0000000..5ed6a7f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0632
@@ -0,0 +1,4 @@
+# Nokia CS-7M-01
+TargetVendor=0x0421
+TargetProduct=0x0632
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0637 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0637
new file mode 100755
index 0000000..e1415b7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0421_0637
@@ -0,0 +1,4 @@
+# Nokia CS-21M-02
+TargetVendor=0x0421
+TargetProduct=0x0638
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/046d_c261 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/046d_c261
new file mode 100755
index 0000000..25a45c7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/046d_c261
@@ -0,0 +1,5 @@
+# Logitech G920 Racing Wheel
+MessageEndpoint=0x01
+ResponseEndpoint=0x01
+TargetClass=0x03
+MessageContent="0f00010142"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1210_uMa=Philips b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1210_uMa=Philips
new file mode 100755
index 0000000..74eca5a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1210_uMa=Philips
@@ -0,0 +1,3 @@
+# Philips (?)
+TargetClass=0xff
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1210_uMa=Wisue b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1210_uMa=Wisue
new file mode 100755
index 0000000..b3cd0a7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1210_uMa=Wisue
@@ -0,0 +1,4 @@
+# Vodafone MD950 (Wisue Technology)
+TargetVendor=0x1dbc
+TargetProduct=0x0005
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1237 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1237
new file mode 100755
index 0000000..e48527c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0471_1237
@@ -0,0 +1,4 @@
+# Philips TalkTalk (NXP Semiconductors "Dragonfly")
+TargetVendor=0x0471
+TargetProductList="1206,1234"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0482_024d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0482_024d
new file mode 100755
index 0000000..570794f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0482_024d
@@ -0,0 +1,2 @@
+# Kyocera W06K CDMA modem
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04bb_bccd b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04bb_bccd
new file mode 100755
index 0000000..7c4e229
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04bb_bccd
@@ -0,0 +1,4 @@
+# I-O Data WMX2-U Wimax
+TargetVendor=0x04bb
+TargetProduct=0x0949
+MessageContent="55534243f0298d8124000000800006bc626563240000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_2251 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_2251
new file mode 100755
index 0000000..9d6e469
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_2251
@@ -0,0 +1,4 @@
+# Alcatel-Lucent ABS-T920
+TargetVendor=0x04cc
+TargetProductList="2259,226e"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_225c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_225c
new file mode 100755
index 0000000..3f6e8ab
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_225c
@@ -0,0 +1,2 @@
+# Alcatel-Lucent T930S
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_226e b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_226e
new file mode 100755
index 0000000..fe4bd3a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_226e
@@ -0,0 +1,2 @@
+# Nexperia TM TD-SCDMA
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_226f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_226f
new file mode 100755
index 0000000..a65c5cf
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04cc_226f
@@ -0,0 +1,2 @@
+# Nexperia TM TD-SCDMA (Variant)
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_680c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_680c
new file mode 100755
index 0000000..871cbd8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_680c
@@ -0,0 +1,4 @@
+# Samsung GT-B1110
+TargetVendor=0x04e8
+TargetProduct=0x6792
+MessageContent="0902200001010080fa0904000002080650000705010200020007058102000200"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_689a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_689a
new file mode 100755
index 0000000..55977b9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_689a
@@ -0,0 +1,6 @@
+# Samsung GT-B3730
+TargetVendor=0x04e8
+TargetProduct=0x6889
+MessageContent="55534243785634120100000080000601000000000000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_f000_sMo=U209 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_f000_sMo=U209
new file mode 100755
index 0000000..c445158
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04e8_f000_sMo=U209
@@ -0,0 +1,4 @@
+# Samsung U209
+TargetVendor=0x04e8
+TargetProduct=0x6601
+MessageContent="55534243123456780000000000000616000000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04fc_2140 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04fc_2140
new file mode 100755
index 0000000..35e00a1
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/04fc_2140
@@ -0,0 +1,4 @@
+# Sunplus Techn. SU-3200U
+TargetVendor=0x04fc
+TargetProductList="0615,1240"
+MessageContent="55534243123456782400000080000612000024000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/057c_62ff b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/057c_62ff
new file mode 100755
index 0000000..a73effb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/057c_62ff
@@ -0,0 +1,7 @@
+# AVM Fritz!Wlan USB Stick N v2
+TargetVendor=0x057c
+TargetProductList="8501,8502"
+# Std.Eject not working
+MessageContent="5553424312345678000000000000061b000000ff0000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/057c_84ff b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/057c_84ff
new file mode 100755
index 0000000..3da7f76
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/057c_84ff
@@ -0,0 +1,7 @@
+# AVM Fritz!Wlan USB Stick N
+TargetVendor=0x057c
+TargetProduct=0x8401
+# Std.Eject not working
+MessageContent="5553424312345678000000000000061b000000ff0000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_0010 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_0010
new file mode 100755
index 0000000..d7db758
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_0010
@@ -0,0 +1,4 @@
+# Axesstel Modems (w/ initial idProduct 0x0010)
+TargetVendor=0x05c6
+TargetProduct=0x00a0
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_sVe=GT b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_sVe=GT
new file mode 100755
index 0000000..330d07c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_sVe=GT
@@ -0,0 +1,4 @@
+# Option GlobeTrotter GX0201
+TargetVendor=0x0af0
+TargetProduct=0x6701
+OptionMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_sVe=Option b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_sVe=Option
new file mode 100755
index 0000000..c76cde8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_sVe=Option
@@ -0,0 +1,4 @@
+# Older Option devices
+TargetVendor= 0x0af0
+TargetProductList="6901,6701,6600"
+OptionMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=AnyDATA b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=AnyDATA
new file mode 100755
index 0000000..ea414de
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=AnyDATA
@@ -0,0 +1,4 @@
+# AnyDATA devices, Bless UC165
+TargetVendor= 0x16d5
+TargetProduct=0x6502
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=CELOT b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=CELOT
new file mode 100755
index 0000000..044da01
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=CELOT
@@ -0,0 +1,4 @@
+# Celot K-300 a.o.
+TargetVendor=0x211f
+TargetProductList="6801,6802"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Co.,Ltd b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Co.,Ltd
new file mode 100755
index 0000000..a4e70e8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Co.,Ltd
@@ -0,0 +1,4 @@
+# TechFaith Venus VT-18
+TargetVendor=0x1d09
+TargetProduct=0x4306
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=DGT b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=DGT
new file mode 100755
index 0000000..8a787a4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=DGT
@@ -0,0 +1,4 @@
+# Celot CT-680
+TargetVendor=0x211f
+TargetProduct=0x6802
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Option b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Option
new file mode 100755
index 0000000..0f2ce47
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Option
@@ -0,0 +1,4 @@
+# Quirky Option devices
+TargetVendor=0x0af0
+TargetProduct=0x6901
+OptionMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=SAMSUNG b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=SAMSUNG
new file mode 100755
index 0000000..bbd8a30
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=SAMSUNG
@@ -0,0 +1,4 @@
+# Samsung SGH-Z810
+TargetVendor= 0x04e8
+TargetProduct=0x6601
+MessageContent="55534243123456780000000000000616000000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=SSE b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=SSE
new file mode 100755
index 0000000..8ed06ca
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=SSE
@@ -0,0 +1,4 @@
+# Prolink P2000 CDMA
+TargetVendor=0x05c6
+TargetProduct=0x6000
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=StrongRising b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=StrongRising
new file mode 100755
index 0000000..171cae3
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=StrongRising
@@ -0,0 +1,4 @@
+# StrongRising device 
+TargetVendor= 0x028a
+TargetProduct=0x1006
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Vertex b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Vertex
new file mode 100755
index 0000000..8fbcd80
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_1000_uMa=Vertex
@@ -0,0 +1,4 @@
+# Vertex Wireless 100 Series
+TargetVendor=0x1fe7
+TargetProduct=0x0100
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_2000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_2000
new file mode 100755
index 0000000..65897a8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_2000
@@ -0,0 +1,6 @@
+# Various USB modems
+TargetVendor=0x05c6
+TargetProductList="0015,0016,0018,ce17"
+MessageContent="5553424368032c882400000080000612000000240000000000000000000000"
+NeedResponse=1
+CheckSuccess=40
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_2001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_2001
new file mode 100755
index 0000000..f13efd9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_2001
@@ -0,0 +1,4 @@
+# D-Link DWM-162-U5, DWM-162 C1, Micromax MMX 300c
+TargetVendor=0x1e0e
+TargetProductList="ce16,ce17,cefe"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_6503 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_6503
new file mode 100755
index 0000000..43c6217
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_6503
@@ -0,0 +1,4 @@
+# AnyDATA APE-540H
+TargetVendor=0x16d5
+TargetProduct=0x6502
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_9024 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_9024
new file mode 100755
index 0000000..c809a67
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_9024
@@ -0,0 +1,4 @@
+# Alcatel-sbell ASB TL131 TD-LTE
+TargetVendor=0x05c6
+TargetProduct=0x9025
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_98ff b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_98ff
new file mode 100755
index 0000000..72e252a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_98ff
@@ -0,0 +1,4 @@
+# U901 (LTE modem)
+TargetVendor=0x05c6
+TargetProduct=0x6001
+SierraMode=1
\ No newline at end of file
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_f000
new file mode 100755
index 0000000..d064949
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c6_f000
@@ -0,0 +1,5 @@
+# Siptune LM-75 ("LinuxModem"), EWangshikong 4G
+TargetVendor=0x05c6
+TargetProductList="0016,6000,9000"
+StandardEject=1
+MessageContent="5553424308306384c000000080000671030000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c7_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c7_1000
new file mode 100755
index 0000000..9db6c68
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/05c7_1000
@@ -0,0 +1,4 @@
+# Qtronix EVDO 3G Modem (for TianYi)
+TargetVendor=0x05c7
+TargetProduct=0x6000
+MessageContent="5553424312345678c00000008000069f140000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0685_2000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0685_2000
new file mode 100755
index 0000000..d0b85b8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0685_2000
@@ -0,0 +1,5 @@
+# ZE-3G 7.2Mbs HSPA modem
+TargetVendor=0x1c9e
+TargetProduct=0x9603
+MessageContent="5553424368032c882400000080000612000000240000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/072f_100d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/072f_100d
new file mode 100755
index 0000000..95f7c45
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/072f_100d
@@ -0,0 +1,7 @@
+# InfoCert Business Key (SmartCard/Reader emulation)
+TargetVendor=0x072f
+TargetProduct=0x90cc
+MessageEndpoint=0x02
+MessageContent="01b0000000000000000000000000000000000000000000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_a800 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_a800
new file mode 100755
index 0000000..2adc178
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_a800
@@ -0,0 +1,4 @@
+# D-Link DWM-156 HSUPA 3.75G a.o.
+TargetVendor=0x07d1
+TargetProductList="3e01,3e02,7e0c"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_a804 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_a804
new file mode 100755
index 0000000..6fced74
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_a804
@@ -0,0 +1,4 @@
+# D-Link DWM-156 HSUPA 3.75G USB Modem
+TargetVendor=0x07d1
+TargetProduct=0x7e11
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_f000
new file mode 100755
index 0000000..f79dba7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/07d1_f000
@@ -0,0 +1,4 @@
+# D-Link DWM-151 A1
+TargetVendor=0x07d1
+TargetProduct=0x7e07
+MessageContent="555342431234567800000000000006bd000000020000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1001
new file mode 100755
index 0000000..86886a2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1001
@@ -0,0 +1,8 @@
+# Dymo LabelManager
+TargetVendor=0x0922
+TargetProduct=0x1002
+MessageEndpoint=0x01
+ResponseEndpoint=0x01
+MessageContent="1b5a01"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1003 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1003
new file mode 100755
index 0000000..82f42e3
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1003
@@ -0,0 +1,6 @@
+# Dymo LabelManager 420P
+TargetVendor= 0x0922
+TargetProduct= 0x1004
+MessageContent="1b5a01"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1007 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1007
new file mode 100755
index 0000000..2b48fb0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0922_1007
@@ -0,0 +1,6 @@
+# Dymo LabelManager Wireless PnP
+TargetVendor= 0x0922
+TargetProduct= 0x1008
+MessageContent="1b5a01"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0930_0d46 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0930_0d46
new file mode 100755
index 0000000..2dcca74
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0930_0d46
@@ -0,0 +1,4 @@
+# Toshiba G450
+TargetVendor=0x0930
+TargetProduct=0x0d45
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0ace_2011 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0ace_2011
new file mode 100755
index 0000000..9b5a78f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0ace_2011
@@ -0,0 +1,4 @@
+# Zydas ZD1211RW WLAN USB, Sphairon HomeLink 1202 (Variant 1)
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0ace_20ff b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0ace_20ff
new file mode 100755
index 0000000..55178af
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0ace_20ff
@@ -0,0 +1,4 @@
+# Zydas ZD1211RW WLAN USB, Sphairon HomeLink 1202 (Variant 2)
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_4007 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_4007
new file mode 100755
index 0000000..d209494
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_4007
@@ -0,0 +1,6 @@
+# Option iCon 711
+TargetVendor=0x0af0
+TargetProduct=0x4005
+SierraMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6711 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6711
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6711
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6731 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6731
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6731
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6751 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6751
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6751
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6771 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6771
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6771
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6791 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6791
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6791
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6811 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6811
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6811
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6911 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6911
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6911
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6951 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6951
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6951
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6971 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6971
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_6971
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7011 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7011
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7011
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7031 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7031
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7031
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7051 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7051
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7051
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7071 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7071
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7071
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7111 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7111
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7111
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7211 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7211
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7211
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7251 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7251
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7251
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7271 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7271
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7271
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7301 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7301
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7301
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7311 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7311
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7311
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7361 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7361
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7361
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7381 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7381
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7381
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7401 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7401
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7401
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7501 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7501
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7501
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7601 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7601
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7601
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7701 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7701
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7701
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7706 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7706
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7706
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7801 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7801
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7801
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7901 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7901
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7901
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7a01 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7a01
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7a01
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7a05 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7a05
new file mode 100755
index 0000000..ffaea9c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_7a05
@@ -0,0 +1,5 @@
+# Option iCon 461
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8006 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8006
new file mode 100755
index 0000000..ccdd7f5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8006
@@ -0,0 +1,6 @@
+# Option Globetrotter (Variant)
+TargetVendor=0x0af0
+TargetProduct=0x9100
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8200 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8200
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8200
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8201 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8201
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8201
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8300 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8300
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8300
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8302 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8302
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8302
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8304 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8304
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8304
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8400 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8400
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8400
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8600 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8600
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8600
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8700 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8700
new file mode 100755
index 0000000..2d73b1c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8700
@@ -0,0 +1,5 @@
+# Option GI0643 (aka XYFI)
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8800 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8800
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8800
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8900 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8900
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_8900
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_9000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_9000
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_9000
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_9200 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_9200
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_9200
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_c031 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_c031
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_c031
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_c100 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_c100
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_c100
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d001
new file mode 100755
index 0000000..4f2b39e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d001
@@ -0,0 +1,6 @@
+# Option GlobeTrotter GI1515
+TargetVendor=0x0af0
+TargetProductList="d157,d255,d257"
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d013 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d013
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d013
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d031 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d031
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d031
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d033 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d033
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d033
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d035 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d035
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d035
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d055 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d055
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d055
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d057 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d057
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d057
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d058 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d058
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d058
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d155 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d155
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d155
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d157 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d157
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d157
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d255 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d255
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d255
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d257 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d257
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d257
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d357 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d357
new file mode 100755
index 0000000..1a21ca2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0af0_d357
@@ -0,0 +1,5 @@
+# Option HSO device
+TargetClass=0xff
+OptionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_c700 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_c700
new file mode 100755
index 0000000..fd4da50
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_c700
@@ -0,0 +1,4 @@
+# Olivetti Olicard 100 and others
+TargetVendor=0x0b3c
+TargetProductList="c000,c001,c002"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f000
new file mode 100755
index 0000000..b17d1eb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f000
@@ -0,0 +1,5 @@
+# Olivetti Olicard 145, 155
+TargetVendor=0x0b3c
+TargetProductList="c003,c004"
+MessageContent="5553424312345678c000000080010606f50402527000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f00c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f00c
new file mode 100755
index 0000000..00f1298
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f00c
@@ -0,0 +1,4 @@
+# Olivetti Olicard 160
+TargetVendor=0x0b3c
+TargetProduct=0xc00a
+MessageContent="55534243123456788000000080000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f017 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f017
new file mode 100755
index 0000000..72df51d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0b3c_f017
@@ -0,0 +1,4 @@
+# Olivetti Olicard 500
+TargetVendor=0x0b3c
+TargetProduct=0xc00b
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0bdb_190d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0bdb_190d
new file mode 100755
index 0000000..aa901b8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0bdb_190d
@@ -0,0 +1,2 @@
+# Ericsson F5521gw
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0bdb_1910 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0bdb_1910
new file mode 100755
index 0000000..5e9049e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0bdb_1910
@@ -0,0 +1,2 @@
+# Ericsson F5521gw (Variant)
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0cf3_20ff b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0cf3_20ff
new file mode 100755
index 0000000..3ce9058
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0cf3_20ff
@@ -0,0 +1,6 @@
+# Atheros Wireless / Netgear WNDA3200
+TargetVendor=0x0cf3
+TargetProduct=0x7010
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0d46_45a1 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0d46_45a1
new file mode 100755
index 0000000..1d82e3f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0d46_45a1
@@ -0,0 +1,4 @@
+# Kobil mIdentity 3G (1)
+TargetVendor=0x0d46
+TargetProduct=0x45a9
+KobilMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0d46_45a5 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0d46_45a5
new file mode 100755
index 0000000..2074a95
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0d46_45a5
@@ -0,0 +1,4 @@
+# Kobil mIdentity 3G (2)
+TargetVendor=0x0d46
+TargetProduct=0x45ad
+KobilMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0df7_0800 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0df7_0800
new file mode 100755
index 0000000..826501c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0df7_0800
@@ -0,0 +1,5 @@
+# Mobile Action ("Smart Cable")
+TargetClass=0xff
+MobileActionMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_0002_uPr=MT b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_0002_uPr=MT
new file mode 100755
index 0000000..f23f468
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_0002_uPr=MT
@@ -0,0 +1,4 @@
+# MediaTek MT6276M and others
+TargetVendor=0x0e8d
+TargetProductList="00a1,00a2,00a5"
+MessageContent="555342431234567800000000000006f0010300000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_0002_uPr=Product b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_0002_uPr=Product
new file mode 100755
index 0000000..f36fa83
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_0002_uPr=Product
@@ -0,0 +1,4 @@
+# MediaTek/Medion S4222 and probably others
+TargetVendor=0x0e8d
+TargetProductList="00a1,00a2,00a5"
+MessageContent="555342431234567800000000000006f0010300000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_7109 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_7109
new file mode 100755
index 0000000..a71557f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0e8d_7109
@@ -0,0 +1,6 @@
+# MediaTek Wimax USB Card
+TargetVendor=0x0e8d
+TargetProductList="7115,7118"
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fca_8020 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fca_8020
new file mode 100755
index 0000000..7a07ad9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fca_8020
@@ -0,0 +1,4 @@
+# BlackBerry Q10 and Z10
+TargetVendor=0x0fca
+TargetProduct=0x8012
+BlackberryMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0cf b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0cf
new file mode 100755
index 0000000..85dc2c8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0cf
@@ -0,0 +1,2 @@
+# Sony Ericsson MD300
+Configuration=3
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0df b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0df
new file mode 100755
index 0000000..4bb9dca
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0df
@@ -0,0 +1,2 @@
+# Sony Ericsson EC400
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0e1 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0e1
new file mode 100755
index 0000000..f3e9e86
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d0e1
@@ -0,0 +1,4 @@
+# Sony Ericsson MD400
+TargetClass=0x02
+SonyMode=1
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d103 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d103
new file mode 100755
index 0000000..cc9e7a4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fce_d103
@@ -0,0 +1,4 @@
+# Sony Ericsson MD400G
+TargetClass=0x02
+SonyMode=1
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fd1_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fd1_1000
new file mode 100755
index 0000000..04101aa
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/0fd1_1000
@@ -0,0 +1,2 @@
+# GW D301 (Advinne AMC)
+Configuration=3
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_1000
new file mode 100755
index 0000000..4468271
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_1000
@@ -0,0 +1,3 @@
+# LG LDU-1900D EV-DO (Rev. A)
+TargetClass=0xff
+MessageContent="55534243123456780000000000000aff554d53434847000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_607f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_607f
new file mode 100755
index 0000000..25ccde5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_607f
@@ -0,0 +1,5 @@
+# LG HDM-2100 (EVDO Rev.A USB modem)
+TargetVendor=0x1004
+TargetProductList="6000,6114"
+MessageContent="555342431234567803000000800006f1010100000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_610c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_610c
new file mode 100755
index 0000000..dc25e1f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_610c
@@ -0,0 +1,4 @@
+# LG L-02A
+TargetVendor=0x1004
+TargetProduct=0x6109
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_613a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_613a
new file mode 100755
index 0000000..02bc44b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_613a
@@ -0,0 +1,4 @@
+# LG L-05A
+TargetVendor=0x1004
+TargetProduct=0x6124
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_613f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_613f
new file mode 100755
index 0000000..ce75c58
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_613f
@@ -0,0 +1,4 @@
+# LG LUU-2100TI (aka AT&T USBConnect Turbo)
+TargetVendor=0x1004
+TargetProduct=0x6141
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_614e b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_614e
new file mode 100755
index 0000000..0492200
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_614e
@@ -0,0 +1,4 @@
+# LG L-07A
+TargetVendor=0x1004
+TargetProduct=0x6135
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6156 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6156
new file mode 100755
index 0000000..89b1b85
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6156
@@ -0,0 +1,4 @@
+# LG LUU-2110TI
+TargetVendor=0x1004
+TargetProduct=0x6157
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6190 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6190
new file mode 100755
index 0000000..4334c0a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6190
@@ -0,0 +1,5 @@
+# LG AD600
+TargetVendor=0x1004
+TargetProduct=0x61a7
+WaitBefore=10
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61aa b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61aa
new file mode 100755
index 0000000..0db0efb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61aa
@@ -0,0 +1,4 @@
+# LG VL600
+TargetVendor=0x1004
+TargetProduct=0x61a7
+StandardEject=1
\ No newline at end of file
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61dd b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61dd
new file mode 100755
index 0000000..2ccd9bc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61dd
@@ -0,0 +1,4 @@
+# LG L-02C LTE
+TargetVendor=0x1004
+TargetProduct=0x618f
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61e7 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61e7
new file mode 100755
index 0000000..097e7e2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61e7
@@ -0,0 +1,4 @@
+# LG SD711
+TargetVendor=0x1004
+TargetProduct=0x61e6
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61eb b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61eb
new file mode 100755
index 0000000..10f1591
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_61eb
@@ -0,0 +1,4 @@
+# LG L-08C (NTT docomo)
+TargetVendor=0x1004
+TargetProduct=0x61ea
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6327 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6327
new file mode 100755
index 0000000..f34ce2a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1004_6327
@@ -0,0 +1,4 @@
+# LG L-03D LTE/3G
+TargetVendor=0x1004
+TargetProduct=0x6326
+MessageContent=555342431234567800000000000005f1010100000000000000000000000000
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1033_0035 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1033_0035
new file mode 100755
index 0000000..2541fd2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1033_0035
@@ -0,0 +1,4 @@
+# Huawei E630
+TargetVendor=0x12d1
+TargetProduct=0x1003
+HuaweiMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b03 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b03
new file mode 100755
index 0000000..4201228
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b03
@@ -0,0 +1,4 @@
+# UTStarcom UM175 (distributor "Alltel")
+TargetVendor=0x106c
+TargetProduct=0x3715
+MessageContent="555342431234567824000000800008ff024445564348470000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b05 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b05
new file mode 100755
index 0000000..e7f732d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b05
@@ -0,0 +1,4 @@
+# Pantech / UTStarcom UMW190 (Verizon)
+TargetVendor=0x106c
+TargetProduct=0x3716
+MessageContent="555342431234567824000000800008ff020000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b06 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b06
new file mode 100755
index 0000000..9351e41
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b06
@@ -0,0 +1,4 @@
+# UTStarcom UM185E (distributor "Alltel")
+TargetVendor=0x106c
+TargetProduct=0x3717
+MessageContent="55534243b82e238c24000000800008ff020000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b11 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b11
new file mode 100755
index 0000000..7ebbf49
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b11
@@ -0,0 +1,4 @@
+# Pantech UML290
+TargetVendor=0x106c
+TargetProduct=0x3718
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b14 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b14
new file mode 100755
index 0000000..eb351af
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/106c_3b14
@@ -0,0 +1,6 @@
+# Option Beemo / Pantech P4200 LTE
+TargetVendor=0x106c
+TargetProduct=0x3721
+MessageContent="555342431234567824000000800008ff024445564348470000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1076_7f40 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1076_7f40
new file mode 100755
index 0000000..60e9117
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1076_7f40
@@ -0,0 +1,4 @@
+# Sagem F@ST 9520-35-GLR
+TargetVendor=0x1076
+TargetProduct=0x7f00
+GCTMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/109b_f009 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/109b_f009
new file mode 100755
index 0000000..7d1e2c8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/109b_f009
@@ -0,0 +1,4 @@
+# Hisense E910 EVDO Phone
+TargetVendor=0x109b
+TargetProduct=0x9114
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/10a9_606f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/10a9_606f
new file mode 100755
index 0000000..45dda80
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/10a9_606f
@@ -0,0 +1,7 @@
+# Pantech/Verizon UML295
+TargetVendor=0x10a9
+TargetProductList="6064,6074"
+# Use 1 for automatic choice, 2 for RNDIS, 4 for QMI
+PantechMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/10a9_6080 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/10a9_6080
new file mode 100755
index 0000000..3883005
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/10a9_6080
@@ -0,0 +1,4 @@
+# Pantech LTE Modem
+TargetVendor=0x10a9
+TargetProduct=0x6085
+PantechMode=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_0fff b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_0fff
new file mode 100755
index 0000000..88c8882
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_0fff
@@ -0,0 +1,6 @@
+# Sierra devices (specific driver)
+TargetVendor= 0x1199
+TargetProductList="0017,0018,0019,0020,0021,0022,0023,0024,0025,0026,0027,0028,0029,0112,0120,0218,0220,0224,0301,6802,6803,6804,6805,6808,6809,6812,6813,6815,6816,6820,6821,6822,6832,6833,6834,6835,6838,6839,683a,683b,683c,683d,683e,6850,6851,6852,6853,6855,6856,6859,685a,6880,6890,6891,6892,6893,68a2,68a3,68aa,9011,9012,9051"
+SierraMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9011 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9011
new file mode 100755
index 0000000..e1ac1fe
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9011
@@ -0,0 +1,4 @@
+# Sierra MC8305
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9013 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9013
new file mode 100755
index 0000000..d60fac0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9013
@@ -0,0 +1,4 @@
+# Sierra MC8355
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9017 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9017
new file mode 100755
index 0000000..d33a899
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9017
@@ -0,0 +1,4 @@
+# Sierra MC8355 Variant
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901b
new file mode 100755
index 0000000..f291e83
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901b
@@ -0,0 +1,4 @@
+# Sierra MC7770
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901c
new file mode 100755
index 0000000..3a13e2f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901c
@@ -0,0 +1,4 @@
+# Sierra EM7700
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901f
new file mode 100755
index 0000000..ca03f4c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_901f
@@ -0,0 +1,4 @@
+# Sierra EM7355
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9041 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9041
new file mode 100755
index 0000000..2389f40
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9041
@@ -0,0 +1,4 @@
+# Sierra EM7305
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9051 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9051
new file mode 100755
index 0000000..0e10ef2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9051
@@ -0,0 +1,4 @@
+# Sierra AC340U
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9053 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9053
new file mode 100755
index 0000000..debd945
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9053
@@ -0,0 +1,4 @@
+# Sierra AC770S
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9063 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9063
new file mode 100755
index 0000000..2389f40
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1199_9063
@@ -0,0 +1,4 @@
+# Sierra EM7305
+Configuration=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1266_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1266_1000
new file mode 100755
index 0000000..cf859d0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1266_1000
@@ -0,0 +1,4 @@
+# Digicom 8E4455 (and all Pirelli devices - EXPERIMENTAL)
+TargetVendor=0x1266
+TargetProductList="1002,1003,1004,1005,1006,1007,1008,1009,100a,100b,100c,100d,100e,100f,1011,1012"
+StandardEject=1
diff --git "a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_\043android" "b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_\043android"
new file mode 100755
index 0000000..f7d7928
--- /dev/null
+++ "b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_\043android"
@@ -0,0 +1,3 @@
+# Huawei generic for Android
+TargetVendor= 0x12d1
+MessageContent="55534243123456780000000000000011063000000100010000000000000000"
diff --git "a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_\043linux" "b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_\043linux"
new file mode 100755
index 0000000..78e7ea5
--- /dev/null
+++ "b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_\043linux"
@@ -0,0 +1,3 @@
+# Huawei generic for Linux (fall-back for unknown products)
+TargetVendor= 0x12d1
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1001
new file mode 100755
index 0000000..273c035
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1001
@@ -0,0 +1,3 @@
+# Huawei E169
+TargetClass=0xff
+HuaweiMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1003 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1003
new file mode 100755
index 0000000..5c37062
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1003
@@ -0,0 +1,3 @@
+# Huawei E220, E230, E270, E870
+TargetClass=0xff
+HuaweiMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1009 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1009
new file mode 100755
index 0000000..2b03464
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1009
@@ -0,0 +1,3 @@
+# Huawei V725 Phone (aka Vodafone 725)
+TargetClass=0xff
+HuaweiMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1010 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1010
new file mode 100755
index 0000000..c7c1d03
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1010
@@ -0,0 +1,3 @@
+# Huawei ETS1201
+TargetClass=0xff
+HuaweiMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_101e b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_101e
new file mode 100755
index 0000000..dae8e2e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_101e
@@ -0,0 +1,3 @@
+# Huawei U7510 / U7517
+TargetClass=0xff
+MessageContent="55534243123456780600000080000601000000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1030 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1030
new file mode 100755
index 0000000..d5c73d7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1030
@@ -0,0 +1,6 @@
+# Huawei U8220, T-Mobile Pulse (Android smartphone)
+TargetVendor=0x12d1
+TargetProduct=0x1034
+MessageContent="55534243123456780600000080010a11060000000000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1031 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1031
new file mode 100755
index 0000000..cc262da
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1031
@@ -0,0 +1,7 @@
+# Huawei U8110 / Joy, Vodafone 845 (Android smartphone)
+TargetVendor=0x12d1
+TargetProduct=0x1035
+MessageContent="55534243123456780600000080010a11060000000000000000000000000000"
+# for Android SDK
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1413 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1413
new file mode 100755
index 0000000..1158582
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1413
@@ -0,0 +1,3 @@
+# Huawei EC168
+TargetClass=0xff
+HuaweiMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1414 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1414
new file mode 100755
index 0000000..742d75d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1414
@@ -0,0 +1,3 @@
+# Huawei E180
+TargetClass=0xff
+HuaweiMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1446 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1446
new file mode 100755
index 0000000..48c6d35
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1446
@@ -0,0 +1,4 @@
+# Huawei, newer modems, and rebrandings
+TargetVendor=0x12d1
+TargetProductList="1001,1404,1406,140b,140c,1412,1417,141b,1429,1432,1433,1436,14ac,1506,150c,1511"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1449 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1449
new file mode 100755
index 0000000..1713857
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1449
@@ -0,0 +1,4 @@
+# Huawei E352
+TargetVendor=0x12d1
+TargetProduct=0x1444
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14ad b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14ad
new file mode 100755
index 0000000..e3d4328
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14ad
@@ -0,0 +1,4 @@
+# Vodafone (Huawei) K3806
+TargetVendor=0x12d1
+TargetProduct=0x14ae
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14b5 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14b5
new file mode 100755
index 0000000..322da5f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14b5
@@ -0,0 +1,4 @@
+# Huawei E173 (Viettel 3G)
+TargetVendor=0x12d1
+TargetProductList="14a8,14aa"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14b7 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14b7
new file mode 100755
index 0000000..e9f7cee
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14b7
@@ -0,0 +1,4 @@
+# Vodafone (Huawei) K4511
+TargetVendor=0x12d1
+TargetProduct=0x14cc
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14ba b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14ba
new file mode 100755
index 0000000..a2c257e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14ba
@@ -0,0 +1,4 @@
+# Huawei E173u-2, E177
+TargetVendor=0x12d1
+TargetProduct=0x14d2
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c1 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c1
new file mode 100755
index 0000000..309830f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c1
@@ -0,0 +1,4 @@
+# Vodafone (Huawei) K4605
+TargetVendor=0x12d1
+TargetProduct=0x14c6
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c3 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c3
new file mode 100755
index 0000000..413e8d2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c3
@@ -0,0 +1,4 @@
+# K5005 Vodafone/Huawei
+TargetVendor=0x12d1
+TargetProduct=0x14c8
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c4 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c4
new file mode 100755
index 0000000..e7ffc66
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c4
@@ -0,0 +1,4 @@
+# Vodafone/Huawei K3771
+TargetVendor=0x12d1
+TargetProduct=0x14ca
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c5 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c5
new file mode 100755
index 0000000..17ecd3c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14c5
@@ -0,0 +1,4 @@
+# Vodafone (Huawei) K4510
+TargetVendor=0x12d1
+TargetProduct=0x14cb
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14d1 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14d1
new file mode 100755
index 0000000..2ab14e6
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14d1
@@ -0,0 +1,4 @@
+# Vodafone / Huawei K3770
+TargetVendor=0x12d1
+TargetProduct=0x14c9
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14fe b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14fe
new file mode 100755
index 0000000..9c16d2a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_14fe
@@ -0,0 +1,4 @@
+# Huawei E352 (T-Mobile NL), E173s (Variant)
+TargetVendor=0x12d1
+TargetProductList="1506,150f,151d,1c1e"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1505 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1505
new file mode 100755
index 0000000..ab5e1cd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1505
@@ -0,0 +1,4 @@
+# Huawei EC156, Huawei E372u-8
+TargetVendor=0x12d1
+TargetProductList="140b,140c,1506,150f,150a"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_151a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_151a
new file mode 100755
index 0000000..283ae5b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_151a
@@ -0,0 +1,4 @@
+# Huawei E392u-12, E3131 (Variant)
+TargetVendor=0x12d1
+TargetProductList="151b,151d,151e"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1520 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1520
new file mode 100755
index 0000000..d03f821
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1520
@@ -0,0 +1,4 @@
+# Huawei K3765
+TargetVendor=0x12d1
+TargetProduct=0x1465
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1521 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1521
new file mode 100755
index 0000000..620690c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1521
@@ -0,0 +1,4 @@
+# Huawei K4505
+TargetVendor=0x12d1
+TargetProduct=0x1464
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1523 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1523
new file mode 100755
index 0000000..0eb4b7a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1523
@@ -0,0 +1,4 @@
+# Huawei R201
+TargetVendor=0x12d1
+TargetProduct=0x1491
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1526 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1526
new file mode 100755
index 0000000..60b8457
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1526
@@ -0,0 +1,4 @@
+# Vodafone / Huawei K3772
+TargetVendor=0x12d1
+TargetProduct=0x14cf
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1527 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1527
new file mode 100755
index 0000000..84fe445
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1527
@@ -0,0 +1,4 @@
+# Vodafone / Huawei R206 Router 
+TargetVendor=0x12d1
+TargetProduct=0x1594
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1553 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1553
new file mode 100755
index 0000000..0d2552e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1553
@@ -0,0 +1,4 @@
+# Huawei E1553
+TargetVendor=0x12d1
+TargetProduct=0x1001
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1557 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1557
new file mode 100755
index 0000000..beef342
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1557
@@ -0,0 +1,4 @@
+# Huawei E173
+TargetVendor=0x12d1
+TargetProduct=0x14a5
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_155a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_155a
new file mode 100755
index 0000000..451a8f9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_155a
@@ -0,0 +1,4 @@
+# Vodafone (Huawei) R205
+TargetVendor=0x12d1
+TargetProduct=0x14cd
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_155b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_155b
new file mode 100755
index 0000000..d10d02d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_155b
@@ -0,0 +1,4 @@
+# Huawei E171
+TargetVendor=0x12d1
+TargetProduct=0x1506
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_156a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_156a
new file mode 100755
index 0000000..55e6d38
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_156a
@@ -0,0 +1,4 @@
+# Huawei E3276s-151 and E3251
+TargetVendor=0x12d1
+TargetProductList="156b,156c"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1570 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1570
new file mode 100755
index 0000000..5b8ac78
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1570
@@ -0,0 +1,2 @@
+# Huawei ME906E
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1571 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1571
new file mode 100755
index 0000000..2b2eb6b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1571
@@ -0,0 +1,2 @@
+# Huawei EM820W
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1572 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1572
new file mode 100755
index 0000000..20b6e2e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1572
@@ -0,0 +1,2 @@
+# Huawei MU733
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1573 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1573
new file mode 100755
index 0000000..0397c2e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1573
@@ -0,0 +1,2 @@
+# Huawei ME909u-521 (MBIM, handled by kernel, dummy config)
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_157c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_157c
new file mode 100755
index 0000000..35d811d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_157c
@@ -0,0 +1,4 @@
+# Huawei E3276-s150
+TargetVendor=0x12d1
+TargetProduct=0x1506
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_157d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_157d
new file mode 100755
index 0000000..f42d3b8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_157d
@@ -0,0 +1,4 @@
+# Huawei E3331, E3372
+TargetVendor=0x12d1
+TargetProductList="14db,14dc"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1580 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1580
new file mode 100755
index 0000000..9b27048
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1580
@@ -0,0 +1,4 @@
+# Vodafone / Huawei R210 Router
+TargetVendor=0x12d1
+TargetProduct=0x1585
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1581 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1581
new file mode 100755
index 0000000..507ab0e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1581
@@ -0,0 +1,4 @@
+# Vodafone / Huawei R208 Router
+TargetVendor=0x12d1
+TargetProduct=0x1587
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1582 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1582
new file mode 100755
index 0000000..c8588a8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1582
@@ -0,0 +1,4 @@
+# Vodafone / Huawei R215 Router
+TargetVendor=0x12d1
+TargetProduct=0x1588
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1583 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1583
new file mode 100755
index 0000000..d45b089
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1583
@@ -0,0 +1,4 @@
+# Vodafone / Huawei W5101 Router
+TargetVendor=0x12d1
+TargetProduct=0x1589
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1597 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1597
new file mode 100755
index 0000000..0a91c2d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1597
@@ -0,0 +1,4 @@
+# Huawei E327s-150 (Variant)
+TargetVendor=0x12d1
+TargetProduct=0x1598
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15bb b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15bb
new file mode 100755
index 0000000..d6b1add
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15bb
@@ -0,0 +1,2 @@
+# Huawei ME936
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15c0 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15c0
new file mode 100755
index 0000000..c0b7769
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15c0
@@ -0,0 +1,2 @@
+# Huawei ME906C
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15c1 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15c1
new file mode 100755
index 0000000..24e2ec0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15c1
@@ -0,0 +1,2 @@
+# Huawei ME906, ME909 (MBIM, handled by kernel, dummy config)
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15ca b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15ca
new file mode 100755
index 0000000..cf9da86
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15ca
@@ -0,0 +1,4 @@
+# Huawei E3131
+TargetVendor=0x12d1
+TargetProduct=0x1506
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15cd b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15cd
new file mode 100755
index 0000000..28a5fc3
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15cd
@@ -0,0 +1,4 @@
+# Huawei E3372
+TargetVendor=0x12d1
+TargetProduct=0x1506
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15ce b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15ce
new file mode 100755
index 0000000..3ec6ce3
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15ce
@@ -0,0 +1,4 @@
+# Huawei E3531s-2, E3131 (Variant)
+TargetVendor=0x12d1
+TargetProductList="15b1,15b3"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15cf b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15cf
new file mode 100755
index 0000000..7addb2d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15cf
@@ -0,0 +1,4 @@
+# Huawei E3372s-153
+TargetVendor=0x12d1
+TargetProduct=0x1506
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15d0 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15d0
new file mode 100755
index 0000000..5d2ee64
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15d0
@@ -0,0 +1,4 @@
+# Huawei E3131 (Variant)
+TargetVendor=0x12d1
+TargetProduct=0x15d1
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15d2 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15d2
new file mode 100755
index 0000000..94bbbac
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15d2
@@ -0,0 +1,4 @@
+# Huawei E3531 (Variant)
+TargetVendor=0x12d1
+TargetProduct=0x15d3
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15e7 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15e7
new file mode 100755
index 0000000..6be0d6f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15e7
@@ -0,0 +1,4 @@
+# Huawei E3531
+TargetVendor=0x12d1
+TargetProduct=0x1506
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15f0 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15f0
new file mode 100755
index 0000000..c98abfd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_15f0
@@ -0,0 +1,2 @@
+# Huawei MU736
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1805 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1805
new file mode 100755
index 0000000..d408152
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1805
@@ -0,0 +1,3 @@
+# Huawei U2800 Phone
+TargetClass=0xff
+MessageContent="55534243123456780600000080000601000000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c0b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c0b
new file mode 100755
index 0000000..c6bb69f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c0b
@@ -0,0 +1,4 @@
+# Huawei E173s
+TargetVendor=0x12d1
+TargetProductList="1c05,1c06,1c07,1c08,1c10"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c1b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c1b
new file mode 100755
index 0000000..3773123
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c1b
@@ -0,0 +1,6 @@
+# Huawei GP02 (E587 Variant)
+TargetVendor=0x12d1
+TargetProduct=0x1506
+HuaweiNewMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c24 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c24
new file mode 100755
index 0000000..3b9f196
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c24
@@ -0,0 +1,4 @@
+# Huawei E173 (Moviestar), E173s (Variant)
+TargetVendor=0x12d1
+TargetProductList="1c12,1c23"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c25 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c25
new file mode 100755
index 0000000..fa88d4d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1c25
@@ -0,0 +1,2 @@
+# Huawei MU709s-2 Module
+Configuration=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1d50 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1d50
new file mode 100755
index 0000000..b218355
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1d50
@@ -0,0 +1,2 @@
+# Huawei ET302
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1da1 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1da1
new file mode 100755
index 0000000..3bb1cab
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1da1
@@ -0,0 +1,4 @@
+# Huawei ET8282, Huawei ET127
+TargetVendor=0x12d1
+TargetProduct=0x1d09
+HuaweiMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f01 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f01
new file mode 100755
index 0000000..68cea57
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f01
@@ -0,0 +1,6 @@
+# Huawei E353 (3.se) and others
+TargetVendor=0x12d1
+TargetProductList="14db,14dc"
+HuaweiNewMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f02 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f02
new file mode 100755
index 0000000..32a87b0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f02
@@ -0,0 +1,6 @@
+# Huawei E5377
+TargetVendor=0x12d1
+TargetProduct=0x14dc
+HuaweiNewMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f03 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f03
new file mode 100755
index 0000000..a9db535
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f03
@@ -0,0 +1,6 @@
+# KDDI (Huawei) HWD12 LTE
+TargetVendor=0x12d1
+TargetProduct=0x14db
+HuaweiNewMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f04 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f04
new file mode 100755
index 0000000..aad96a9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f04
@@ -0,0 +1,4 @@
+# Vodafone / Huawei R206_MR Router
+TargetVendor=0x12d1
+TargetProduct=0x15bc
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f05 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f05
new file mode 100755
index 0000000..cbde895
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f05
@@ -0,0 +1,4 @@
+# Vodafone / Huawei R207 Router
+TargetVendor=0x12d1
+TargetProduct=0x15bd
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f06 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f06
new file mode 100755
index 0000000..844e858
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f06
@@ -0,0 +1,4 @@
+# Vodafone / Huawei R215_MR Router
+TargetVendor=0x12d1
+TargetProduct=0x15c7
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f07 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f07
new file mode 100755
index 0000000..0a023f7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f07
@@ -0,0 +1,6 @@
+# Huawei/Vodafone R226
+TargetVendor=0x12d1
+TargetProduct=0x15bf
+HuaweiNewMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f09 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f09
new file mode 100755
index 0000000..6a99608
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f09
@@ -0,0 +1,6 @@
+# Huawei/Vodafone R216
+TargetVendor=0x12d1
+TargetProduct=0x1c50
+HuaweiNewMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f11 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f11
new file mode 100755
index 0000000..0786aad
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f11
@@ -0,0 +1,4 @@
+# Vodafone / Huawei K3773
+TargetVendor=0x12d1
+TargetProduct=0x14bc
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f15 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f15
new file mode 100755
index 0000000..93de9b3
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f15
@@ -0,0 +1,4 @@
+# Vodafone K4305
+TargetVendor=0x12d1
+TargetProductList="1400,14f7"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f16 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f16
new file mode 100755
index 0000000..a32d517
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f16
@@ -0,0 +1,4 @@
+# Vodafone K5150
+TargetVendor=0x12d1
+TargetProductList="14f8,1575"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f17 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f17
new file mode 100755
index 0000000..e31f0b4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f17
@@ -0,0 +1,4 @@
+# Vodafone K4201
+TargetVendor=0x12d1
+TargetProduct=0x1576
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f18 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f18
new file mode 100755
index 0000000..767644a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f18
@@ -0,0 +1,4 @@
+# Vodafone K4202
+TargetVendor=0x12d1
+TargetProduct=0x1577
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f19 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f19
new file mode 100755
index 0000000..b823b1a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f19
@@ -0,0 +1,4 @@
+# Vodafone K4606
+TargetVendor=0x12d1
+TargetProductList="14fa,1575,1578"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1b
new file mode 100755
index 0000000..6068a4c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1b
@@ -0,0 +1,4 @@
+# Vodafone / Huawei Kxxxx
+TargetVendor=0x12d1
+TargetProduct=0x1579
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1c
new file mode 100755
index 0000000..cf43358
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1c
@@ -0,0 +1,4 @@
+# Vodafone / Huawei K4203
+TargetVendor=0x12d1
+TargetProductList="157a,1590"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1d
new file mode 100755
index 0000000..eb4c393
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1d
@@ -0,0 +1,4 @@
+# Vodafone / Huawei Kxxxx
+TargetVendor=0x12d1
+TargetProductList="157b,1591"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1e b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1e
new file mode 100755
index 0000000..a20456a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_1f1e
@@ -0,0 +1,4 @@
+# Vodafone / Huawei K5160
+TargetVendor=0x12d1
+TargetProductList="157f,1592"
+HuaweiNewMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_380b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_380b
new file mode 100755
index 0000000..293ec72
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/12d1_380b
@@ -0,0 +1,3 @@
+# Huawei BM358 WiMAX
+TargetClass=0x02
+StandardEject=1 
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1307_1169 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1307_1169
new file mode 100755
index 0000000..823c9ec
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1307_1169
@@ -0,0 +1,6 @@
+# Cisco AM10 "Valet Connector"
+TargetVendor=0x13b1
+TargetProduct=0x0031
+CiscoMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5010 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5010
new file mode 100755
index 0000000..56ec385
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5010
@@ -0,0 +1,4 @@
+# Novatel Wireless devices
+TargetVendor=0x1410
+TargetProductList="4100,4400,7030"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5020 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5020
new file mode 100755
index 0000000..884787a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5020
@@ -0,0 +1,4 @@
+# Novatel MC990D
+TargetVendor=0x1410
+TargetProductList="6000,7001"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5023 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5023
new file mode 100755
index 0000000..ffe9b64
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5023
@@ -0,0 +1,4 @@
+# Novatel MC996D
+TargetVendor=0x1410
+TargetProduct=0x7030
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5030 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5030
new file mode 100755
index 0000000..ffc730a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5030
@@ -0,0 +1,4 @@
+# Novatel U760
+TargetVendor=0x1410
+TargetProduct=0x6000
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5031 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5031
new file mode 100755
index 0000000..6f0fe13
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5031
@@ -0,0 +1,4 @@
+# Novatel MC760 3G
+TargetVendor=0x1410
+TargetProduct=0x6002
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5041 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5041
new file mode 100755
index 0000000..747a4ce
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5041
@@ -0,0 +1,4 @@
+# Novatel Generic MiFi 2352 / Vodafone MiFi 2352
+TargetVendor=0x1410
+TargetProductList="7001,7003"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5055 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5055
new file mode 100755
index 0000000..bce995d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5055
@@ -0,0 +1,4 @@
+# Novatel MiFi 4082
+TargetVendor=0x1410
+TargetProduct=0x6032
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5059 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5059
new file mode 100755
index 0000000..e191387
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_5059
@@ -0,0 +1,4 @@
+# Novatel Wireless MC545 HSPA, U679 LTE
+TargetVendor=0x1410
+TargetProductList="7031,7042"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_7001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_7001
new file mode 100755
index 0000000..e02f95e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_7001
@@ -0,0 +1,3 @@
+# Novatel Generic MiFi 2372 / Vodafone MiFi 2372
+TargetClass=0xff
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_9020 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_9020
new file mode 100755
index 0000000..ba50114
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1410_9020
@@ -0,0 +1,2 @@
+# Novatel U620L
+Configuration=4
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/148e_a000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/148e_a000
new file mode 100755
index 0000000..6ff409b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/148e_a000
@@ -0,0 +1,3 @@
+# Sequans SQN1210/SQN1220 (generic chipsets)
+TargetClass=0x02
+SequansMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/148f_2578 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/148f_2578
new file mode 100755
index 0000000..7fd5163
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/148f_2578
@@ -0,0 +1,6 @@
+# Motorola 802.11 bg WLAN (TER/GUSB3-E)
+TargetVendor=0x148f
+TargetProduct=0x9021
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/15eb_7153 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/15eb_7153
new file mode 100755
index 0000000..2969bd8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/15eb_7153
@@ -0,0 +1,4 @@
+# China TeleCom CBP7.0
+TargetVendor=0x15eb
+TargetProduct=0x7152
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1614_0800 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1614_0800
new file mode 100755
index 0000000..9dd94a0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1614_0800
@@ -0,0 +1,5 @@
+# Amoi H-01
+TargetClass=0xff
+MessageContent="55534243123456780000000000000601000000000000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1614_0802 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1614_0802
new file mode 100755
index 0000000..67d5946
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1614_0802
@@ -0,0 +1,5 @@
+# Amoi H-02
+TargetClass=0xff
+MessageContent="55534243123456780000000000000601000000000000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d5_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d5_f000
new file mode 100755
index 0000000..b140d0f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d5_f000
@@ -0,0 +1,4 @@
+# Anydata ADU-890WH
+TargetVendor=0x16d5
+TargetProduct=0x6603
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6281 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6281
new file mode 100755
index 0000000..97c0773
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6281
@@ -0,0 +1,3 @@
+# C-motech CHU-628S
+TargetClass=0xff
+MessageContent="555342431234567824000000800008ff524445564348470000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6803 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6803
new file mode 100755
index 0000000..bbe9bca
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6803
@@ -0,0 +1,3 @@
+# C-motech D-50 (aka "CDU-680", "CNU-680")
+TargetClass=0x02
+MessageContent="555342431234567824000000800008ff524445564348473100000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6804 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6804
new file mode 100755
index 0000000..0b0220b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_6804
@@ -0,0 +1,3 @@
+# C-motech CDU-685a
+TargetClass=0xff
+MessageContent="555342431234567824000000800008ff524445564348470000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_700a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_700a
new file mode 100755
index 0000000..f0375c5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_700a
@@ -0,0 +1,3 @@
+# C-motech CHU-629S
+TargetClass=0xff
+MessageContent="55534243123456782400000080000dfe524445564348473d4e444953000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_700b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_700b
new file mode 100755
index 0000000..b006d06
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_700b
@@ -0,0 +1,3 @@
+# C-motech CHU-629S (Variant)
+TargetClass=0xff
+MessageContent="55534243123456782400000080000dfe524445564348473d4e444953000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_f000
new file mode 100755
index 0000000..540292f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/16d8_f000
@@ -0,0 +1,4 @@
+# C-motech CGU-628 (aka "Franklin Wireless CGU-628A" aka "4G Systems XS Stick W12")
+TargetVendor=0x16d8
+TargetProduct=0x6006
+MessageContent="55534243d85dd88524000000800008ff524445564348470000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1726_1900 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1726_1900
new file mode 100755
index 0000000..fd8acfd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1726_1900
@@ -0,0 +1,4 @@
+# Axesstel MV210
+TargetVendor=0x1726
+TargetProduct=0x1000
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1726_f00e b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1726_f00e
new file mode 100755
index 0000000..abdbe53
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1726_f00e
@@ -0,0 +1,4 @@
+# Axesstel MU130
+TargetVendor=0x1726
+TargetProduct=0xa000
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1782_0003 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1782_0003
new file mode 100755
index 0000000..22556bd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1782_0003
@@ -0,0 +1,2 @@
+# Spreadtrum SC7702
+Configuration=2
\ No newline at end of file
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1782_0023 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1782_0023
new file mode 100755
index 0000000..e5f0e4a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1782_0023
@@ -0,0 +1,2 @@
+# Spreadtrum SC7702 (Variant)
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/198a_0003 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/198a_0003
new file mode 100755
index 0000000..2a88764
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/198a_0003
@@ -0,0 +1,4 @@
+# JOA Telecom LM-700r
+TargetVendor=0x198a
+TargetProduct=0x0002
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/198f_bccd b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/198f_bccd
new file mode 100755
index 0000000..20e6c85
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/198f_bccd
@@ -0,0 +1,6 @@
+# Beceem BCSM250
+TargetVendor=0x198f
+TargetProduct=0x0220
+MessageContent="55534243f0298d8124000000800006bc626563240000000000000000000000"
+
+
diff --git "a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_\043linux" "b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_\043linux"
new file mode 100755
index 0000000..ec66b7d
--- /dev/null
+++ "b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_\043linux"
@@ -0,0 +1,7 @@
+# ZTE generic for Linux (fall-back for unknown products)
+
+# Uncomment the following lines to activate
+
+#TargetVendor= 0x19d2
+#StandardEject=1
+#MessageContent="55534243123456702000000080000c85010101180101010101000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0003 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0003
new file mode 100755
index 0000000..1e1f24a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0003
@@ -0,0 +1,3 @@
+# ZTE MU351
+TargetClass=0xff
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0026 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0026
new file mode 100755
index 0000000..3d90363
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0026
@@ -0,0 +1,4 @@
+# ZTE AC581
+TargetVendor=0x19d2
+TargetProductList="0073,0094,0152"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0040 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0040
new file mode 100755
index 0000000..6600b33
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0040
@@ -0,0 +1,4 @@
+# Vodafone (ZTE) K2525
+TargetVendor=0x19d2
+TargetProduct=0x0022
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0053 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0053
new file mode 100755
index 0000000..8c19d56
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0053
@@ -0,0 +1,4 @@
+# ZTE MF110 (Variant)
+TargetVendor=0x19d2
+TargetProduct=0x0031
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0083_uPr=WCDMA b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0083_uPr=WCDMA
new file mode 100755
index 0000000..3ce0285
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0083_uPr=WCDMA
@@ -0,0 +1,4 @@
+# ZTE MF110 (Variant)
+TargetVendor=0x19d2
+TargetProduct=0x0124
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0101 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0101
new file mode 100755
index 0000000..4c078d8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0101
@@ -0,0 +1,4 @@
+# Vodafone (ZTE) K4505-Z
+TargetVendor=0x19d2
+TargetProduct=0x0104
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0103 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0103
new file mode 100755
index 0000000..214f5c0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0103
@@ -0,0 +1,4 @@
+# ZTE MF112
+TargetVendor=0x19d2
+TargetProduct=0x0031
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0110 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0110
new file mode 100755
index 0000000..e929a64
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0110
@@ -0,0 +1,5 @@
+# ZTE MF637 (Variant for Orange France)
+TargetVendor=0x19d2
+TargetProduct=0x0121
+StandardEject=1
+ 
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0115 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0115
new file mode 100755
index 0000000..ae1468e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0115
@@ -0,0 +1,4 @@
+# ZTE MF651
+TargetVendor=0x19d2
+TargetProduct=0x0116
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0120 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0120
new file mode 100755
index 0000000..5003cfc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0120
@@ -0,0 +1,7 @@
+#ZTE-T A356
+TargetVendor=0x19d2
+TargetProduct=0x0079
+DetachStorageOnly=0
+StandardEject=1
+Interface=0x00
+NeedResponse=0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0146 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0146
new file mode 100755
index 0000000..d7e8196
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0146
@@ -0,0 +1,4 @@
+# ZTE MF652 (Variant)
+TargetVendor=0x19d2
+TargetProductList="0142,0143"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0149 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0149
new file mode 100755
index 0000000..0b06b0f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0149
@@ -0,0 +1,5 @@
+# ZTE MF190 (Variant)
+TargetVendor=0x19d2
+TargetProduct=0x0124
+StandardEject=1
+MessageContent="55534243123456702000000080000c85010101180101010101000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0150 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0150
new file mode 100755
index 0000000..0b7cd3b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0150
@@ -0,0 +1,4 @@
+# ZTE MF656A, MF668A, MF669
+TargetVendor=0x19d2
+TargetProduct=0x0124
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0154 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0154
new file mode 100755
index 0000000..7fb3c05
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0154
@@ -0,0 +1,4 @@
+# ZTE MF190 (Variant) and others
+TargetVendor=0x19d2
+TargetProductList="0017,0117,2003"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0166 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0166
new file mode 100755
index 0000000..8e4414f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0166
@@ -0,0 +1,4 @@
+# ZTE MF820 4G LTE
+TargetVendor=0x19d2
+TargetProduct=0x0167
+MessageContent="55534243123456782400000080000685000000240000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0169 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0169
new file mode 100755
index 0000000..4aac36c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0169
@@ -0,0 +1,4 @@
+# ZTE A371B
+TargetVendor=0x19d2
+TargetProduct=0x0170
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0198 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0198
new file mode 100755
index 0000000..c12e299
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0198
@@ -0,0 +1,4 @@
+# ZTE MF820s, MF832s
+TargetVendor=0x19d2
+TargetProduct=0x0199
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0266 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0266
new file mode 100755
index 0000000..ed2082f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0266
@@ -0,0 +1,5 @@
+# Onda MT8205 LTE
+TargetVendor=0x19d2
+TargetProduct=0x0265
+StandardEject=1
+MessageContent="55534243d8a523862400000080000685000000240000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0304 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0304
new file mode 100755
index 0000000..f93dccd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0304
@@ -0,0 +1,4 @@
+# ZTE MF821D (Variant)
+TargetVendor=0x19d2
+TargetProduct=0x0349
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0318 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0318
new file mode 100755
index 0000000..c5bb6e6
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0318
@@ -0,0 +1,4 @@
+# ZTE MF821D/MF826
+TargetVendor=0x19d2
+TargetProductList="0317,0330"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0325 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0325
new file mode 100755
index 0000000..3c23ebd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0325
@@ -0,0 +1,4 @@
+# ZTE MF821D
+TargetVendor=0x19d2
+TargetProduct=0x0326
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0388 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0388
new file mode 100755
index 0000000..f7a6966
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0388
@@ -0,0 +1,4 @@
+# ZTE MF90 Mobile Hotspot
+TargetVendor=0x19d2
+TargetProduct=0x0447
+MessageContent="55534243123456782400000080000685000000240000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0413 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0413
new file mode 100755
index 0000000..3cf0cca
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_0413
@@ -0,0 +1,4 @@
+# Telewell TW-LTE 4G
+TargetVendor=0x19d2
+TargetProduct=0x0412
+MessageContent="55534243d8a523862400000080000685000000240000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1001
new file mode 100755
index 0000000..2d66c17
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1001
@@ -0,0 +1,6 @@
+# Vodafone (ZTE) K3805-Z
+TargetVendor=0x19d2
+TargetProductList="1002,1003"
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1007 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1007
new file mode 100755
index 0000000..61a7f71
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1007
@@ -0,0 +1,4 @@
+# Vodafone (ZTE) K3570-Z
+TargetVendor=0x19d2
+TargetProduct=0x1008
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1009 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1009
new file mode 100755
index 0000000..878fcdd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1009
@@ -0,0 +1,4 @@
+# Vodafone (ZTE) K3571-Z
+TargetVendor=0x19d2
+TargetProduct=0x1010
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1013 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1013
new file mode 100755
index 0000000..58f33cb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1013
@@ -0,0 +1,6 @@
+# Vodafone (ZTE) K3806-Z
+TargetVendor=0x19d2
+TargetProduct=0x1015
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1017 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1017
new file mode 100755
index 0000000..667e00a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1017
@@ -0,0 +1,4 @@
+# Vodafone K5006Z (MF821)
+TargetVendor=0x19d2
+TargetProduct=0x1018
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1019 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1019
new file mode 100755
index 0000000..ef133ca
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1019
@@ -0,0 +1,4 @@
+# Vodafone / ZTE R203 Router
+TargetVendor=0x19d2
+TargetProduct=0x1021
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1020 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1020
new file mode 100755
index 0000000..ef133ca
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1020
@@ -0,0 +1,4 @@
+# Vodafone / ZTE R203 Router
+TargetVendor=0x19d2
+TargetProduct=0x1021
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1022 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1022
new file mode 100755
index 0000000..de52f8c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1022
@@ -0,0 +1,4 @@
+# Vodafone / ZTE K4201-z
+TargetVendor=0x19d2
+TargetProductList="1023,1024"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1026 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1026
new file mode 100755
index 0000000..a6762cc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1026
@@ -0,0 +1,4 @@
+# Vodafone / ZTE R212 Router
+TargetVendor=0x19d2
+TargetProductList="1027,1028,1029"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1030 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1030
new file mode 100755
index 0000000..a00acd1
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1030
@@ -0,0 +1,4 @@
+# Vodafone K5008-z (MF823)
+TargetVendor=0x19d2
+TargetProductList="1031,1032"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1034 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1034
new file mode 100755
index 0000000..03372d1
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1034
@@ -0,0 +1,4 @@
+# Vodafone / ZTE R206-z Router
+TargetVendor=0x19d2
+TargetProductList="1035,1036,1037"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1038 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1038
new file mode 100755
index 0000000..aac2900
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1038
@@ -0,0 +1,4 @@
+# ZTE / Vodafone K4607-Z
+TargetVendor=0x19d2
+TargetProductList="1039,1040"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1042 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1042
new file mode 100755
index 0000000..878b3fc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1042
@@ -0,0 +1,4 @@
+# Vodafone / ZTE R209-z Router
+TargetVendor=0x19d2
+TargetProduct=0x1043
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1046 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1046
new file mode 100755
index 0000000..ebf0d0e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1046
@@ -0,0 +1,4 @@
+# ZTE MF730
+TargetVendor=0x19d2
+TargetProduct=0x1047
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1171 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1171
new file mode 100755
index 0000000..4c722c4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1171
@@ -0,0 +1,6 @@
+# Vodafone (ZTE) K4510-Z
+TargetVendor=0x19d2
+TargetProduct=0x1173
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1175 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1175
new file mode 100755
index 0000000..61ef605
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1175
@@ -0,0 +1,6 @@
+# Vodafone / ZTE K3770-Z
+TargetVendor=0x19d2
+TargetProduct=0x1177
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1179 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1179
new file mode 100755
index 0000000..086ade9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1179
@@ -0,0 +1,6 @@
+# Vodafone (ZTE) K3772-Z
+TargetVendor=0x19d2
+TargetProduct=0x1181
+StandardEject=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1201 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1201
new file mode 100755
index 0000000..052d473
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1201
@@ -0,0 +1,4 @@
+# ZTE MF691 (T-Mobile Rocket 2.0)
+TargetVendor=0x19d2
+TargetProduct=0x1203
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1207 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1207
new file mode 100755
index 0000000..f7e1e50d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1207
@@ -0,0 +1,4 @@
+# ZTE MF192 (Variant)
+TargetVendor=0x19d2
+TargetProduct=0x1208
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1210 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1210
new file mode 100755
index 0000000..ef7946c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1210
@@ -0,0 +1,4 @@
+# ZTE MF195
+TargetVendor=0x19d2
+TargetProduct=0x1211
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1216 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1216
new file mode 100755
index 0000000..2634bc1
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1216
@@ -0,0 +1,4 @@
+# ZTE MF192 (Variant)
+TargetVendor=0x19d2
+TargetProduct=0x1217
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1219 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1219
new file mode 100755
index 0000000..f75da93
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1219
@@ -0,0 +1,4 @@
+# ZTE MF192 (Variant)
+TargetVendor=0x19d2
+TargetProductList="1220,1222"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1224 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1224
new file mode 100755
index 0000000..baa492f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1224
@@ -0,0 +1,4 @@
+# ZTE MF190
+TargetVendor=0x19d2
+TargetProduct=0x0082
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1225 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1225
new file mode 100755
index 0000000..90b32f9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1225
@@ -0,0 +1,4 @@
+# ZTE MF668 (Variant), MF70
+TargetVendor=0x19d2
+TargetProduct=0x1405
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1227 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1227
new file mode 100755
index 0000000..3ed950f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1227
@@ -0,0 +1,4 @@
+# ZTE MF680
+TargetVendor=0x19d2
+TargetProduct=0x1252
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1232 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1232
new file mode 100755
index 0000000..086af2c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1232
@@ -0,0 +1,4 @@
+# ZTE MFxxx
+TargetVendor=0x19d2
+TargetProductList="1268,2003"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1233 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1233
new file mode 100755
index 0000000..ac2c702
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1233
@@ -0,0 +1,4 @@
+# ZTE MFxxx
+TargetVendor=0x19d2
+TargetProduct=0x1270
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1237 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1237
new file mode 100755
index 0000000..5b4def7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1237
@@ -0,0 +1,4 @@
+# ZTE / Vodafone K4201
+TargetVendor=0x19d2
+TargetProduct=0x0017
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1238 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1238
new file mode 100755
index 0000000..ff575e6
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1238
@@ -0,0 +1,4 @@
+# ZTE MF825A
+TargetVendor=0x19d2
+TargetProduct=0x0017
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1420 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1420
new file mode 100755
index 0000000..a5d5af4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1420
@@ -0,0 +1,4 @@
+# ZTE MF730
+TargetVendor=0x19d2
+TargetProduct=0x1405
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1511 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1511
new file mode 100755
index 0000000..469143b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1511
@@ -0,0 +1,4 @@
+# ZTE MFxxx
+TargetVendor=0x19d2
+TargetProduct=0x1512
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1514 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1514
new file mode 100755
index 0000000..7f08f33
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1514
@@ -0,0 +1,4 @@
+# ZTE MF192 (Variant)
+TargetVendor=0x19d2
+TargetProduct=0x1515
+MessageContent="5553424348c4758600000000000010ff000000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1517 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1517
new file mode 100755
index 0000000..8a7450e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1517
@@ -0,0 +1,4 @@
+# ZTE MF192 (Variant)
+TargetVendor=0x19d2
+TargetProduct=0x1519
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1520 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1520
new file mode 100755
index 0000000..06c58c5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1520
@@ -0,0 +1,4 @@
+# ZTE MF652
+TargetVendor=0x19d2
+TargetProduct=0x0142
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1523 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1523
new file mode 100755
index 0000000..2a16858
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1523
@@ -0,0 +1,4 @@
+# ZTE MF591 TMobile
+TargetVendor=0x19d2
+TargetProduct=0x1525
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1528 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1528
new file mode 100755
index 0000000..25e78c0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1528
@@ -0,0 +1,4 @@
+# ZTE MF196
+TargetVendor=0x19d2
+TargetProduct=0x1527
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1536 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1536
new file mode 100755
index 0000000..b3617a6
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1536
@@ -0,0 +1,4 @@
+# ZTE MF190J
+TargetVendor=0x19d2
+TargetProductList="1537,1538"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1542 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1542
new file mode 100755
index 0000000..60b06eb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1542
@@ -0,0 +1,4 @@
+# ZTE MF190J
+TargetVendor=0x19d2
+TargetProduct=0x1544
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1580 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1580
new file mode 100755
index 0000000..5b99ce8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1580
@@ -0,0 +1,4 @@
+# ZTE MF195E
+TargetVendor= 0x19d2
+TargetProduct=0x1582
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1588 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1588
new file mode 100755
index 0000000..2cbf979
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1588
@@ -0,0 +1,5 @@
+# ZTE MF710M Variants
+TargetVendor= 0x19d2
+TargetProductList="1589,1591,1592"
+StandardEject=1
+MessageContent="55534243123456702000000080000c85010101180101010101000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1595 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1595
new file mode 100755
index 0000000..13cc530
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_1595
@@ -0,0 +1,5 @@
+# ZTE MF710 (Vietnam) a.o.
+TargetVendor= 0x19d2
+TargetProductList="1592,1596,1600"
+StandardEject=1
+MessageContent="55534243123456702000000080000c85010101180101010101000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_2000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_2000
new file mode 100755
index 0000000..067173e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_2000
@@ -0,0 +1,5 @@
+# ZTE devices, some Onda devices
+TargetVendor= 0x19d2
+TargetProductList="0001,0002,0015,0016,0017,0019,0024,0031,0033,0037,0042,0052,0055,0061,0063,0064,0066,0091,0108,0117,0128,0151,0157,0177,1402,2002,2003"
+StandardEject=1
+MessageContent="55534243123456702000000080000c85010101180101010101000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_2004 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_2004
new file mode 100755
index 0000000..5d97b1e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_2004
@@ -0,0 +1,4 @@
+# ZTE MF60
+TargetVendor=0x19d2
+TargetProduct=0x1402
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_bccd b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_bccd
new file mode 100755
index 0000000..dd47bee
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_bccd
@@ -0,0 +1,6 @@
+# ZTE AX226 WiMax
+TargetVendor=0x19d2
+TargetProduct=0x0172
+MessageContent="555342431234567824000000800006bc626563240000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_ffde b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_ffde
new file mode 100755
index 0000000..1beb1df
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_ffde
@@ -0,0 +1,4 @@
+# ZTE AC682 (a.k.a. SmartFren Connex)
+TargetVendor=0x19d2
+TargetProduct=0xffdd
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_ffe6 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_ffe6
new file mode 100755
index 0000000..e0b6d26
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_ffe6
@@ -0,0 +1,4 @@
+# ZTE "ffe" devices 1 (e.g. Cricket A605)
+TargetVendor=0x19d2
+TargetProduct=0xffe5
+MessageContent="5553424330f4cf8124000000800108df200000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_fff5 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_fff5
new file mode 100755
index 0000000..1fa9350
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_fff5
@@ -0,0 +1,4 @@
+# ZTE "ff" devices 1
+TargetVendor=0x19d2
+TargetProductList="ffe4,ffe9,fff1,fffe,ffff"
+MessageContent="5553424312345678c00000008000069f030000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_fff6 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_fff6
new file mode 100755
index 0000000..e894e96
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/19d2_fff6
@@ -0,0 +1,4 @@
+# ZTE "fff" devices 2
+TargetVendor=0x19d2
+TargetProduct=0xfff1
+MessageContent="5553424312345678c00000008000069f030000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1a8d_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1a8d_1000
new file mode 100755
index 0000000..3580f54
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1a8d_1000
@@ -0,0 +1,6 @@
+# BandRich BandLuxe C100, C120, C170, C270, C3xx, C508
+TargetVendor=0x1a8d
+TargetProductList="1002,1007,1009,100d,2006"
+StandardEject=1
+ReleaseDelay=4000
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1a8d_2000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1a8d_2000
new file mode 100755
index 0000000..16d85c4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1a8d_2000
@@ -0,0 +1,4 @@
+# BandRich BandLuxe C339
+TargetVendor=0x1a8d
+TargetProduct=0x2006
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ab7_5700 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ab7_5700
new file mode 100755
index 0000000..983903a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ab7_5700
@@ -0,0 +1,4 @@
+# Hummer DTM5731, Aircard 901 
+TargetVendor=0x1ab7
+TargetProductList="2000,5731"
+StandardEject=1 
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1b7d_0700 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1b7d_0700
new file mode 100755
index 0000000..f357fcc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1b7d_0700
@@ -0,0 +1,4 @@
+# EpiValley SEC-7089 (featured by Alegro and Starcomms / iZAP)
+TargetVendor=0x1b7d
+TargetProduct=0x0001
+MessageContent="555342431234567824000000800008FF05B112AEE102000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_000f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_000f
new file mode 100755
index 0000000..c618dce
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_000f
@@ -0,0 +1,4 @@
+# ETCOM E300
+TargetVendor=0x1bbb
+TargetProduct=0x000f
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_00ca b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_00ca
new file mode 100755
index 0000000..df5753b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_00ca
@@ -0,0 +1,3 @@
+# Alcatel OT-X080C
+TargetClass=0xff
+MessageContent="55534243123456788000000080000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_011f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_011f
new file mode 100755
index 0000000..97f7a3a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_011f
@@ -0,0 +1,4 @@
+# Haier EVDO Rev. A
+TargetVendor=0x1bbb
+TargetProduct=0x0106
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_022c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_022c
new file mode 100755
index 0000000..46e4105
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_022c
@@ -0,0 +1,2 @@
+# Alcatel X602D
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_025e b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_025e
new file mode 100755
index 0000000..717aa47
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_025e
@@ -0,0 +1,4 @@
+# Yota 4G LTE W8
+TargetVendor=0x1bbb
+TargetProduct=0x0195
+MessageContent="55534243123456788000000080000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f000
new file mode 100755
index 0000000..bd30b57
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f000
@@ -0,0 +1,4 @@
+# Alcatel X200/X200L/X060S/L100V, Archos G9 3G Key
+TargetVendor=0x1bbb
+TargetProductList="0000,0017,00b7,011e,0191,0195"
+MessageContent="55534243123456788000000080000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f017 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f017
new file mode 100755
index 0000000..d68767d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f017
@@ -0,0 +1,4 @@
+# Alcatel OT-X220D, L100V
+TargetVendor=0x1bbb
+TargetProductList="0017,011e,0203"
+MessageContent="55534243123456788000000080000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f052 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f052
new file mode 100755
index 0000000..11262b0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1bbb_f052
@@ -0,0 +1,4 @@
+# Alcatel OT X220L
+TargetVendor=0x1bbb
+TargetProduct=0x0052
+MessageContent="55534243123456788000000080000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_1001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_1001
new file mode 100755
index 0000000..d43b947
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_1001
@@ -0,0 +1,4 @@
+# Alcatel One Touch X020
+TargetVendor=0x1c9e
+TargetProductList="6060,6061"
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_6000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_6000
new file mode 100755
index 0000000..77cb169
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_6000
@@ -0,0 +1,5 @@
+# TU930, IVIO IV-2010u
+TargetClass=0xff
+MessageContent="55534243123456780000000000000601000000000000000000000000000000"
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_6061_uPr=Storage b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_6061_uPr=Storage
new file mode 100755
index 0000000..3d6d53d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_6061_uPr=Storage
@@ -0,0 +1,3 @@
+# Vibe 3G Modem 
+TargetClass=0xff
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9101 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9101
new file mode 100755
index 0000000..ed42e10
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9101
@@ -0,0 +1,4 @@
+# Emobile D12LC
+TargetVendor=0x1c9e
+TargetProduct=0x9104
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9200 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9200
new file mode 100755
index 0000000..d0a1e1d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9200
@@ -0,0 +1,4 @@
+# MyWave SW006 Sport Phone/Modem Combination
+TargetVendor=0x1c9e
+TargetProduct=0x9202
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9401 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9401
new file mode 100755
index 0000000..e02d00d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9401
@@ -0,0 +1,4 @@
+# Emobile D21LC
+TargetVendor=0x1c9e
+TargetProduct=0x9404
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9800 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9800
new file mode 100755
index 0000000..ef03cd9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9800
@@ -0,0 +1,3 @@
+# Longcheer SU9800
+TargetClass=0xff
+MessageContent="55534243123456788000000080000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_98ff b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_98ff
new file mode 100755
index 0000000..80a3146
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_98ff
@@ -0,0 +1,4 @@
+# Telewell TW-3G HSPA+, FS01BU 3G, SmartBro WM66E
+TargetVendor=0x1c9e
+TargetProductList="6801,9801,9803"
+MessageContent="55534243123456780000000080000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9bfe b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9bfe
new file mode 100755
index 0000000..25767f0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9bfe
@@ -0,0 +1,4 @@
+# XS Stick W100 (Omega)
+TargetVendor=0x1c9e
+TargetProduct=0x9b01
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9d00 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9d00
new file mode 100755
index 0000000..f8bbedd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9d00
@@ -0,0 +1,3 @@
+# Prolink PCM100
+TargetClass=0xff
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9e00 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9e00
new file mode 100755
index 0000000..3a03904
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9e00
@@ -0,0 +1,3 @@
+# BSNL Capitel
+TargetClass=0xff
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9e08 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9e08
new file mode 100755
index 0000000..e90fd46
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_9e08
@@ -0,0 +1,6 @@
+# Explay Slim
+TargetVendor=0x1c9e
+TargetProduct=0x9e18
+SierraMode=1
+
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f000
new file mode 100755
index 0000000..a5b7a8e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f000
@@ -0,0 +1,5 @@
+# Longcheer/Longsoon (aka Omega Technology) devices
+TargetVendor=0x1c9e
+TargetProductList="9000,9603,9605,9607,9900"
+MessageContent="555342431234567800000000000001ff000000000000000000000000000000"
+WaitBefore=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f000_uMa=USB_Modem b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f000_uMa=USB_Modem
new file mode 100755
index 0000000..a645abc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f000_uMa=USB_Modem
@@ -0,0 +1,5 @@
+# MobiData MBD-200HU and others
+TargetVendor=0x1c9e
+TargetProductList="9000,9603,9605,9607,9900,9a00"
+MessageContent="55534243123456788000000080000606f50402527000000000000000000000"
+WaitBefore=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f010 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f010
new file mode 100755
index 0000000..d1d007b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1c9e_f010
@@ -0,0 +1,4 @@
+# Micromax MMX400R / 4G Systems XSBOXGO
+TargetVendor=0x1c9e
+TargetProduct=0xf101
+MessageContent="55534243123456780000000000000606f50402527000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1000
new file mode 100755
index 0000000..62675f7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1000
@@ -0,0 +1,4 @@
+# TechFaith BSNL Capitel
+TargetVendor=0x1d09
+TargetProduct=0x1010
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1021 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1021
new file mode 100755
index 0000000..3af3048
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1021
@@ -0,0 +1,4 @@
+# Aiko 81D
+TargetVendor=0x1d09
+TargetProduct=0x1010
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1025 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1025
new file mode 100755
index 0000000..eb9133c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1d09_1025
@@ -0,0 +1,4 @@
+# TechFaith FlyingLARK46
+TargetVendor=0x1d09
+TargetProduct=0x1026
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1da5_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1da5_f000
new file mode 100755
index 0000000..8cb08ae
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1da5_f000
@@ -0,0 +1,4 @@
+# Qisda H21 Flying Beetle
+TargetVendor=0x1da5
+TargetProduct=0x4512
+QisdaMode=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1dbc_0669 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1dbc_0669
new file mode 100755
index 0000000..c137caa
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1dbc_0669
@@ -0,0 +1,2 @@
+# Wisue W340
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1dd6_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1dd6_1000
new file mode 100755
index 0000000..2ad5e61
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1dd6_1000
@@ -0,0 +1,5 @@
+# Solomon S3Gm-660
+TargetVendor=0x1dd6
+TargetProduct=0x1002
+MessageContent="55534243123456781200000080000603000000020000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1de1_1101 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1de1_1101
new file mode 100755
index 0000000..92145ba
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1de1_1101
@@ -0,0 +1,4 @@
+# Philips PicoPix 1020 Projector
+TargetVendor=0x21e7
+TargetProduct=0x000e
+MessageContent="55534243123456780000000000000cff020000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1e0e_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1e0e_f000
new file mode 100755
index 0000000..04931f9
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1e0e_f000
@@ -0,0 +1,5 @@
+# Option iCON 210, PROLiNK PHS100 + PH300, Hyundai MB-810, A-Link 3GU
+TargetVendor=0x1e0e
+TargetProductList="9000,9100,9200"
+MessageContent="555342431234567800000000000006bd000000020000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1e89_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1e89_f000
new file mode 100755
index 0000000..db6a46d
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1e89_f000
@@ -0,0 +1,4 @@
+# 3GO 3GO11 HSUPA
+TargetVendor=0x1e89
+TargetProduct=0x1a20
+MessageContent="5553424312345678800000008000060619181a207000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1edf_6003 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1edf_6003
new file mode 100755
index 0000000..eb04ecd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1edf_6003
@@ -0,0 +1,2 @@
+# AirPlus MCD-800
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0003 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0003
new file mode 100755
index 0000000..a292e64
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0003
@@ -0,0 +1,5 @@
+# Onda MV815U
+TargetVendor=0x1ee8
+TargetProduct=0x0004
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0007 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0007
new file mode 100755
index 0000000..9a9fbaa
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0007
@@ -0,0 +1,4 @@
+# Onda POM1051
+TargetVendor=0x1ee8
+TargetProduct=0x000b
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0009 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0009
new file mode 100755
index 0000000..7b7f881
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0009
@@ -0,0 +1,5 @@
+# Onda MW833UP
+TargetVendor=0x1ee8
+TargetProduct=0x000b
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0013 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0013
new file mode 100755
index 0000000..4fc5320
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0013
@@ -0,0 +1,5 @@
+# Onda MW833UP + MW835UP
+TargetVendor=0x1ee8
+TargetProductList="0011,0012,0014"
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0018 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0018
new file mode 100755
index 0000000..d50cde6
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0018
@@ -0,0 +1,5 @@
+# Onda MO835UP
+TargetVendor=0x1ee8
+TargetProduct=0x0017
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0040 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0040
new file mode 100755
index 0000000..251f807
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0040
@@ -0,0 +1,5 @@
+# Onda MW836UP-K
+TargetVendor=0x1ee8
+TargetProductList="003e,003f"
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0045 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0045
new file mode 100755
index 0000000..92b567f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0045
@@ -0,0 +1,5 @@
+# Onda MDC655
+TargetVendor=0x1ee8
+TargetProduct=0x0044
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0048 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0048
new file mode 100755
index 0000000..a0618ab
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0048
@@ -0,0 +1,4 @@
+# Onda MT655
+TargetVendor=0x1ee8
+TargetProduct=0x0049
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_004a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_004a
new file mode 100755
index 0000000..97dd71b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_004a
@@ -0,0 +1,4 @@
+# Onda MDC655
+TargetVendor=0x1ee8
+TargetProduct=0x0049
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_004f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_004f
new file mode 100755
index 0000000..e81eb29
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_004f
@@ -0,0 +1,5 @@
+# Onda MDC655 Variant
+TargetVendor=0x1ee8
+TargetProduct=0x004e
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0054 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0054
new file mode 100755
index 0000000..8638639
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0054
@@ -0,0 +1,5 @@
+# Onda MW875UP
+TargetVendor=0x1ee8
+TargetProduct=0x0053
+MessageContent="555342431234567800000000000010ff000000000000000000000000000000"
+NeedResponse=1
\ No newline at end of file
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0060 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0060
new file mode 100755
index 0000000..985e4a3
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0060
@@ -0,0 +1,4 @@
+# Onda MSA 14.4 (TIM Brasil)
+TargetVendor=0x1ee8
+TargetProduct=0x005f
+MessageContent="555342431234567800000000000008ff000000000000030000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0063 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0063
new file mode 100755
index 0000000..b46c775
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0063
@@ -0,0 +1,4 @@
+# Onda TM201, CM201
+TargetVendor=0x1ee8
+TargetProductList="0064,0065"
+MessageContent="555342431234567800000000000008ff000000000000030000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0068 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0068
new file mode 100755
index 0000000..da73ac1
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1ee8_0068
@@ -0,0 +1,4 @@
+# Onda WM301
+TargetVendor=0x1ee8
+TargetProduct=0x0069
+MessageContent="555342431234567800000000000008ff000000000000030000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1f28_0021 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1f28_0021
new file mode 100755
index 0000000..162c20b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1f28_0021
@@ -0,0 +1,4 @@
+# Cricket A600
+TargetVendor=0x1f28
+TargetProduct=0x0020
+MessageContent="555342431234567824000000800108df200000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0032 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0032
new file mode 100755
index 0000000..2eabd0a
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0032
@@ -0,0 +1,2 @@
+# Franklin Wireless U210 (Variant)
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0130 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0130
new file mode 100755
index 0000000..100ce55
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0130
@@ -0,0 +1,4 @@
+# Franklin Wireless U210
+TargetVendor=0x1fac
+TargetProduct=0x0131
+MessageContent="555342431234567824000000800108df200000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0150 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0150
new file mode 100755
index 0000000..e04b132
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0150
@@ -0,0 +1,4 @@
+# Franklin Wireless U600
+TargetVendor=0x1fac
+TargetProduct=0x0151
+MessageContent="555342431234567824000000800108df200000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0151 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0151
new file mode 100755
index 0000000..9db4de7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/1fac_0151
@@ -0,0 +1,2 @@
+# Franklin Wireless U600
+Configuration=2
\ No newline at end of file
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_00a6 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_00a6
new file mode 100755
index 0000000..6362dad
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_00a6
@@ -0,0 +1,4 @@
+# D-Link DWM-157 B1
+TargetVendor=0x2001
+TargetProduct=0x7d02
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_7600 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_7600
new file mode 100755
index 0000000..b1fe1f7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_7600
@@ -0,0 +1,2 @@
+# D-Link DWM-157 C1
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_98ff b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_98ff
new file mode 100755
index 0000000..383e0c7
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_98ff
@@ -0,0 +1,5 @@
+# D-Link DWM-221
+TargetVendor=0x2001
+TargetProduct=0x7e16
+MessageContent="55534243f8d2e6838000000080000606f50402527000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a401 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a401
new file mode 100755
index 0000000..8d4e874
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a401
@@ -0,0 +1,4 @@
+# D-Link DWM-221 B1
+TargetVendor=0x2001
+TargetProduct=0x7e19
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a403 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a403
new file mode 100755
index 0000000..d6c4893
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a403
@@ -0,0 +1,4 @@
+# D-Link DWM-156 A8, DWP-157 B1
+TargetVendor=0x2001
+TargetProductList="7d0b,7d0c"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a405 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a405
new file mode 100755
index 0000000..3208b3b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a405
@@ -0,0 +1,4 @@
+# D-Link DWM-167 A1
+TargetVendor=0x2001
+TargetProduct=0x7d0d
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a406 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a406
new file mode 100755
index 0000000..4148807
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a406
@@ -0,0 +1,4 @@
+# D-Link DWM-221
+TargetVendor=0x2001
+TargetProduct=0x7e19
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a407 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a407
new file mode 100755
index 0000000..6522888
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a407
@@ -0,0 +1,4 @@
+# D-Link DWM-157 C1
+TargetVendor=0x2001
+TargetProduct=0x7d0e
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a40a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a40a
new file mode 100755
index 0000000..3db2e55
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a40a
@@ -0,0 +1,4 @@
+# D-Link DWM-156 A8 (Myanmar)
+TargetVendor=0x2001
+TargetProduct=0x7d10
+MessageContent="555342431234567800000000000003f0010100000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a40d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a40d
new file mode 100755
index 0000000..4f12646
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a40d
@@ -0,0 +1,4 @@
+# D-Link DWR-910
+TargetVendor=0x2001
+TargetProduct=0x7e38
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a706 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a706
new file mode 100755
index 0000000..1b4ee3e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a706
@@ -0,0 +1,4 @@
+# D-Link DWM-156 A7
+TargetVendor=0x2001
+TargetProduct=0x7d01
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a707 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a707
new file mode 100755
index 0000000..6362dad
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a707
@@ -0,0 +1,4 @@
+# D-Link DWM-157 B1
+TargetVendor=0x2001
+TargetProduct=0x7d02
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a708 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a708
new file mode 100755
index 0000000..15c8323
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a708
@@ -0,0 +1,4 @@
+# D-Link DWM-158 D1
+TargetVendor=0x2001
+TargetProduct=0x7d03
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a805 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a805
new file mode 100755
index 0000000..97e0c7b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a805
@@ -0,0 +1,4 @@
+# D-Link DWR-510
+TargetVendor=0x2001
+TargetProduct=0x7e12
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a80b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a80b
new file mode 100755
index 0000000..fbbb6c8
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2001_a80b
@@ -0,0 +1,5 @@
+# D-Link DWM-156 (Variant)
+TargetVendor=0x2001
+TargetProduct=0x7d00
+MessageContent="555342431234567800000000000003f0010100000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2015_0001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2015_0001
new file mode 100755
index 0000000..02a559f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2015_0001
@@ -0,0 +1,3 @@
+# Venus VT-18
+TargetClass=0xff
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/201e_1023 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/201e_1023
new file mode 100755
index 0000000..98fe5a4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/201e_1023
@@ -0,0 +1,6 @@
+# Haier CE682 (EVDO)
+TargetVendor=0x201e
+TargetProduct=0x1022
+MessageContent="55534243123456780000000000000600000000000000000000000000000000"
+MessageContent2="5553424312345679c000000080000671030000000000000000000000000000"
+NeedResponse=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/201e_2009 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/201e_2009
new file mode 100755
index 0000000..84fefe1
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/201e_2009
@@ -0,0 +1,3 @@
+# Haier CE 100 
+TargetClass=0xff
+StandardEject=1 
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_0002 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_0002
new file mode 100755
index 0000000..f67f7a2
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_0002
@@ -0,0 +1,4 @@
+# Mediatek MT6229, Micromax MMX 377G, Olicard 300
+TargetVendor=0x2020
+TargetProductList="2000,4000,4010"
+MessageContent="555342430820298900000000000003f0010100000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_f00e b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_f00e
new file mode 100755
index 0000000..ec38550
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_f00e
@@ -0,0 +1,5 @@
+# SpeedUp SU-8000 and others
+TargetVendor=0x2020
+TargetProductList="1005,1008"
+StandardEject=1
+WaitBefore=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_f00f b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_f00f
new file mode 100755
index 0000000..64e60f0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2020_f00f
@@ -0,0 +1,5 @@
+# SpeedUp SU-8000U
+TargetVendor=0x2020
+TargetProduct=0x1005
+StandardEject=1
+WaitBefore=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2077_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2077_1000
new file mode 100755
index 0000000..8bac36b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2077_1000
@@ -0,0 +1,4 @@
+# Changhong CH690, D-Link DWM-163 + DWM-168
+TargetVendor=0x2077
+TargetProductList="7001,7010,7011"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2077_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2077_f000
new file mode 100755
index 0000000..e65c97b
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2077_f000
@@ -0,0 +1,5 @@
+# Telenet 3G dongle (T&W WU160), Netgear AC327U and others
+TargetVendor=0x2077
+TargetProductList="9000,9062,a000,a003"
+StandardEject=1
+MessageContent="55534243123456700000000000000616aa0000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20a6_f00a b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20a6_f00a
new file mode 100755
index 0000000..9e20b7e
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20a6_f00a
@@ -0,0 +1,4 @@
+# BM WM78
+TargetVendor=0x20a6
+TargetProduct=0x1000
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20a6_f00e b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20a6_f00e
new file mode 100755
index 0000000..dd6aefa
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20a6_f00e
@@ -0,0 +1,4 @@
+# Intex 3.5G
+TargetVendor=0x20a6
+TargetProduct=0x1105
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20b9_1682 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20b9_1682
new file mode 100755
index 0000000..a65c1ea
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/20b9_1682
@@ -0,0 +1,3 @@
+# Tlaytech TEU800
+TargetClass=0xff
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/21f5_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/21f5_1000
new file mode 100755
index 0000000..ebb13da
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/21f5_1000
@@ -0,0 +1,4 @@
+# StrongRising (China Telcom), Air FlexiNet
+TargetVendor=0x21f5
+TargetProduct=0x2008
+MessageContent="5553424312345678c000000080000671010000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/21f5_3010 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/21f5_3010
new file mode 100755
index 0000000..ef2c097
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/21f5_3010
@@ -0,0 +1,4 @@
+# StrongRising STD808
+TargetVendor=0x21f5
+TargetProduct=0x1101
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2262_0001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2262_0001
new file mode 100755
index 0000000..4339910
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2262_0001
@@ -0,0 +1,4 @@
+# Viettel VT100
+TargetVendor=0x2262
+TargetProduct=0x0002
+MessageContent="5553424340799288C000000080010A16000000C00000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22de_6801 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22de_6801
new file mode 100755
index 0000000..a610b60
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22de_6801
@@ -0,0 +1,3 @@
+# WeTelecom WM-D200
+TargetClass=0xff
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22de_6803 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22de_6803
new file mode 100755
index 0000000..55b59c5
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22de_6803
@@ -0,0 +1,4 @@
+# WeTelecom WM-D300
+TargetVendor=0x22de
+TargetProduct=0x6801
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22f4_0021 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22f4_0021
new file mode 100755
index 0000000..7980f66
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/22f4_0021
@@ -0,0 +1,3 @@
+# Tata Photon+, Olive VME102
+TargetClass=0xff
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0001 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0001
new file mode 100755
index 0000000..5008f5c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0001
@@ -0,0 +1,2 @@
+# Linktop LW272/LW273 (BSNL Teracom)
+Configuration=3
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0003 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0003
new file mode 100755
index 0000000..5008f5c
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0003
@@ -0,0 +1,2 @@
+# Linktop LW272/LW273 (BSNL Teracom)
+Configuration=3
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0007 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0007
new file mode 100755
index 0000000..63996da
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0007
@@ -0,0 +1,2 @@
+# Visiontek 82GH 3G
+Configuration=3
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000b b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000b
new file mode 100755
index 0000000..e8dd4bb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000b
@@ -0,0 +1,2 @@
+# Zoom 3G
+Configuration=3
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000c b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000c
new file mode 100755
index 0000000..e8dd4bb
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000c
@@ -0,0 +1,2 @@
+# Zoom 3G
+Configuration=3
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000d b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000d
new file mode 100755
index 0000000..66ec4cc
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_000d
@@ -0,0 +1,2 @@
+# Intex Speed 3G v7.2
+Configuration=3
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0101 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0101
new file mode 100755
index 0000000..721e5c4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0101
@@ -0,0 +1,2 @@
+# Linktop LW272/LW273
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0103 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0103
new file mode 100755
index 0000000..e543736
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/230d_0103
@@ -0,0 +1,2 @@
+# Teracom LW272
+Configuration=2
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2357_0200 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2357_0200
new file mode 100755
index 0000000..6251747
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2357_0200
@@ -0,0 +1,4 @@
+# TP-Link MA180
+TargetVendor=0x2357
+TargetProduct=0x0201
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2357_f000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2357_f000
new file mode 100755
index 0000000..aba6b49
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/2357_f000
@@ -0,0 +1,4 @@
+# TP-Link MA260
+TargetVendor=0x2357
+TargetProduct=0x9000
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/23a2_1010 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/23a2_1010
new file mode 100755
index 0000000..95cee31
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/23a2_1010
@@ -0,0 +1,4 @@
+# Titan 3.5G
+TargetVendor=0x23a2
+TargetProduct=0x1234
+MessageContent="555342431234567800000000000006161f6d62706b00000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_a000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_a000
new file mode 100755
index 0000000..6981490
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_a000
@@ -0,0 +1,4 @@
+# Unknown devices
+TargetVendor=0x257a
+TargetProductList="1601,161f,162f,261f,262f,361f,362f"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_b000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_b000
new file mode 100755
index 0000000..6981490
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_b000
@@ -0,0 +1,4 @@
+# Unknown devices
+TargetVendor=0x257a
+TargetProductList="1601,161f,162f,261f,262f,361f,362f"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_c000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_c000
new file mode 100755
index 0000000..6981490
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_c000
@@ -0,0 +1,4 @@
+# Unknown devices
+TargetVendor=0x257a
+TargetProductList="1601,161f,162f,261f,262f,361f,362f"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_d000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_d000
new file mode 100755
index 0000000..6981490
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/257a_d000
@@ -0,0 +1,4 @@
+# Unknown devices
+TargetVendor=0x257a
+TargetProductList="1601,161f,162f,261f,262f,361f,362f"
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/6000_1000 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/6000_1000
new file mode 100755
index 0000000..e9d346f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/6000_1000
@@ -0,0 +1,4 @@
+# BlueLink BL-EV08C
+TargetVendor=0x05c6
+TargetProduct=0x6000
+MessageContent="5553424312345678c000000080000671010000000000000000000000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/8888_6500 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/8888_6500
new file mode 100755
index 0000000..85b2776
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/8888_6500
@@ -0,0 +1,4 @@
+# Exiss Mobile E-190 series (made by C-motech)
+TargetVendor=0x16d8
+TargetProduct=0x6533
+MessageContent="5553424398e2c4812400000080000bff524445564348473d43440000000000"
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/ed09_1021 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/ed09_1021
new file mode 100755
index 0000000..d23a846
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.d/ed09_1021
@@ -0,0 +1,4 @@
+# Aiko 81D, fw with wrong vendor ID
+TargetVendor=0xed09
+TargetProduct=0x1010
+StandardEject=1
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.h b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.h
new file mode 100755
index 0000000..f40796f
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.h
@@ -0,0 +1,116 @@
+/*
+  This file is part of usb_modeswitch, a mode switching tool for controlling
+  the mode of 'multi-state' USB devices
+
+  Version 2.4.0, 2016/06/12
+  Copyright (C) 2007 - 2016  Josua Dietze
+
+  Config file parsing stuff borrowed from Guillaume Dargaud
+  (http://www.gdargaud.net/Hack/SourceCode.html)
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details:
+
+  http://www.gnu.org/licenses/gpl.txt
+
+*/
+
+#include <stdlib.h>
+#include <libusb.h>
+
+void readConfigFile(const char *configFilename);
+void printConfig();
+int switchSendMessage();
+int switchConfiguration();
+int switchAltSetting();
+void switchHuaweiMode();
+
+void switchSierraMode();
+void switchGCTMode();
+void switchKobilMode();
+void switchQisdaMode();
+void switchQuantaMode();
+void switchSequansMode();
+void switchActionMode();
+void switchBlackberryMode();
+void switchPantechMode();
+void switchCiscoMode();
+int switchSonyMode();
+int detachDriver();
+int checkSuccess();
+int sendMessage(char* message, int count);
+int write_bulk(int endpoint, unsigned char *message, int length);
+int read_bulk(int endpoint, unsigned char *buffer, int length);
+void release_usb_device(int dummy);
+struct libusb_device* search_devices( int *numFound, int vendor, char* productList,
+		int targetClass, int configuration, int mode);
+int find_first_bulk_endpoint(int direction);
+int get_current_config_value();
+int get_interface_class();
+char* ReadParseParam(const char* FileName, char *VariableName);
+int hex2num(char c);
+int hex2byte(const char *hex);
+int hexstr2bin(const char *hex, unsigned char *buffer, int len);
+void printVersion();
+void printHelp();
+void close_all();
+void abortExit();
+int readArguments(int argc, char **argv);
+void deviceDescription();
+void resetUSB();
+void release_usb_device(int dummy);
+int findMBIMConfig(int vendor, int product, int mode);
+
+
+// Boolean
+#define  and     &&
+#define  or      ||
+#define  not     !
+
+// Bitwise
+#define  bitand  &
+#define  bitor   |
+#define  compl   ~
+#define  xor     ^
+
+// Equals
+#define  and_eq  &=
+#define  not_eq  !=
+#define  or_eq   |=
+#define  xor_eq  ^=
+
+extern char* ReadParseParam(const char* FileName, char *VariableName);
+
+extern char *TempPP;
+
+#define ParseParamString(ParamFileName, Str) \
+	if ((TempPP=ReadParseParam((ParamFileName), #Str))!=NULL) \
+		strcpy(Str, TempPP); else Str[0]='\0'
+		
+#define ParseParamInt(ParamFileName, Int) \
+	if ((TempPP=ReadParseParam((ParamFileName), #Int))!=NULL) \
+		Int=atoi(TempPP)
+
+#define ParseParamHex(ParamFileName, Int) \
+	if ((TempPP=ReadParseParam((ParamFileName), #Int))!=NULL) \
+		Int=strtol(TempPP, NULL, 16)
+
+#define ParseParamFloat(ParamFileName, Flt) \
+	if ((TempPP=ReadParseParam((ParamFileName), #Flt))!=NULL) \
+		Flt=atof(TempPP)
+
+#define ParseParamBool(ParamFileName, B) \
+	if ((TempPP=ReadParseParam((ParamFileName), #B))!=NULL) \
+		B=(toupper(TempPP[0])=='Y' || toupper(TempPP[0])=='T'|| TempPP[0]=='1'); else B=0
+
+#define ParseParamBoolMap(ParamFileName, B, M, Const) \
+	if ((TempPP=ReadParseParam((ParamFileName), #B))!=NULL) \
+		if (toupper(TempPP[0])=='Y' || toupper(TempPP[0])=='T'|| TempPP[0]=='1') \
+			M=M+Const
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.sh b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.sh
new file mode 100755
index 0000000..b126ec3
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+# part of usb_modeswitch 2.4.0
+device_in()
+{
+	if [ ! -e /var/lib/usb_modeswitch/$1 ]; then
+		return 0
+	fi
+	while read line
+	do
+		if [ $(expr "$line" : "$2:$3") != 0 ]; then
+			return 1
+		fi
+	done </var/lib/usb_modeswitch/$1
+	if [ $(expr "$line" : "$2:$3") != 0 ]; then
+		return 1
+	fi
+	return 0
+}
+
+if [ $(expr "$1" : "--.*") ]; then
+	p_id=$4
+	if [ -z $p_id ]; then
+		prod=$5
+		if [ -z $prod ]; then
+			prod=$3
+		fi
+		prod=${prod%/*}
+		v_id=0x${prod%/*}
+		p_id=0x${prod#*/}
+		if [ "$v_id" = "0x" ]; then
+			v_id="0"
+			p_id="0"
+		fi
+		v_id="$(printf %04x $(($v_id)))"
+		p_id="$(printf %04x $(($p_id)))"
+	else
+		v_id=$3
+	fi
+fi
+PATH=/sbin:/usr/sbin:$PATH
+case "$1" in
+	--driver-bind)
+		# driver binding code removed
+		exit 0
+		;;
+	--symlink-name)
+		device_in "link_list" $v_id $p_id
+		if [ "$?" = "1" ]; then
+			if [ -e "/usr/sbin/usb_modeswitch_dispatcher" ]; then
+				exec usb_modeswitch_dispatcher $1 $2 2>>/dev/null
+			fi
+		fi
+		exit 0
+		;;
+esac
+
+IFS='/' read -r p1 p2 <<EOF
+$1
+EOF
+
+PATH=/bin:/sbin:/usr/bin:/usr/sbin
+init_path=`readlink /sbin/init`
+if [ `basename $init_path` = "systemd" ]; then
+	systemctl --no-block start usb_modeswitch@$p1'_'$p2.service
+elif [ -e "/etc/init/usb-modeswitch-upstart.conf" ]; then
+	initctl emit --no-wait usb-modeswitch-upstart UMS_PARAM=$1
+else
+	# only old distros, new udev will kill all subprocesses
+	exec 1<&- 2<&- 5<&- 7<&-
+	exec usb_modeswitch_dispatcher --switch-mode $1 &
+fi
+exit 0
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.tcl b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.tcl
new file mode 100755
index 0000000..3e590fd
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch.tcl
@@ -0,0 +1,1015 @@
+#!/usr/bin/tclsh
+
+# Wrapper (tcl) for usb_modeswitch, called from
+# /lib/udev/rules.d/40-usb_modeswitch.rules
+# (part of data pack "usb-modeswitch-data") via
+# /lib/udev/usb_modeswitch
+#
+# Does ID check on newly discovered USB devices and calls
+# the mode switching program with the matching parameter
+# file from /usr/share/usb_modeswitch
+#
+# Part of usb-modeswitch-2.4.0 package
+# (C) Josua Dietze 2009-2016
+
+set arg0 [lindex $argv 0]
+if [regexp {\.tcl$} $arg0] {
+	if [file exists $arg0] {
+		set argv [lrange $argv 1 end]
+		source $arg0
+		exit
+	}
+}
+
+# Setting of these switches is done in the global config
+# file (/etc/usb_modeswitch.conf) if available
+
+set flags(logging) 1
+set flags(noswitching) 0
+set flags(stordelay) 0
+set flags(logwrite) 0
+# also settable in device config files
+set flags(nombim) 0
+
+# Execution starts at file bottom
+
+proc {Main} {argv argc} {
+
+global scsi usb config match device flags setup devdir loginit
+
+set flags(config) ""
+Log "[ParseGlobalConfig]"
+
+# The facility to add a symbolic link pointing to the
+# ttyUSB port which provides interrupt transfer, i.e.
+# the port to connect through.
+# Will check for interrupt endpoint in ttyUSB port (lowest if
+# there is more than one); if found, return "gsmmodem[n]" name
+# to udev for symlink creation
+
+# This is run once for every port of LISTED devices by
+# a udev rule
+
+if {[lindex $argv 0] == "--symlink-name"} {
+	puts -nonewline [SymLinkName [lindex $argv 1]]
+	SafeExit
+}
+
+if {[lindex $argv 0] == "--switch-systemd"} {
+	set argList [split [lindex $argv 1] _]
+	Log "\nStarted via systemd"
+} else {
+	if {[lindex $argv 0] == "--switch-upstart"} {
+		Log "\nStarted via upstart"
+	}
+	set argList [split [lindex $argv 1] /]
+}
+if [string length [lindex $argList 1]] {
+	set device [lindex $argList 1]
+} else {
+	set device "noname"
+}
+if {$flags(stordelay) > 0} {
+	SetStorageDelay $flags(stordelay)
+}
+
+Log "Raw args from udev: [lindex $argv 1]\n"
+
+if {$device == "noname"} {
+	Log "\nNo data from udev. Exit"
+	SafeExit
+}
+
+if {![regexp -- {--switch-} [lindex $argv 0]]} {
+	Log "\nNo command given. Exit"
+	SafeExit
+}
+
+set setup(dbdir) /usr/share/usb_modeswitch
+set setup(dbdir_etc) /etc/usb_modeswitch.d
+
+
+if {![file exists $setup(dbdir)] && ![file exists $setup(dbdir_etc)]} {
+	Log "\nError: no config database found in /usr/share or /etc. Exit"
+	SafeExit
+}
+set bindir /usr/sbin
+
+set devList1 {}
+set devList2 {}
+
+
+# arg 0: the bus id for the device (udev: %b), often ommitted
+# arg 1: the "kernel name" for the device (udev: %k)
+#
+# Used to determine the top directory for the device in sysfs
+
+set ifChk 0
+if {[string length [lindex $argList 0]] == 0} {
+	if {[string length [lindex $argList 1]] == 0} {
+		Log "No device number values given from udev! Exit"
+		SafeExit
+	} else {
+		if {![regexp {(.*?):} [lindex $argList 1] d dev_top]} {
+			if {![regexp {([0-9]+-[0-9]+\.?[0-9]*.*)} [lindex $argList 1] d dev_top]} {
+				Log "Could not determine device dir from udev values! Exit"
+				SafeExit
+			}
+		}
+	}
+} else {
+	set dev_top [lindex $argList 0]
+	regexp {(.*?):} $dev_top d dev_top
+}
+
+set devdir /sys/bus/usb/devices/$dev_top
+if {![file isdirectory $devdir]} {
+	Log "Top device directory not found ($devdir)! Exit"
+	SafeExit
+}
+Log "Use top device dir $devdir"
+
+set iface 0
+Log "Check class of first interface ..."
+set config(class) [IfClass 0 $devdir]
+if {$config(class) < 0} {
+	Log " No access to interface 0. Exit"
+	SafeExit
+}
+Log " Interface 0 class is $config(class)."
+
+set ifdir [file tail [IfDir $iface $devdir]]
+regexp {:([0-9]+\.[0-9]+)$} $ifdir d iface
+
+set flags(logwrite) 1
+
+# Mapping of the short string identifiers (in the config
+# file names) to the long name used here
+#
+# If we need them it's a snap to add new attributes here!
+
+set match(sVe) scsi(vendor)
+set match(sMo) scsi(model)
+set match(sRe) scsi(rev)
+set match(uMa) usb(manufacturer)
+set match(uPr) usb(product)
+set match(uSe) usb(serial)
+
+
+# Now reading the USB attributes
+if {![ReadUSBAttrs $devdir]} {
+	Log "USB attributes not found in sysfs tree. Exit"
+	SafeExit
+}
+set config(vendor) $usb(idVendor)
+set config(product) $usb(idProduct)
+
+
+if $flags(logging) {
+	Log "\n----------------\nUSB values from sysfs:"
+	foreach attr {manufacturer product serial} {
+		Log "  $attr\t$usb($attr)"
+	}
+	Log "----------------"
+}
+
+if $flags(noswitching) {
+	SysLog "usb_modeswitch: switching disabled, no action for $usb(idVendor):$usb(idProduct)"
+	Log "\nSwitching globally disabled. Exit"
+	SafeExit
+}
+
+if {$usb(bNumConfigurations) == "1"} {
+	set configParam "-u -1"
+	Log "bNumConfigurations is 1 - don't check for active configuration"
+} else {
+	set configParam ""
+}
+
+# Check (and switch) for operating system if Huawei device present
+
+set flags(os) "linux"
+if {$usb(idVendor) == "12d1" && [regexp -nocase {android} [exec cat /proc/version]]} {
+	set flags(os) "android"
+}
+if {$flags(os) == "android"} {
+	set configList [ConfigGet conflist $usb(idVendor):#android]
+} else {
+	set configList [ConfigGet conflist $usb(idVendor):$usb(idProduct)]
+}
+
+if {[llength $configList] == 0} {
+	Log "Aargh! Config file missing for $usb(idVendor):$usb(idProduct)! Exit"
+	SafeExit
+}
+Log "ConfigList: $configList"
+
+# Check if there is more than one config file for this USB ID,
+# which would make an attribute test necessary. If so, check if
+# SCSI values are needed
+
+set scsiNeeded 0
+if {[llength $configList] > 1} {
+	if [regexp {:s} $configList] {
+		set scsiNeeded 1
+	}
+}
+if $scsiNeeded {
+	if [ReadSCSIAttrs $devdir:$iface] {
+		Log "----------------\nSCSI values from sysfs:"
+		foreach attr {vendor model rev} {
+			Log " $attr\t$scsi($attr)"
+		}
+		Log "----------------"
+	} else {
+		Log "Could not get SCSI attributes, exclude devices with SCSI match"
+	}
+} else {
+	Log "SCSI attributes not needed, move on"
+}
+
+# General wait - some devices need this
+after 500
+
+# Now check for a matching config file. Matching is done
+# by MatchDevice
+
+set report {}
+foreach mconfig $configList {
+
+	# skipping installer leftovers like "*.rpmnew"
+	if [regexp {\.(dpkg|rpm)} $mconfig] {continue}
+
+	Log "Check config: $mconfig"
+	if [MatchDevice $mconfig] {
+		Log "! matched. Read config data"
+#		set flags(config) $mconfig
+		if [string length $usb(busnum)] {
+			set busParam "-b [string trimleft $usb(busnum) 0]"
+			set devParam "-g [string trimleft $usb(devnum) 0]"
+		} else {
+			set busParam ""
+			set devParam ""
+		}
+		set flags(config) [ConfigGet conffile $mconfig]
+		ParseDeviceConfig $flags(config)
+		if [regexp -nocase {/[0-9a-f]+:#} $flags(config)] {
+			Log "Note: Using generic manufacturer configuration for \"$flags(os)\""
+		}
+		if $flags(nombim) {
+			set config(NoMBIMCheck) 1
+		}
+		if {$config(WaitBefore) != ""} {
+			Log "Delay time of $config(WaitBefore) seconds"
+			append config(WaitBefore) "000"
+			after $config(WaitBefore)
+			Log " wait is over, start mode switch"
+		}
+		if {$config(NoMBIMCheck)==0 && $usb(bNumConfigurations) > 1} {
+			Log "Device may have an MBIM configuration, check driver ..."
+			if [CheckMBIM] {
+				Log " driver for MBIM devices is available"
+				Log "Find MBIM configuration number ..."
+				if [catch {set cfgno [exec /usr/sbin/usb_modeswitch -j -Q $busParam $devParam -v $usb(idVendor) -p $usb(idProduct)]} err] {
+					Log "Error when trying to find MBIM configuration, switch to legacy modem mode"
+				} else {
+					set cfgno [string trim $cfgno]
+					if {$cfgno > 0} {
+						set config(Configuration) $cfgno
+						set flags(config) "Configuration=$cfgno"
+					} else {
+						Log " No MBIM configuration found, switch to legacy modem mode"
+					}
+				}
+			} else {
+				Log " no MBIM driver found, switch to legacy modem mode"
+			}
+		}
+		if [PantechAutoSwitch] {
+			Log "Waiting for Pantech auto-modeswitch"
+			set report "ok:busdev"
+			break
+		}
+		if {$config(Configuration) == 0} {
+			Log "Config file contains dummy method, do nothing. Exit"
+			SafeExit
+		}
+		UnbindDriver $devdir $ifdir
+		# Now we are actually switching
+		if $flags(logging) {
+			Log "Command to be run:\nusb_modeswitch -W -D $configParam $busParam $devParam -v $usb(idVendor) -p $usb(idProduct) -f \$flags(config)"
+			set report [exec /usr/sbin/usb_modeswitch -W -D $configParam $busParam $devParam -v $usb(idVendor) -p $usb(idProduct) -f "$flags(config)" 2>@1]
+			Log "\nVerbose debug output of usb_modeswitch and libusb follows"
+			Log "(Note that some USB errors are to be expected in the process)"
+			Log "--------------------------------"
+			Log $report
+			Log "--------------------------------"
+			Log "(end of usb_modeswitch output)\n"
+		} else {
+			set report [exec /usr/sbin/usb_modeswitch -Q -D $configParam $busParam $devParam -v $usb(idVendor) -p $usb(idProduct) -f "$flags(config)" 2>@1]
+		}
+		break
+	} else {
+		Log "* no match, don't use this config"
+	}
+}
+
+# Switching is complete; success checking was either
+# done by usb_modeswitch and logged via syslog OR bus/dev
+# parameter were used; then we do check for success HERE
+
+if {$config(Configuration) != ""} {
+	set ifdir [regsub {(\d):\d+\.0} $ifdir "\\1:$config(Configuration).0"]
+}
+
+if [regexp {ok:busdev} $report] {
+	if [CheckSuccess $devdir] {
+		Log "Mode switching was successful, found $usb(idVendor):$usb(idProduct) ($usb(manufacturer): $usb(product))"
+		SysLog "usb_modeswitch: switched to $usb(idVendor):$usb(idProduct) on [format %03d $usb(busnum)]/[format %03d $usb(devnum)]"
+	} else {
+		Log "\nTarget config not matching - current values are"
+		LogAttributes
+		Log "\nMode switching may have failed. Exit"
+		SafeExit
+	}
+} else {
+	if {![file isdirectory $devdir]} {
+		Log "Device directory in sysfs is gone! Something went wrong, abort"
+		SafeExit
+	}
+	if {![regexp {ok:} $report]} {
+		Log "\nCore program reported switching failure. Exit"
+		SafeExit
+	}
+	# Give the device another second if it's not fully back yet
+	if {![file exists $devdir/idProduct]} {
+		after 1000
+	}
+	ReadUSBAttrs $devdir $ifdir
+}
+
+# driver binding removed !!
+
+if {[string length "$usb(idVendor)$usb(idProduct)"] < 8} {
+	if {![regexp {ok:(\w{4}):(\w{4})} $report d usb(idVendor) usb(idProduct)]} {
+		Log "No target vendor/product ID found or given, can't continue. Abort"
+		SafeExit
+	}
+}
+# wait for drivers to bind
+after 500
+if {[llength [glob -nocomplain $devdir/$ifdir/ttyUSB*]] > 0} {
+	Log "Serial USB driver bound to interface 0\n will try to guess and symlink modem port on next connect"
+	AddToList link_list $usb(idVendor):$usb(idProduct)
+}
+
+# In newer kernels there is a switch to avoid the use of a device
+# reset (e.g. from usb-storage) which would possibly switch back
+# a mode-switching device to initial mode
+if [regexp {ok:} $report] {
+	Log "Check for AVOID_RESET_QUIRK kernel attribute"
+	if [file exists $devdir/avoid_reset_quirk] {
+		if [catch {exec echo "1" >$devdir/avoid_reset_quirk 2>/dev/null} err] {
+			Log " Error setting the attribute: $err"
+		} else {
+			Log " AVOID_RESET_QUIRK activated"
+		}
+	} else {
+		Log " not present in this kernel"
+	}
+}
+
+Log "\nAll done, exit\n"
+SafeExit
+
+}
+# end of proc {Main}
+
+
+proc {ReadSCSIAttrs} {topdir} {
+
+global scsi
+set counter 0
+set sysdir $topdir
+Log "Check storage tree in sysfs ..."
+while {$counter < 20} {
+	Log " loop $counter/20"
+	if {![file isdirectory $sysdir]} {
+		# Device is gone. Unplugged? Switched by kernel?
+		Log " sysfs device tree is gone; abort SCSI value check"
+		return 0
+	}
+	# Searching the storage/SCSI tree; might take a while
+	if {[set dirList [glob -nocomplain $topdir/host*]] != ""} {
+		set sysdir [lindex $dirList 0]
+		if {[set dirList [glob -nocomplain $sysdir/target*]] != ""} {
+			set sysdir [lindex $dirList 0]
+			regexp {.*target(.*)} $sysdir d subdir
+			if {[set dirList [glob -nocomplain $sysdir/$subdir*]] != ""} {
+				set sysdir [lindex $dirList 0]
+				if [file exists $sysdir/vendor] {
+					Log " Storage tree is ready"
+					break
+				}
+			}
+		}
+	}
+	after 500
+	incr counter
+}
+if {$counter == 20} {
+	Log "SCSI tree not found; you may want to check if this path/file exists:"
+	Log "$sysdir/vendor\n"
+	return 0
+}
+
+Log "Read SCSI values ..."
+foreach attr {vendor model rev} {
+	if [file exists $sysdir/$attr] {
+		set rc [open $sysdir/$attr r]
+		set scsi($attr) [read -nonewline $rc]
+		close $rc
+	} else {
+		set scsi($attr) ""
+		Log "Warning: SCSI attribute \"$attr\" not found."
+	}
+}
+return 1
+
+}
+# end of proc {ReadSCSIAttrs}
+
+
+proc {ReadUSBAttrs} {dir args} {
+
+global usb
+
+set attrList {idVendor idProduct bConfigurationValue manufacturer product serial devnum busnum bNumConfigurations}
+set mandatoryList {idVendor idProduct bNumConfigurations}
+set result 1
+if {$args != ""} {
+	lappend attrList "$args/bInterfaceClass"
+	lappend mandatoryList "$args/bInterfaceClass"
+}
+foreach attr $attrList {
+	if [file exists $dir/$attr] {
+		set rc [open $dir/$attr r]
+		set usb($attr) [string trim [read -nonewline $rc]]
+		close $rc
+	} else {
+		set usb($attr) ""
+		if {[lsearch $mandatoryList $attr] > -1} {
+			set result 0
+		}
+		if {$attr == "serial"} {continue}
+		Log "   Warning: USB attribute \"$attr\" not found"
+	}
+}
+return $result
+
+}
+# end of proc {ReadUSBAttrs}
+
+
+proc {MatchDevice} {config} {
+
+global scsi usb match
+
+set devinfo [file tail $config]
+set infoList [split $devinfo :]
+set stringList [lrange $infoList 2 end]
+if {[llength $stringList] == 0} {return 1}
+
+foreach teststring $stringList {
+	if {$teststring == "?"} {return 0}
+	set tokenList [split $teststring =]
+	set id [lindex $tokenList 0]
+	set matchstring [lindex $tokenList 1]
+	set blankstring ""
+	regsub -all {_} $matchstring { } blankstring
+	Log "match $match($id)"
+	Log "  string1 (exact):  $matchstring"
+	Log "  string2 (blanks): $blankstring"
+	Log " device string: [set $match($id)]"
+	if {!([string match *$matchstring* [set $match($id)]] || [string match *$blankstring* [set $match($id)]])} {
+		return 0
+	}
+}
+return 1
+
+}
+# end of proc {MatchDevice}
+
+
+proc {ParseGlobalConfig} {} {
+
+global flags
+set configFile ""
+set places [list /etc/usb_modeswitch.conf /etc/sysconfig/usb_modeswitch /etc/default/usb_modeswitch]
+foreach cfg $places {
+	if [file exists $cfg] {
+		set configFile $cfg
+		break
+	}
+}
+if {$configFile == ""} {return}
+
+set rc [open $configFile r]
+while {![eof $rc]} {
+	gets $rc line
+	if [regexp {^#} [string trim $line]] {continue}
+	if [regexp {DisableMBIMGlobal\s*=\s*([^\s]+)} $line d val] {
+		if [regexp -nocase {1|yes|true} $val] {
+			set flags(nombim) 1
+		} else {
+			set flags(nombim) 0
+		}
+	}
+	if [regexp {DisableSwitching\s*=\s*([^\s]+)} $line d val] {
+		if [regexp -nocase {1|yes|true} $val] {
+			set flags(noswitching) 1
+		}
+	}
+	if [regexp {EnableLogging\s*=\s*([^\s]+)} $line d val] {
+		if [regexp -nocase {1|yes|true} $val] {
+			set flags(logging) 1
+		} else {
+			set flags(logging) 0
+		}
+	}
+	if [regexp {SetStorageDelay\s*=\s*([^\s]+)} $line d val] {
+		if [regexp {\d+} $val] {
+			set flags(stordelay) $val
+		}
+	}
+
+}
+return "Use global config file: $configFile"
+
+}
+# end of proc {ParseGlobalConfig}
+
+
+proc ParseDeviceConfig {cfg} {
+
+global config
+set config(WaitBefore) ""
+set config(TargetVendor) ""
+set config(TargetProduct) ""
+set config(TargetClass) ""
+set config(Configuration) ""
+set config(NoMBIMCheck) 0
+set config(PantechMode) 0
+set config(CheckSuccess) 20
+
+foreach pname [lsort [array names config]] {
+	if [regexp -line "^\[^# \]*?$pname.*?= *(0x(\\w+)|\"(\[0-9a-fA-F,\]+)\"|(\[0-9\]+)) *\$" $cfg d config($pname)] {
+#		Log "config: $pname set to $config($pname)"
+	}
+}
+
+set config(WaitBefore) [string trimleft $config(WaitBefore) 0]
+
+}
+# end of proc {ParseDeviceConfig}
+
+
+proc ConfigGet {command config} {
+
+global setup usb flags
+
+switch $command {
+
+	conflist {
+		# Unpackaged configs first; sorting is essential for priority
+		set configList [lsort -decreasing [glob -nocomplain $setup(dbdir_etc)/$config*]]
+		set configList [concat $configList [lsort -decreasing [glob -nocomplain $setup(dbdir)/$config*]]]
+		eval lappend configList [glob -nocomplain $setup(dbdir)/$usb(idVendor):#$flags(os)]
+		if [file exists $setup(dbdir)/configPack.tar.gz] {
+			Log "Found packed config collection $setup(dbdir)/configPack.tar.gz"
+			if [catch {set packedList [exec tar -tzf $setup(dbdir)/configPack.tar.gz 2>/dev/null]} err] {
+				Log "Error: problem opening config package; tar returned\n $err"
+				return {}
+			}
+			set packedList [split $packedList \n]
+			set packedConfigList [lsort -decreasing [lsearch -glob -all -inline $packedList $config*]]
+			lappend packedConfigList [lsearch -inline $packedList $usb(idVendor):#$flags(os)]
+			# Now add packaged configs with a mark, again sorted for priority
+			foreach packedConfig $packedConfigList {
+				lappend configList "pack/$packedConfig"
+			}
+		}
+		return $configList
+	}
+	conffile {
+		if [regexp {^pack/} $config] {
+			set config [regsub {pack/} $config {}]
+			Log "Extract config $config from collection $setup(dbdir)/configPack.tar.gz"
+			set configContent [exec tar -xzOf $setup(dbdir)/configPack.tar.gz $config 2>/dev/null]
+		} else {
+			if [regexp [list $setup(dbdir_etc)] $config] {
+				Log "Use config file from override folder $setup(dbdir_etc)"
+				SysLog "usb_modeswitch: use overriding config file $config; make sure this is intended"
+				SysLog "usb_modeswitch: please report any new or corrected settings; otherwise, check for outdated files"
+			}
+			set rc [open $config r]
+			set configContent [read $rc]
+			close $rc
+		}
+		return $configContent
+	}
+}
+
+}
+# end of proc {ConfigGet}
+
+proc {Log} {msg} {
+
+global flags device loginit
+
+if {$flags(logging) == 0} {return}
+
+if $flags(logwrite) {
+	if [string length $loginit] {
+		exec echo "\nUSB_ModeSwitch log from [clock format [clock seconds]]" >/var/log/usb_modeswitch_$device
+		exec echo "$loginit" >>/var/log/usb_modeswitch_$device
+		set loginit ""
+	}
+	exec echo $msg >>/var/log/usb_modeswitch_$device
+} else {
+	append loginit "\n$msg"
+}
+
+}
+# end of proc {Log}
+
+
+# Writing the log file and exit
+proc {SafeExit} {} {
+
+global flags
+set flags(logwrite) 1
+Log ""
+exit
+
+}
+# end of proc {SafeExit}
+
+
+proc {SymLinkName} {path} {
+global device flags
+
+proc {hasInterrupt} {ifDir} {
+	if {[llength [glob -nocomplain $ifDir/ttyUSB*]] == 0} {
+		Log "  no ttyUSB interface - skip endpoint check"
+		return 0
+	}
+	foreach epDir [glob -nocomplain $ifDir/ep_*] {
+		set e [file tail $epDir]
+		Log "  check $e ..."
+		if [file exists $epDir/type] {
+			set rc [open $epDir/type r]
+			set type [read $rc]
+			close $rc
+			if [regexp {Interrupt} $type] {
+				Log "  $e has interrupt transfer type"
+				return 1
+			}
+		}
+	}
+	return 0
+}
+
+set loginit "usb_modeswitch called with --symlink-name\n parameter: $path\n"
+
+# In case the device path is returned as /class/tty/ttyUSB,
+# get the USB device path from linked tree "device"
+set linkpath /sys$path/device
+if [file exists $linkpath] {
+	if {[file type $linkpath] == "link"} {
+		set rawpath [file readlink $linkpath]
+		set trimpath [regsub -all {\.\./} $rawpath {}]
+ 		if [file isdirectory /sys/$trimpath] {
+			append loginit "\n Use path $path\n"
+			set path /$trimpath
+		}
+	}
+}
+if {![regexp {([0-9]+-[0-9]+[\.0-9]*:[^/]*).*(ttyUSB[0-9]+)} $path d myDev myPort]} {
+	if $flags(logging) {
+		set device [clock clicks]
+		set flags(logwrite) 1
+		Log "$loginit\nThis is not a ttyUSB port. Abort"
+	}
+	return ""
+}
+
+set device ttyUSB_$myDev
+set flags(logwrite) 1
+Log "$loginit\nMy name is $myPort\n"
+
+if {![regexp {(.*?[0-9]+)\.([0-9]+)/ttyUSB} /sys$path d ifRoot ifNum]} {
+	Log "Could not find interface in path\n $path. Abort"
+	return ""
+}
+
+set ifDir $ifRoot.$ifNum
+
+Log "Check my endpoints ...\n in $ifDir"
+if [hasInterrupt $ifDir] {
+	Log "\n--> I am an interrupt port"
+	set rightPort 1
+} else {
+	Log "\n--> I am not an interrupt port\n"
+	set rightPort 0
+}
+
+# There are devices with more than one interrupt interface.
+# Assume that the lowest of these is usable. Check all
+# possible lower interfaces
+
+if { $rightPort && ($ifNum > 0) } {
+	Log "\nLook for lower ports with interrupt endpoints"
+	for {set i 0} {$i < $ifNum} {incr i} {
+		set ifDir $ifRoot.$i
+		Log " in ifDir $ifDir ..."
+		if [hasInterrupt $ifDir] {
+			Log "\n--> found an interrupt interface below me\n"
+			set rightPort 0
+			break
+		}
+	}
+}
+if {$rightPort == 0} {
+	Log "Return empty name and exit"
+	return ""
+}
+
+Log "\n--> No interrupt interface below me\n"
+
+cd /dev
+set idx 2
+set symlinkName "gsmmodem"
+while {$idx < 256} {
+	if {![file exists $symlinkName]} {
+		set placeholder [open /dev/$symlinkName w]
+		close $placeholder
+		break
+	}
+	set symlinkName gsmmodem$idx
+	incr idx
+}
+if {$idx == 256} {return ""}
+
+Log "Return symlink name \"$symlinkName\" and exit"
+return $symlinkName
+
+}
+# end of proc {SymLinkName}
+
+
+# Add USB ID to list of devices needing later treatment
+proc {AddToList} {name id} {
+
+set listfile /var/lib/usb_modeswitch/$name
+if [file exists $listfile] {
+	set rc [open $listfile r]
+	set buffer [read $rc]
+	close $rc
+	if [string match *$id* $buffer] {
+		return
+	}
+	set idList [split [string trim $buffer] \n]
+}
+lappend idList $id
+set buffer [join $idList "\n"]
+if [catch {set lc [open $listfile w]}] {return}
+puts $lc $buffer
+close $lc
+
+}
+# end of proc {AddToList}
+
+
+proc {CheckSuccess} {devdir} {
+
+global config usb flags
+
+# For Cisco AM10, target device not on same port
+if {$usb(idVendor) == "1307" && $usb(idProduct) == "1169"} {
+	set devdir [string range $devdir 0 end-1]2
+}
+set ifdir [file tail [IfDir 0 $devdir]]
+if {[string length $config(TargetClass)] || [string length $config(Configuration)]} {
+	set config(TargetVendor) $usb(idVendor)
+	set config(TargetProduct) $usb(idProduct)
+}
+Log "Check success of mode switch for max. $config(CheckSuccess) seconds ..."
+
+set expected 1
+for {set i 1} {$i <= $config(CheckSuccess)} {incr i} {
+	after 1000
+	if {![file isdirectory $devdir]} {
+		Log " Wait for device file system ($i sec.) ..."
+		continue
+	} else {
+		Log " Read attributes ..."
+	}
+	set ifdir [IfDir 0 $devdir]
+	if {$ifdir == ""} {continue}
+	set ifdir [file tail $ifdir]
+	if {![ReadUSBAttrs $devdir $ifdir]} {
+		Log " Essential attributes are missing, continue wait ..."
+		continue
+	}
+	if [string length $config(Configuration)] {
+		if {$usb(bConfigurationValue) != $config(Configuration)} {continue}
+	}
+	if [string length $config(TargetClass)] {
+		if {![regexp $usb($ifdir/bInterfaceClass) $config(TargetClass)]} {
+			if {$config(class) != $usb($ifdir/bInterfaceClass} {
+				set expected 0
+			} else {continue}
+		}
+	}
+	if {![regexp $usb(idVendor) $config(TargetVendor)]} {
+		if {![regexp $usb(idVendor) $config(vendor)]} {
+			set expected 0
+		} else {continue}
+	}
+	if {![regexp $usb(idProduct) $config(TargetProduct)]} {
+		if {![regexp $usb(idProduct) $config(product)]} {
+			set expected 0
+		} else {continue}
+	}
+	# Arriving here means that device attributes have changed
+	if $expected {
+		Log " All attributes matched"
+	} else {
+		if [regexp -nocase {/[0-9a-f]+:#} $flags(config)] {
+			Log " idProduct has changed after generic mode-switch, assume success"
+		} else {
+			Log " Attributes are different but target values are unexpected:"
+			LogAttributes
+		}
+	}
+	break
+}
+if {$i > 20} {return 0} else {return 1}
+
+}
+# end of proc {CheckSuccess}
+
+
+proc {IfDir} {iface devdir} {
+
+set allfiles [glob -nocomplain $devdir/*]
+set files [glob -nocomplain $devdir/*.$iface]
+if {[llength $files] == 0} {
+	return ""
+}
+set ifdir [lindex $files 0]
+if {![file isdirectory $ifdir]} {
+	return ""
+}
+return $ifdir
+
+}
+# end of proc {IfDir}
+
+proc {IfClass} {iface devdir} {
+
+set ifdir [IfDir $iface $devdir]
+
+if {![file exists $ifdir/bInterfaceClass]} {
+	return -1
+}
+set rc [open $ifdir/bInterfaceClass r]
+set c [read $rc]
+close $rc
+return [string trim $c]
+
+}
+# end of proc {IfClass}
+
+
+proc {SysLog} {msg} {
+
+global flags
+if {![info exists flags(logger)]} {
+	set flags(logger) ""
+	foreach fn {/bin/logger /usr/bin/logger} {
+		if [file exists $fn] {
+			set flags(logger) $fn
+		}
+	}
+	Log "Logger is $flags(logger)"
+}
+if {$flags(logger) == ""} {
+	Log "Can't add system message, no syslog helper found"
+	return
+}
+catch {exec $flags(logger) -p syslog.notice "$msg" 2>/dev/null}
+
+}
+# end of proc {SysLog}
+
+proc {SetStorageDelay} {secs} {
+
+Log "Adjust delay for USB storage devices ..."
+set attrib /sys/module/usb_storage/parameters/delay_use
+if {![file exists $attrib]} {
+	Log "Error: could not find delay_use attribute"
+	return
+}
+if [catch {set ch [open $attrib r+]} err] {
+	Log "Error: could not access delay_use attribute: $err"
+	return
+}
+if {[read $ch] < $secs} {
+	seek $ch 0 start
+	puts -nonewline $ch $secs
+	Log " Delay set to $secs seconds\n"
+} else {
+	Log " Current value is higher than $secs. Leave it alone\n"
+}
+close $ch
+
+}
+# end of proc {SetStorageDelay}
+
+proc {CheckMBIM} {} {
+
+set kversion [exec uname -r]
+if [llength [glob -nocomplain /lib/modules/$kversion/kernel/drivers/net/usb/cdc_mbim*]] {return 1}
+if [file exists /sys/bus/usb/drivers/cdc_mbim] {return 1}
+return 0
+
+}
+
+proc {CheckQMI} {} {
+
+set kversion [exec uname -r]
+if [llength [glob -nocomplain /lib/modules/$kversion/kernel/drivers/net/usb/qmi_wwan*]] {return 1}
+if [file exists /sys/bus/usb/drivers/cdc_mbim] {return 1}
+return 0
+
+}
+
+proc {PantechAutoSwitch} {} {
+
+global config flags
+if {$config(PantechMode) == 3} {return 1}
+if {$config(PantechMode) == 1} {
+	if {"$config(vendor):$config(product)" == "10a9:6080"} {
+		set flags(config) [regsub {PantechMode *= *1} $flags(config) "PantechMode=2"]
+		Log " PantechMode changed to 2"
+		return 0
+	} elseif [CheckQMI] {
+		set flags(config) [regsub {PantechMode *= *1} $flags(config) "PantechMode=4"]
+		Log " PantechMode changed to 4"
+		return 0
+	} else {
+		return 1
+	}
+} else {return 0}
+
+}
+
+proc UnbindDriver {devdir ifdir} {
+
+set att $devdir/$ifdir/driver/unbind
+if [file exists $att] {
+	Log "Unbinding driver"
+	exec echo -n "$ifdir" > $att
+}
+
+}
+
+proc {LogAttributes} {} {
+
+global flags usb
+if $flags(logging) {
+	set attrList {idVendor idProduct bConfigurationValue manufacturer product serial}
+	foreach attr [lsort [array names usb]] {
+		Log "    [format %-26s $attr:] $usb($attr)"
+	}
+}
+
+}
+
+proc {HasFF} {devdir} {
+
+set i 0
+while {[set dir [IfDir $i $devdir]] != ""} {
+	set c [exec cat $dir/bInterfaceClass]
+	if {$c == "ff"} {return 1}
+	incr i
+}
+return 0
+
+}
+
+
+# The actual entry point
+Main $argv $argc
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch@.service b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch@.service
new file mode 100755
index 0000000..91e5ac0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch@.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=USB_ModeSwitch_%i
+
+[Service]
+Type=oneshot
+ExecStart=/usr/sbin/usb_modeswitch_dispatcher --switch-systemd %i
+#ExecStart=/bin/echo %i
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch_dispatcher.1 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch_dispatcher.1
new file mode 100755
index 0000000..5b826d4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch/usb_modeswitch_dispatcher.1
@@ -0,0 +1,21 @@
+.TH "USB_MODESWITCH_DISPATCHER" "1"
+.SH "NAME"
+usb_modeswitch_dispatcher - Linux wrapper for usb_modeswitch (not intended for direct invocation)
+.SH "SYNOPSIS"
+.PP
+\fBusb_modeswitch_dispatcher\fR
+.SH "DESCRIPTION"
+.PP
+usb_modeswitch_dispatcher will do detailed device checking and will subsequently
+use the Linux-independent usb_modeswitch binary together with the selected device
+config file to switch the mode of certain USB devices.
+.PP
+If no drivers are taking care of the device after the mode switch, the dispatcher
+will try to load and bind the "option" serial driver to any USB interfaces with
+class 0xff, in order to make the device useable in case it is not recognized by that
+driver yet. This may or may not work.
+.PP
+This program is called by udev and is not supposed to be called directly
+by the user.
+.SH SEE ALSO
+.BR usb_modeswitch(1).
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch@.service b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch@.service
new file mode 100755
index 0000000..91e5ac0
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch@.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=USB_ModeSwitch_%i
+
+[Service]
+Type=oneshot
+ExecStart=/usr/sbin/usb_modeswitch_dispatcher --switch-systemd %i
+#ExecStart=/bin/echo %i
+
diff --git a/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch_dispatcher.1 b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch_dispatcher.1
new file mode 100755
index 0000000..5b826d4
--- /dev/null
+++ b/android/external/usb_modeswitch/usb_modeswitch/usb_modeswitch_dispatcher.1
@@ -0,0 +1,21 @@
+.TH "USB_MODESWITCH_DISPATCHER" "1"
+.SH "NAME"
+usb_modeswitch_dispatcher - Linux wrapper for usb_modeswitch (not intended for direct invocation)
+.SH "SYNOPSIS"
+.PP
+\fBusb_modeswitch_dispatcher\fR
+.SH "DESCRIPTION"
+.PP
+usb_modeswitch_dispatcher will do detailed device checking and will subsequently
+use the Linux-independent usb_modeswitch binary together with the selected device
+config file to switch the mode of certain USB devices.
+.PP
+If no drivers are taking care of the device after the mode switch, the dispatcher
+will try to load and bind the "option" serial driver to any USB interfaces with
+class 0xff, in order to make the device useable in case it is not recognized by that
+driver yet. This may or may not work.
+.PP
+This program is called by udev and is not supposed to be called directly
+by the user.
+.SH SEE ALSO
+.BR usb_modeswitch(1).
diff --git a/android/hardware/ril/libril/Android.mk b/android/hardware/ril/libril/Android.mk
index e5f7104..b79d4c7 100755
--- a/android/hardware/ril/libril/Android.mk
+++ b/android/hardware/ril/libril/Android.mk
@@ -5,6 +5,9 @@
 
 LOCAL_VENDOR_MODULE := true
 
+LOCAL_POST_INSTALL_CMD := \
+    cp -ravf vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libril-an10.so $(TARGET_OUT_VENDOR_SHARED_LIBRARIES)/libril.so 
+
 LOCAL_SRC_FILES:= \
     ril.cpp \
     ril_event.cpp\
diff --git a/android/hardware/ril/rild/Android.mk b/android/hardware/ril/rild/Android.mk
index b8ba508..1b3d5bf 100755
--- a/android/hardware/ril/rild/Android.mk
+++ b/android/hardware/ril/rild/Android.mk
@@ -29,7 +29,7 @@
 LOCAL_MODULE_RELATIVE_PATH := hw
 LOCAL_PROPRIETARY_MODULE := true
 LOCAL_MODULE:= rild
-LOCAL_VINTF_FRAGMENTS := radio.xml
+#LOCAL_VINTF_FRAGMENTS := radio.xml
 ifeq ($(PRODUCT_COMPATIBLE_PROPERTY),true)
 LOCAL_INIT_RC := rild.rc
 LOCAL_CFLAGS += -DPRODUCT_COMPATIBLE_PROPERTY
diff --git a/android/vendor/aw/public/prebuild/lib/librild/libquecte/Android.mk b/android/vendor/aw/public/prebuild/lib/librild/libquecte/Android.mk
new file mode 100755
index 0000000..f421803
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/libquecte/Android.mk
@@ -0,0 +1,43 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libreference-ril-an12
+
+LOCAL_MODULE_SUFFIX := .so
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+
+ifeq ($(TARGET_ARCH), arm64)
+    LOCAL_SRC_FILES := lib64/libreference-ril-an12.so
+else
+	LOCAL_SRC_FILES := lib32/libreference-ril-an12.so
+endif
+
+LOCAL_VENDOR_MODULE := true
+LOCAL_CHECK_ELF_FILES := false
+
+include $(BUILD_PREBUILT)
+
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libreference-ril-an10
+
+LOCAL_MODULE_SUFFIX := .so
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+
+# ifeq ($(TARGET_ARCH), arm64)
+#     LOCAL_SRC_FILES := lib64/libreference-ril-an10.so
+# else
+# 	LOCAL_SRC_FILES := lib32/libreference-ril-an10.so
+# endif
+
+LOCAL_SRC_FILES_32 := lib32/libreference-ril-an10.so
+LOCAL_SRC_FILES_64 := lib64/libreference-ril-an10.so
+
+LOCAL_VENDOR_MODULE := true
+LOCAL_CHECK_ELF_FILES := false
+
+include $(BUILD_PREBUILT)
+
+
diff --git a/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libreference-ril-an10.so b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libreference-ril-an10.so
new file mode 100755
index 0000000..76ccc0d
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libreference-ril-an10.so
Binary files differ
diff --git a/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libreference-ril-an12.so b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libreference-ril-an12.so
new file mode 100755
index 0000000..dd5697e
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libreference-ril-an12.so
Binary files differ
diff --git a/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libreference-ril-ndk.so b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libreference-ril-ndk.so
new file mode 100755
index 0000000..3ddb73f
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libreference-ril-ndk.so
Binary files differ
diff --git a/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libril-an10.so b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libril-an10.so
new file mode 100755
index 0000000..4f3e4fa
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libril-an10.so
Binary files differ
diff --git a/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libril-an12.so b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libril-an12.so
new file mode 100755
index 0000000..8b4ac2d
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib32/libril-an12.so
Binary files differ
diff --git a/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libreference-ril-an10.so b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libreference-ril-an10.so
new file mode 100755
index 0000000..2b51ac6
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libreference-ril-an10.so
Binary files differ
diff --git a/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libreference-ril-an12.so b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libreference-ril-an12.so
new file mode 100755
index 0000000..4ed32d1
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libreference-ril-an12.so
Binary files differ
diff --git a/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libreference-ril-ndk.so b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libreference-ril-ndk.so
new file mode 100755
index 0000000..5f13078
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libreference-ril-ndk.so
Binary files differ
diff --git a/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libril-an10.so b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libril-an10.so
new file mode 100755
index 0000000..9b58791
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libril-an10.so
Binary files differ
diff --git a/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libril-an12.so b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libril-an12.so
new file mode 100755
index 0000000..5f07421
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/libquecte/lib64/libril-an12.so
Binary files differ
diff --git a/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/apns-full-conf.xml b/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/apns-full-conf.xml
new file mode 100755
index 0000000..5718e10a
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/apns-full-conf.xml
@@ -0,0 +1,35501 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<!-- use empty string to specify no proxy or port -->
+<!-- This version must agree with that in apps/common/res/apns.xml -->
+<apns version="8">
+
+  <apn carrier="AT&amp;T PHONE TEST SIM"
+      carrier_id = "1911"
+      mcc="001"
+      mnc="01"
+      apn="phone"
+      user=""
+      password=""
+      proxy=""
+      port=""
+      mmsc="http://mmsc.mobile.att.net"
+      mmsproxy="proxy.mobile.att.net"
+      mmsport="80"
+      type="default,mms,supl,hipri,fota,dun"
+      mtu="1410"
+  />
+
+  <apn carrier="T-Mobile TEST SIM"
+      carrier_id = "1911"
+      mcc="001"
+      mnc="01"
+      apn="phone"
+      user=""
+      password=""
+      proxy=""
+      port=""
+      type="default,supl,hipri,dun"
+      mtu="1440"
+  />
+
+  <apn carrier="U.S.Cellular TEST SIM"
+      carrier_id = "1911"
+      mcc="001"
+      mnc="01"
+      apn="usccinternet"
+      user=""
+      password=""
+      proxy=""
+      port=""
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,hipri,dun,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mtu="1422"
+  />
+
+  <!-- bearer 13, 14 -->
+  <apn carrier="Test FOTA"
+      carrier_id = "1911"
+      mcc="001"
+      mnc="01"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13|14"
+      profile_id="3"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <!-- bearer 13, 14 -->
+  <apn carrier="Test CBS"
+      carrier_id = "1911"
+      mcc="001"
+      mnc="01"
+      apn="VZWAPP"
+      type="cbs,mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13|14"
+      profile_id="4"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <!-- bearer 13, 14 -->
+  <apn carrier="Test IMS"
+      carrier_id = "1911"
+      mcc="001"
+      mnc="01"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13|14"
+      profile_id="2"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Test Internet"
+      carrier_id = "1911"
+      mcc="001"
+      mnc="01"
+      apn="VZWINTERNET"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      type="default,dun"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      authtype="3"
+      bearer_bitmask="6"
+  />
+
+  <!-- bearer 13, 14 -->
+  <apn carrier="Test Internet"
+      carrier_id = "1911"
+      mcc="001"
+      mnc="01"
+      apn="VZWINTERNET"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      type="default,dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13|14"
+      profile_id="0"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+   <!-- bearer 13, 14 -->
+  <apn carrier="Test FOTA"
+      mcc="001"
+      mnc="010"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13|14"
+      profile_id="3"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <!-- bearer 13, 14 -->
+  <apn carrier="Test CBS"
+      mcc="001"
+      mnc="010"
+      apn="VZWAPP"
+      type="cbs,mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13|14"
+      profile_id="4"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Test IMS"
+      mcc="001"
+      mnc="010"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      profile_id="2"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Test IMS"
+      mcc="001"
+      mnc="010"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      profile_id="2"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Test Internet"
+      mcc="001"
+      mnc="010"
+      apn="VZWINTERNET"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      type="default,dun"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      authtype="3"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Test Internet"
+      mcc="001"
+      mnc="010"
+      apn="VZWINTERNET"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      type="default,dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      profile_id="0"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Test Internet"
+      mcc="001"
+      mnc="010"
+      apn="VZWINTERNET"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      type="default,dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      profile_id="0"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Cosmote Wireless Internet"
+      carrier_id = "747"
+      mcc="202"
+      mnc="01"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="Cosmote Wireless Internet"
+      carrier_id = "747"
+      mcc="202"
+      mnc="01"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Cosmote Mms"
+      carrier_id = "747"
+      mcc="202"
+      mnc="01"
+      apn="mms"
+      mmsc="http://mmsc.cosmote.gr:8002"
+      mmsproxy="10.10.10.20"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Vf Mobile Internet"
+      carrier_id = "2399"
+      mcc="202"
+      mnc="05"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="Vf Mobile Internet"
+      carrier_id = "2399"
+      mcc="202"
+      mnc="05"
+      apn="internet.vodafone.gr"
+      type="default,supl"
+  />
+
+  <apn carrier="Vf MMS"
+      carrier_id = "2399"
+      mcc="202"
+      mnc="05"
+      apn="mms.vodafone.net"
+      user="user"
+      password="pass"
+      mmsc="http://mms.vodafone.gr"
+      mmsproxy="213.249.19.49"
+      mmsport="5080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Q Internet"
+      carrier_id = "749"
+      mcc="202"
+      mnc="09"
+      apn="myq"
+      type="default,supl"
+  />
+
+  <apn carrier="Q-Telecom MMS GPRS"
+      carrier_id = "749"
+      mcc="202"
+      mnc="09"
+      apn="q-mms.myq.gr"
+      mmsc="http://mms.myq.gr"
+      mmsproxy="192.168.80.134"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Wind Internet"
+      carrier_id = "1519"
+      mcc="202"
+      mnc="10"
+      apn="gint.b-online.gr"
+      type="default,supl"
+  />
+
+  <apn carrier="Wind MMS"
+      carrier_id = "1519"
+      mcc="202"
+      mnc="10"
+      apn="mnet.b-online.gr"
+      mmsc="http://192.168.200.95/servlets/mms"
+      mmsproxy="192.168.200.11"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Tele2 GPRS"
+      carrier_id = "1643"
+      mcc="204"
+      mnc="02"
+      apn="internet.tele2.nl"
+      mmsc="http://mmsc.tele2.nl"
+      mmsproxy="193.12.40.64"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="MVNO NL"
+      carrier_id = "2149"
+      mcc="204"
+      mnc="03"
+      apn="internet.mvno.mobi"
+      user="mvno"
+      password="mvno"
+      authtype="1"
+      type="default,supl"
+      mvno_match_data="20403"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="MVNO NL"
+      carrier_id = "2149"
+      mcc="204"
+      mnc="03"
+      apn="ims"
+      protocol="IPV4"
+      type="ims"
+      mvno_match_data="20403"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Jump Roam"
+      carrier_id = "2138"
+      mcc="204"
+      mnc="04"
+      apn="mobiledata"
+      authtype="0"
+      mvno_type="spn"
+      mvno_match_data="Jump"
+  />
+
+  <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="204"
+      mnc="04"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+      mvno_type="gid"
+      mvno_match_data="547275554B3030656E"
+  />
+
+  <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="204"
+      mnc="04"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+      mvno_type="gid"
+      mvno_match_data="54727555533030656E"
+  />
+
+  <apn carrier="Vodafone NL"
+      mcc="204"
+      mnc="04"
+      apn="live.vodafone.com"
+      user="vodafone"
+      password="vodafone"
+      authtype="1"
+      mmsc="http://mmsc.mms.vodafone.nl"
+      mmsproxy="192.168.251.150"
+      mmsport="8799"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="EHRPD - VZW Roaming Internet"
+      carrier_id = "1839"
+      mcc="204"
+      mnc="04"
+      apn="VZWINTERNET"
+      type="default,dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mvno_type="gid"
+      mvno_match_data="BAE0000000000000"
+      profile_id="0"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="LTE - VZW Roaming Internet"
+      carrier_id = "1839"
+      mcc="204"
+      mnc="04"
+      apn="VZWINTERNET"
+      type="default,dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_type="gid"
+      mvno_match_data="BAE0000000000000"
+      profile_id="0"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="EHRPD - VZW Roaming FOTA"
+      carrier_id = "1839"
+      mcc="204"
+      mnc="04"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mvno_type="gid"
+      mvno_match_data="BAE0000000000000"
+      profile_id="3"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="LTE - VZW Roaming FOTA"
+      carrier_id = "1839"
+      mcc="204"
+      mnc="04"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_type="gid"
+      mvno_match_data="BAE0000000000000"
+      profile_id="3"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="LTE - VZW Roaming IMS"
+      carrier_id = "1839"
+      mcc="204"
+      mnc="04"
+      apn="IMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_type="gid"
+      mvno_match_data="BAE0000000000000"
+      profile_id="2"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="EHRPD - VZW Roaming IMS"
+      carrier_id = "1839"
+      mcc="204"
+      mnc="04"
+      apn="IMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mvno_type="gid"
+      mvno_match_data="BAE0000000000000"
+      profile_id="2"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="LTE - VZW Roaming CBS"
+      carrier_id = "1839"
+      mcc="204"
+      mnc="04"
+      apn="VZWAPP"
+      type="cbs,mms"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_type="gid"
+      mvno_match_data="BAE0000000000000"
+      profile_id="4"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="EHRPD - VZW Roaming CBS"
+      carrier_id = "1839"
+      mcc="204"
+      mnc="04"
+      apn="VZWAPP"
+      type="cbs,mms"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mvno_type="gid"
+      mvno_match_data="BAE0000000000000"
+      profile_id="4"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="CSpire international"
+      carrier_id = "1836"
+      mcc="204"
+      mnc="04"
+      apn="internet.cs4glte.com"
+      server="*"
+      user="Uniroam@inet.cs.com"
+      password="cs3g"
+      authtype ="3"
+      mmsport=""
+      mmsproxy=""
+      mmsc="http://pix.cspire.com"
+      mvno_type="spn"
+      mvno_match_data="C Spire"
+      type="default,internet,mms"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="CSpire international"
+      carrier_id = "1836"
+      mcc="204"
+      mnc="04"
+      apn="admin.cs4glte.com"
+      server="*"
+      mmsport=""
+      mmsproxy=""
+      mmsc="http://pix.cspire.com"
+      mvno_type="spn"
+      mvno_match_data="C Spire"
+      type="admin,fota,ota"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="CSpire international"
+      carrier_id = "1836"
+      mcc="204"
+      mnc="04"
+      apn="tethering.cs4glte.com"
+      server="*"
+      mmsport=""
+      mmsproxy=""
+      mmsc="http://pix.cspire.com"
+      mvno_type="spn"
+      mvno_match_data="C Spire"
+      type="dun,pam"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="KPN/Hi 4G LTE Mobiel internet"
+      carrier_id = "1644"
+      mcc="204"
+      mnc="08"
+      apn="KPN4G.nl"
+      mmsc="http://mp.mobiel.kpn/mmsc"
+      mmsproxy="10.10.100.20"
+      mmsport="5080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="KPN/Hi Mobiel Internet"
+      carrier_id = "1644"
+      mcc="204"
+      mnc="08"
+      apn="portalmmm.nl"
+      mmsc="http://mp.mobiel.kpn/mmsc"
+      mmsproxy="10.10.100.20"
+      mmsport="5080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="MVNO NL"
+      carrier_id = "2149"
+      mcc="204"
+      mnc="08"
+      apn="internet.mvno.mobi"
+      user="mvno"
+      password="mvno"
+      authtype="1"
+      type="default,supl"
+      mvno_match_data="204080950"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Rabo Mobiel Int."
+      carrier_id = "2406"
+      mcc="204"
+      mnc="08"
+      apn="rabo"
+      type="default,supl"
+      mvno_match_data="Rabo Mobiel"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Rabo Mobiel MMS"
+      carrier_id = "2406"
+      mcc="204"
+      mnc="08"
+      apn="rabo"
+      mmsc="http://mp.mobiel.kpn/mmsc"
+      mmsproxy="10.10.100.10"
+      mmsport="5080"
+      type="mms"
+      mvno_match_data="Rabo Mobiel"
+      mvno_type="spn"
+  />
+
+   <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="204"
+      mnc="08"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+      mvno_type="gid"
+      mvno_match_data="547275554B3030656E"
+  />
+
+   <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="204"
+      mnc="08"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+      mvno_type="gid"
+      mvno_match_data="54727555533030656E"
+  />
+
+  <apn carrier="HOT mobile Internet"
+      carrier_id = "1991"
+      mcc="204"
+      mnc="04"
+      apn="net.hotm"
+      type="default,supl"
+      mvno_match_data="HOT mobile"
+      mvno_type="spn"
+  />
+
+  <apn carrier="HOT mobile MMS"
+      carrier_id = "1991"
+      mcc="204"
+      mnc="04"
+      apn="mms.hotm"
+      mmsc="http://mms.hotmobile.co.il"
+      mmsproxy="80.246.131.99"
+      mmsport="80"
+      type="mms"
+      mvno_match_data="HOT mobile"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Telfort Internet"
+      carrier_id = "1644"
+      mcc="204"
+      mnc="12"
+      apn="internet"
+      mmsc="http://mms"
+      mmsproxy="193.113.200.195"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="T-Mobile Internet"
+      carrier_id = "2386"
+      mcc="204"
+      mnc="16"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="T-Mobile Internet"
+      carrier_id = "2386"
+      mcc="204"
+      mnc="16"
+      apn="internet"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="T-Mobile MMS"
+      carrier_id = "2386"
+      mcc="204"
+      mnc="16"
+      apn="mms"
+      user="tmobilemms"
+      password="tmobilemms"
+      authtype="1"
+      mmsc="http://t-mobilemms"
+      mmsproxy="10.10.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Ben Internet Abonnee"
+      carrier_id = "2095"
+      mcc="204"
+      mnc="16"
+      apn="internet.ben"
+      type="default,supl"
+      mvno_match_data="BEN NL"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Ben Internet PrePaid"
+      carrier_id = "2095"
+      mcc="204"
+      mnc="16"
+      apn="basic.internet.ben.data"
+      type="default,supl"
+      mvno_match_data="BEN NL"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Ben MMS"
+      carrier_id = "2095"
+      mcc="204"
+      mnc="16"
+      apn="mms.ben"
+      authtype="1"
+      mmsc="http://benmms/"
+      mmsproxy="10.10.10.11"
+      mmsport="8080"
+      type="mms"
+      mvno_match_data="BEN NL"
+      mvno_type="spn"
+  />
+
+  <apn carrier="T-Mobile Internet"
+      carrier_id = "2386"
+      mcc="204"
+      mnc="20"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="T-Mobile Internet"
+      carrier_id = "2386"
+      mcc="204"
+      mnc="20"
+      apn="internet"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="T-Mobile MMS"
+      carrier_id = "2386"
+      mcc="204"
+      mnc="20"
+      apn="mms"
+      user="tmobilemms"
+      password="tmobilemms"
+      authtype="1"
+      mmsc="http://t-mobilemms"
+      mmsproxy="10.10.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="204"
+      mnc="33"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+  />
+
+  <apn carrier="EMnify"
+      carrier_id = "2326"
+      mcc="206"
+      mnc="01"
+      apn="em"
+      mvno_match_data="206018"
+      mvno_type="imsi"
+      type="default,supl"
+  />
+
+  <apn carrier="Px MMS"
+      carrier_id = "1365"
+      mcc="206"
+      mnc="01"
+      apn="EVENT.PROXIMUS.BE"
+      user="mms"
+      password="mms"
+      authtype="1"
+      mmsc="http://mmsc.proximus.be/mms"
+      mmsproxy="10.55.14.75"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Px Internet"
+      carrier_id = "1365"
+      mcc="206"
+      mnc="01"
+      apn="INTERNET.PROXIMUS.BE"
+      type="default,supl"
+  />
+
+  <apn carrier="Telenet Internet"
+      carrier_id = "2270"
+      mcc="206"
+      mnc="01"
+      apn="telenetwap.be"
+      type="default,supl"
+      mvno_match_data="20601889"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Telenet MMS"
+      carrier_id = "2270"
+      mcc="206"
+      mnc="01"
+      apn="mms.be"
+      mmsc="http://mmsc.telenet.be"
+      mmsproxy="195.130.149.100"
+      mmsport="80"
+      type="mms"
+      mvno_match_data="20601889"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="IIJmio (TypeI/Roaming)"
+      carrier_id = "2106"
+      mcc="206"
+      mnc="01"
+      apn="iijmio.jp"
+      user="mio@iij"
+      password="iij"
+      authtype="3"
+      protocol="IP"
+      type="default"
+      roaming_protocol="IP"
+      mvno_type="spn"
+      mvno_match_data="IIJ"
+  />
+
+  <apn carrier="vmobile.jp (Roaming)"
+      carrier_id = "2106"
+      mcc="206"
+      mnc="01"
+      apn="vmobile.jp"
+      user="vmobile@jp"
+      password="vmobile"
+      authtype="3"
+      protocol="IP"
+      type="default"
+      roaming_protocol="IP"
+      mvno_type="spn"
+      mvno_match_data="IIJ"
+  />
+
+  <apn carrier="Telenet Internet"
+      carrier_id = "2150"
+      mcc="206"
+      mnc="05"
+      apn="telenetwap.be"
+      type="default,supl"
+  />
+
+  <apn carrier="Telenet MMS"
+      carrier_id = "2150"
+      mcc="206"
+      mnc="05"
+      apn="mms.be"
+      mmsc="http://mmsc.telenet.be"
+      mmsproxy="195.130.149.100"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="Mobistar MMS"
+      carrier_id = "1366"
+      mcc="206"
+      mnc="10"
+      apn="mms.be"
+      mmsc="http://mmsc.mobistar.be"
+      mmsproxy="212.65.63.143"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Mobistar Internet"
+      carrier_id = "1366"
+      mcc="206"
+      mnc="10"
+      apn="mworld.be"
+      type="default,supl"
+  />
+
+  <apn carrier="netgprs.com"
+      carrier_id = "2271"
+      mcc="206"
+      mnc="10"
+      apn="netgprs.com"
+      user="tsl"
+      password="tsl"
+      type="default,supl"
+      mvno_match_data="BE-Transatel"
+      mvno_type="spn"
+   />
+
+
+ <apn carrier="netgprs.com"
+      carrier_id = "2271"
+      mcc="206"
+      mnc="10"
+      apn="netgprs.com"
+      user="tsl"
+      password="tsl"
+      type="default,supl"
+      mvno_match_data="BB00"
+      mvno_type="gid"
+  />
+
+  <apn carrier="BASE WAP"
+      carrier_id = "1367"
+      mcc="206"
+      mnc="20"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="BASE WAP"
+      carrier_id = "1367"
+      mcc="206"
+      mnc="20"
+      apn="gprs.base.be"
+      user="base"
+      password="base"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="BASE MMS"
+      carrier_id = "1367"
+      mcc="206"
+      mnc="20"
+      apn="mms.base.be"
+      user="base"
+      password="base"
+      authtype="1"
+      mmsc="http://mmsc.base.be"
+      mmsproxy="217.72.235.1"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="BICS Internet"
+      carrier_id = "2132"
+      mcc="206"
+      mnc="28"
+      apn="bicsapn"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange World"
+      carrier_id = "32"
+      mcc="208"
+      mnc="01"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="Orange World"
+      carrier_id = "32"
+      mcc="208"
+      mnc="01"
+      apn="orange"
+      user="orange"
+      password="orange"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange MMS"
+      carrier_id = "32"
+      mcc="208"
+      mnc="01"
+      apn="orange.acte"
+      user="orange"
+      password="orange"
+      mmsc="http://mms.orange.fr"
+      mmsproxy="192.168.10.200"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Orange Entreprise"
+      carrier_id = "32"
+      mcc="208"
+      mnc="01"
+      apn="orange-mib"
+      proxy="172.16.2.8"
+      port="8000"
+      user="orange"
+      password="orange"
+      authtype="2"
+      type="default"
+  />
+
+  <apn carrier="Orange Internet"
+      carrier_id = "32"
+      mcc="208"
+      mnc="01"
+      apn="orange.fr"
+      authtype="0"
+      user="orange"
+      password="orange"
+      type="dun"
+  />
+
+  <apn carrier="Carrefour WAP"
+      carrier_id = "2133"
+      mcc="208"
+      mnc="01"
+      apn="ofnew.fr"
+      proxy="192.168.10.100"
+      port="8080"
+      user="orange"
+      password="orange"
+      authtype="1"
+      type="default,supl"
+      mvno_match_data="33"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Carrefour MMS"
+      carrier_id = "2133"
+      mcc="208"
+      mnc="01"
+      apn="orange.acte"
+      user="orange"
+      password="orange"
+      mmsc="http://mms.orange.fr"
+      mmsproxy="192.168.10.200"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+      mvno_match_data="33"
+      mvno_type="gid"
+  />
+
+  <apn carrier="NRJWEB"
+      carrier_id = "2005"
+      mcc="208"
+      mnc="01"
+      apn="ofnew.fr"
+      user="orange"
+      password="orange"
+      authtype="1"
+      type="default,supl"
+      mvno_match_data="4E"
+      mvno_type="gid"
+  />
+
+  <apn carrier="NRJMMS"
+      carrier_id = "2005"
+      mcc="208"
+      mnc="01"
+      apn="orange.acte"
+      user="orange"
+      password="orange"
+      mmsc="http://mms.orange.fr"
+      mmsproxy="192.168.10.200"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+      mvno_match_data="4E"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Coriolis"
+      carrier_id = "2135"
+      mcc="208"
+      mnc="01"
+      apn="coriolis"
+      type="default,supl"
+      mvno_match_data="208011511"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Coriolis MMS"
+      carrier_id = "2135"
+      mcc="208"
+      mnc="01"
+      apn="mmscoriolis"
+      mmsc="http://mms.coriolis.fr"
+      mmsproxy="10.12.0.1"
+      mmsport="9028"
+      type="mms"
+      mvno_match_data="208011511"
+      mvno_type="imsi"
+  />
+
+
+  <apn carrier="SFR webphone"
+      carrier_id = "27"
+      mcc="208"
+      mnc="09"
+      apn="sl2sfr"
+      mmsc="http://mms1"
+      mmsproxy="10.151.0.1"
+      mmsport="8080"
+      protocol="IP"
+      type="default,mms,supl,agps,fota"
+  />
+
+  <apn carrier="SFR option modem"
+      carrier_id = "27"
+      mcc="208"
+      mnc="09"
+      apn="websfr"
+      protocol="IP"
+      type="dun"
+  />
+
+  <apn carrier="Be Aliv"
+      carrier_id = "2130"
+      mcc="208"
+      mnc="09"
+      apn="pda.newcomobile.com"
+      type="default,supl"
+      mvno_match_data="208090021"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="208"
+      mnc="09"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+      mvno_type="gid"
+      mvno_match_data="547275554B3030656E"
+  />
+
+  <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="208"
+      mnc="09"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+	  mvno_type="gid"
+      mvno_match_data="54727555533030656E"
+  />
+
+  <apn carrier="Coriolis"
+      carrier_id = "2135"
+      mcc="208"
+      mnc="09"
+      apn="coriolis"
+      type="default,supl"
+      mvno_match_data="208090036"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Coriolis MMS"
+      carrier_id = "2135"
+      mcc="208"
+      mnc="09"
+      apn="mmscoriolis"
+      mmsc="http://mms.coriolis.fr"
+      mmsproxy="10.12.0.1"
+      mmsport="9028"
+      type="mms"
+      mvno_match_data="208090036"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="SFR webphone"
+      carrier_id = "27"
+      mcc="208"
+      mnc="10"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="SFR webphone"
+      carrier_id = "27"
+      mcc="208"
+      mnc="10"
+      apn="sl2sfr"
+      mmsc="http://mms1"
+      mmsproxy="10.151.0.1"
+      mmsport="8080"
+      type="default,mms,supl"
+  />
+
+  <apn carrier="SFR option Modem"
+      carrier_id = "27"
+      mcc="208"
+      mnc="10"
+      apn="websfr"
+      authtype="0"
+      type="dun"
+  />
+
+  <apn carrier="NRJWEB"
+      carrier_id = "2005"
+      mcc="208"
+      mnc="10"
+      apn="fnetnrj"
+      type="default,supl"
+      mvno_match_data="4E"
+      mvno_type="gid"
+  />
+
+  <apn carrier="NRJMMS"
+      carrier_id = "2005"
+      mcc="208"
+      mnc="10"
+      mmsc="http://mmsnrj"
+      mmsproxy="10.143.156.5"
+      mmsport="8080"
+      apn="mmsnrj"
+      type="mms"
+      mvno_match_data="4E"
+      mvno_type="gid"
+  />
+
+  <apn carrier="INTERNET NRJ"
+      carrier_id = "2005"
+      mcc="208"
+      mnc="10"
+      apn="internetnrj"
+      authtype="0"
+      type="dun"
+      mvno_type="gid"
+      mvno_match_data="4E"
+  />
+
+  <apn carrier="Auchan WAP"
+      carrier_id = "2272"
+      mcc="208"
+      mnc="10"
+      apn="wap65"
+      type="default,supl"
+      mvno_match_data="A MOBILE"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Auchan MMS"
+      carrier_id = "2272"
+      mcc="208"
+      mnc="10"
+      mmsc="http://mms65"
+      mmsproxy="10.143.156.8"
+      mmsport="8080"
+      apn="mms65"
+      type="mms"
+      mvno_match_data="A MOBILE"
+      mvno_type="spn"
+  />
+
+  <apn carrier="WAP LeclercMobile"
+      carrier_id = "2273"
+      mcc="208"
+      mnc="10"
+      proxy="192.168.21.9"
+      port="8080"
+      apn="wap66"
+      type="default,supl"
+      mvno_match_data="LeclercMobile"
+      mvno_type="spn"
+  />
+
+  <apn carrier="MMS LeclercMobile"
+      carrier_id = "2273"
+      mcc="208"
+      mnc="10"
+      mmsc="http://mms66"
+      mmsproxy="10.143.156.9"
+      mmsport="8080"
+      apn="mms66"
+      type="mms"
+      mvno_match_data="LeclercMobile"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Coriolis WAP"
+      carrier_id = "2135"
+      mcc="208"
+      mnc="10"
+      apn="fnetcoriolis"
+      type="default,supl"
+      mvno_match_data="12"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Coriolis MMS"
+      carrier_id = "2135"
+      mcc="208"
+      mnc="10"
+      mmsc="http://mmscoriolis"
+      mmsproxy="10.143.156.6"
+      mmsport="8080"
+      apn="mmscoriolis"
+      type="mms"
+      mvno_match_data="12"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Coriolis WEB"
+      carrier_id = "2135"
+      mcc="208"
+      mnc="10"
+      apn="internetcoriolis"
+      authtype="0"
+      type="default,supl,agps,fota,dun"
+      mvno_type="gid"
+      mvno_match_data="12"
+  />
+
+  <apn carrier="4G La Poste Mobile"
+      carrier_id = "2274"
+      mcc="208"
+      mnc="10"
+      apn=""
+      type="ia"
+      mvno_match_data="4C"
+      mvno_type="gid"
+  />
+
+  <apn carrier="4G La Poste Mobile"
+      carrier_id = "2274"
+      mcc="208"
+      mnc="10"
+      apn="sl2sfr"
+      mmsc="http://mms1"
+      mmsproxy="010.143.156.003"
+      mmsport="8080"
+      type="default,supl,mms"
+      mvno_match_data="4C"
+      mvno_type="gid"
+  />
+
+  <apn carrier="WEB La Poste Mobile"
+      carrier_id = "2274"
+      mcc="208"
+      mnc="10"
+      proxy="192.168.21.3"
+      port="8080"
+      apn="wapdebitel"
+      type="default,supl"
+      mvno_match_data="4C"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MMS La Poste Mobile"
+      carrier_id = "2274"
+      mcc="208"
+      mnc="10"
+      apn="mmsdebitel"
+      mmsc="http://mmsdebitel"
+      mmsproxy="10.143.156.3"
+      mmsport="8080"
+      type="mms"
+      mvno_match_data="4C"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Darty Surf&amp;Mails"
+      carrier_id = "2275"
+      mcc="208"
+      mnc="10"
+      apn="wap68"
+      proxy="192.168.21.11"
+      port="8080"
+      type="default,supl"
+      mvno_match_data="44"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Darty MMS"
+      carrier_id = "2275"
+      mcc="208"
+      mnc="10"
+      apn="mms68"
+      mmsc="http://mms68/"
+      mmsproxy="10.143.156.11"
+      mmsport="8080"
+      type="mms"
+      mvno_match_data="44"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Keyyo Mobile Internet"
+      carrier_id = "2276"
+      mcc="208"
+      mnc="10"
+      apn="internet68"
+      authtype="0"
+      type="default,supl,agps,fota,dun"
+      mvno_type="spn"
+      mvno_match_data="Keyyo Mobile"
+  />
+
+  <apn carrier="Keyyo Mobile MMS"
+      carrier_id = "2276"
+      mcc="208"
+      mnc="10"
+      apn="mms68"
+      authtype="0"
+      mmsc="http://mms68"
+      mmsproxy="10.143.156.11"
+      mmsport="8080"
+      type="mms"
+      mvno_type="spn"
+      mvno_match_data="Keyyo Mobile"
+  />
+
+  <apn carrier="Keyyo Mobile Wap"
+      carrier_id = "2276"
+      mcc="208"
+      mnc="10"
+      apn="wap68"
+      proxy="192.168.21.11"
+      port="8080"
+      authtype="0"
+      type="default,supl,agps,fota"
+      mvno_type="spn"
+      mvno_match_data="Keyyo Mobile"
+  />
+
+  <apn carrier="Zero forfait"
+      carrier_id = "2277"
+      mcc="208"
+      mnc="10"
+      apn="internet68"
+      authtype="0"
+      type="default,supl,agps,fota,dun"
+      mvno_type="spn"
+      mvno_match_data="ZERO FORFAIT"
+  />
+
+  <apn carrier="Zero forfait MMS"
+      carrier_id = "2277"
+      mcc="208"
+      mnc="10"
+      apn="mms68"
+      authtype="0"
+      mmsc="http://mms68"
+      mmsproxy="10.143.156.11"
+      mmsport="8080"
+      type="mms"
+      mvno_type="spn"
+      mvno_match_data="ZERO FORFAIT"
+  />
+
+  <apn carrier="WAP RegloMobile"
+      carrier_id = "2273"
+      mcc="208"
+      mnc="10"
+      apn="wap66"
+      proxy="192.168.21.9"
+      port="8080"
+      authtype="0"
+      type="default,supl,agps,fota,dun"
+      mvno_type="spn"
+      mvno_match_data="RegloMobile"
+  />
+
+  <apn carrier="MMS RegloMobile"
+      carrier_id = "2273"
+      mcc="208"
+      mnc="10"
+      apn="mms66"
+      authtype="0"
+      mmsc="http://mms66"
+      mmsproxy="10.143.156.9"
+      mmsport="8080"
+      type="mms"
+      mvno_type="spn"
+      mvno_match_data="RegloMobile"
+  />
+  <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="208"
+      mnc="12"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+  />
+
+  <apn carrier="Free"
+      carrier_id = "1958"
+      mcc="208"
+      mnc="15"
+      apn="free"
+      mmsc="http://mms.free.fr"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Free MMS"
+      carrier_id = "1958"
+      mcc="208"
+      mnc="15"
+      mmsc="http://mms.free.fr"
+      apn="mmsfree"
+      type="mms"
+  />
+
+  <apn carrier="Free Re Int"
+      carrier_id = "2127"
+      mcc="208"
+      mnc="15"
+      apn="free.re"
+      mmsc="http://mms.free.re"
+      type="default,supl,mms"
+      mvno_match_data="F2330002"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Iliad Int"
+      carrier_id = "2124"
+      mcc="208"
+      mnc="15"
+      apn="iliad"
+      mmsc="http://mms.iliad.it"
+      type="default,supl,mms"
+      mvno_match_data="F003"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Legos"
+      carrier_id = "2151"
+      mcc="208"
+      mnc="17"
+      apn="bornsip"
+      type="default,supl"
+  />
+
+  <apn carrier="Legos MMS"
+      carrier_id = "2151"
+      mcc="208"
+      mnc="17"
+      mmsc="http://mms.bornsip.fr:8191"
+      apn="bornsipmms"
+      type="mms"
+  />
+
+  <apn carrier="Bouygues Telecom"
+      carrier_id = "1487"
+      mcc="208"
+      mnc="20"
+      apn="mmsbouygtel.com"
+      mmsc="http://mms.bouyguestelecom.fr/mms/wapenc"
+      mmsproxy="62.201.129.226"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="mobiledata"
+      mcc="208"
+      mnc="22"
+      apn="mobiledata"
+      mmsc="http://mms"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="netgprs.com"
+      mcc="208"
+      mnc="22"
+      apn="netgprs.com"
+      user="tsl"
+      password="tsl"
+      type="default,supl"
+      mvno_match_data="FR-Transatel"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Virgin mobile"
+      carrier_id = "1984"
+      mcc="208"
+      mnc="23"
+      apn="virgin-mobile.fr"
+      proxy="10.6.10.1"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="VM MMS"
+      carrier_id = "1984"
+      mcc="208"
+      mnc="23"
+      apn="virgin-mobile.fr"
+      mmsc="http://virginmms.fr"
+      mmsproxy="10.6.10.1"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="NRJ WEB"
+      carrier_id = "2005"
+      mcc="208"
+      mnc="26"
+      apn="fnetnrj"
+      type="default,supl"
+  />
+
+  <apn carrier="NRJ MMS"
+      carrier_id = "2005"
+      mcc="208"
+      mnc="26"
+      apn="mmsnrj"
+      mmsc="http://mmsnrj"
+      mmsproxy="10.143.156.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Coriolis"
+      carrier_id = "2135"
+      mcc="208"
+      mnc="27"
+      apn="coriolis"
+      type="default,supl"
+  />
+
+  <apn carrier="Coriolis MMS"
+      carrier_id = "2135"
+      mcc="208"
+      mnc="27"
+      apn="mmscoriolis"
+      mmsc="http://mms.coriolis.fr"
+      mmsproxy="10.12.0.1"
+      mmsport="9028"
+      type="mms"
+  />
+
+
+  <apn carrier="Internet móvil"
+      mcc="214"
+      mnc="01"
+      apn="airtelwap.es"
+      user="wap@wap"
+      password="wap125"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="INTERNET"
+      mcc="214"
+      mnc="01"
+      apn="airtelnet.es"
+      authtype="1"
+      user="vodafone"
+      password="vodafone"
+      type="dun"
+  />
+
+  <apn carrier="MMS VODAFONE"
+      mcc="214"
+      mnc="01"
+      apn="mms.vodafone.net"
+      user="wap@wap"
+      password="wap125"
+      mmsc="http://mmsc.vodafone.es/servlets/mms"
+      mmsproxy="212.73.32.10"
+      mmsport="80"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="IMS Vodafone"
+      mcc="214"
+      mnc="01"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="ALTECOM"
+      carrier_id = "2131"
+      mcc="214"
+      mnc="02"
+      apn="altecom.net"
+      type="default"
+  />
+
+  <apn carrier="FIBRACAT"
+      carrier_id = "2136"
+      mcc="214"
+      mnc="02"
+      apn="fibracat.cat"
+      type="default"
+      mvno_type="spn"
+      mvno_match_data="FIBRACAT"
+  />
+
+  <apn carrier="Orange Internet Móvil"
+      carrier_id = "2369"
+      mcc="214"
+      mnc="03"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="Orange Internet Móvil"
+      carrier_id = "678"
+      mcc="214"
+      mnc="03"
+      apn="orangeworld"
+      user="orange"
+      password="orange"
+      authtype="1"
+      mvno_type="spn"
+      mvno_match_data="Orange"
+      type="default"
+  />
+
+  <apn carrier="Orange MMS"
+      carrier_id = "678"
+      mcc="214"
+      mnc="03"
+      apn="orangemms"
+      user="orange"
+      password="orange"
+      mmsc="http://mms.orange.es"
+      mmsproxy="172.22.188.25"
+      mmsport="8080"
+      authtype="1"
+      mvno_type="spn"
+      mvno_match_data="Orange"
+      type="mms"
+  />
+
+  <apn carrier="Orange Internet PC"
+      carrier_id = "2369"
+      mcc="214"
+      mnc="03"
+      apn="internet"
+      authtype="0"
+      user="orange"
+      password="orange"
+      type="dun"
+  />
+
+  <apn carrier="Euskaltel Internet"
+      mcc="214"
+      mnc="03"
+      apn="internet.euskaltel.mobi"
+      user="CLIENTE"
+      password="EUSKALTEL"
+      authtype="1"
+      type="default,supl"
+      mvno_type="imsi"
+      mvno_match_data="2140359"
+  />
+
+  <apn carrier="Euskaltel MMS"
+      mcc="214"
+      mnc="03"
+      apn="euskaltelmms.euskaltel.mobi"
+      user="MMS"
+      password="EUSKALTEL"
+      authtype="1"
+      mmsc="http://mms.euskaltel.mobi"
+      mmsproxy="172.16.18.74"
+      mmsport="8080"
+      type="mms"
+      mvno_type="imsi"
+      mvno_match_data="2140359"
+  />
+
+  <apn carrier="Carrefour"
+      carrier_id = "2133"
+      mcc="214"
+      mnc="03"
+      apn="CARREFOURINTERNET"
+      authtype="1"
+      type="default,supl"
+      mvno_type="imsi"
+      mvno_match_data="2140352xxxxxxxx"
+  />
+
+  <apn carrier="Carrefour MMS"
+      carrier_id = "2133"
+      mcc="214"
+      mnc="03"
+      apn="CARREFOURMMS"
+      user="CARREFOUR"
+      password="CARREFOUR"
+      authtype="1"
+      mmsc="http://mms.orange.es"
+      mmsproxy="172.022.188.025"
+      mmsport="8080"
+      mvno_type="imsi"
+      mvno_match_data="2140352xxxxxxxx"
+      type="mms"
+  />
+
+  <apn carrier="Happy Internet"
+      carrier_id = "2297"
+      mcc="214"
+      mnc="03"
+      apn="internettph"
+      type="default,supl"
+      mvno_type="spn"
+      mvno_match_data="Happy"
+  />
+
+  <apn carrier="RACC INTERNET"
+      carrier_id = "2298"
+      mcc="214"
+      mnc="03"
+      apn="internet.racc.net"
+      user="CLIENTERACC"
+      password="RACC"
+      type="default,supl"
+      mvno_type="spn"
+      mvno_match_data="RACC"
+  />
+
+  <apn carrier="RACC MMS"
+      carrier_id = "2298"
+      mcc="214"
+      mnc="03"
+      apn="mms.racc.net"
+      user="MMS"
+      password="RACC"
+      mmsc="http://mms.racc.net"
+      mmsproxy="172.16.18.74"
+      mmsport="8080"
+      mvno_type="spn"
+      mvno_match_data="RACC"
+      type="mms"
+  />
+
+  <apn carrier="CABLE movil Internet"
+      carrier_id = "2299"
+      mcc="214"
+      mnc="03"
+      apn="internettph"
+      type="default,supl"
+      mvno_type="spn"
+      mvno_match_data="CABLE movil"
+   />
+
+  <apn carrier="MASMovil Internet"
+      carrier_id = "2300"
+      mcc="214"
+      mnc="03"
+      apn="internetmas"
+      type="default,supl"
+      mvno_type="spn"
+      mvno_match_data="MASMovil"
+  />
+
+  <apn carrier="Ibercom Internet"
+      carrier_id = "2301"
+      mcc="214"
+      mnc="03"
+      apn="ibercominternet"
+      type="default,supl"
+      mvno_type="spn"
+      mvno_match_data="Ibercom"
+  />
+
+  <apn carrier="jazzinternet"
+      carrier_id = "1974"
+      mcc="214"
+      mnc="03"
+      apn="jazzinternet"
+      mvno_type="spn"
+      mvno_match_data="JAZZTEL"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1974"
+      mcc="214"
+      mnc="03"
+      apn="jazzmms"
+      user=""
+      password=""
+      authtype="1"
+      mmsc="http://jazztelmms.com/servlets/mms"
+      mmsproxy="37.132.0.10"
+      mmsport="8080"
+      mvno_type="spn"
+      mvno_match_data="JAZZTEL"
+      type="mms"
+  />
+
+  <apn carrier="internet simyo"
+      carrier_id = "2125"
+      mcc="214"
+      mnc="03"
+      apn="orangeworld"
+      authtype="1"
+      user="orange"
+      password = "orange"
+      mvno_type="spn"
+      mvno_match_data="simyo"
+      type="default,supl"
+  />
+
+  <apn carrier="simyo MMS"
+      carrier_id = "2125"
+      mcc="214"
+      mnc="03"
+      apn="orangemms"
+      user="orange"
+      password="orange"
+      authtype="1"
+      mmsc="http://mms.orange.es"
+      mmsproxy="172.22.188.25"
+      mmsport="8080"
+      mvno_type="spn"
+      mvno_match_data="simyo"
+      type="mms"
+  />
+
+  <apn carrier="Yoigo Internet"
+      carrier_id = "679"
+      mcc="214"
+      mnc="04"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="Yoigo Internet"
+      carrier_id = "679"
+      mcc="214"
+      mnc="04"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Yoigo MMS"
+      carrier_id = "679"
+      mcc="214"
+      mnc="04"
+      apn="mms"
+      mmsc="http://mmss/"
+      mmsproxy="193.209.134.141"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="Tuenti"
+      carrier_id = "34"
+      mcc="214"
+      mnc="05"
+      apn="tuenti.com"
+      authtype="1"
+      user="tuenti"
+      password="tuenti"
+      mmsc="http://tuenti.com"
+      mmsproxy="10.138.255.43"
+      mmsport="8080"
+  />
+
+  <apn carrier="INET Roaming"
+      mcc="214"
+      mnc="05"
+      apn="inet.es"
+      user=""
+      password=""
+      port=""
+      proxy=""
+      type="default,supl,fota,hipri"
+      roaming_protocol="IPV4V6"
+      mvno_type="imsi"
+      mvno_match_data="214050104xxxxxx"
+  />
+
+  <apn carrier="DIGI Spain"
+      carrier_id="2442"
+      mcc="214"
+      mnc="05"
+      apn="internet.digimobil.es"
+      type="default,supl"
+      mvno_type="gid"
+      mvno_match_data="44474553"
+  />
+
+  <apn carrier="DIGI Italy"
+      carrier_id="2443"
+      mcc="214"
+      mnc="05"
+      apn="digi.mobile"
+      type="default,supl"
+      mvno_type="gid"
+      mvno_match_data="44474954"
+  />
+
+  <apn carrier="INTERNET GPRS"
+      carrier_id = "1909"
+      mcc="214"
+      mnc="06"
+      apn="airtelnet.es"
+      user="vodafone"
+      password="vodafone"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Vodafone"
+      carrier_id = "1909"
+      mcc="214"
+      mnc="06"
+      apn="mms.vodafone.net"
+      user="wap@wap"
+      password="wap125"
+      mmsc="http://mmsc.vodafone.es/servlets/mms"
+      mmsproxy="212.73.32.10"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="Euskaltel MMS"
+      mcc="214"
+      mnc="06"
+      apn="euskaltelmms.euskaltel.mobi"
+      user="MMS"
+      password="EUSKALTEL"
+      mmsc="http://mms.euskaltel.mobi"
+      mmsproxy="172.16.18.74"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Euskaltel Internet"
+      mcc="214"
+      mnc="06"
+      apn="internet.euskaltel.mobi"
+      user="CLIENTE"
+      password="EUSKALTEL"
+      authtype="1"
+      type="default,supl"
+      mvno_match_data="0008"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Internet R"
+      carrier_id = "2278"
+      mcc="214"
+      mnc="06"
+      apn="internet.mundo-r.com"
+      authtype="1"
+      type="default,supl"
+      mvno_match_data="2140612"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="MMS R"
+      carrier_id = "2278"
+      mcc="214"
+      mnc="06"
+      apn="mms.mundo-r.com"
+      mmsc="http://mms.mundo-r.com"
+      mmsproxy="10.0.157.169"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+      mvno_match_data="2140612"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="TeleCable Internet"
+      carrier_id = "2112"
+      mcc="214"
+      mnc="06"
+      apn="internet.telecable.es"
+      user="telecable"
+      password="telecable"
+      authtype="1"
+      type="default,supl"
+      mvno_match_data="2140613"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="TeleCable MMS"
+      carrier_id = "2112"
+      mcc="214"
+      mnc="06"
+      apn="mms.telecable.es"
+      user="telecable"
+      password="telecable"
+      mmsc="http://mms.telecable.es/mms/"
+      mmsproxy="212.89.0.84"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+      mvno_match_data="2140613"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Eroski Movil GPRS"
+      carrier_id = "2279"
+      mcc="214"
+      mnc="06"
+      apn="gprs.eroskimovil.es"
+      user="wap@wap"
+      password="wap125"
+      authtype="1"
+      type="default,supl"
+      mvno_match_data="2140606"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Eroski Movil MMS"
+      carrier_id = "2279"
+      mcc="214"
+      mnc="06"
+      apn="mms.eroskimovil.es"
+      user="wap@wap"
+      password="wap125"
+      mmsc="http://mms.eroskimovil.es/servlets/mms"
+      mmsproxy="212.73.32.10"
+      mmsport="80"
+      authtype="1"
+      type="mms"
+      mvno_match_data="2140606"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="DUN"
+      carrier_id = "2280"
+      mcc="214"
+      mnc="06"
+      apn="gprs.pepephone.com"
+      authtype="0"
+      type="dun"
+      mvno_type="spn"
+      mvno_match_data="pepephone"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "2280"
+      mcc="214"
+      mnc="06"
+      apn="gprsmov.pepephone.com"
+      authtype="0"
+      type="default,supl,agps,fota"
+      mvno_type="spn"
+      mvno_match_data="pepephone"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "2280"
+      mcc="214"
+      mnc="06"
+      apn="mms.pepephone.com"
+      authtype="0"
+      user="wap@wap"
+      password="wap125"
+      mmsc="http://mms.pepephone.com/servlets/mms"
+      mmsproxy="212.73.32.10"
+      mmsport="80"
+      type="mms"
+      mvno_type="spn"
+      mvno_match_data="pepephone"
+  />
+
+  <apn carrier="Mobiland"
+      carrier_id = "450"
+      mcc="213"
+      mnc="03"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar"
+      carrier_id = "34"
+      mcc="214"
+      mnc="07"
+      apn="telefonica.es"
+      user="telefonica"
+      password="telefonica"
+      mmsc="http://mms.movistar.com"
+      mmsproxy="10.138.255.5"
+      mmsport="8080"
+      authtype="1"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Jazztel Internet"
+      carrier_id = "1974"
+      mcc="214"
+      mnc="07"
+      apn="jazzinternet"
+      type="default,supl"
+      mvno_match_data="JAZZTEL"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Jazztel MMS"
+      carrier_id = "1974"
+      mcc="214"
+      mnc="07"
+      apn="jazzmms"
+      user=""
+      password=""
+      mmsc="http://jazztelmms.com/servlets/mms"
+      mmsproxy="37.132.0.10"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+      mvno_match_data="JAZZTEL"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Conexióompartida"
+      carrier_id = "34"
+      mcc="214"
+      mnc="07"
+      apn="movistar.es"
+      authtype="1"
+      user="MOVISTAR"
+      password="MOVISTAR"
+      type="dun"
+  />
+
+  <apn carrier="T-2"
+      carrier_id = "2281"
+      mcc="214"
+      mnc="07"
+      apn="internet.t-2.net"
+      mmsc="http://www.mms.t-2.net:8002"
+      mmsproxy="172.20.18.137"
+      mmsport="8080"
+      mvno_type="imsi"
+      mvno_match_data="2140759577xxxxx"
+      type="default,ims,mms,supl"
+  />
+
+  <apn carrier="T-2"
+      carrier_id = "2281"
+      mcc="214"
+      mnc="07"
+      apn="internet.t-2.net"
+      mmsc="http://www.mms.t-2.net:8002"
+      mmsproxy="172.20.18.137"
+      mmsport="8080"
+      type="default,ims,mms,supl"
+      mvno_type="imsi"
+      mvno_match_data="2140796692xxxxx"
+  />
+
+  <apn carrier="Euskaltel MMS"
+      carrier_id = "1909"
+      mcc="214"
+      mnc="08"
+      apn="euskaltelmms.euskaltel.mobi"
+      user="MMS"
+      password="EUSKALTEL"
+      mmsc="http://mms.euskaltel.mobi"
+      mmsproxy="172.16.18.74"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Euskaltel Internet"
+      carrier_id = "1909"
+      mcc="214"
+      mnc="08"
+      apn="internet.euskaltel.mobi"
+      user="CLIENTE"
+      password="EUSKALTEL"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="TeleCable Internet"
+      mcc="214"
+      mnc="16"
+      apn="internet.telecable.es"
+      user="telecable"
+      password="telecable"
+      type="default,supl"
+  />
+
+  <apn carrier="TeleCable MMS"
+      mcc="214"
+      mnc="16"
+      apn="mms.telecable.es"
+      user="telecable"
+      password="telecable"
+      mmsc="http://mms.telecable.es/mms/"
+      mmsproxy="212.89.0.84"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="ONO Internet"
+      carrier_id = "1976"
+      mcc="214"
+      mnc="18"
+      apn="internet.ono.com"
+      type="default,supl"
+  />
+
+  <apn carrier="ONO MMS"
+      carrier_id = "1976"
+      mcc="214"
+      mnc="18"
+      apn="mms.ono.com"
+      mmsc="http://mms.ono.com/"
+      mmsproxy="10.126.0.50"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="internet simyo"
+      carrier_id = "2125"
+      mcc="214"
+      mnc="19"
+      apn="orangeworld"
+      authtype="1"
+      user="orange"
+      password = "orange"
+      type="default,supl"
+    />
+
+  <apn carrier="simyo MMS"
+      carrier_id = "2125"
+      mcc="214"
+      mnc="19"
+      apn="orangemms"
+      user="orange"
+      password="orange"
+      authtype="1"
+      mmsc="http://mms.orange.es"
+      mmsproxy="172.22.188.25"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="jazzinternet"
+      carrier_id = "1974"
+      mcc="214"
+      mnc="21"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="jazzinternet"
+      carrier_id = "1974"
+      mcc="214"
+      mnc="21"
+      apn="jazzinternet"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1974"
+      mcc="214"
+      mnc="21"
+      apn="jazzmms"
+      user=""
+      password=""
+      authtype="1"
+      mmsc="http://jazztelmms.com/servlets/mms"
+      mmsproxy="37.132.0.10"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="DIGI Spain"
+      carrier_id="2442"
+      mcc="214"
+      mnc="22"
+      apn="internet.digimobil.es"
+      type="default,supl"
+  />
+
+  <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="214"
+      mnc="27"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+  />
+
+  <apn carrier="Tuenti"
+      carrier_id = "2357"
+      mcc="214"
+      mnc="32"
+      apn="tuenti.com"
+      user="tuenti"
+      password="tuenti"
+      authtype="3"
+      mmsc="http://tuenti.com"
+      mmsproxy="10.138.255.43"
+      mmsport="8080"
+      type="default,mms,supl"
+      mvno_type="spn"
+      mvno_match_data="Tuenti"
+  />
+
+  <apn carrier="INET Internet"
+      mcc="214"
+      mnc="34"
+      apn="inet.es"
+      user=""
+      password=""
+      port=""
+      proxy=""
+      type="default,supl,fota,hipri"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="Telenor MMS"
+      carrier_id = "1534"
+      mcc="216"
+      mnc="01"
+      apn="mms"
+      mmsc="http://mmsc.telenor.hu/"
+      mmsproxy="84.225.255.1"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Telenor Online"
+      carrier_id = "1534"
+      mcc="216"
+      mnc="01"
+      apn="online"
+      type="default,supl"
+  />
+
+  <apn carrier="Djuice MMS"
+      mcc="216"
+      mnc="01"
+      apn="mms"
+      mmsproxy="84.225.255.1"
+      mmsport="8080"
+      mmsc="http://mmsc.pgsm.hu/"
+      type="mms"
+      authtype="0"
+      mvno_match_data="Djuice"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Djuice NET"
+      mcc="216"
+      mnc="01"
+      apn="net"
+      type="default"
+      authtype="0"
+      mvno_match_data="Djuice"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Djuice WAP"
+      mcc="216"
+      mnc="01"
+      apn="wap"
+      proxy="84.225.255.1"
+      port="8080"
+      type="default"
+      authtype="0"
+      mvno_match_data="Djuice"
+      mvno_type="spn"
+  />
+
+  <apn carrier="T-Mobile H"
+      carrier_id = "2401"
+      mcc="216"
+      mnc="30"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="T-Mobile H MMS"
+      carrier_id = "2401"
+      mcc="216"
+      mnc="30"
+      apn="internet.telekom"
+      mmsc="http://mms.t-mobile.hu/servlets/mms"
+      mmsproxy="212.51.126.10"
+      mmsport="8080"
+      type="mms"
+      authtype="1"
+  />
+
+  <apn carrier="T-Mobile H"
+      carrier_id = "2401"
+      mcc="216"
+      mnc="30"
+      apn="internet.telekom"
+      type="default,supl"
+      authtype="1"
+  />
+
+  <apn carrier="Vodafone Internet"
+      carrier_id = "1535"
+      mcc="216"
+      mnc="70"
+      apn="internet.vodafone.net"
+      type="default,supl"
+      authtype="0"
+      mvno_match_data="21670xx2xxx"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Vodafone MMS"
+      carrier_id = "1535"
+      mcc="216"
+      mnc="70"
+      apn="mms.vodafone.net"
+      mmsproxy="80.244.97.2"
+      mmsport="8080"
+      mmsc="http://mms.vodafone.hu/servlets/mms"
+      type="mms"
+      authtype="0"
+      mvno_match_data="21670xx2xxx"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Vodafone Live!"
+      carrier_id = "1535"
+      mcc="216"
+      mnc="70"
+      apn="wap.vodafone.net"
+      user="vodawap"
+      password="vodawap"
+      proxy="10.9.8.7"
+      port="8080"
+      type="default,supl"
+      authtype="1"
+      mvno_match_data="21670xx2xxx"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Vodafone Internet VitaMAX"
+      mcc="216"
+      mnc="70"
+      apn="vitamax.internet.vodafone.net"
+      type="default,supl"
+      mvno_match_data="21670xx1xxx"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Vodafone MMS"
+      mcc="216"
+      mnc="70"
+      apn="mms.vodafone.net"
+      mmsproxy="80.244.97.2"
+      mmsport="8080"
+      mmsc="http://mms.vodafone.hu/servlets/mms"
+      type="mms"
+      mvno_match_data="21670xx1xxx"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Vodafone Live! VitaMAX"
+      mcc="216"
+      mnc="70"
+      apn="vitamax.wap.vodafone.net"
+      user="vodawap"
+      password="vodawap"
+      proxy="10.9.8.7"
+      port="8080"
+      type="default,supl"
+      authtype="1"
+      mvno_match_data="21670xx1xxx"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="HT Eronet WAP"
+      carrier_id = "1357"
+      mcc="218"
+      mnc="03"
+      apn="wap.eronet.ba"
+      proxy="10.12.3.10"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="HT Eronet GPRS"
+      carrier_id = "1357"
+      mcc="218"
+      mnc="03"
+      apn="gprs.eronet.ba"
+      type="default,supl"
+  />
+
+  <apn carrier="Ht Eronet MMS"
+      carrier_id = "1357"
+      mcc="218"
+      mnc="03"
+      apn="mms.eronet.ba"
+      mmsc="http://mms.gprs.eronet.ba/mms/wapenc"
+      mmsproxy="10.12.3.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="m:tel"
+      carrier_id = "1358"
+      mcc="218"
+      mnc="05"
+      apn="3g1"
+      proxy="192.168.61.10"
+      port="80"
+      type="default,supl"
+  />
+
+  <apn carrier="mtelgprs"
+      carrier_id = "1358"
+      mcc="218"
+      mnc="05"
+      apn="3g1"
+      type="default,supl"
+  />
+
+  <apn carrier="mtelmms"
+      carrier_id = "1358"
+      mcc="218"
+      mnc="05"
+      apn="mtelmms"
+      mmsc="http://mmsc.mtel.ba/mms/wapenc"
+      mmsproxy="192.168.61.11"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="BHMobileInternet"
+      carrier_id = "1359"
+      mcc="218"
+      mnc="90"
+      apn="active.bhmobile.ba"
+      type="default,supl"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="BHMobileMMS"
+      carrier_id = "1359"
+      mcc="218"
+      mnc="90"
+      apn="mms.bhmobile.ba"
+      mmsc="http://mms.bhmobile.ba/servlets/mms"
+      mmsproxy="195.222.56.41"
+      mmsport="8080"
+      type="mms"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="T-Mobile MMS"
+      carrier_id = "2365"
+      mcc="219"
+      mnc="01"
+      apn="mms.htgprs"
+      mmsc="http://mms.t-mobile.hr/servlets/mms"
+      mmsproxy="10.12.0.4"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="T-Mobile"
+      carrier_id = "2365"
+      mcc="219"
+      mnc="01"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="T-Mobile Internet"
+      carrier_id = "2365"
+      mcc="219"
+      mnc="01"
+      apn="internet.ht.hr"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="bonbon Internet"
+      carrier_id = "2091"
+      mcc="219"
+      mnc="01"
+      apn="web.htgprs"
+      authtype="1"
+      type="default,supl,agps,fota,dun"
+      mvno_type="spn"
+      mvno_match_data="bonbon"
+  />
+
+  <apn carrier="bonbon MMS"
+      carrier_id = "2091"
+      mcc="219"
+      mnc="01"
+      apn="mms.htgprs"
+      authtype="1"
+      mmsc="http://mms.bonbon.com.hr/servlets/mms"
+      mmsproxy="10.12.0.4"
+      mmsport="8080"
+      type="mms"
+      mvno_type="spn"
+      mvno_match_data="bonbon"
+  />
+
+  <apn carrier="Tele2"
+      carrier_id = "1529"
+      mcc="219"
+      mnc="02"
+      apn="internet.tele2.hr"
+      mmsc="http://mmsc.tele2.hr"
+      mmsproxy="193.12.40.66"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Broadband"
+      carrier_id = "1530"
+      mcc="219"
+      mnc="10"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="Broadband"
+      carrier_id = "1530"
+      mcc="219"
+      mnc="10"
+      apn="data.vip.hr"
+      user="38591"
+      password="38591"
+      authtype="1"
+      proxy="212.91.99.91"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="VIP.mms"
+      carrier_id = "1530"
+      mcc="219"
+      mnc="10"
+      apn="mms.vipnet.hr"
+      mmsc="http://mms.vipnet.hr/servlets/mms"
+      mmsproxy="212.91.99.91"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Telenor internet"
+      carrier_id = "1012"
+      mcc="220"
+      mnc="01"
+      apn="internet"
+      user="telenor"
+      password="gprs"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Telenor MMS"
+      carrier_id = "1012"
+      mcc="220"
+      mnc="01"
+      apn="mms"
+      mmsc="http://mms.telenor.rs/servlets/mms"
+      mmsproxy="217.65.192.33"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Telenor MNE internet"
+      carrier_id = "1012"
+      mcc="220"
+      mnc="02"
+      apn="internet"
+      user="gprs"
+      password="gprs"
+      proxy="192.168.246.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Telenor MNE mms"
+      carrier_id = "1012"
+      mcc="220"
+      mnc="02"
+      apn="mms"
+      user="mms"
+      password="mms"
+      mmsc="http://mm.vor.telenor.me"
+      mmsproxy="192.168.246.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="mt:s wap"
+      carrier_id = "1013"
+      mcc="220"
+      mnc="03"
+      apn="gprswap"
+      user="mts"
+      password="064"
+      proxy="172.17.88.198"
+      port="8080"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="mt:s mms"
+      carrier_id = "1013"
+      mcc="220"
+      mnc="03"
+      apn="mms"
+      user="mts"
+      password="064"
+      mmsc="http://mms.mts064.telekom.rs/mms/wapenc"
+      mmsproxy="172.17.85.131"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="MTS Internet RS"
+      carrier_id = "1013"
+      mcc="220"
+      mnc="03"
+      apn="gprsinternet"
+      authtype="0"
+      user="mts"
+      password="064"
+      type="default,supl,agps,fota,dun"
+  />
+
+  <apn carrier="T-Mobile MMS"
+      carrier_id = "10"
+      mcc="220"
+      mnc="04"
+      apn="mms"
+      user="38267"
+      password="38267"
+      mmsc="http://192.168.180.100/servlets/mms"
+      mmsproxy="10.0.5.19"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="T-Mobile Internet"
+      carrier_id = "10"
+      mcc="220"
+      mnc="04"
+      apn="tmcg-wnw"
+      user="38267"
+      password="38267"
+      proxy="10.0.5.19"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="SaskTel"
+      carrier_id = "580"
+      mcc="204"
+      mnc="04"
+      apn="pda.stm.sk.ca"
+      type="default,mms,supl"
+      mmsc="http://mms.sasktel.com/"
+      mmsproxy="mig.sasktel.com"
+      mmsport="80"
+      mvno_match_data="5A"
+      mvno_type="gid"
+  />
+
+  <apn carrier="agms"
+      carrier_id = "2351"
+      mcc="204"
+      mnc="65"
+      apn="agms"
+      type="default,supl"
+  />
+
+  <apn carrier="Vip GPRS"
+      carrier_id = "1014"
+      mcc="220"
+      mnc="05"
+      apn="vipmobile"
+      user="vipmobile"
+      password="vipmobile"
+      proxy="212.15.182.82"
+      port="8080"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Vip MMS"
+      carrier_id = "1014"
+      mcc="220"
+      mnc="05"
+      apn="vipmobile.mms"
+      user="vipmobile"
+      password="vipmobile"
+      mmsc="http://mmsc.vipmobile.rs"
+      mmsproxy="212.15.182.82"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="TIM WAP"
+      carrier_id = "33"
+      mcc="222"
+      mnc="01"
+      apn="wap.tim.it"
+      type="default,supl"
+  />
+
+  <apn carrier="TIM DUN (IT)"
+      carrier_id = "33"
+      mcc="222"
+      mnc="01"
+      apn="ibox.tim.it"
+      authtype="0"
+      type="dun"
+  />
+
+  <apn carrier="TIM MMS"
+      carrier_id = "33"
+      mcc="222"
+      mnc="01"
+      apn="unico.tim.it"
+      mmsc="http://mms.tim.it/servlets/mms"
+      mmsproxy="213.230.130.89"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "1895"
+      mcc="222"
+      mnc="01"
+      apn="internet.windmobile.ca"
+      type="default,supl"
+      protocol="IPV4V6"
+      mvno_match_data="FFFFFF00"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1895"
+      mcc="222"
+      mnc="01"
+      apn="mms.windmobile.ca"
+      mmsc="http://mms.windmobile.ca"
+      mmsproxy="74.115.197.70"
+      mmsport="8080"
+      type="mms"
+      mvno_match_data="FFFFFF00"
+      mvno_type="gid"
+  />
+
+ <apn carrier="MMS"
+      carrier_id = "1912"
+      mcc="222"
+      mnc="01"
+      authtype="0"
+      mmsc="http://mms.iusacell3g.com/"
+      type="mms"
+      user="mmsiusacellgsm"
+      password="mmsiusacellgsm"
+      apn="mms.iusacellgsm.mx"
+      mvno_type="spn"
+      mvno_match_data="IUSACELL"
+  />
+
+  <apn carrier="Modem"
+      carrier_id = "1912"
+      mcc="222"
+      mnc="01"
+      authtype="0"
+      type="dun"
+      user="iusacellgsm"
+      password="iusacellgsm"
+      apn="modem.iusacellgsm.mx"
+      mvno_type="spn"
+      mvno_match_data="IUSACELL"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "1912"
+      mcc="222"
+      mnc="01"
+      authtype="0"
+      type="default"
+      user="iusacellgsm"
+      password="iusacellgsm"
+      apn="web.iusacellgsm.mx"
+      mvno_type="spn"
+      mvno_match_data="IUSACELL"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1912"
+      mcc="222"
+      mnc="01"
+      apn="mms.iusacellgsm.mx"
+      authtype="0"
+      mmsc="http://mms.iusacell3g.com/"
+      type="mms"
+      user="mmsiusacellgsm"
+      password="mmsiusacellgsm"
+      mvno_type="spn"
+      mvno_match_data="UNEFON"
+  />
+
+  <apn carrier="Modem"
+      carrier_id = "1912"
+      mcc="222"
+      mnc="01"
+      apn="modem.iusacellgsm.mx"
+      authtype="0"
+      type="dun"
+      user="iusacellgsm"
+      password="iusacellgsm"
+      mvno_type="spn"
+      mvno_match_data="UNEFON"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "1912"
+      mcc="222"
+      mnc="01"
+      apn="web.iusacellgsm.mx"
+      authtype="0"
+      type="default"
+      user="iusacellgsm"
+      password="iusacellgsm"
+      mvno_type="spn"
+      mvno_match_data="UNEFON"
+  />
+
+  <apn carrier="NOVERCA MMS"
+      carrier_id = "2282"
+      mcc="222"
+      mnc="01"
+      apn="mms.noverca.it"
+      authtype="0"
+      mmsc="http://mms.noverca.it/"
+      mmsproxy="213.230.130.89"
+      mmsport="80"
+      type="mms"
+      mvno_type="spn"
+      mvno_match_data="Noverca"
+  />
+
+  <apn carrier="NOVERCA WEB"
+      carrier_id = "2282"
+      mcc="222"
+      mnc="01"
+      apn="web.noverca.it"
+      authtype="0"
+      type="default,supl,agps,fota,dun"
+      mvno_type="spn"
+      mvno_match_data="Noverca"
+  />
+
+  <apn carrier="GigSky"
+      carrier_id="2459"
+      mcc="222"
+      mnc="01"
+      apn="gigsky"
+      type="default"
+      mvno_type="spn"
+      mvno_match_data="GigSky"
+  />
+
+  <apn carrier="Acc. Internet da cell"
+      mcc="222"
+      mnc="10"
+      apn=""
+      type="ia"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="MMS Vodafone"
+      mcc="222"
+      mnc="10"
+      apn="mms.vodafone.it"
+      mmsc="http://mms.vodafone.it/servlets/mms"
+      mmsproxy="10.128.224.10"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="ho."
+      carrier_id = "2455"
+      mcc="222"
+      mnc="10"
+      apn="web.ho-mobile.it"
+      authtype="0"
+      type="default,supl,hipri,fota"
+      mvno_type="spn"
+      mvno_match_data="ho."
+  />
+
+  <apn carrier="ho. (Tethering)"
+      carrier_id = "2455"
+      mcc="222"
+      mnc="10"
+      apn="internet.ho-mobile.it"
+      authtype="0"
+      type="dun"
+      mvno_type="spn"
+      mvno_match_data="ho."
+  />
+
+  <apn carrier="Acc. Internet da cell"
+      mcc="222"
+      mnc="10"
+      apn="mobile.vodafone.it"
+      type="default,supl"
+  />
+
+  <apn carrier="Tethering Internet"
+      mcc="222"
+      mnc="10"
+      apn="web.omnitel.it"
+      authtype="0"
+      mmsport="80"
+      type="dun"
+  />
+
+  <apn carrier="IMS Vodafone"
+      mcc="222"
+      mnc="10"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="PosteMobile"
+      carrier_id = "2303"
+      mcc="222"
+      mnc="10"
+      apn="wap.postemobile.it"
+      authtype="0"
+      type="default,supl,agps,fota"
+      mvno_type="spn"
+      mvno_match_data="PosteMobile"
+  />
+
+  <apn carrier="PosteMobile (DUN)"
+      carrier_id = "2303"
+      mcc="222"
+      mnc="10"
+      apn="internet.postemobile.it"
+      authtype="0"
+      type="dun"
+      mvno_type="spn"
+      mvno_match_data="PosteMobile"
+  />
+
+  <apn carrier="PosteMobile MMS"
+      carrier_id = "2303"
+      mcc="222"
+      mnc="10"
+      apn="mms.postemobile.it"
+      authtype="0"
+      mmsc="http://mms.postemobile.it/servlets/mms"
+      mmsproxy="10.128.224.10"
+      mmsport="80"
+      type="mms"
+      mvno_type="spn"
+      mvno_match_data="PosteMobile"
+  />
+
+  <apn carrier="ErgMobile WAP"
+      carrier_id = "2304"
+      mcc="222"
+      mnc="10"
+      apn="mobile.erg.it"
+      authtype="0"
+      type="default,supl,agps,fota,dun"
+      mvno_type="spn"
+      mvno_match_data="ERG"
+  />
+
+  <apn carrier="DailyTelecomWAP"
+        carrier_id = "2438"
+        mcc="222"
+        mnc="10"
+        apn="wap.dtm.it"
+        type="default,supl,dun"
+        mvno_type="spn"
+        mvno_match_data="Daily Telecom"
+  />
+
+  <apn carrier="DIGI Italy"
+      carrier_id="2443"
+      mcc="222"
+      mnc="36"
+      apn="digi.mobile"
+      type="default,supl"
+  />
+
+  <apn carrier="Iliad"
+      carrier_id = "2124"
+      mcc="222"
+      mnc="50"
+      apn="iliad"
+      mmsc="http://mms.iliad.it"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="WEB CoopVoce"
+        mcc="222"
+        mnc="53"
+        apn="internet.coopvoce.it"
+        type="default"
+  />
+
+  <apn carrier="MMS CoopVoce"
+        mcc="222"
+        mnc="53"
+        apn="message.coopvoce.it"
+        type="mms"
+        mmsc="http://mms.coop.it/servlets/mms"
+        mmsproxy="213.230.130.89"
+        mmsport="80"
+  />
+
+  <apn carrier="Plintron"
+      mcc="222"
+      mnc="54"
+      apn="data.plintron.it"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Plintron"
+  />
+
+  <apn carrier="INTERNET"
+      carrier_id = "1573"
+      mcc="222"
+      mnc="88"
+      apn="internet.it"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1573"
+      mcc="222"
+      mnc="88"
+      apn="mms.it"
+      mmsc="http://mms.windtre.it"
+      mmsproxy="mmsproxy.windtre.it"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "1895"
+      mcc="222"
+      mnc="88"
+      apn="internet.windmobile.ca"
+      type="default,supl"
+      protocol="IPV4V6"
+      mvno_match_data="FFFFFF00"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1895"
+      mcc="222"
+      mnc="88"
+      apn="mms.windmobile.ca"
+      mmsc="http://mms.windmobile.ca"
+      mmsproxy="74.115.197.70"
+      mmsport="8080"
+      type="mms"
+      mvno_match_data="FFFFFF00"
+      mvno_type="gid"
+  />
+
+  <apn carrier="INTERNET"
+      carrier_id = "1575"
+      mcc="222"
+      mnc="99"
+      apn="internet.it"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1575"
+      mcc="222"
+      mnc="99"
+      apn="mms.it"
+      mmsc="http://mms.windtre.it"
+      mmsproxy="mmsproxy.windtre.it"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Fastweb WEB"
+      carrier_id = "2039"
+      mcc="222"
+      mnc="99"
+      apn="apn.fastweb.it"
+      mmsc="http://mms.fastweb.it/mms/wapenc"
+      mmsproxy="10.0.65.9"
+      mmsport="8080"
+      type="default,supl,mms"
+      mvno_match_data="FASTWEB"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Vodafone live!"
+      carrier_id = "2391"
+      mcc="226"
+      mnc="01"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="Vodafone live!"
+      carrier_id = "2391"
+      mcc="226"
+      mnc="01"
+      apn="live.vodafone.com"
+      user="live"
+      password="vodafone"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone MMS"
+      carrier_id = "2391"
+      mcc="226"
+      mnc="01"
+      apn="mms.vodafone.ro"
+      user="mms"
+      password="vodafone"
+      mmsc="http://multimedia/servlets/mms"
+      mmsproxy="193.230.161.231"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone live!PRE"
+      carrier_id = "2391"
+      mcc="226"
+      mnc="01"
+      apn="live.pre.vodafone.com"
+      proxy="193.230.161.231"
+      port="8080"
+      authtype="0"
+      user="live"
+      password="vodafone"
+      type="default"
+  />
+
+  <apn carrier="Cosmote Connect Mobile"
+      mcc="226"
+      mnc="03"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="Cosmote Connect Mobile"
+      mcc="226"
+      mnc="03"
+      apn="broadband"
+      type="default,supl"
+  />
+
+  <apn carrier="Cosmote MMS"
+      mcc="226"
+      mnc="03"
+      apn="mms"
+      user="mms"
+      password="mms"
+      mmsc="http://mmsc1.mms.cosmote.ro:8002"
+      mmsproxy="10.252.1.62"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="web'n'walk"
+      mcc="226"
+      mnc="03"
+      apn="wnw"
+      user="wnw"
+      password="wnw"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1959"
+      mcc="226"
+      mnc="05"
+      apn="mms"
+      mmsc="http://10.10.3.133:8002"
+      mmsproxy="10.10.3.130"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Digi.Mobil"
+      carrier_id = "1959"
+      mcc="226"
+      mnc="05"
+      apn="internet"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="DIGI Spain"
+      carrier_id="2442"
+      mcc="226"
+      mnc="05"
+      apn="internet.digimobil.es"
+      type="default,supl"
+      mvno_type="gid"
+      mvno_match_data="44474553"
+  />
+
+  <apn carrier="DIGI Italy"
+      carrier_id="2443"
+      mcc="226"
+      mnc="05"
+      apn="digi.mobile"
+      type="default,supl"
+      mvno_type="gid"
+      mvno_match_data="44474954"
+  />
+
+  <apn carrier="Cosmote Connect Mobile"
+      mcc="226"
+      mnc="06"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="Cosmote Connect Mobile"
+      mcc="226"
+      mnc="06"
+      apn="broadband"
+      type="default,supl"
+  />
+
+  <apn carrier="Cosmote MMS"
+      mcc="226"
+      mnc="06"
+      apn="mms"
+      user="mms"
+      password="mms"
+      mmsc="http://mmsc1.mms.cosmote.ro:8002"
+      mmsproxy="10.252.1.62"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="web'n'walk"
+      mcc="226"
+      mnc="06"
+      apn="wnw"
+      user="wnw"
+      password="wnw"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange Internet"
+      carrier_id = "1011"
+      mcc="226"
+      mnc="10"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="Orange MMS"
+      carrier_id = "1011"
+      mcc="226"
+      mnc="10"
+      apn="mms"
+      user="mms"
+      password="mms"
+      mmsc="http://wap.mms.orange.ro:8002"
+      mmsproxy="62.217.247.252"
+      mmsport="8799"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Orange Internet"
+      carrier_id = "1011"
+      mcc="226"
+      mnc="10"
+      apn="net"
+      type="default"
+  />
+
+  <apn carrier="Swisscom MMS"
+      carrier_id = "2366"
+      mcc="228"
+      mnc="01"
+      apn="event.swisscom.ch"
+      mmsc="http://mms.natel.ch:8079"
+      mmsproxy="192.168.210.2"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Swisscom Services"
+      carrier_id = "2366"
+      mcc="228"
+      mnc="01"
+      apn="gprs.swisscom.ch"
+      proxy="192.168.210.1"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Sunrise live"
+      carrier_id = "1413"
+      mcc="228"
+      mnc="02"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Sunrise MMS"
+      carrier_id = "1413"
+      mcc="228"
+      mnc="02"
+      apn="mms.sunrise.ch"
+      mmsc="http://mmsc.sunrise.ch"
+      mmsproxy="212.35.34.75"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Orange Internet"
+      carrier_id = "1414"
+      mcc="228"
+      mnc="03"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange MMS"
+      carrier_id = "1414"
+      mcc="228"
+      mnc="03"
+      apn="mms"
+      mmsc="http://192.168.151.3:8002"
+      mmsproxy="192.168.151.2"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="netgprs.com"
+      carrier_id = "2271"
+      mcc="228"
+      mnc="03"
+      apn="netgprs.com"
+      user="tsl"
+      password="tsl"
+      type="default,supl"
+      mvno_match_data="CH-Transatel"
+      mvno_type="spn"
+   />
+
+   <apn carrier="netgprs.com"
+      carrier_id = "2271"
+      mcc="228"
+      mnc="03"
+      apn="netgprs.com"
+      user="tsl"
+      password="tsl"
+      type="default,supl"
+      mvno_match_data="BB00"
+      mvno_type="gid"
+  />
+
+  <apn carrier="T-Mobile CZ"
+      carrier_id = "2394"
+      mcc="230"
+      mnc="01"
+      apn=""
+      type="ia"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="T-Mobile IMS"
+      carrier_id = "2394"
+      mcc="230"
+      mnc="01"
+      apn="IMS"
+      type="ims"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="T-Mobile CZ"
+      carrier_id = "2394"
+      mcc="230"
+      mnc="01"
+      apn="internet.t-mobile.cz"
+      user="wap"
+      password="wap"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="T-Mobile MMS"
+      carrier_id = "2394"
+      mcc="230"
+      mnc="01"
+      apn="mms.t-mobile.cz"
+      user="mms"
+      password="mms"
+      mmsc="http://mms"
+      mmsproxy="10.0.0.10"
+      mmsport="80"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="O2 internet"
+      carrier_id = "1449"
+      mcc="230"
+      mnc="02"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="O2 MMS"
+      carrier_id = "1449"
+      mcc="230"
+      mnc="02"
+      apn="mms"
+      mmsc="http://mms.o2active.cz:8002"
+      mmsproxy="160.218.160.218"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "2398"
+      mcc="230"
+      mnc="03"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "2398"
+      mcc="230"
+      mnc="03"
+      apn="mms"
+      user="mms"
+      password="mms"
+      mmsc="http://mms"
+      mmsproxy="10.11.10.111"
+      mmsport="80"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Orange SK"
+      carrier_id = "1713"
+      mcc="231"
+      mnc="01"
+      apn="internet"
+      type="default"
+  />
+
+  <apn carrier="Orange SK MMS"
+      carrier_id = "1713"
+      mcc="231"
+      mnc="01"
+      apn="mms"
+      user="wap"
+      password="wap"
+      authtype="1"
+      mmsc="http://imms.orange.sk"
+      mmsproxy="213.151.208.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Orange World"
+      carrier_id = "1713"
+      mcc="231"
+      mnc="01"
+      apn="orangewap"
+      user="wap"
+      password="wap"
+      authtype="1"
+      proxy="213.151.208.156"
+      port="8799"
+      type="default,supl"
+  />
+
+  <apn carrier="T-Mobile internet"
+      carrier_id = "2385"
+      mcc="231"
+      mnc="02"
+      apn="internet"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="T-Mobile MMS"
+      carrier_id = "2385"
+      mcc="231"
+      mnc="02"
+      apn="mms"
+      user="mms"
+      password="mms"
+      authtype="1"
+      mmsc="http://mms"
+      mmsproxy="192.168.1.1"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="O2 internet"
+      carrier_id = "1988"
+      mcc="231"
+      mnc="06"
+      apn="o2internet"
+      type="default,supl"
+  />
+
+  <apn carrier="O2 MMS"
+      carrier_id = "1988"
+      mcc="231"
+      mnc="06"
+      apn="o2mms"
+      mmsc="http://mms.o2world.sk:8002"
+      mmsproxy="10.97.1.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="live!"
+      mcc="232"
+      mnc="01"
+      apn="a1.net"
+      user="ppp@a1plus.at"
+      password="ppp"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="A1 MMS"
+      mcc="232"
+      mnc="01"
+      apn="free.a1.net"
+      user="ppp@a1plus.at"
+      password="ppp"
+      mmsc="http://mmsc.a1.net"
+      mmsproxy="194.48.124.71"
+      mmsport="8001"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="T-Mobile Internet"
+      mcc="232"
+      mnc="03"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="T-Mobile LTE"
+      mcc="232"
+      mnc="03"
+      apn="internet.t-mobile.at"
+      user="t-mobile"
+      password="tm"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="T-Mobile MMS"
+      mcc="232"
+      mnc="03"
+      apn="gprsmms"
+      user="t-mobile"
+      password="tm"
+      mmsc="http://mmsc.t-mobile.at/servlets/mms"
+      mmsproxy="10.12.0.20"
+      mmsport="80"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Planet 3"
+      carrier_id = "1344"
+      mcc="232"
+      mnc="05"
+      apn="drei.at"
+      mmsc="http://mmsc"
+      mmsproxy="213.94.78.133"
+      mmsport="8799"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="tele.ring mms"
+      mcc="232"
+      mnc="07"
+      apn="mms"
+      user="wap@telering.at"
+      password="wap"
+      mmsc="http://relay.mms.telering.at"
+      mmsproxy="212.95.31.50"
+      mmsport="80"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="tele.ring web"
+      mcc="232"
+      mnc="07"
+      apn="web"
+      user="web@telering.at"
+      password="web"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Planet3"
+      carrier_id = "1344"
+      mcc="232"
+      mnc="10"
+      apn="drei.at"
+      mmsc="http://mmsc"
+      mmsproxy="213.94.78.133"
+      mmsport="8799"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="data.bob"
+      mcc="232"
+      mnc="11"
+      apn="bob.at"
+      user="data@bob.at"
+      password="ppp"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="data.bob MMS"
+      mcc="232"
+      mnc="11"
+      apn="mms.bob.at"
+      user="data@bob.at"
+      password="ppp"
+      mmsc="http://mmsc.bob.at"
+      mmsproxy="194.48.124.7"
+      mmsport="8001"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="yesss!"
+      mcc="232"
+      mnc="12"
+      apn="web.yesss.at"
+      type="default,supl"
+  />
+
+  <apn carrier="Plintron"
+      mcc="232"
+      mnc="22"
+      apn="data.plintron.at"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Plintron"
+  />
+
+  <apn carrier="UBIQUISYS"
+      carrier_id = "1491"
+      mcc="234"
+      mnc="01"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="O2 MOBILE WEB"
+      carrier_id = "1492"
+      mcc="234"
+      mnc="02"
+      apn="mobile.o2.co.uk"
+      user="O2web"
+      password="O2web"
+      type="default,supl"
+  />
+
+  <apn carrier="O2 MMS Prepay"
+      carrier_id = "1492"
+      mcc="234"
+      mnc="02"
+      apn="payandgo.o2.co.uk"
+      user="payandgo"
+      password="password"
+      mmsc="http://mmsc.mms.o2.co.uk:8002"
+      mmsproxy="82.132.254.1"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="O2 MMS Postpay"
+      carrier_id = "1492"
+      mcc="234"
+      mnc="02"
+      apn="wap.o2.co.uk"
+      user="o2wap"
+      password="password"
+      mmsc="http://mmsc.mms.o2.co.uk:8002"
+      mmsproxy="82.132.254.1"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="BT One Phone Internet"
+      carrier_id = "2103"
+      mcc="234"
+      mnc="08"
+      apn="internet.btonephone.com"
+      mvno_type="gid"
+      mvno_match_data="B2"
+      type="default,supl"
+  />
+
+  <apn carrier="BT One Phone MMS"
+      carrier_id = "2103"
+      mcc="234"
+      mnc="08"
+      apn="mms.btonephone.com"
+      mmsc="http://MMSC/"
+      mmsproxy="proxy.btonephone.com"
+      mmsport="8080"
+      mvno_type="gid"
+      mvno_match_data="B2"
+      type="mms"
+  />
+
+  <apn carrier="O2 Mobile Web"
+      carrier_id = "1492"
+      mcc="234"
+      mnc="10"
+      apn="mobile.o2.co.uk"
+      user="o2web"
+      password="password"
+      type="default,supl"
+  />
+
+  <apn carrier="O2 MMS"
+      carrier_id = "1492"
+      mcc="234"
+      mnc="10"
+      apn="wap.o2.co.uk"
+      user="o2wap"
+      password="password"
+      authtype="1"
+      mmsc="http://mmsc.mms.o2.co.uk:8002"
+      mmsproxy="82.132.254.1"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="O2 Pay &amp; Go"
+      carrier_id = "1492"
+      mcc="234"
+      mnc="10"
+      apn="payandgo.o2.co.uk"
+      proxy="82.132.254.1"
+      port="8080"
+      user="payandgo"
+      password="password"
+      mmsc="http://mmsc.mms.o2.co.uk:8002"
+      mmsproxy="82.132.254.1"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="TESCO"
+      carrier_id = "2093"
+      mcc="234"
+      mnc="10"
+      apn="prepay.tesco-mobile.com"
+      proxy="193.113.200.195"
+      port="8080"
+      user="tescowap"
+      password="password"
+      mmsc="http://mmsc.mms.o2.co.uk:8002"
+      mmsproxy="193.113.200.195"
+      mmsport="8080"
+      authtype="1"
+      type="default,supl,mms"
+      mvno_match_data="0A"
+      mvno_type="gid"
+  />
+
+  <apn carrier="giffgaff"
+      carrier_id = "2118"
+      mcc="234"
+      mnc="10"
+      apn="giffgaff.com"
+      authtype="1"
+      user="giffgaff"
+      password="password"
+      mmsc="http://mmsc.mediamessaging.co.uk:8002"
+      mmsproxy="193.113.200.195"
+      mmsport="8080"
+      mvno_type="spn"
+      mvno_match_data="giffgaff"
+  />
+
+  <apn carrier="Jump UK"
+      carrier_id = "2138"
+      mcc="234"
+      mnc="10"
+      apn="mobiledata"
+      authtype="0"
+      mvno_type="spn"
+      mvno_match_data="Jump"
+  />
+
+  <apn carrier="O2 MOBILE WEB"
+      carrier_id = "1492"
+      mcc="234"
+      mnc="11"
+      apn="mobile.o2.co.uk"
+      user="O2web"
+      password="O2web"
+      type="default,supl"
+  />
+
+  <apn carrier="O2 MMS Prepay"
+      carrier_id = "1492"
+      mcc="234"
+      mnc="11"
+      apn="payandgo.o2.co.uk"
+      user="payandgo"
+      password="password"
+      mmsc="http://mmsc.mms.o2.co.uk:8002"
+      mmsproxy="82.132.254.1"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="O2 MMS Postpay"
+      carrier_id = "1492"
+      mcc="234"
+      mnc="11"
+      apn="wap.o2.co.uk"
+      user="o2wap"
+      password="password"
+      mmsc="http://mmsc.mms.o2.co.uk:8002"
+      mmsproxy="82.132.254.1"
+      mmsport="8080"
+      type="mms"
+  />
+
+
+  <apn carrier="O2 MOBILE WEB"
+      carrier_id = "1492"
+      mcc="234"
+      mnc="11"
+      apn="mobile.o2.co.uk"
+      user="O2web"
+      password="O2web"
+      type="default,supl"
+  />
+
+  <apn carrier="O2 MMS Prepay"
+      carrier_id = "1492"
+      mcc="234"
+      mnc="11"
+      apn="payandgo.o2.co.uk"
+      user="payandgo"
+      password="password"
+      mmsc="http://mmsc.mms.02.co.uk:8002"
+      mmsproxy="82.132.254.1"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="O2 MMS Postpay"
+      carrier_id = "1492"
+      mcc="234"
+      mnc="11"
+      apn="wap.o2.co.uk"
+      user="o2wap"
+      password="password"
+      mmsc="http://mmsc.mms.02.co.uk:8002"
+      mmsproxy="82.132.254.1"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone UK"
+      mcc="234"
+      mnc="15"
+      apn="wap.vodafone.co.uk"
+      user="wap"
+      password="wap"
+      mmsc="http://mms.vodafone.co.uk/servlets/mms"
+      mmsproxy="212.183.137.12"
+      mmsport="8799"
+      authtype="1"
+      type="default,supl,mms"
+      user_editable="false"
+  />
+
+  <apn carrier="Vodafone UK Prepay"
+      mcc="234"
+      mnc="15"
+      apn="pp.vodafone.co.uk"
+      user="wap"
+      password="wap"
+      mmsc="http://mms.vodafone.co.uk/servlets/mms"
+      mmsproxy="212.183.137.12"
+      mmsport="8799"
+      authtype="1"
+      type="default,supl,mms"
+      user_editable="false"
+  />
+
+  <apn carrier="ASDA WAP"
+      mcc="234"
+      mnc="15"
+      apn="asdamobiles.co.uk"
+      proxy="212.183.137.12"
+      port="8799"
+      user="wap"
+      password="wap"
+      mmsc="http://mms.asdamobiles.co.uk/servlets/mms"
+      mmsproxy="212.183.137.12"
+      mmsport="8799"
+      authtype="1"
+      type="default,supl,mms"
+      mvno_match_data="A0"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Talkmob PAYG WAP"
+      mcc="234"
+      mnc="15"
+      apn="payg.talkmobile.co.uk"
+      proxy="212.183.137.12"
+      port="8799"
+      user="wap"
+      password="wap"
+      mmsc="http://mms.talkmobile.co.uk/servlets/mms"
+      mmsproxy="212.183.137.12"
+      mmsport="8799"
+      authtype="1"
+      type="default,supl,mms"
+      mvno_match_data="C1"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Talkmob WAP"
+      mcc="234"
+      mnc="15"
+      apn="talkmobile.co.uk"
+      proxy="212.183.137.12"
+      port="8799"
+      user="wap"
+      password="wap"
+      mmsc="http://mms.talkmobile.co.uk/servlets/mms"
+      mmsproxy="212.183.137.12"
+      mmsport="8799"
+      authtype="1"
+      type="default,supl,mms"
+      mvno_match_data="C1"
+      mvno_type="gid"
+  />
+
+  <apn carrier="TalkTalk WAP"
+      mcc="234"
+      mnc="15"
+      apn="mobile.talktalk.co.uk"
+      mmsc="http://mms.talktalk.co.uk/servlets/mms"
+      mmsproxy="212.183.137.12"
+      mmsport="8799"
+      type="default,supl,mms"
+      mvno_match_data="70"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Sainsbury's PAYG"
+      carrier_id = "2308"
+      mcc="234"
+      mnc="15"
+      apn="payg.mobilebysainsburys.co.uk"
+      authtype="1"
+      mmsc="http://mms.mobilebysainsburys.co.uk/servlets/mms"
+      mmsproxy="212.183.137.12"
+      mmsport="8799"
+      mvno_type="spn"
+      mvno_match_data="Sainsbury's"
+  />
+
+  <apn carrier="Lebara Internet"
+      carrier_id = "2309"
+      mcc="234"
+      mnc="15"
+      apn="uk.lebara.mobi"
+      authtype="1"
+      user="wap"
+      password="wap"
+      mmsc="http://mms.lebara.co.uk/servlets/mms"
+      mmsproxy="212.183.137.012"
+      mmsport="8799"
+      mvno_type="spn"
+      mvno_match_data="Lebara"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="3"
+      carrier_id = "1505"
+      mcc="234"
+      mnc="20"
+      apn="three.co.uk"
+      mmsc="http://mms.um.three.co.uk:10021/mmsc"
+      mmsproxy="mms.three.co.uk"
+      mmsport="8799"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="3 Hotspot"
+      carrier_id = "1505"
+      mcc="234"
+      mnc="20"
+      apn="3hotspot"
+      authtype="0"
+      type="dun"
+  />
+
+  <apn carrier="Lycamobile"
+      carrier_id = "2152"
+      mcc="234"
+      mnc="26"
+      apn="data.lycamobile.co.uk"
+      authtype="1"
+      user="lmuk"
+      password="plus"
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Virgin Media Mobile Internet"
+      carrier_id = "717"
+      mcc="234"
+      mnc="30"
+      apn="goto.virginmobile.uk"
+      user="user"
+      mmsc="http://mms.virginmobile.co.uk:8002"
+      mmsproxy="193.30.166.2"
+      mmsport="8080"
+      authtype="1"
+      type="default,supl,mms"
+      mvno_match_data="28"
+      mvno_type="gid"
+  />
+
+  <apn carrier="EE Internet"
+      carrier_id = "718"
+      mcc="234"
+      mnc="30"
+      apn="everywhere"
+      user="eesecure"
+      password="secure"
+      authtype="1"
+      type="default,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4"
+  />
+
+  <apn carrier="EE MMS"
+      carrier_id = "718"
+      mcc="234"
+      mnc="30"
+      apn="eezone"
+      user="eesecure"
+      password="secure"
+      mmsc="http://mms/"
+      mmsproxy="149.254.201.135"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+      protocol="IPV4"
+  />
+
+  <apn carrier="EE Emergency"
+      carrier_id = "718"
+      mcc="234"
+      mnc="30"
+      apn="SOS"
+      authtype="1"
+      type="Emergency"
+      protocol="IPV6"
+  />
+
+  <apn carrier="EE IMS"
+      carrier_id = "718"
+      mcc="234"
+      mnc="30"
+      apn="ims"
+      authtype="1"
+      type="ims"
+      protocol="IPV6"
+      roaming_protocol="IPV6"
+  />
+
+  <apn carrier="BT One Phone Internet"
+      carrier_id = "2103"
+      mcc="234"
+      mnc="30"
+      apn="internet.btonephone.com"
+      mvno_type="gid"
+      mvno_match_data="B2"
+      type="default,supl"
+  />
+
+  <apn carrier="BT One Phone MMS"
+      carrier_id = "2103"
+      mcc="234"
+      mnc="30"
+      apn="mms.btonephone.com"
+      mmsc="http://MMSC/"
+      mmsproxy="proxy.btonephone.com"
+      mmsport="8080"
+      mvno_type="gid"
+      mvno_match_data="B2"
+      type="mms"
+  />
+
+  <apn carrier="BT Internet"
+      carrier_id = "2102"
+      mcc="234"
+      mnc="30"
+      apn="everywhere"
+      user="eesecure"
+      password="secure"
+      authtype="1"
+      mvno_type="gid"
+      mvno_match_data="B3"
+      type="default,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4"
+  />
+
+  <apn carrier="BT MMS"
+      carrier_id = "2102"
+      mcc="234"
+      mnc="30"
+      apn="eezone"
+      user="eesecure"
+      password="secure"
+      authtype="1"
+      mmsc="http://mms/"
+      mmsproxy="149.254.201.135"
+      mmsport="8080"
+      mvno_type="gid"
+      mvno_match_data="B3"
+      type="mms"
+  />
+
+  <apn carrier="BT Emergency"
+      carrier_id = "2102"
+      mcc="234"
+      mnc="30"
+      apn="SOS"
+      authtype="1"
+      mvno_type="gid"
+      mvno_match_data="B3"
+      type="Emergency"
+      protocol="IPV6"
+  />
+
+  <apn carrier="BT IMS"
+      carrier_id = "2102"
+      mcc="234"
+      mnc="30"
+      apn="ims"
+      authtype="1"
+      mvno_type="gid"
+      mvno_match_data="B3"
+      type="ims"
+      protocol="IPV6"
+      roaming_protocol="IPV6"
+  />
+
+  <apn carrier="BT Internet"
+      carrier_id = "2101"
+      mcc="234"
+      mnc="30"
+      apn="everywhere"
+      user="eesecure"
+      password="secure"
+      authtype="1"
+      mvno_type="gid"
+      mvno_match_data="C3"
+      type="default,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4"
+  />
+
+  <apn carrier="BT MMS"
+      carrier_id = "2101"
+      mcc="234"
+      mnc="30"
+      apn="eezone"
+      user="eesecure"
+      password="secure"
+      authtype="1"
+      mmsc="http://mms/"
+      mmsproxy="149.254.201.135"
+      mmsport="8080"
+      mvno_type="gid"
+      mvno_match_data="C3"
+      type="mms"
+  />
+
+  <apn carrier="BT Emergency"
+      carrier_id = "2101"
+      mcc="234"
+      mnc="30"
+      apn="SOS"
+      authtype="1"
+      mvno_type="gid"
+      mvno_match_data="C3"
+      type="Emergency"
+      protocol="IPV6"
+  />
+
+  <apn carrier="BT IMS"
+      carrier_id = "2101"
+      mcc="234"
+      mnc="30"
+      apn="ims"
+      authtype="1"
+      mvno_type="gid"
+      mvno_match_data="C3"
+      type="ims"
+      protocol="IPV6"
+      roaming_protocol="IPV6"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "2283"
+      mcc="234"
+      mnc="33"
+      apn="tslpaygnet"
+      authtype="0"
+      type="default,supl,agps,fota,dun"
+      mvno_type="spn"
+      mvno_match_data="LIFE"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "2283"
+      mcc="234"
+      mnc="33"
+      apn="tslmms"
+      authtype="1"
+      user="wap"
+      password="wap"
+      mmsc="http://mms/"
+      mmsproxy="193.35.133.194"
+      mmsport="8080"
+      type="mms"
+      mvno_type="spn"
+      mvno_match_data="LIFE"
+  />
+
+  <apn carrier="EE Internet"
+      carrier_id = "718"
+      mcc="234"
+      mnc="33"
+      apn="everywhere"
+      user="eesecure"
+      password="secure"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="EE MMS"
+      carrier_id = "718"
+      mcc="234"
+      mnc="33"
+      apn="eezone"
+      user="eesecure"
+      password="secure"
+      mmsc="http://mms/"
+      mmsproxy="149.254.201.135"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="EE Emergency"
+      carrier_id = "718"
+      mcc="234"
+      mnc="33"
+      apn="SOS"
+      authtype="1"
+      type="Emergency"
+      protocol="IPV6"
+  />
+
+  <apn carrier="EE IMS"
+      carrier_id = "718"
+      mcc="234"
+      mnc="33"
+      apn="ims"
+      authtype="1"
+      type="ims"
+      protocol="IPV6"
+      roaming_protocol="IPV6"
+  />
+
+  <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="234"
+      mnc="25"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+  />
+
+  <apn carrier="Jump"
+      carrier_id = "2138"
+      mcc="234"
+      mnc="39"
+      apn="Jump"
+      mmsc="http://mmsc.mobi/servlets/mms"
+      mmsproxy="164.39.236.69"
+      mmsport="80"
+      protocol="IP"
+      roaming_protocol="IP"
+      mvno_type="spn"
+      mvno_match_data="Jump"
+  />
+
+  <apn carrier="Gamma Data"
+      carrier_id = "2137"
+      mcc="234"
+      mnc="39"
+      apn="gamma.co.uk"
+      mmsc="http://mms.gamma.co.uk/servlets/mms"
+      mmsproxy="164.39.236.69"
+      mmsport="80"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="EMnify"
+      carrier_id = "2326"
+      mcc="234"
+      mnc="50"
+      apn="em"
+      mvno_match_data="234500022"
+      mvno_type="imsi"
+      type="default,supl"
+  />
+
+  <apn carrier="Jersey Telecom"
+      carrier_id = "1506"
+      mcc="234"
+      mnc="50"
+      apn="mms"
+      user="mms"
+      password="mms"
+      mmsc="http://mms.surfmail.com/mmsc"
+      mmsproxy="212.9.19.199"
+      mmsport="3130"
+      type="mms"
+  />
+
+  <apn carrier="pepperWEB (Jersey)"
+      carrier_id = "1506"
+      mcc="234"
+      mnc="50"
+      apn="pepper"
+      type="default,supl"
+  />
+
+  <apn carrier="C&amp;W Guernsey Internet"
+      carrier_id = "720"
+      mcc="234"
+      mnc="55"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Sure Picture Messaging"
+      carrier_id = "720"
+      mcc="234"
+      mnc="55"
+      apn="mms"
+      mmsc="http://mmsc.gprs.cw.com/"
+      mmsproxy="10.0.3.101"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="3G HSDPA"
+      carrier_id = "1507"
+      mcc="234"
+      mnc="58"
+      apn="3gpronto"
+      type="default,supl"
+  />
+
+  <apn carrier="Manx Telecom Contract MMS"
+      carrier_id = "1507"
+      mcc="234"
+      mnc="58"
+      apn="mms.manxpronto.net"
+      user="mms"
+      password="mms"
+      mmsc="http://mms.manxpronto.net:8002"
+      mmsproxy="195.10.99.46"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Manx Telecom Prepay MMS"
+      carrier_id = "1507"
+      mcc="234"
+      mnc="58"
+      apn="mms.prontogo.net"
+      user="mmsgo"
+      password="mmsgo"
+      mmsc="http://mms.manxpronto.net:8002"
+      mmsproxy="195.10.99.41"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Manx Telecom Contract WEB"
+      carrier_id = "1507"
+      mcc="234"
+      mnc="58"
+      apn="web.manxpronto.net"
+      user="gprs"
+      password="gprs"
+      type="default,supl"
+  />
+
+  <apn carrier="EE Internet"
+      carrier_id = "718"
+      mcc="234"
+      mnc="86"
+      apn="everywhere"
+      user="eesecure"
+      password="secure"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="EE MMS"
+      carrier_id = "718"
+      mcc="234"
+      mnc="86"
+      apn="eezone"
+      user="eesecure"
+      password="secure"
+      mmsc="http://mms/"
+      mmsproxy="149.254.201.135"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="3hotspot"
+      carrier_id = "1505"
+      mcc="235"
+      mnc="94"
+      apn="3hotspot"
+      authtype="0"
+      type="dun"
+  />
+
+  <apn carrier="3"
+      carrier_id = "1505"
+      mcc="235"
+      mnc="94"
+      apn="three.co.uk"
+      mmsc="http://mms.um.three.co.uk:10021/mmsc"
+      mmsproxy="mms.three.co.uk"
+      mmsport="8799"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="DK TDC"
+      carrier_id = "1463"
+      mcc="238"
+      mnc="01"
+      apn="internet"
+      authtype="0"
+      type="default,supl,agps,fota,dun"
+  />
+
+  <apn carrier="DK TDC mms"
+      carrier_id = "1463"
+      mcc="238"
+      mnc="01"
+      apn="mms"
+      authtype="0"
+      mmsc="http://192.168.241.114:8002"
+      mmsproxy="194.182.251.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="TDC Internet"
+      mcc="238"
+      mnc="01"
+      apn="internet"
+      type="default,supl"
+      mvno_match_data="2380101xxxxxxxx"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="TDC MMS"
+      mcc="238"
+      mnc="01"
+      apn="mms"
+      mmsc="http://mmsc.tdc.dk:8002"
+      mmsproxy="194.182.251.15"
+      mmsport="8080"
+      type="mms"
+      mvno_match_data="2380101xxxxxxxx"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Telmore Internet"
+      carrier_id = "2284"
+      mcc="238"
+      mnc="01"
+      apn="internet"
+      type="default,supl"
+      mvno_type="spn"
+      mvno_match_data="TELMORE"
+  />
+
+  <apn carrier="Telmore MMS"
+      carrier_id = "2284"
+      mcc="238"
+      mnc="01"
+      apn="mms"
+      mmsproxy="194.182.251.15"
+      mmsport="8080"
+      mmsc="http://192.168.241.114:8002"
+      type="mms"
+      mvno_type="spn"
+      mvno_match_data="TELMORE"
+  />
+
+  <apn carrier="TELMORE WAP"
+      carrier_id = "2284"
+      mcc="238"
+      mnc="01"
+      apn="wap"
+      proxy="194.182.251.15"
+      port="8080"
+      authtype="0"
+      type="default"
+      mvno_type="spn"
+      mvno_match_data="TELMORE"
+  />
+
+   <apn carrier="GigSky"
+      carrier_id="2459"
+      mcc="238"
+      mnc="01"
+      apn="gigsky"
+      type="default"
+      mvno_type="spn"
+      mvno_match_data="GigSky"
+  />
+
+  <apn carrier="Telenor Internet"
+      carrier_id = "1464"
+      mcc="238"
+      mnc="02"
+      apn="Internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Telenor MMS"
+      carrier_id = "1464"
+      mcc="238"
+      mnc="02"
+      apn="telenor"
+      mmsc="http://mms.telenor.dk"
+      mmsproxy="212.88.64.8"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="3"
+      carrier_id = "1466"
+      mcc="238"
+      mnc="06"
+      apn="data.tre.dk"
+      mmsc="http://mms.3.dk/"
+      mmsproxy="mmsproxy.3.dk"
+      mmsport="8799"
+      type="default,supl,mms"
+      protocol="IPV4V6"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Telia SurfPort"
+      carrier_id = "656"
+      mcc="238"
+      mnc="20"
+      apn="www.internet.mtelia.dk"
+      type="default,supl"
+  />
+
+  <apn carrier="Telia MMS"
+      carrier_id = "656"
+      mcc="238"
+      mnc="20"
+      apn="www.mms.mtelia.dk"
+      mmsc="http://mms.telia.dk"
+      mmsproxy="193.209.134.131"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Call me Internet"
+      carrier_id = "2285"
+      mcc="238"
+      mnc="20"
+      apn="webSP"
+      type="default,supl"
+      mvno_type="spn"
+      mvno_match_data="Call me"
+  />
+
+  <apn carrier="Call me MMS"
+      carrier_id = "2285"
+      mcc="238"
+      mnc="20"
+      apn="mmsSP"
+      mmsproxy="193.209.134.131"
+      mmsport="8080"
+      mmsc="http://mms.telia.dk"
+      type="mms"
+      mvno_type="spn"
+      mvno_match_data="Call me"
+  />
+
+  <apn carrier="DLG Tele GPRS"
+      carrier_id = "2286"
+      mcc="238"
+      mnc="20"
+      apn="webSP"
+      type="default,supl"
+      mvno_type="spn"
+      mvno_match_data="DLG Tele"
+  />
+
+  <apn carrier="DLG Tele MMS"
+      carrier_id = "2286"
+      mcc="238"
+      mnc="20"
+      apn="mmsSP"
+      mmsproxy="193.209.134.131"
+      mmsport="8080"
+      mmsc="http://mms.telia.dk"
+      type="mms"
+      mvno_type="spn"
+      mvno_match_data="DLG Tele"
+  />
+
+  <apn carrier="Orange DE"
+      carrier_id = "656"
+      mcc="238"
+      mnc="30"
+      apn="web.orange.dk"
+      user=""
+      password=""
+  />
+
+  <apn carrier="Telenor Internet"
+      carrier_id = "657"
+      mcc="238"
+      mnc="77"
+      apn="Internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Telenor MMS"
+      carrier_id = "657"
+      mcc="238"
+      mnc="77"
+      apn="telenor"
+      mmsc="http://mms.telenor.dk"
+      mmsproxy="212.88.64.8"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Telia MMS"
+      carrier_id = "1690"
+      mcc="240"
+      mnc="01"
+      apn="mms.telia.se"
+      mmsc="http://mmss"
+      mmsproxy="193.209.134.132"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="Telia"
+      carrier_id = "1690"
+      mcc="240"
+      mnc="01"
+      apn="online.telia.se"
+      type="default,supl"
+  />
+
+  <apn carrier="Halebop Internet"
+      carrier_id = "2287"
+      mcc="240"
+      mnc="01"
+      apn="halebop.telia.se"
+      type="default,supl"
+      mvno_match_data="240017xxxxxxxxx"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Halebop MMS"
+      carrier_id = "2287"
+      mcc="240"
+      mnc="01"
+      apn="mms.telia.se"
+      mmsc="http://mmss"
+      mmsproxy="193.209.134.132"
+      mmsport="80"
+      type="mms"
+      mvno_match_data="240017xxxxxxxxx"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="3"
+      carrier_id = "1691"
+      mcc="240"
+      mnc="02"
+      apn="data.tre.se"
+      mmsc="http://mms.tre.se"
+      mmsproxy="mmsproxy.tre.se"
+      mmsport="8799"
+      type="default,supl,mms"
+      protocol="IPV4V6"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="3"
+      carrier_id = "1693"
+      mcc="240"
+      mnc="04"
+      apn="data.tre.se"
+      mmsc="http://mms.tre.se"
+      mmsproxy="mmsproxy.tre.se"
+      mmsport="8799"
+      type="default,supl,mms"
+      protocol="IPV4V6"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Tele2 Internet"
+      mcc="240"
+      mnc="05"
+      apn="4g.tele2.se"
+      type="default,supl"
+      mvno_match_data="Tele2"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Tele2 MMS"
+      mcc="240"
+      mnc="05"
+      apn="4g.tele2.se"
+      mmsc="http://mmsc.tele2.se"
+      mmsproxy="130.244.202.30"
+      mmsport="8080"
+      type="mms"
+      mvno_match_data="Tele2"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Tele2 Internet 3G"
+      mcc="240"
+      mnc="05"
+      apn="internet.tele2.se"
+      type="default,supl"
+      mvno_match_data="Tele2"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Tele2 MMS 3G"
+      mcc="240"
+      mnc="05"
+      apn="internet.tele2.se"
+      mmsc="http://mmsc.tele2.se"
+      mmsproxy="130.244.202.30"
+      mmsport="8080"
+      type="mms"
+      mvno_match_data="Tele2"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Telia MMS"
+      carrier_id = "1690"
+      mcc="240"
+      mnc="05"
+      apn="mms.telia.se"
+      mmsc="http://mmss"
+      mmsproxy="193.209.134.132"
+      mmsport="80"
+      type="mms"
+      mvno_match_data="Telia"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Telia"
+      carrier_id = "1690"
+      mcc="240"
+      mnc="05"
+      apn="online.telia.se"
+      type="default,supl"
+      mvno_match_data="Telia"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Halebop Internet"
+      carrier_id = "2287"
+      mcc="240"
+      mnc="05"
+      apn="halebop.telia.se"
+      type="default,supl"
+      mvno_match_data="Halebop"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Halebop MMS"
+      carrier_id = "2287"
+      mcc="240"
+      mnc="05"
+      apn="mms.telia.se"
+      mmsc="http://mmss"
+      mmsproxy="193.209.134.132"
+      mmsport="80"
+      type="mms"
+      mvno_match_data="Halebop"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "1695"
+      mcc="240"
+      mnc="06"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1695"
+      mcc="240"
+      mnc="06"
+      apn="mms"
+      mmsc="http://mms.media"
+      type="mms"
+  />
+
+  <apn carrier="Tele2 Internet"
+      carrier_id = "1696"
+      mcc="240"
+      mnc="07"
+      apn="4g.tele2.se"
+      type="default,supl"
+  />
+
+  <apn carrier="Tele2 MMS"
+      carrier_id = "1696"
+      mcc="240"
+      mnc="07"
+      apn="4g.tele2.se"
+      mmsc="http://mmsc.tele2.se"
+      mmsproxy="130.244.202.30"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Tele2 Internet 3G"
+      carrier_id = "1696"
+      mcc="240"
+      mnc="07"
+      apn="internet.tele2.se"
+      type="default,supl"
+  />
+
+  <apn carrier="Tele2 MMS 3G"
+      carrier_id = "1696"
+      mcc="240"
+      mnc="07"
+      apn="internet.tele2.se"
+      mmsc="http://mmsc.tele2.se"
+      mmsproxy="130.244.202.30"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Tele2 Internet"
+      mcc="240"
+      mnc="07"
+      apn="internet.tele2.no"
+      user="wap"
+      password="wap"
+      type="default,supl"
+      authtype="1"
+      mvno_match_data="2400768xxxxxxxx"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Tele2 MMS"
+      mcc="240"
+      mnc="07"
+      apn="internet.tele2.no"
+      mmsproxy="193.12.40.14"
+      mmsport="8080"
+      mmsc="http://mmsc.tele2.no"
+      type="mms"
+      mvno_match_data="2400768xxxxxxxx"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Jump"
+      carrier_id = "2138"
+      mcc="240"
+      mnc="07"
+      apn="Jump"
+      mmsc="http://mmsc.mobi/servlets/mms"
+      mmsproxy="164.39.236.69"
+      mmsport="80"
+      protocol="IP"
+      roaming_protocol="IP"
+      mvno_type="spn"
+      mvno_match_data="Jump"
+  />
+
+  <apn carrier="Gamma Data"
+      carrier_id = "2137"
+      mcc="240"
+      mnc="07"
+      apn="gamma.co.uk"
+      mmsc="http://mms.gamma.co.uk/servlets/mms"
+      mmsproxy="164.39.236.69"
+      mmsport="80"
+      protocol="IP"
+      roaming_protocol="IP"
+      mvno_type="imsi"
+      mvno_match_data="240075610"
+  />
+
+  <apn carrier="GigSky"
+      carrier_id="2459"
+      mcc="240"
+      mnc="07"
+      apn="gigsky"
+      type="default"
+      mvno_type="spn"
+      mvno_match_data="GigSky"
+  />
+
+  <apn carrier="Telenor Mobilsurf"
+      carrier_id = "1695"
+      mcc="240"
+      mnc="08"
+      apn="services.telenor.se"
+      type="default,supl"
+  />
+
+  <apn carrier="Telenor MMS"
+      carrier_id = "1695"
+      mcc="240"
+      mnc="08"
+      apn="mms"
+      mmsc="http://mms"
+      mmsproxy="172.30.253.241"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Com4"
+      carrier_id = "1956"
+      mcc="240"
+      mnc="09"
+      apn="com4"
+      type="default,supl"
+  />
+
+  <apn carrier="Spring data"
+      carrier_id = "1697"
+      mcc="240"
+      mnc="10"
+      apn="data.springmobil.se"
+      type="default,supl"
+  />
+
+  <apn carrier="Spring MMS"
+      carrier_id = "1697"
+      mcc="240"
+      mnc="10"
+      apn="mms.springmobil.se"
+      mmsc="http://mms.springmobil.se"
+      mmsproxy="213.88.184.37"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Halebop Internet"
+      mcc="240"
+      mnc="017"
+      apn="halebop.telia.se"
+      type="default,supl"
+  />
+
+  <apn carrier="Halebop MMS"
+      mcc="240"
+      mnc="017"
+      apn="mms.telia.se"
+      user="mms"
+      password="telia"
+      mmsc="http://mmss"
+      mmsproxy="193.209.134.132"
+      mmsport="9201"
+      type="mms"
+  />
+
+  <apn carrier="Tele2 Internet"
+      carrier_id = "1696"
+      mcc="240"
+      mnc="24"
+      apn="4g.tele2.se"
+      type="default,supl"
+      mvno_match_data="Tele2"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Tele2 MMS"
+      carrier_id = "1696"
+      mcc="240"
+      mnc="24"
+      apn="4g.tele2.se"
+      mmsc="http://mmsc.tele2.se"
+      mmsproxy="130.244.202.30"
+      mmsport="8080"
+      type="mms"
+      mvno_match_data="Tele2"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Tele2 Internet 3G"
+      carrier_id = "1696"
+      mcc="240"
+      mnc="24"
+      apn="internet.tele2.se"
+      type="default,supl"
+      mvno_match_data="Tele2"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Tele2 MMS 3G"
+      carrier_id = "1696"
+      mcc="240"
+      mnc="24"
+      apn="internet.tele2.se"
+      mmsc="http://mmsc.tele2.se"
+      mmsproxy="130.244.202.30"
+      mmsport="8080"
+      type="mms"
+      mvno_match_data="Tele2"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Ventelo Internett"
+      carrier_id = "2333"
+      mcc="242"
+      mnc="01"
+      apn="internet.ventelo.no"
+      type="default,supl"
+      mvno_match_data="24201700xxxxxxx"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Ventelo MMS"
+      carrier_id = "2333"
+      mcc="242"
+      mnc="01"
+      apn="mms.ventelo.no"
+      user="ventelo"
+      password="1111"
+      mmsc="http://mmsc/"
+      mmsproxy="10.10.10.11"
+      mmsport="8080"
+      type="mms"
+      authtype="1"
+      mvno_match_data="24201700xxxxxxx"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Telenor"
+      carrier_id = "958"
+      mcc="242"
+      mnc="01"
+      apn="telenor"
+      mmsc="http://mmsc"
+      mmsproxy="10.10.10.11"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="NetCom"
+      carrier_id = "959"
+      mcc="242"
+      mnc="02"
+      apn="netcom"
+      mmsc="http://mm/"
+      mmsproxy="212.169.66.4"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Chess MMS"
+      carrier_id = "2334"
+      mcc="242"
+      mnc="02"
+      apn="netcom"
+      user="mms"
+      password="netcom"
+      mmsproxy="212.169.66.4"
+      mmsport="8080"
+      mmsc="http://mm/"
+      type="mms"
+      authtype="1"
+      mvno_match_data="2420256xxxxxxxx"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Chess Internett"
+      carrier_id = "2334"
+      mcc="242"
+      mnc="02"
+      apn="netcom"
+      type="default,supl"
+      mvno_match_data="2420256xxxxxxxx"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Tele2 Internet"
+      carrier_id = "961"
+      mcc="242"
+      mnc="04"
+      apn="internet.tele2.no"
+      mmsc="http://mmsc.tele2.no"
+      mmsproxy="193.12.40.14"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="NwN Internet"
+      carrier_id = "1900"
+      mcc="242"
+      mnc="05"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="NwN MMS"
+      carrier_id = "1900"
+      mcc="242"
+      mnc="05"
+      apn="mms"
+      mmsc="http://mms.nwn.no"
+      mmsproxy="188.149.250.10"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="Com4"
+      carrier_id = "2134"
+      mcc="242"
+      mnc="09"
+      apn="com4"
+      type="default,supl"
+  />
+
+  <apn carrier="DNA Internet"
+      carrier_id = "1904"
+      mcc="244"
+      mnc="03"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="DNA MMS"
+      carrier_id = "1904"
+      mcc="244"
+      mnc="03"
+      apn="mms"
+      mmsc="http://mmsc.dna.fi"
+      mmsproxy="10.1.1.2"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="DNA Internet"
+      carrier_id = "682"
+      mcc="244"
+      mnc="04"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="DNA MMS"
+      carrier_id = "682"
+      mcc="244"
+      mnc="04"
+      apn="mms"
+      user="dna"
+      password="mms"
+      mmsc="http://mmsc.dnafinland.fi/"
+      mmsproxy="10.1.1.2"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Elisa Internet"
+      carrier_id = "1475"
+      mcc="244"
+      mnc="05"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Elisa MMS"
+      carrier_id = "1475"
+      mcc="244"
+      mnc="05"
+      apn="mms"
+      mmsc="http://mms.elisa.fi"
+      mmsproxy="213.161.41.57"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="Saunalahti Internet"
+      carrier_id = "1479"
+      mcc="244"
+      mnc="05"
+      apn="internet.saunalahti"
+      type="default,supl"
+      mvno_match_data="2440541"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Saunalahti MMS"
+      carrier_id = "1479"
+      mcc="244"
+      mnc="05"
+      apn="mms.saunalahti.fi"
+      mmsc="http://mms.saunalahti.fi:8002/"
+      mmsproxy="62.142.4.197"
+      mmsport="8080"
+      type="mms"
+      mvno_match_data="2440541"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="TDC Internet"
+      carrier_id = "1907"
+      mcc="244"
+      mnc="10"
+      apn="internet.song.fi"
+      user="song@internet"
+      password="songnet"
+      type="default,supl"
+  />
+
+  <apn carrier="TDC MMS"
+      carrier_id = "1907"
+      mcc="244"
+      mnc="10"
+      apn="mms.song.fi"
+      mmsc="http://mms.song.fi"
+      mmsproxy="213.161.41.58"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="DNA Internet"
+      carrier_id = "1904"
+      mcc="244"
+      mnc="12"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="DNA MMS"
+      carrier_id = "1904"
+      mcc="244"
+      mnc="12"
+      apn="mms"
+      mmsc="http://mmsc.dna.fi"
+      mmsproxy="10.1.1.2"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="DNA Pro Internet"
+      carrier_id = "1904"
+      mcc="244"
+      mnc="12"
+      apn="dnapro.fi"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="DNA Pro MMS"
+      carrier_id = "1904"
+      mcc="244"
+      mnc="12"
+      apn="mms.dnapro.fi"
+      mmsc="http://mmsc.dnapro.fi/"
+      mmsproxy="10.1.1.21"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="TDC Internet Finland"
+      carrier_id = "1904"
+      mcc="244"
+      mnc="12"
+      apn="inet.tdc.fi"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="TDC MMS Finland"
+      carrier_id = "1904"
+      mcc="244"
+      mnc="12"
+      apn="mms.tdc.fi"
+      mmsc="http://mmsc.tdc.fi"
+      mmsproxy="10.1.12.2"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="DNA Internet"
+      carrier_id = "1904"
+      mcc="244"
+      mnc="13"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="DNA MMS"
+      carrier_id = "1904"
+      mcc="244"
+      mnc="13"
+      apn="mms"
+      user="dna"
+      password="mms"
+      mmsc="http://mmsc.dnafinland.fi/"
+      mmsproxy="10.1.1.2"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Saunalahti Internet"
+      carrier_id = "1479"
+      mcc="244"
+      mnc="21"
+      apn="internet.saunalahti"
+      type="default,supl"
+  />
+
+  <apn carrier="Saunalahti MMS"
+      carrier_id = "1479"
+      mcc="244"
+      mnc="21"
+      apn="mms.saunalahti.fi"
+      mmsc="http://mms.saunalahti.fi:8002/"
+      mmsproxy="62.142.4.197"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="SONERA Internet"
+      carrier_id = "1480"
+      mcc="244"
+      mnc="91"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="SONERA MMS"
+      carrier_id = "1480"
+      mcc="244"
+      mnc="91"
+      apn="wap.sonera.net"
+      mmsc="http://mms.sonera.fi:8002"
+      mmsproxy="195.156.25.33"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="Omnitel MMS"
+      carrier_id = "892"
+      mcc="246"
+      mnc="01"
+      apn="gprs.mms.lt"
+      user="mms"
+      password="mms"
+      mmsc="http://mms.omnitel.net:8002/"
+      mmsproxy="194.176.32.149"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Omnitel Internet"
+      carrier_id = "892"
+      mcc="246"
+      mnc="01"
+      apn="omnitel"
+      user="omni"
+      password="omni"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Bite Internet"
+      carrier_id = "893"
+      mcc="246"
+      mnc="02"
+      apn="wap"
+      type="default,supl"
+  />
+
+  <apn carrier="Bite MMS"
+      carrier_id = "893"
+      mcc="246"
+      mnc="02"
+      apn="mms"
+      user="mms@mms"
+      password="mms"
+      mmsc="http://mmsc/servlets/mms"
+      mmsproxy="192.168.150.2"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Tele2 Internet LT"
+      carrier_id = "894"
+      mcc="246"
+      mnc="03"
+      apn="internet.tele2.lt"
+      mmsc="http://mmsc.tele2.lt/"
+      mmsproxy="193.12.40.29"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Test FOTA"
+      mcc="246"
+      mnc="081"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Test FOTA"
+      mcc="246"
+      mnc="081"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Test CBS"
+      mcc="246"
+      mnc="081"
+      apn="VZWAPP"
+      type="cbs,mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Test CBS"
+      mcc="246"
+      mnc="081"
+      apn="VZWAPP"
+      type="cbs,mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Test IMS"
+      mcc="246"
+      mnc="081"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Test IMS"
+      mcc="246"
+      mnc="081"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Test Internet"
+      mcc="246"
+      mnc="081"
+      apn="VZWINTERNET"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      type="default,dun"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      authtype="3"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Test Internet"
+      mcc="246"
+      mnc="081"
+      apn="VZWINTERNET"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      type="default,dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      profile_id="0"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Test Internet"
+      mcc="246"
+      mnc="081"
+      apn="VZWINTERNET"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      type="default,dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      profile_id="0"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Test FOTA"
+      mcc="246"
+      mnc="81"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      profile_id="3"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Test FOTA"
+      mcc="246"
+      mnc="81"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      profile_id="3"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Test CBS"
+      mcc="246"
+      mnc="81"
+      apn="VZWAPP"
+      type="cbs,mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      profile_id="4"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Test CBS"
+      mcc="246"
+      mnc="81"
+      apn="VZWAPP"
+      type="cbs,mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      profile_id="4"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Test IMS"
+      mcc="246"
+      mnc="81"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      profile_id="2"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Test IMS"
+      mcc="246"
+      mnc="81"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      profile_id="2"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Test Internet"
+      mcc="246"
+      mnc="81"
+      apn="VZWINTERNET"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      type="default,dun"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      authtype="3"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Test Internet"
+      mcc="246"
+      mnc="81"
+      apn="VZWINTERNET"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      type="default,dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      profile_id="0"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Test Internet"
+      mcc="246"
+      mnc="81"
+      apn="VZWINTERNET"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      type="default,dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      profile_id="0"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="LMT Internet"
+      carrier_id = "898"
+      mcc="247"
+      mnc="01"
+      apn="internet.lmt.lv"
+      type="default,supl"
+  />
+
+  <apn carrier="LMT MMS"
+      carrier_id = "898"
+      mcc="247"
+      mnc="01"
+      apn="internet.lmt.lv"
+      mmsc="http://mmsc.lmt.lv/mmsc"
+      type="mms"
+  />
+
+  <apn carrier="Tele2 LV Internet"
+      carrier_id = "899"
+      mcc="247"
+      mnc="02"
+      apn="internet.tele2.lv"
+      type="default,supl"
+  />
+
+  <apn carrier="Tele2 LV MMS"
+      carrier_id = "899"
+      mcc="247"
+      mnc="02"
+      apn="mms.tele2.lv"
+      user="wap"
+      password="wap"
+      mmsc="http://mmsc.tele2.lv/"
+      mmsproxy="193.12.40.38"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Bite LV Internet"
+      carrier_id = "2037"
+      mcc="247"
+      mnc="05"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Bite LV MMS"
+      carrier_id = "2037"
+      mcc="247"
+      mnc="05"
+      apn="mms"
+      user="mms@mms"
+      password="mms"
+      mmsc="http://mmsc/servlets/mms"
+      mmsproxy="192.168.150.2"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Bite LV WAP"
+      carrier_id = "2037"
+      mcc="247"
+      mnc="05"
+      apn="wap"
+      proxy="213.226.131.133"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="EMT Internet"
+      carrier_id = "667"
+      mcc="248"
+      mnc="01"
+      apn="internet.emt.ee"
+      type="default,supl"
+  />
+
+  <apn carrier="EMT MMS"
+      carrier_id = "667"
+      mcc="248"
+      mnc="01"
+      apn="mms.emt.ee"
+      mmsc="http://mms.emt.ee/servlets/mms"
+      mmsproxy="217.71.32.82"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="EMT WAP"
+      carrier_id = "667"
+      mcc="248"
+      mnc="01"
+      apn="wap.emt.ee"
+      proxy="217.71.32.236"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Send"
+      carrier_id = "2332"
+      mcc="248"
+      mnc="01"
+      apn="send.ee"
+      mmsc="http://mms.emt.ee/servlets/mms"
+      mmsproxy="217.71.32.82"
+      mmsport="8080"
+      type="default,supl,mms"
+      mvno_match_data="248010x2"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Send"
+      carrier_id = "2332"
+      mcc="248"
+      mnc="01"
+      apn="send.ee"
+      mmsc="http://mms.emt.ee/servlets/mms"
+      mmsproxy="217.71.32.82"
+      mmsport="8080"
+      type="default,supl,mms"
+      mvno_match_data="248010x3"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Elisa Internet"
+      carrier_id = "668"
+      mcc="248"
+      mnc="02"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Elisa MMS"
+      carrier_id = "668"
+      mcc="248"
+      mnc="02"
+      apn="mms"
+      mmsc="http://194.204.2.10"
+      mmsproxy="194.204.2.6"
+      mmsport="8000"
+      type="mms"
+  />
+
+  <apn carrier="Elisa WAP"
+      carrier_id = "668"
+      mcc="248"
+      mnc="02"
+      apn="wap"
+      proxy="194.204.2.6"
+      port="8000"
+      type="default,supl"
+  />
+
+  <apn carrier="Tele2 Internet"
+      carrier_id = "669"
+      mcc="248"
+      mnc="03"
+      apn="internet.tele2.ee"
+      type="default,supl"
+  />
+
+  <apn carrier="Tele2 MMS"
+      carrier_id = "669"
+      mcc="248"
+      mnc="03"
+      apn="mms.tele2.ee"
+      mmsc="http://mmsc.tele2.ee"
+      mmsproxy="193.12.40.6"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Smart/Ultra MMS"
+      carrier_id = "669"
+      mcc="248"
+      mnc="03"
+      apn="internet.tele2.ee"
+      mmsc="http://mmsc.tele2.ee"
+      mmsproxy="193.12.40.6"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="MTS Internet"
+      carrier_id = "1678"
+      mcc="250"
+      mnc="01"
+      apn="internet.mts.ru"
+      user="mts"
+      password="mts"
+      authtype="1"
+      type="default,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="MTS MMS"
+      carrier_id = "1678"
+      mcc="250"
+      mnc="01"
+      apn="mms.mts.ru"
+      user="mts"
+      password="mts"
+      mmsc="http://mmsc"
+      mmsproxy="192.168.192.192"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Megafon Internet"
+      carrier_id = "1016"
+      mcc="250"
+      mnc="02"
+      apn="internet"
+      user=""
+      password=""
+      type="default,supl"
+  />
+
+  <apn carrier="Megafon MMS"
+      carrier_id = "1016"
+      mcc="250"
+      mnc="02"
+      apn="mms"
+      user="mms"
+      password="mms"
+      mmsc="http://mmsc:8002"
+      mmsproxy="10.10.10.10"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="YOTA Internet"
+      carrier_id = "1022"
+      mcc="250"
+      mnc="11"
+      apn="yota.ru"
+      type="default,supl"
+  />
+
+  <apn carrier="TELE2 Internet"
+      carrier_id = "1028"
+      mcc="250"
+      mnc="20"
+      apn="internet.tele2.ru"
+      type="default,supl"
+  />
+
+  <apn carrier="TELE2 MMS"
+      carrier_id = "1028"
+      mcc="250"
+      mnc="20"
+      apn="mms.tele2.ru"
+      mmsc="http://mmsc.tele2.ru"
+      mmsproxy="193.12.40.65"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="VTB Mobile"
+      carrier_id = "2448"
+      mcc="250"
+      mnc="26"
+      apn="vtb"
+      user=""
+      password=""
+      type="default,supl"
+  />
+
+  <apn carrier="VODA internet"
+      carrier_id = "1029"
+      mcc="250"
+      mnc="28"
+      apn="vodalte.ru"
+      type="default,supl"
+  />
+
+  <apn carrier="Next Mobile"
+      carrier_id="2444"
+      mcc="250"
+      mnc="47"
+      apn="Next"
+      user=""
+      password=""
+      type="default,supl"
+  />
+
+  <apn carrier="Tinkoff Mobile"
+      carrier_id = "2142"
+      mcc="250"
+      mnc="62"
+      apn="m.tinkoff"
+      user=""
+      password=""
+      type="default,supl"
+  />
+
+  <apn carrier="Beeline Internet"
+      carrier_id = "1681"
+      mcc="250"
+      mnc="99"
+      apn="internet.beeline.ru"
+      user="beeline"
+      password="beeline"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Beeline MMS"
+      carrier_id = "1681"
+      mcc="250"
+      mnc="99"
+      apn="mms.beeline.ru"
+      user="beeline"
+      password="beeline"
+      mmsc="http://mms/"
+      mmsproxy="192.168.94.23"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="MTS MMS"
+      carrier_id = "1746"
+      mcc="255"
+      mnc="01"
+      apn="mms"
+      mmsc="http://mmsc:8002/"
+      mmsproxy="192.168.10.10"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="MTS-internet"
+      carrier_id = "1746"
+      mcc="255"
+      mnc="01"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Beeline-internet"
+      carrier_id = "12"
+      mcc="255"
+      mnc="02"
+      apn="internet.beeline.ua"
+      type="default,supl"
+  />
+
+  <apn carrier="Beeline MMS"
+      carrier_id = "12"
+      mcc="255"
+      mnc="02"
+      apn="mms.beeline.ua"
+      mmsc="http://mms/"
+      mmsproxy="172.29.18.192"
+      mmsport="8080"
+      type="mms"
+  />
+
+
+  <apn carrier="Kyivstar MMS"
+      carrier_id = "1747"
+      mcc="255"
+      mnc="03"
+      apn="mms.kyivstar.net"
+      user="mms"
+      password="mms"
+      authtype="1"
+      mmsc="http://mms.kyivstar.net"
+      mmsproxy="10.10.10.10"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Kyivstar Internet"
+      carrier_id = "1747"
+      mcc="255"
+      mnc="03"
+      apn="www.kyivstar.net"
+      user="igprs"
+      password="internet"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Djuice MMS"
+      carrier_id = "2331"
+      mcc="255"
+      mnc="03"
+      apn="mms.djuice.com.ua"
+      user="djuice"
+      password="mms"
+      authtype="1"
+      mmsc="http://mms.kyivstar.net"
+      mmsproxy="10.10.10.10"
+      mmsport="8080"
+      type="mms"
+      mvno_match_data="DJUICE"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Djuice Internet"
+      carrier_id = "2331"
+      mcc="255"
+      mnc="03"
+      apn="www.djuice.com.ua"
+      type="default,supl"
+      mvno_match_data="DJUICE"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Life:) internet"
+      carrier_id = "1750"
+      mcc="255"
+      mnc="06"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Life:) MMS"
+      carrier_id = "1750"
+      mcc="255"
+      mnc="06"
+      apn="mms"
+      mmsc="http://mms.life.com.ua/cmmsc/post"
+      mmsproxy="212.58.162.230"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Utel Internet"
+      carrier_id = "1751"
+      mcc="255"
+      mnc="07"
+      apn="3g.utel.ua"
+      type="default,supl"
+  />
+
+  <apn carrier="Utel MMS"
+      carrier_id = "1751"
+      mcc="255"
+      mnc="07"
+      apn="3g.utel.ua"
+      mmsc="http://10.212.1.4/mms/wapenc"
+      mmsproxy="10.212.3.148"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Velcom Internet"
+      carrier_id = "568"
+      mcc="257"
+      mnc="01"
+      apn="web.velcom.by"
+      authtype="1"
+      proxy="10.200.15.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Velcom MMS"
+      carrier_id = "568"
+      mcc="257"
+      mnc="01"
+      apn="mms.velcom.by"
+      user="mms"
+      password="mms"
+      authtype="1"
+      mmsc="http://mmsc"
+      mmsproxy="10.200.15.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="MTS Internet"
+      carrier_id = "569"
+      mcc="257"
+      mnc="02"
+      apn="mts"
+      user="mts"
+      password="mts"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MTS MMS"
+      carrier_id = "569"
+      mcc="257"
+      mnc="02"
+      apn="mts"
+      user="mts"
+      password="mts"
+      authtype="1"
+      mmsc="http://mmsc"
+      mmsproxy="192.168.192.192"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="life:) Internet"
+      carrier_id = "1950"
+      mcc="257"
+      mnc="04"
+      apn="internet.life.com.by"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="life:) MMS"
+      carrier_id = "1950"
+      mcc="257"
+      mnc="04"
+      apn="mms.life.com.by"
+      authtype="1"
+      mmsc="http://mms.life.com.by/mmsc/"
+      mmsproxy="10.10.10.20"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Orange_Internet_GPRS"
+      carrier_id = "904"
+      mcc="259"
+      mnc="01"
+      apn="wap.orange.md"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange_MMS_GPRS"
+      carrier_id = "904"
+      mcc="259"
+      mnc="01"
+      apn="mms.orange.md"
+      mmsc="http://mms/mms"
+      mmsproxy="192.168.127.125"
+      mmsport="3128"
+      type="mms"
+  />
+
+  <apn carrier="Moldcell Internet"
+      carrier_id = "905"
+      mcc="259"
+      mnc="02"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Moldcell MMS"
+      carrier_id = "905"
+      mcc="259"
+      mnc="02"
+      apn="mms"
+      mmsc="http://mms.moldcell.md/cmmsc/post"
+      mmsproxy="10.0.10.10"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Unite Internet PrePay"
+      carrier_id = "2153"
+      mcc="259"
+      mnc="05"
+      apn="internet3g.unite.md"
+      type="default,supl"
+  />
+
+  <apn carrier="Unite Internet PostPay"
+      carrier_id = "2153"
+      mcc="259"
+      mnc="05"
+      apn="internet.unite.md"
+      type="default,supl"
+  />
+
+  <apn carrier="Unite MMS"
+      carrier_id = "2153"
+      mcc="259"
+      mnc="05"
+      apn="mms.unite.md"
+      mmsc="http://10.32.15.68:38090/was"
+      mmsproxy="10.32.15.164"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Orange MMS"
+      apn="mms.orange.md"
+      mmsc="http://mms/mms"
+      mmsproxy="192.168.127.125"
+      mmsport="3128"
+      carrier_id = "904"
+      mcc="259"
+      mnc="01"
+      type="mms"
+  />
+
+  <apn carrier="Plus Internet"
+      carrier_id = "1658"
+      mcc="260"
+      mnc="01"
+      apn="plus"
+      type="default,supl"
+  />
+
+  <apn carrier="Plus MMS"
+      carrier_id = "1658"
+      mcc="260"
+      mnc="01"
+      apn="mms"
+      mmsc="http://mms.plusgsm.pl:8002"
+      mmsproxy="212.2.96.16"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="T-mobile.pl"
+      carrier_id = "2367"
+      mcc="260"
+      mnc="02"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="T-mobile.pl"
+      carrier_id = "2367"
+      mcc="260"
+      mnc="02"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="T-mobile.pl"
+      carrier_id = "2367"
+      mcc="260"
+      mnc="02"
+      apn="mms"
+      mmsc="http://mms/servlets/mms"
+      mmsproxy="213.158.194.226"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="heyahinternet"
+      carrier_id = "2367"
+      mcc="260"
+      mnc="02"
+      apn="heyah.pl"
+      type="default,supl"
+  />
+
+  <apn carrier="heyahmms"
+      carrier_id = "2367"
+      mcc="260"
+      mnc="02"
+      apn="heyahmms"
+      mmsc="http://mms.heyah.pl/servlets/mms"
+      mmsproxy="213.158.194.226"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Orange Internet"
+      carrier_id = "1659"
+      mcc="260"
+      mnc="03"
+      apn="Internet"
+      user="internet"
+      password="internet"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange MMS"
+      carrier_id = "1659"
+      mcc="260"
+      mnc="03"
+      apn="mms"
+      user="mms"
+      password="mms"
+      mmsc="http://mms.orange.pl"
+      mmsproxy="192.168.6.104"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Play Internet"
+      carrier_id = "1662"
+      mcc="260"
+      mnc="06"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Play MMS"
+      carrier_id = "1662"
+      mcc="260"
+      mnc="06"
+      apn="mms"
+      mmsc="http://mmsc.play.pl/mms/wapenc"
+      type="mms"
+  />
+
+  <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="260"
+      mnc="33"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+  />
+
+  <apn carrier="Rebtel"
+      carrier_id = "2229"
+      mcc="260"
+      mnc="44"
+      apn="rebtel"
+      mmsc="http://mmsc.rebtel.com"
+      mmsproxy="185.114.248.80"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Telekom Internet"
+      carrier_id = "2395"
+      mcc="262"
+      mnc="01"
+      apn="internet.telekom"
+      user="telekom"
+      password="telekom"
+      authtype="1"
+      type="default,supl,ia"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="Telekom Internet"
+      carrier_id = "2395"
+      mcc="262"
+      mnc="01"
+      apn="internet.telekom"
+      user="telekom"
+      password="telekom"
+      mmsc="http://mms.t-mobile.de/servlets/mms"
+      mmsproxy="109.237.176.193"
+      mmsport="8008"
+      bearer_bitmask="1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17"
+      authtype="1"
+      type="mms"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="Telekom Internet"
+      carrier_id = "2395"
+      mcc="262"
+      mnc="01"
+      apn="hos"
+      user="telekom"
+      password="telekom"
+      mmsc="http://mms.t-mobile.de/servlets/mms"
+      mmsproxy="109.237.176.193"
+      mmsport="8008"
+      bearer_bitmask="18"
+      authtype="1"
+      type="mms"
+      protocol="IPV4V6"
+      user_visible="false"
+  />
+
+  <apn carrier="Telekom Internet"
+      carrier_id = "2310"
+      mcc="262"
+      mnc="01"
+      apn="internet.telekom"
+      user="telekom"
+      password="telekom"
+      authtype="1"
+      mmsproxy="172.28.23.131"
+      mmsc="http://mms.t-mobile.de/servlets/mms"
+      mmsport="8008"
+      mvno_match_data="debitel"
+      mvno_type="spn"
+      protocol="IP"
+  />
+
+  <apn carrier="Vodafone DE"
+      carrier_id = "2397"
+      mcc="262"
+      mnc="02"
+      apn=""
+      type="ia"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="Vodafone DE-MMS"
+      carrier_id = "2397"
+      mcc="262"
+      mnc="02"
+      apn="event.vodafone.de"
+      mmsc="http://139.7.24.1/servlets/mms"
+      mmsproxy="139.7.29.17"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone DE"
+      carrier_id = "2397"
+      mcc="262"
+      mnc="02"
+      apn="web.vodafone.de"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone DE-IMS"
+      carrier_id = "2397"
+      mcc="262"
+      mnc="02"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="E-Plus Internet"
+      carrier_id = "1453"
+      mcc="262"
+      mnc="03"
+      apn="internet.eplus.de"
+      user="eplus"
+      password="internet"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="E-Plus MMS"
+      carrier_id = "1453"
+      mcc="262"
+      mnc="03"
+      apn="mms.eplus.de"
+      user="mms"
+      password="eplus"
+      mmsc="http://mms/eplus/"
+      mmsproxy="212.23.97.153"
+      mmsport="5080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="MVNO DE"
+     carrier_id = "2461"
+     mcc="262"
+     mnc="03"
+     apn="internet.mvno.mobi"
+     user="mvno"
+     password="mvno"
+     authtype="1"
+     type="default,supl"
+     mvno_match_data="26203483"
+     mvno_type="imsi"
+  />
+
+  <apn carrier="o2 Internet"
+      mcc="262"
+      mnc="07"
+      apn="internet"
+      mmsc="http://10.81.0.7:8002"
+      mmsproxy="82.113.100.5"
+      mmsport="8080"
+      type="default,supl,mms"
+      mvno_match_data="2620739"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="O2 DE IMS"
+      carrier_id = "1454"
+      mcc="262"
+      mnc="07"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="o2 Internet Prepaid"
+      mcc="262"
+      mnc="07"
+      apn="pinternet.interkom.de"
+      mmsc="http://10.81.0.7:8002"
+      mmsproxy="82.113.100.6"
+      mmsport="8080"
+      type="default,supl,mms"
+      mvno_match_data="2620749"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Fonic Prepaid"
+      carrier_id = "2328"
+      mcc="262"
+      mnc="07"
+      apn="pinternet.interkom.de"
+      mmsc="http://10.81.0.7:8002"
+      mmsproxy="82.113.100.6"
+      mmsport="8080"
+      type="default,supl,mms"
+      mvno_match_data="26207515"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Lidl Mobile"
+      carrier_id = "2329"
+      mcc="262"
+      mnc="07"
+      apn="pinternet.interkom.de"
+      mmsc="http://10.81.0.7:8002"
+      mmsproxy="82.113.100.6"
+      mmsport="8080"
+      type="default,supl,mms"
+      mvno_match_data="26207520"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Tchibo Internet"
+      carrier_id = "2330"
+      mcc="262"
+      mnc="07"
+      apn="webmobil1"
+      mmsc="http://10.81.0.7:8002"
+      mmsproxy="82.113.100.8"
+      mmsport="8080"
+      type="default,supl,mms"
+      mvno_match_data="26207500"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="O2 DE IMS"
+      carrier_id = "1454"
+      mcc="262"
+      mnc="08"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="MVNO DE"
+     carrier_id = "2461"
+     mcc="262"
+     mnc="20"
+     apn="internet.mvno.mobi"
+     user="mvno"
+     password="mvno"
+     authtype="1"
+     type="default,supl"
+     mvno_match_data="26220"
+     mvno_type="imsi"
+  />
+
+  <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="262"
+      mnc="42"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+  />
+
+  <apn carrier="Vodafone Net2"
+      mcc="268"
+      mnc="01"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="Vodafone Net2"
+      mcc="268"
+      mnc="01"
+      apn="net2.vodafone.pt"
+      user="vodafone"
+      password="vodafone"
+      authtype="1"
+      mmsc="http://mms.vodafone.pt/servlets/mms"
+      mmsproxy="iproxy.vodafone.pt"
+      mmsport="80"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="vodafone P dun"
+      mcc="268"
+      mnc="01"
+      apn="internet.vodafone.pt"
+      authtype="0"
+      type="dun"
+  />
+
+  <apn carrier="PortalOptimus"
+      carrier_id = "1668"
+      mcc="268"
+      mnc="03"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="PortalOptimus"
+      carrier_id = "1668"
+      mcc="268"
+      mnc="03"
+      apn="umts"
+      mmsc="http://mmsc:10021/mmsc"
+      mmsproxy="62.169.66.5"
+      mmsport="8799"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Optimus HotSpot"
+      carrier_id = "1668"
+      mcc="268"
+      mnc="03"
+      apn="modem"
+      type="dun"
+  />
+
+  <apn carrier="tmn internet"
+      carrier_id = "1670"
+      mcc="268"
+      mnc="06"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="tmn internet"
+      carrier_id = "1670"
+      mcc="268"
+      mnc="06"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="mms tmn"
+      carrier_id = "1670"
+      mcc="268"
+      mnc="06"
+      apn="mmsc.tmn.pt"
+      user="tmn"
+      password="tmnnet"
+      authtype="1"
+      mmsc="http://mmsc/"
+      mmsproxy="10.111.2.16"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="LUXGSM MMS"
+      carrier_id = "895"
+      mcc="270"
+      mnc="01"
+      apn="mms.pt.lu"
+      user="mms"
+      password="mms"
+      mmsc="http://mmsc.pt.lu"
+      mmsproxy="194.154.192.88"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="LUXGSM WAP"
+      carrier_id = "895"
+      mcc="270"
+      mnc="01"
+      apn="wap.pt.lu"
+      user="wap"
+      password="wap"
+      proxy="194.154.192.98"
+      port="8080"
+      type="default,supl"
+  />
+
+   <apn carrier="MTXC"
+      mcc="270"
+      mnc="02"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Tango WAP"
+      carrier_id = "896"
+      mcc="270"
+      mnc="77"
+      apn="internet"
+      user="tango"
+      password="tango"
+      proxy="130.244.196.90"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Tango MMS"
+      carrier_id = "896"
+      mcc="270"
+      mnc="77"
+      apn="mms"
+      user="tango"
+      password="tango"
+      mmsc="http://mms.tango.lu"
+      mmsproxy="212.66.75.3"
+      mmsport="8080"
+      type="mms"
+  />
+
+   <apn carrier="netgprs.com"
+      carrier_id = "2271"
+      mcc="270"
+      mnc="77"
+      apn="netgprs.com"
+      user="tsl"
+      password="tsl"
+      type="default,supl"
+      mvno_match_data="BB00"
+      mvno_type="gid"
+  />
+
+  <apn carrier="netgprs.com"
+      carrier_id = "2271"
+      mcc="270"
+      mnc="77"
+      apn="netgprs.com"
+      user="tsl"
+      password="tsl"
+      type="default,supl"
+      mvno_match_data="LU-Transatel"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Orange"
+      carrier_id = "897"
+      mcc="270"
+      mnc="99"
+      apn="orange.lu"
+      mmsc="http://mms.orange.lu"
+      mmsproxy="212.88.139.44"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Vodafone IE"
+      carrier_id = "2387"
+      mcc="272"
+      mnc="01"
+      apn="live.vodafone.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone IE-MMS"
+      carrier_id = "2387"
+      mcc="272"
+      mnc="01"
+      apn="mms.vodafone.net"
+      mmsc="http://www.vodafone.ie/mms"
+      mmsproxy="10.24.59.200"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone MISP"
+      carrier_id = "2387"
+      mcc="272"
+      mnc="01"
+      apn="hs.vodafone.ie"
+      authtype="0"
+      user="vodafone"
+      password="vodafone"
+      type="dun"
+  />
+
+  <apn carrier="3"
+      carrier_id = "792"
+      mcc="272"
+      mnc="02"
+      apn="internet"
+      mmsc="http://mms.three.ie"
+      mmsproxy="62.40.32.40"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="O2.ie Mobile Hotspot"
+      carrier_id = "792"
+      mcc="272"
+      mnc="02"
+      apn="Open.internet"
+      authtype="0"
+      type="dun"
+  />
+
+  <apn carrier="Meteor Data"
+      carrier_id = "793"
+      mcc="272"
+      mnc="03"
+      apn="data.mymeteor.ie"
+      user="my"
+      password="wap"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Meteor MMS"
+      carrier_id = "793"
+      mcc="272"
+      mnc="03"
+      apn="mms.mymeteor.ie"
+      user="my"
+      password="wap"
+      authtype="1"
+      mmsc="http://mms.mymeteor.ie"
+      mmsproxy="10.85.85.85"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="3"
+      carrier_id = "1903"
+      mcc="272"
+      mnc="05"
+      apn="3ireland.ie"
+      mmsc="http://mms.um.3ireland.ie:10021/mmsc"
+      mmsproxy="mms.3ireland.ie"
+      mmsport="8799"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Tesco"
+      carrier_id = "2154"
+      mcc="272"
+      mnc="11"
+      apn="tescomobile.liffeytelecom.com"
+      mmsc="http://mmc1/servlets/mms"
+      mmsproxy="10.1.11.19"
+      mmsport="8080"
+      type="default,supl,mms"
+      mvno_match_data="0A"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Siminn Internet"
+      carrier_id = "1565"
+      mcc="274"
+      mnc="01"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Siminn MMS"
+      carrier_id = "1565"
+      mcc="274"
+      mnc="01"
+      apn="mms.simi.is"
+      mmsc="http://mms.simi.is/servlets/mms"
+      mmsproxy="213.167.138.200"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone Internet"
+      carrier_id = "1566"
+      mcc="274"
+      mnc="02"
+      apn="gprs.is"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone MMS"
+      carrier_id = "1566"
+      mcc="274"
+      mnc="02"
+      apn="mms.gprs.is"
+      mmsc="http://mmsc.vodafone.is"
+      mmsproxy="10.22.0.10"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone Internet"
+      carrier_id = "1567"
+      mcc="274"
+      mnc="03"
+      apn="gprs.is"
+      authtype="0"
+      type="default,supl,agps,fota,dun"
+  />
+
+  <apn carrier="Vodafone MMS"
+      carrier_id = "1567"
+      mcc="274"
+      mnc="03"
+      apn="mms.gprs.is"
+      authtype="0"
+      mmsc="http://mmsc.vodafone.is"
+      mmsproxy="10.22.0.10"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="MMS Nova"
+      carrier_id = "2155"
+      mcc="274"
+      mnc="11"
+      apn="mms.nova.is"
+      mmsc="http://mmsc.nova.is"
+      mmsproxy="10.10.2.60"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Net Nova"
+      carrier_id = "2155"
+      mcc="274"
+      mnc="11"
+      apn="net.nova.is"
+      proxy="10.10.2.60"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone MT"
+      carrier_id = "2368"
+      mcc="278"
+      mnc="01"
+      apn="internet"
+      user="internet"
+      password="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone MT-MMS"
+      carrier_id = "2368"
+      mcc="278"
+      mnc="01"
+      apn="mms.vodafone.com.mt"
+      mmsc="http://mms.vodafone.com.mt/servlets/mms"
+      mmsproxy="10.12.0.3"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="CYTA"
+      carrier_id = "1447"
+      mcc="280"
+      mnc="01"
+      apn="cytamobile"
+      mmsc="http://mmsc.cyta.com.cy"
+      mmsproxy="212.31.96.161"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="MTN MMS"
+      carrier_id = "1448"
+      mcc="280"
+      mnc="10"
+      apn="mms"
+      user="mms"
+      password="mms"
+      mmsc="http://mms.mtn.com.cy/mmsc"
+      mmsproxy="172.24.97.1"
+      mmsport="3130"
+      type="mms"
+  />
+
+  <apn carrier="MTN Internet"
+      carrier_id = "1448"
+      mcc="280"
+      mnc="10"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="PrimeTel"
+      carrier_id = "2156"
+      mcc="280"
+      mnc="20"
+      apn="ip.primetel"
+      mmsc="http://mms.primetel"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="MTel"
+      carrier_id = "1370"
+      mcc="284"
+      mnc="01"
+      apn="inet-gprs.mtel.bg"
+      type="default,supl"
+  />
+
+  <apn carrier="MTel MMS"
+      carrier_id = "1370"
+      mcc="284"
+      mnc="01"
+      apn="mms-gprs.mtel.bg"
+      user="mtel"
+      password="mtel"
+      authtype="1"
+      mmsc="http://mmsc/"
+      mmsproxy="10.150.0.33"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="VIVACOM Internet"
+      carrier_id = "1999"
+      mcc="284"
+      mnc="03"
+      apn="internet.vivacom.bg"
+      user="vivacom"
+      password="vivacom"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Vivacom MMS"
+      carrier_id = "1999"
+      mcc="284"
+      mnc="03"
+      apn="mms.vivacom.bg"
+      user="mms"
+      password="mms"
+      authtype="1"
+      mmsc="http://mmsc.vivacom.bg"
+      mmsproxy="192.168.123.123"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Telenor Internet"
+      carrier_id = "1371"
+      mcc="284"
+      mnc="05"
+      apn="telenorbg"
+      authtype="0"
+      type="default,supl"
+  />
+
+  <apn carrier="Telenor MMS"
+      carrier_id = "1371"
+      mcc="284"
+      mnc="05"
+      apn="mms"
+      user="mms"
+      authtype="1"
+      mmsc="http://mmsc"
+      mmsproxy="192.168.87.11"
+      mmsport="8004"
+      type="mms"
+  />
+
+  <apn carrier="bulsatcom"
+      carrier_id = "2230"
+      mcc="284"
+      mnc="11"
+      apn="bulsat.com"
+      type="default,supl"
+  />
+
+  <apn carrier="MAX TELECOM"
+      carrier_id = "2231"
+      mcc="284"
+      mnc="13"
+      apn="apn.maxtelecom.bg"
+      type="default,supl"
+  />
+
+  <apn carrier="TURKCELL INTERNET"
+      carrier_id = "1735"
+      mcc="286"
+      mnc="01"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="TURKCELL MMS"
+      carrier_id = "1735"
+      mcc="286"
+      mnc="01"
+      apn="mms"
+      user="mms"
+      password="mms"
+      authtype="1"
+      mmsc="http://mms.turkcell.com.tr/servlets/mms"
+      mmsproxy="212.252.169.217"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone internet"
+      carrier_id = "1736"
+      mcc="286"
+      mnc="02"
+      apn="internet"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone MMS"
+      carrier_id = "1736"
+      mcc="286"
+      mnc="02"
+      apn="mms"
+      user="vodafone"
+      password="vodafone"
+      authtype="1"
+      mmsc="http://217.31.233.18:6001/MM1Servlet"
+      mmsproxy="217.31.233.18"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="AVEA INTERNET"
+      carrier_id = "1737"
+      mcc="286"
+      mnc="03"
+      apn="internet"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="AVEA MMS"
+      carrier_id = "1737"
+      mcc="286"
+      mnc="03"
+      apn="mms"
+      user="mms"
+      password="mms"
+      authtype="1"
+      mmsc="http://mms.avea.com.tr/servlets/mms"
+      mmsproxy="213.161.151.201"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Tele Internet"
+      carrier_id = "735"
+      mcc="290"
+      mnc="01"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Tele MMS"
+      carrier_id = "735"
+      mcc="290"
+      mnc="01"
+      apn="mms"
+      mmsc="http://mms.tele.gl/mms/wapenc"
+      mmsproxy="10.112.222.37"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Si.mobil GPRS"
+      carrier_id = "1709"
+      mcc="293"
+      mnc="40"
+      apn="internet.simobil.si"
+      user="simobil"
+      password="internet"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Si.mobil MMS"
+      carrier_id = "1709"
+      mcc="293"
+      mnc="40"
+      apn="mms.simobil.si"
+      user="simobil"
+      password="internet"
+      authtype="1"
+      mmsc="http://mmc/"
+      mmsproxy="80.95.224.46"
+      mmsport="9201"
+      type="mms"
+  />
+
+ <apn carrier="Mobilni Internet"
+      carrier_id = "1710"
+      mcc="293"
+      mnc="41"
+      apn="internet"
+      user="mobitel"
+      password="internet"
+      authtype="1"
+      mmsc="http://mms.mobitel.si/servlets/mms"
+      mmsproxy="213.229.249.40"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="T2"
+      carrier_id = "1711"
+      mcc="293"
+      mnc="64"
+      apn="internet.t-2.net"
+      mmsc="http://www.mms.t-2.net:8002"
+      mmsproxy="172.20.18.137"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Tusmobil Internet"
+      carrier_id = "1712"
+      mcc="293"
+      mnc="70"
+      apn="internet.tusmobil.si"
+      user="tusmobil"
+      password="internet"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Tusmobil MMS"
+      carrier_id = "1712"
+      mcc="293"
+      mnc="70"
+      apn="mms.tusmobil.si"
+      user="tusmobil"
+      password="mms"
+      authtype="1"
+      mmsc="http://mms.tusmobil.si:8002"
+      mmsproxy="91.185.221.85"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Telemach Internet"
+      carrier_id = "2327"
+      mcc="293"
+      mnc="70"
+      apn="telemach.net"
+      mmsc="http://mms.telemach.net:8002"
+      mmsproxy="91.185.221.85"
+      mmsport="8080"
+      mvno_type="imsi"
+      mvno_match_data="29370029xxxxxxx"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="T-Mobile MK Internet"
+      carrier_id = "2396"
+      mcc="294"
+      mnc="01"
+      apn=""
+      type="ia"
+  />
+
+  <apn carrier="T-Mobile MK Internet"
+      carrier_id = "2396"
+      mcc="294"
+      mnc="01"
+      apn="internet"
+      user="internet"
+      password="t-mobile"
+      type="default,supl"
+  />
+
+  <apn carrier="T-Mobile MK MMS"
+      carrier_id = "2396"
+      mcc="294"
+      mnc="01"
+      apn="mms"
+      user="mms"
+      password="mms"
+      mmsc="http://mms.t-mobile.com.mk"
+      mmsproxy="62.162.155.227"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Cosmofon"
+      carrier_id = "1608"
+      mcc="294"
+      mnc="02"
+      apn="Internet"
+      user="Internet"
+      password="Internet"
+      proxy="http://wap.planet.mk"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Cosmofon MMS"
+      carrier_id = "1608"
+      mcc="294"
+      mnc="02"
+      apn="mms"
+      mmsc="http://195.167.65.220:8002"
+      mmsproxy="10.10.10.20"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "1609"
+      mcc="294"
+      mnc="03"
+      apn="vipoperator"
+      user="vipoperator"
+      password="vipoperator"
+      proxy="78.40.0.1"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1609"
+      mcc="294"
+      mnc="03"
+      apn="vipoperator.mms"
+      user="vipoperator"
+      password="vipoperator"
+      mmsc="http://mmsc.vipoperator.com.mk"
+      mmsproxy="78.40.0.1"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="EMnify"
+      carrier_id = "2326"
+      mcc="295"
+      mnc="05"
+      apn="em"
+      mvno_match_data="2950509"
+      mvno_type="imsi"
+      type="default,supl"
+  />
+
+  <apn carrier="EMnify"
+      carrier_id = "2233"
+      mcc="295"
+      mnc="09"
+      apn="em"
+      type="default,supl"
+  />
+
+  <apn carrier="BICS"
+      carrier_id = "2232"
+      mcc="295"
+      mnc="09"
+      apn="bicsapn"
+      mvno_match_data="BICS"
+      mvno_type="spn"
+      type="default"
+  />
+
+  <apn carrier="T-Mobile MMS"
+      carrier_id = "2088"
+      mcc="297"
+      mnc="02"
+      apn="mms"
+      user="38267"
+      password="38267"
+      mmsc="http://192.168.180.100/servlets/mms"
+      mmsproxy="10.0.5.19"
+      mmsport="8080"
+      type="mms"
+      mvno_match_data="Telekom.me"
+      mvno_type="spn"
+  />
+
+  <apn carrier="T-Mobile Internet"
+      carrier_id = "2088"
+      mcc="297"
+      mnc="02"
+      apn="tmcg-wnw"
+      user="38267"
+      password="38267"
+      proxy="10.0.5.19"
+      port="8080"
+      type="default,supl"
+      mvno_match_data="Telekom.me"
+      mvno_type="spn"
+  />
+
+  <apn carrier="TELUS"
+      carrier_id = "1404"
+      mcc="302"
+      mnc="220"
+      apn="sp.telus.com"
+      type="default,mms,supl"
+      mmsc="http://aliasredirect.net/proxy/mmsc"
+      mmsproxy="mmscproxy.mobility.ca"
+      mmsport="8799"
+      mvno_match_data="5455"
+      mvno_type="gid"
+  />
+
+  <apn carrier="TELUS Tether"
+      carrier_id = "1404"
+      mcc="302"
+      mnc="220"
+      apn="isp.telus.com"
+      server="*"
+      type="dun"
+      protocol="IPV4"
+      mvno_match_data="5455"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Koodo"
+      carrier_id = "2020"
+      mcc="302"
+      mnc="220"
+      apn="sp.koodo.com"
+      type="default,mms,supl"
+      mmsc="http://aliasredirect.net/proxy/koodo/mmsc"
+      mmsproxy="mmscproxy.mobility.ca"
+      mmsport="8799"
+      mvno_match_data="4B4F"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Koodo Tether"
+      carrier_id = "2020"
+      mcc="302"
+      mnc="220"
+      apn="sp.koodo.com"
+      server="*"
+      type="dun"
+      protocol="IPV4"
+      mvno_match_data="4B4F"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Mobile Internet"
+      carrier_id = "2053"
+      mcc="302"
+      mnc="220"
+      apn="sp.mb.com"
+      type="default,mms,supl"
+      mmsc="http://aliasredirect.net/proxy/mb/mmsc"
+      mmsproxy="mmscproxy.mobility.ca"
+      mmsport="8799"
+      mvno_match_data="5043"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Tethered Mobile Internet"
+      carrier_id = "2053"
+      mcc="302"
+      mnc="220"
+      apn="isp.mb.com"
+      type="dun"
+      protocol="IPV4"
+      mvno_type="gid"
+      mvno_match_data="5043"
+  />
+
+  <apn carrier="Mobile Internet"
+      carrier_id = "2089"
+      mcc="302"
+      mnc="220"
+      apn="sp.mb.com"
+      type="default,mms,agps,supl,fota,hipri"
+      mmsc="http://aliasredirect.net/proxy/mb/mmsc"
+      mmsproxy="mmscproxy.mobility.ca"
+      mmsport="8799"
+      mvno_type="gid"
+      mvno_match_data="4D4F"
+  />
+
+  <apn carrier="Tethered Mobile Internet"
+      carrier_id = "2089"
+      mcc="302"
+      mnc="220"
+      apn="isp.mb.com"
+      type="dun"
+      protocol="IPV4"
+      mvno_type="gid"
+      mvno_match_data="4D4F"
+  />
+
+  <apn carrier="TELUS ISP"
+      carrier_id = "1404"
+      mcc="302"
+      mnc="221"
+      apn="isp.telus.com"
+      server="*"
+      type="dun"
+      protocol="IPV4"
+      mvno_match_data="5455"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Koodo"
+      carrier_id = "2020"
+      mcc="302"
+      mnc="221"
+      apn="sp.koodo.com"
+      server="*"
+      type="dun"
+      protocol="IPV4"
+      mvno_match_data="4B4F"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Tethered PC Mobile"
+      carrier_id = "2053"
+      mcc="302"
+      mnc="221"
+      apn="isp.mb.com"
+      type="dun"
+      protocol="IPV4"
+      mvno_type="gid"
+      mvno_match_data="5043"
+  />
+
+  <apn carrier="MOWAP"
+      carrier_id = "2055"
+      mcc="302"
+      mnc="320"
+      apn="wap.davewireless.com"
+      proxy="10.100.3.4"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="MOMMS"
+      carrier_id = "2055"
+      mcc="302"
+      mnc="320"
+      apn="mms.davewireless.com"
+      mmsc="http://mms.mobilicity.net"
+      mmsproxy="10.100.3.4"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "2252"
+      mcc="302"
+      mnc="270"
+      apn="mms.mobi.eastlink.ca"
+      mmsc="http://mmss.mobi.eastlink.ca"
+      mmsproxy="10.232.12.49"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "2252"
+      mcc="302"
+      mnc="270"
+      apn="wisp.mobi.eastlink.ca"
+      type="default,supl"
+  />
+
+  <apn carrier="Rogers IMS"
+      carrier_id = "1962"
+      mcc="302"
+      mnc="370"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="Fido Tethering"
+      carrier_id = "1962"
+      mcc="302"
+      mnc="370"
+      apn="ltedata.apn"
+      type="dun"
+      mvno_match_data="DD"
+      mvno_type="gid"
+      protocol="IPV4V6"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Fido Internet"
+      carrier_id = "1962"
+      mcc="302"
+      mnc="370"
+      apn="ltemobile.apn"
+      type="default,mms,agps,supl,fota,hipri"
+      mmsproxy="mmsproxy.fido.ca"
+      mmsc="http://mms.fido.ca"
+      mmsport="80"
+      mvno_match_data="DD"
+      mvno_type="gid"
+      protocol="IPV4V6"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Fido Internet"
+      carrier_id = "1962"
+      mcc="302"
+      mnc="370"
+      apn="IMS"
+      type="ims"
+      mvno_match_data="DD"
+      mvno_type="gid"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="MTS"
+      carrier_id = "578"
+      mcc="302"
+      mnc="370"
+      apn="sp.mts"
+      type="default,mms,supl"
+      mmsc="http://mmsc2.mts.net/"
+      mmsproxy="wapgw1.mts.net"
+      mmsport="9201"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="2C"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MTS Tethering S"
+      carrier_id = "578"
+      mcc="302"
+      mnc="370"
+      apn="internet.mts"
+      type="dun"
+      protocol="IPV4V6"
+      roaming_protocol="IP"
+      mvno_type="gid"
+      mvno_match_data="2C"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "1895"
+      mcc="302"
+      mnc="490"
+      apn="internet.windmobile.ca"
+      type="default,supl"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1895"
+      mcc="302"
+      mnc="490"
+      apn="mms.windmobile.ca"
+      mmsc="http://mms.windmobile.ca"
+      mmsproxy="74.115.197.70"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Media"
+      carrier_id = "2008"
+      mcc="302"
+      mnc="500"
+      apn="media.ng"
+      mmsc="http://media.videotron.com"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Media"
+      carrier_id = "2008"
+      mcc="302"
+      mnc="510"
+      apn="media.ng"
+      mmsc="http://media.videotron.com"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Media"
+      carrier_id = "2008"
+      mcc="302"
+      mnc="520"
+      apn="media.ng"
+      mmsc="http://media.videotron.com"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Bell Mobility"
+      carrier_id = "576"
+      mcc="302"
+      mnc="610"
+      apn="pda.bell.ca"
+      type="default,mms,supl"
+      mmsc="http://mms.bell.ca/mms/wapenc"
+  />
+
+  <apn carrier="Bell Mobility IMS"
+      carrier_id = "576"
+      mcc="302"
+      mnc="610"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="MTS"
+      mcc="302"
+      mnc="660"
+      apn="sp.mts"
+      type="default,mms,supl"
+      mmsc="http://mmsc2.mts.net/"
+      mmsproxy="wapgw1.mts.net"
+      mmsport="9201"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_type="spn"
+      mvno_match_data="MTS"
+  />
+
+  <apn carrier="MTS Tethering"
+      mcc="302"
+      mnc="660"
+      apn="internet.mts"
+      type="dun"
+      protocol="IPV4V6"
+      roaming_protocol="IP"
+      mvno_type="spn"
+      mvno_match_data="MTS"
+  />
+
+  <apn carrier="Rogers LTE"
+      carrier_id = "1403"
+      mcc="302"
+      mnc="720"
+      apn="ltemobile.apn"
+      type="default,mms,supl"
+      mmsproxy="mmsproxy.rogers.com"
+      mmsc="http://mms.gprs.rogers.com"
+      mmsport="80"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="Rogers IMS"
+      carrier_id = "1403"
+      mcc="302"
+      mnc="720"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="chatr"
+      carrier_id = "2055"
+      mcc="302"
+      mnc="720"
+      apn="chatrweb.apn"
+      type="default,mms,supl"
+      mmsc="http://mms.chatrwireless.com"
+      mmsproxy="205.151.11.11"
+      mmsport="80"
+      proxy="205.151.11.11"
+      port="80"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="302720x94"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Chatr Tethering"
+      carrier_id = "2055"
+      mcc="302"
+      mnc="720"
+      apn="chatrisp.apn"
+      type="dun"
+      mvno_type="imsi"
+      mvno_match_data="302720x94"
+      protocol="IPV4V6"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Tbaytel Tethering"
+      carrier_id = "2090"
+      mcc="302"
+      mnc="720"
+      apn="ltedata.apn"
+      type="dun"
+      protocol="IPV4V6"
+      roaming_protocol="IP"
+      mvno_type="gid"
+      mvno_match_data="BA"
+  />
+
+  <apn carrier="Tbaytel Internet"
+      mnc="720"
+      carrier_id = "2090"
+      mcc="302"
+      apn="ltemobile.apn"
+      type="default,mms,agps,supl,fota,hipri"
+      protocol="IPV4V6"
+      roaming_protocol="IP"
+      mmsc="http://mms.gprs.rogers.com"
+      mmsproxy="mmsproxy.rogers.com"
+      mmsport="80"
+      mvno_type="gid"
+      mvno_match_data="BA"
+  />
+
+  <apn carrier="Cityfone Tethering"
+      carrier_id = "2057"
+      mcc="302"
+      mnc="720"
+      apn="ltedata.apn"
+      type="dun"
+      protocol="IPV4V6"
+      roaming_protocol="IP"
+      mvno_type="spn"
+      mvno_match_data="CITYFONE"
+  />
+
+  <apn carrier="Cityfone Internet"
+      mnc="720"
+      carrier_id = "2057"
+      mcc="302"
+      apn="ltemobile.apn"
+      type="default,mms,agps,supl,fota,hipri"
+      protocol="IPV4V6"
+      roaming_protocol="IP"
+      mmsc="http://mms.gprs.rogers.com"
+      mmsproxy="mmsproxy.rogers.com"
+      mmsport="80"
+      mvno_type="spn"
+      mvno_match_data="CITYFONE"
+  />
+
+  <apn carrier="Rogers Tethering"
+      mcc="302"
+      mnc="720"
+      apn="ltedata.apn"
+      type="dun"
+      mvno_match_data="ROGERS"
+      mvno_type="spn"
+      protocol="IPV4V6"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Rogers Internet"
+      mcc="302"
+      mnc="720"
+      apn="ltemobile.apn"
+      type="default,mms,agps,supl,fota,hipri"
+      mmsproxy="mmsproxy.rogers.com"
+      mmsc="http://mms.gprs.rogers.com"
+      mmsport="80"
+      mvno_match_data="ROGERS"
+      mvno_type="spn"
+      protocol="IPV4V6"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="SaskTel"
+      carrier_id = "580"
+      mcc="302"
+      mnc="780"
+      apn="pda.stm.sk.ca"
+      type="default,mms,supl"
+      mmsc="http://mms.sasktel.com/"
+      mmsproxy="mig.sasktel.com"
+      mmsport="80"
+  />
+
+  <apn carrier="Verizon CDMA HRPD"
+      mcc="310"
+      mnc="000"
+      mmsc="http://mms.vzwreseller.com/servlets/mms"
+      type="default,mms,hipri,dun,supl"
+      mvno_type="spn"
+      mvno_match_data="Tracfone"
+      authtype="3"
+  />
+
+  <apn carrier="Bluewire"
+      mcc="310"
+      mnc="000"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="bluewire"
+      mmsc="http://mms.blueunlimited.com"
+      mmsproxy=""
+      mmsport="8514"
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Bluewire IMS"
+      mcc="310"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="bluewire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Bluewire IMS"
+      mcc="310"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="bluewire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Bluewire FOTA"
+      mcc="310"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="bluewire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Bluewire FOTA"
+      mcc="310"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="bluewire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Bluewire"
+      mcc="310"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://mms.blueunlimited.com"
+      mmsproxy=""
+      mmsport="8514"
+      mvno_type="spn"
+      mvno_match_data="bluewire"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Bluewire"
+      mcc="310"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://mms.blueunlimited.com"
+      mmsproxy=""
+      mmsport="8514"
+      mvno_type="spn"
+      mvno_match_data="bluewire"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="flatwire"
+      mcc="310"
+      mnc="000"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="flatwire"
+      mmsc="http://mmsc.cleartalk.csky.us/"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Flatwire IMS"
+      mcc="310"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="flatwire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Flatwire IMS"
+      mcc="310"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="flatwire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Flatwire FOTA"
+      mcc="310"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="flatwire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Flatwire FOTA"
+      mcc="310"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="flatwire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Flatwire"
+      mcc="310"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc.cleartalk.csky.us/"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="flatwire"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Flatwire"
+      mcc="310"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc.cleartalk.csky.us/"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="flatwire"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="mobipcs"
+      mcc="310"
+      mnc="000"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="mobipcs"
+      mmsc="http://mms.mobipcs.com"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Mobipcs IMS"
+      mcc="310"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="mobipcs"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Mobipcs IMS"
+      mcc="310"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="mobipcs"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Mobipcs FOTA"
+      mcc="310"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="mobipcs"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Mobipcs FOTA"
+      mcc="310"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="mobipcs"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Mobipcs"
+      mcc="310"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://mms.mobipcs.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="mobipcs"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Mobipcs"
+      mcc="310"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://mms.mobipcs.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="mobipcs"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="mobilenation"
+      mcc="310"
+      mnc="000"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="mobilenation"
+      mmsc="http://mms.mymn3g.net"
+      mmsproxy="mms.mymn3g.net"
+      mmsport="8081"
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Mobilenation IMS"
+      mcc="310"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="mobilenation"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Mobilenation IMS"
+      mcc="310"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="mobilenation"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Mobilenation FOTA"
+      mcc="310"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="mobilenation"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Mobilenation FOTA"
+      mcc="310"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="mobilenation"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Mobilenation"
+      mcc="310"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://mms.mymn3g.net"
+      mmsproxy="mms.mymn3g.net"
+      mmsport="8081"
+      mvno_type="spn"
+      mvno_match_data="mobilenation"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Mobilenation"
+      mcc="310"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://mms.mymn3g.net"
+      mmsproxy="mms.mymn3g.net"
+      mmsport="8081"
+      mvno_type="spn"
+      mvno_match_data="mobilenation"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="mohave"
+      mcc="310"
+      mnc="000"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="mohave"
+      mmsc="http://mms.mohavewireless.com"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Mohave IMS"
+      mcc="310"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="mohave"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Mohave IMS"
+      mcc="310"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="mohave"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Mohave FOTA"
+      mcc="310"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="mohave"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Mohave FOTA"
+      mcc="310"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="mohave"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Mohave"
+      mcc="310"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://mms.mohavewireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="mohave"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Mohave"
+      mcc="310"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://mms.mohavewireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="mohave"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="peopleswire"
+      mcc="310"
+      mnc="000"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="peopleswire"
+      mmsc="http://172.16.16.130/mms/"
+      mmsproxy=""
+      mmsport="80"
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Peopleswire IMS"
+      mcc="310"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="Peopleswire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Peopleswire IMS"
+      mcc="310"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="Peopleswire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="peopleswire FOTA"
+      mcc="310"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="peopleswire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="peopleswire FOTA"
+      mcc="310"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="peopleswire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Peopleswire"
+      mcc="310"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://172.16.16.130/mms/"
+      mmsproxy=""
+      mmsport="80"
+      mvno_type="spn"
+      mvno_match_data="Peopleswire"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Peopleswire"
+      mcc="310"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://172.16.16.130/mms/"
+      mmsproxy=""
+      mmsport="80"
+      mvno_type="spn"
+      mvno_match_data="Peopleswire"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="revol"
+      mcc="310"
+      mnc="000"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="revol"
+      mmsc="http://mms.revol.us/revol/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Revol IMS"
+      mcc="310"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="revol"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Revol IMS"
+      mcc="310"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="revol"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Revol FOTA"
+      mcc="310"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="revol"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Revol FOTA"
+      mcc="310"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="revol"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Revol"
+      mcc="310"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://mms.revol.us/revol/mms.php"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="revol"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Revol"
+      mcc="310"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://mms.revol.us/revol/mms.php"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="revol"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Commnet"
+      mcc="310"
+      mnc="000"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="commnet"
+      mmsc="http://mmsc.cccomm.csky.us"
+      mmsproxy=""
+      mmsport="6672"
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="distribution"
+      mcc="310"
+      mnc="000"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="distribution"
+      mmsc="http://mms.dst.com/mms/"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Distribution IMS"
+      mcc="310"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="distribution"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Distribution IMS"
+      mcc="310"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="distribution"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Distribution FOTA"
+      mcc="310"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="distribution"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Distribution FOTA"
+      mcc="310"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="distribution"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Distribution"
+      mcc="310"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://mms.dst.com/mms/"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="distribution"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Distribution"
+      mcc="310"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://mms.dst.com/mms/"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="distribution"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Union Wireless Data"
+      carrier_id = "1781"
+      mcc="310"
+      mnc="020"
+      apn="union.wap.com"
+      proxy="166.230.4.83"
+      port="8799"
+      type="default,hipri,dun,supl"
+  />
+
+  <apn carrier="Union Wireless MMS"
+      carrier_id = "1781"
+      mcc="310"
+      mnc="020"
+      apn="union.mms.com"
+      mmsc="http://mmsc/01"
+      mmsproxy="166.230.4.83"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <!-- Need two APNs for CDMA technologies: a default that is used normally -->
+  <!-- and a second APN to be used when DUN is required.  Even though the -->
+  <!-- parameters appear the same, the profileID sent to the radio when requesting -->
+  <!-- a DUN connection will be different -->
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="Verizon"
+      mcc="310"
+      mnc="004"
+      apn="internet"
+      authtype="3"
+      type="default,mms,supl,fota,cbs"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+  />
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="Verizon"
+      mcc="310"
+      mnc="004"
+      apn="internet"
+      authtype="3"
+      type="default,mms,supl,fota,cbs,dun"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      profile_id="1"
+  />
+
+  <!-- bearer 13, 14 -->
+  <apn carrier="Verizon Internet"
+      mcc="310"
+      mnc="004"
+      apn="VZWINTERNET"
+      type="default,dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13|14"
+      profile_id="0"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <!-- bearer 13, 14 -->
+  <apn carrier="Verizon FOTA"
+      mcc="310"
+      mnc="004"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13|14"
+      profile_id="3"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <!-- bearer 13, 14 -->
+  <apn carrier="Verizon IMS"
+      mcc="310"
+      mnc="004"
+      apn="VZWIMS"
+      type="ims"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13|14"
+      profile_id="2"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <!-- bearer 13, 14 -->
+  <apn carrier="Verizon CBS"
+      mcc="310"
+      mnc="004"
+      apn="VZWAPP"
+      type="cbs,mms"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13|14"
+      profile_id="4"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier=" ALU Test-SIM Internet"
+      carrier_id = "2253"
+      mcc="310"
+      mnc="028"
+      apn="VZWINTERNET"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      type="default,dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier=" ALU Test-SIM FOTA"
+      carrier_id = "2253"
+      mcc="310"
+      mnc="028"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier=" ALU Test-SIM IMS"
+      carrier_id = "2253"
+      mcc="310"
+      mnc="028"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier=" ALU Test-SIM CBS"
+      carrier_id = "2253"
+      mcc="310"
+      mnc="028"
+      apn="VZWAPP"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      type="cbs,mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="myBlue Pix"
+      carrier_id = "1187"
+      mcc="310"
+      mnc="030"
+      apn="mmswap.centennialwireless.com"
+      mmsc="http://mms.myblue.com/servlets/mms"
+      mmsproxy="63.99.231.135"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "1187"
+      mcc="310"
+      mnc="030"
+      apn="private.centennialwireless.com"
+      user="privuser"
+      password="priv"
+      type="default,supl"
+  />
+
+  <apn carrier="itewire"
+      mcc="310"
+      mnc="032"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="itewire"
+      mmsc=""
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Itewire IMS"
+      mcc="310"
+      mnc="032"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="itewire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Itewire IMS"
+      mcc="310"
+      mnc="032"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="itewire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Itewire FOTA"
+      mcc="310"
+      mnc="032"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="itewire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Itewire FOTA"
+      mcc="310"
+      mnc="032"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="itewire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Itewire"
+      mcc="310"
+      mnc="032"
+      apn="VZWINTERNET"
+      mmsc=""
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="itewire"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Itewire"
+      mcc="310"
+      mnc="032"
+      apn="VZWINTERNET"
+      mmsc=""
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="itewire"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="etex"
+      carrier_id = "2254"
+      mcc="310"
+      mnc="035"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="etex"
+      mmsc="http://mmsi.etex.mobi"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Etex IMS"
+      carrier_id = "2254"
+      mcc="310"
+      mnc="035"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="etex"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Etex IMS"
+      carrier_id = "2254"
+      mcc="310"
+      mnc="035"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="etex"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Etex FOTA"
+      carrier_id = "2254"
+      mcc="310"
+      mnc="035"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="etex"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Etex FOTA"
+      carrier_id = "2254"
+      mcc="310"
+      mnc="035"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="etex"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Etex"
+      carrier_id = "2254"
+      mcc="310"
+      mnc="035"
+      apn="VZWINTERNET"
+      mmsc="http://mmsi.etex.mobi"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="etex"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Etex"
+      carrier_id = "2254"
+      mcc="310"
+      mnc="035"
+      apn="VZWINTERNET"
+      mmsc="http://mmsi.etex.mobi"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="etex"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="mta"
+      carrier_id = "1784"
+      mcc="310"
+      mnc="040"
+      apn="CdmaNai"
+      mmsc="http://mmsc.mta.dataonair.net/"
+      mmsproxy="209.4.229.85"
+      mmsport="6672"
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Mta IMS"
+      carrier_id = "1784"
+      mcc="310"
+      mnc="040"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Mta IMS"
+      carrier_id = "1784"
+      mcc="310"
+      mnc="040"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Mta FOTA"
+      carrier_id = "1784"
+      mcc="310"
+      mnc="040"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Mta FOTA"
+      carrier_id = "1784"
+      mcc="310"
+      mnc="040"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Mta"
+      carrier_id = "1784"
+      mcc="310"
+      mnc="040"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc.mta.dataonair.net/"
+      mmsproxy="209.4.229.85"
+      mmsport="6672"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Mta"
+      carrier_id = "1784"
+      mcc="310"
+      mnc="040"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc.mta.dataonair.net/"
+      mmsproxy="209.4.229.85"
+      mmsport="6672"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="alaskacomm"
+      mcc="310"
+      mnc="050"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="alaskacomm"
+      mmsc="http://mmsc1.acsalaska.net/servlets/mms"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Alaskacomm IMS"
+      mcc="310"
+      mnc="050"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="alaskacomm"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Alaskacomm IMS"
+      mcc="310"
+      mnc="050"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="alaskacomm"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Alaskacomm FOTA"
+      mcc="310"
+      mnc="050"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="alaskacomm"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Alaskacomm FOTA"
+      mcc="310"
+      mnc="050"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="alaskacomm"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Alaskacomm"
+      mcc="310"
+      mnc="050"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc1.acsalaska.net/servlets/mms"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="alaskacomm"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Alaskacomm"
+      mcc="310"
+      mnc="050"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc1.acsalaska.net/servlets/mms"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="alaskacomm"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="U.S.Cellular"
+      mcc="310"
+      mnc="066"
+      apn="internet"
+      user="*"
+      server="*"
+      password="*"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      mtu="1422"
+  />
+
+  <apn carrier="Corr Wap"
+      carrier_id = "1168"
+      mcc="310"
+      mnc="080"
+      apn="corrgprs"
+      server="http://w.iot1.com/corr/wml.php"
+      proxy="74.112.57.172"
+      port="9201"
+      type="default"
+  />
+
+  <apn carrier="CorrMMS"
+      carrier_id = "1168"
+      mcc="310"
+      mnc="080"
+      apn="corrmms"
+      mmsc="http://mms.iot1.com/corr/mms.php"
+      mmsproxy="66.255.55.23"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "1779"
+      mcc="310"
+      mnc="090"
+      apn="isp"
+      type="default,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1779"
+      mcc="310"
+      mnc="090"
+      apn="mms"
+      mmsc="http://mms.edgemobile.net/mmsc"
+      mmsproxy="12.108.12.13"
+      mmsport="3128"
+      type="mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="Edge MMS Prepay"
+      carrier_id = "1779"
+      mcc="310"
+      mnc="090"
+      apn="ppmms"
+      mmsc="http://mms.edgemobile.net/mmsc"
+      mmsproxy="12.108.12.13"
+      mmsport="3128"
+      type="mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="PLATMMS"
+      carrier_id = "1170"
+      mcc="310"
+      mnc="100"
+      apn="mms.plateau"
+      mmsc="http://mms"
+      mmsproxy="172.23.253.206"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="PLATWEB"
+      carrier_id = "1170"
+      mcc="310"
+      mnc="100"
+      apn="isp.plateau"
+      type="default,supl"
+  />
+
+  <!-- Need two APNs for CDMA technologies: a default that is used normally -->
+  <!-- and a second APN to be used when DUN is required.  Even though the -->
+  <!-- parameters appear the same, the profileID sent to the radio when requesting -->
+  <!-- a DUN connection will be different -->
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="Sprint"
+      carrier_id = "1788"
+      mcc="310"
+      mnc="120"
+      apn="sprint"
+      type="default,supl,mms,ims,cbs"
+      mmsc="http://mms.sprintpcs.com"
+      mmsproxy="68.28.31.7"
+      mmsport="80"
+      bearer_bitmask="4|5|6|7|8|12"
+  />
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="Sprint"
+      carrier_id = "1788"
+      mcc="310"
+      mnc="120"
+      apn="sprint"
+      type="default,supl,mms,ims,cbs,dun"
+      mmsc="http://mms.sprintpcs.com"
+      mmsproxy="68.28.31.7"
+      mmsport="80"
+      bearer_bitmask="4|5|6|7|8|12"
+      profile_id="1"
+  />
+
+  <!-- this APN will be deleted and replaced by a new ia APN by the HFA provisioning process.
+       This is just a bootstrap APN to enable HFA -->
+  <apn carrier="OTA"
+      carrier_id = "1788"
+      mcc="310"
+      mnc="120"
+      apn="otasn"
+      type="fota,ia"
+      protocol="IPV4V6"
+      user="null"
+      password="null"
+  />
+
+  <!-- bearer 1, 2, 3, 9, 10, 11, 15, 16 -->
+  <apn carrier="SPCS Global"
+      carrier_id = "1788"
+      mcc="310"
+      mnc="120"
+      apn="cinet.spcs"
+      mmsc="http://mms.sprintpcs.com"
+      mmsproxy="68.28.31.7"
+      mmsport="80"
+      type="default,supl,mms,dun"
+      bearer_bitmask="1|2|3|9|10|11|15|16"
+  />
+
+  <apn carrier="Carolina West Internet"
+      carrier_id = "1789"
+      mcc="310"
+      mnc="130"
+      apn="home.cww.com"
+      type="default,supl,mms,ims,cbs"
+      mmsc="http://mms.cwwmms.com/cww/mms.php"
+      mmsport="80"
+      bearer_bitmask="4|5|6|7|8|12"
+  />
+
+  <apn carrier="Carolina West Tethering"
+      carrier_id = "1789"
+      mcc="310"
+      mnc="130"
+      apn="tethering.cww.com"
+      type="dun"
+      bearer_bitmask="4|5|6|7|8|12"
+      user_editable="false"
+  />
+
+  <apn carrier="internet"
+      carrier_id = "1964"
+      mcc="310"
+      mnc="150"
+      apn="ndo"
+      user=""
+      password=""
+      proxy=""
+      port=""
+      mmsc="http://mmsc.aiowireless.net"
+      mmsproxy="proxy.aiowireless.net"
+      mmsport="80"
+      type="default,mms,fota,hipri,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+
+  <apn carrier="T-Mobile US 160"
+      carrier_id = "1"
+      mcc="310"
+      mnc="160"
+      apn="fast.t-mobile.com"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="default,supl,mms,ia"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mtu="1440"
+  />
+
+  <apn carrier="T-Mobile US 160 DUN"
+      carrier_id = "1"
+      mcc="310"
+      mnc="160"
+      apn="pcweb.tmobile.com"
+      user="none"
+      server="*"
+      password="none"
+      protocol="IP"
+      type="dun"
+      mtu="1440"
+  />
+
+  <apn carrier="MetroPCS 160"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="160"
+      apn="fast.metropcs.com"
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MetroPCS 160"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="160"
+      apn="fast.metropcs.com"
+      mmsc="http://metropcs.mmsmvno.com/mms/wapenc"
+      type="default,supl,mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="IMS"
+      carrier_id = "1187"
+      mcc="310"
+      mnc="170"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+
+  <apn carrier="DataConnect"
+      carrier_id = "1187"
+      mcc="310"
+      mnc="170"
+      apn="isp.cingular"
+      type="default,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="Cingular MMS"
+      carrier_id = "1187"
+      mcc="310"
+      mnc="170"
+      apn="wap.cingular"
+      user="WAP@CINGULARGPRS.COM"
+      password="CINGULAR1"
+      mmsc="http://mmsc.cingular.com"
+      mmsproxy="66.209.11.32"
+      mmsport="8080"
+      type="mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="WCW-INTERNET"
+      carrier_id = "1792"
+      mcc="310"
+      mnc="180"
+      apn="internet.wcc.net"
+      user="13257630000"
+      password="mmsc"
+      type="default"
+  />
+
+  <apn carrier="WCW-MMS"
+      carrier_id = "1792"
+      mcc="310"
+      mnc="180"
+      apn="mms.wcc.net"
+      user="13257630000"
+      password="mmsc"
+      authtype="3"
+      mmsc="http://mms.wcc.net"
+      mmsproxy="209.55.70.246"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="T-Mobile US 200"
+      carrier_id = "1"
+      mcc="310"
+      mnc="200"
+      apn="fast.t-mobile.com"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="default,supl,mms,ia"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mtu="1440"
+  />
+
+  <apn carrier="T-Mobile US 200 DUN"
+      carrier_id = "1"
+      mcc="310"
+      mnc="200"
+      apn="pcweb.tmobile.com"
+      user="none"
+      server="*"
+      password="none"
+      mtu="1440"
+      protocol="IP"
+      type="dun"
+  />
+
+  <apn carrier="MetroPCS 200"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="200"
+      apn="fast.metropcs.com"
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MetroPCS 200"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="200"
+      apn="fast.metropcs.com"
+      mmsc="http://metropcs.mmsmvno.com/mms/wapenc"
+      type="default,supl,mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="T-Mobile US 210"
+      carrier_id = "1"
+      mcc="310"
+      mnc="210"
+      apn="fast.t-mobile.com"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="default,supl,mms,ia"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mtu="1440"
+  />
+
+  <apn carrier="T-Mobile US 210 DUN"
+      carrier_id = "1"
+      mcc="310"
+      mnc="210"
+      apn="pcweb.tmobile.com"
+      user="none"
+      server="*"
+      password="none"
+      mtu="1440"
+      protocol="IP"
+      type="dun"
+  />
+
+  <apn carrier="MetroPCS 210"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="210"
+      apn="fast.metropcs.com"
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MetroPCS 210"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="210"
+      apn="fast.metropcs.com"
+      mmsc="http://metropcs.mmsmvno.com/mms/wapenc"
+      type="default,supl,mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="T-Mobile US 220"
+      carrier_id = "1"
+      mcc="310"
+      mnc="220"
+      apn="fast.t-mobile.com"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="default,supl,mms,ia"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mtu="1440"
+  />
+
+  <apn carrier="T-Mobile US 220 DUN"
+      carrier_id = "1"
+      mcc="310"
+      mnc="220"
+      apn="pcweb.tmobile.com"
+      user="none"
+      server="*"
+      password="none"
+      mtu="1440"
+      protocol="IP"
+      type="dun"
+  />
+
+  <apn carrier="MetroPCS 220"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="220"
+      apn="fast.metropcs.com"
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MetroPCS 220"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="220"
+      apn="fast.metropcs.com"
+      mmsc="http://metropcs.mmsmvno.com/mms/wapenc"
+      type="default,supl,mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="T-Mobile US 230"
+      carrier_id = "1"
+      mcc="310"
+      mnc="230"
+      apn="fast.t-mobile.com"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="default,supl,mms,ia"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mtu="1440"
+  />
+
+  <apn carrier="T-Mobile US 230 DUN"
+      carrier_id = "1"
+      mcc="310"
+      mnc="230"
+      apn="pcweb.tmobile.com"
+      user="none"
+      server="*"
+      password="none"
+      mtu="1440"
+      protocol="IP"
+      type="dun"
+  />
+
+  <apn carrier="MetroPCS 230"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="230"
+      apn="fast.metropcs.com"
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MetroPCS 230"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="230"
+      apn="fast.metropcs.com"
+      mmsc="http://metropcs.mmsmvno.com/mms/wapenc"
+      type="default,supl,mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="T-Mobile US 240"
+      carrier_id = "1"
+      mcc="310"
+      mnc="240"
+      apn="fast.t-mobile.com"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="default,supl,mms,ia"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mtu="1440"
+  />
+
+  <apn carrier="T-Mobile US 240 DUN"
+      carrier_id = "1"
+      mcc="310"
+      mnc="240"
+      apn="pcweb.tmobile.com"
+      user="none"
+      server="*"
+      password="none"
+      mtu="1440"
+      protocol="IP"
+      type="dun"
+  />
+
+  <apn carrier="MetroPCS 240"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="240"
+      apn="fast.metropcs.com"
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MetroPCS 240"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="240"
+      apn="fast.metropcs.com"
+      mmsc="http://metropcs.mmsmvno.com/mms/wapenc"
+      type="default,supl,mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="T-Mobile US 250"
+      carrier_id = "1"
+      mcc="310"
+      mnc="250"
+      apn="fast.t-mobile.com"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="default,supl,mms,ia"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mtu="1440"
+  />
+
+  <apn carrier="T-Mobile US 250 DUN"
+      carrier_id = "1"
+      mcc="310"
+      mnc="250"
+      apn="pcweb.tmobile.com"
+      user="none"
+      server="*"
+      password="none"
+      mtu="1440"
+      protocol="IP"
+      type="dun"
+  />
+
+  <apn carrier="MetroPCS 250"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="250"
+      apn="fast.metropcs.com"
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MetroPCS 250"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="250"
+      apn="fast.metropcs.com"
+      mmsc="http://metropcs.mmsmvno.com/mms/wapenc"
+      type="default,supl,mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="T-Mobile GPRS"
+      carrier_id = "1"
+      mcc="310"
+      mnc="260"
+      apn="fast.t-mobile.com"
+      type="default,supl,ia"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mtu="1440"
+  />
+
+  <apn carrier="T-Mobile MMS"
+      carrier_id = "1"
+      mcc="310"
+      mnc="260"
+      apn="TMUS"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      bearer_bitmask="1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17"
+  />
+
+  <apn carrier="T-Mobile MMS"
+      carrier_id = "1"
+      mcc="310"
+      mnc="260"
+      apn="TMUS"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="mms"
+      protocol="IPV6"
+      roaming_protocol="IPV6"
+      bearer="18"
+  />
+
+  <apn carrier="T-Mobile IMS"
+      carrier_id = "1"
+      mcc="310"
+      mnc="260"
+      apn="ims"
+      type="ims"
+      modem_cognitive="true"
+      protocol="IPV6"
+      bearer_bitmask="1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17"
+  />
+
+  <apn carrier="T-Mobile IMS"
+      carrier_id = "1"
+      mcc="310"
+      mnc="260"
+      apn="ims"
+      type="ims"
+      modem_cognitive="true"
+      protocol="IPV6"
+      roaming_protocol="IPV6"
+      bearer="18"
+  />
+
+  <apn carrier="Google Fi - T"
+      carrier_id = "1989"
+      mcc="310"
+      mnc="260"
+      apn="h2g2"
+      user="none"
+      server="*"
+      password="none"
+      mmsc="http://mmsc1.g-mms.com/mms/wapenc"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="31026097"
+      mvno_type="IMSI"
+  />
+
+  <apn carrier="MetroPCS 260"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="260"
+      apn="fast.metropcs.com"
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="6D38"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MetroPCS 260"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="260"
+      apn="fast.metropcs.com"
+      mmsc="http://metropcs.mmsmvno.com/mms/wapenc"
+      type="default,supl,mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="6D38"
+      mvno_type="gid"
+  />
+
+  <apn carrier="SIMPLE"
+      carrier_id = "2078"
+      mcc="310"
+      mnc="260"
+      apn="simple"
+      type="default,mms,supl,hipri,fota"
+      protocol="IP"
+      roaming_protocol="IP"
+      mmsc="http://smpl.mms.msg.eng.t-mobile.com/mms/wapenc"
+      mvno_type="gid"
+      mvno_match_data="534D"
+  />
+
+  <apn carrier="TFWAP"
+      carrier_id = "2022"
+      mcc="310"
+      mnc="260"
+      apn="wap.tracfone"
+      type="default,mms,supl,hipri,fota"
+      protocol="IP"
+      roaming_protocol="IP"
+      mmsc="http://mms.tracfone.com"
+      mvno_type="gid"
+      mvno_match_data="deff"
+  />
+
+  <apn carrier="TFWAP"
+      carrier_id = "2022"
+      mcc="310"
+      mnc="260"
+      apn="wap.tracfone"
+      type="default,mms,supl,hipri,fota"
+      protocol="IP"
+      roaming_protocol="IP"
+      mmsc="http://mms.tracfone.com"
+      mvno_type="gid"
+      mvno_match_data="ddff"
+  />
+
+  <apn carrier="Consumer Cellular"
+      carrier_id = "2023"
+      mcc="310"
+      mnc="260"
+      apn="wholesale"
+      user=""
+      password=""
+      proxy=""
+      port=""
+      mmsc="http://wholesale.mmsmvno.com/mms/wapenc"
+      mmsproxy=""
+      mmsport="80"
+      type="default,mms,supl,hipri"
+      mvno_type="gid"
+      mvno_match_data="2AC9"
+  />
+
+  <apn carrier="T-Mobile US 270"
+      carrier_id = "1"
+      mcc="310"
+      mnc="270"
+      apn="fast.t-mobile.com"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="default,supl,mms,ia"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mtu="1440"
+  />
+
+  <apn carrier="T-Mobile US 270 DUN"
+      carrier_id = "1"
+      mcc="310"
+      mnc="270"
+      apn="pcweb.tmobile.com"
+      user="none"
+      server="*"
+      password="none"
+      protocol="IP"
+      type="dun"
+      mtu="1440"
+  />
+
+  <apn carrier="MetroPCS 270"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="270"
+      apn="fast.metropcs.com"
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MetroPCS 270"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="270"
+      apn="fast.metropcs.com"
+      mmsc="http://metropcs.mmsmvno.com/mms/wapenc"
+      type="default,supl,mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="agms"
+      carrier_id = "1187"
+      mcc="310"
+      mnc="280"
+      apn="agms"
+      type="default,supl"
+  />
+
+  <apn carrier="T-Mobile US 300"
+      carrier_id = "1"
+      mcc="310"
+      mnc="300"
+      apn="fast.t-mobile.com"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="default,supl,mms,ia"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mtu="1440"
+  />
+
+  <apn carrier="T-Mobile US 300 DUN"
+      carrier_id = "1"
+      mcc="310"
+      mnc="300"
+      apn="pcweb.tmobile.com"
+      user="none"
+      server="*"
+      password="none"
+      protocol="IP"
+      type="dun"
+      mtu="1440"
+  />
+
+  <apn carrier="MetroPCS 300"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="300"
+      apn="fast.metropcs.com"
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MetroPCS 300"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="300"
+      apn="fast.metropcs.com"
+      mmsc="http://metropcs.mmsmvno.com/mms/wapenc"
+      type="default,supl,mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="310"
+      mnc="30"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+  />
+
+
+  <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="310"
+      mnc="300"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+  />
+
+  <apn carrier="T-Mobile US 310"
+      carrier_id = "1"
+      mcc="310"
+      mnc="310"
+      apn="fast.t-mobile.com"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="default,supl,mms,ia"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mtu="1440"
+  />
+
+  <apn carrier="T-Mobile US 310 DUN"
+      carrier_id = "1"
+      mcc="310"
+      mnc="310"
+      apn="pcweb.tmobile.com"
+      user="none"
+      server="*"
+      password="none"
+      protocol="IP"
+      type="dun"
+      mtu="1440"
+  />
+
+  <apn carrier="MetroPCS 310"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="310"
+      apn="fast.metropcs.com"
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MetroPCS 310"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="310"
+      apn="fast.metropcs.com"
+      mmsc="http://metropcs.mmsmvno.com/mms/wapenc"
+      type="default,supl,mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Cellular One NEAZ ISP"
+      carrier_id = "1796"
+      mcc="310"
+      mnc="320"
+      apn="isp.cellularoneaz.net"
+      type="default,supl"
+  />
+
+  <apn carrier="Cellular One ClearSky MMS"
+      carrier_id = "1796"
+      mcc="310"
+      mnc="320"
+      apn="wap.c1csky.net"
+      mmsc="http://mmsc.c1neaz.csky.us:6672"
+      mmsproxy="209.4.229.94"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="alltel2"
+      mcc="310"
+      mnc="330"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="alltel2"
+      mmsc="http://mms.alltel.com/servlets/mms"
+      mmsproxy="mms.alltel.com"
+      mmsport="8080"
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Alltel2 IMS"
+      mcc="310"
+      mnc="330"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="alltel2"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Alltel2 IMS"
+      mcc="310"
+      mnc="330"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="alltel2"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Alltel2 FOTA"
+      mcc="310"
+      mnc="330"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="alltel2"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Alltel2 FOTA"
+      mcc="310"
+      mnc="330"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="alltel2"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Alltel2"
+      mcc="310"
+      mnc="330"
+      apn="VZWINTERNET"
+      mmsc="http://mms.alltel.com/servlets/mms"
+      mmsproxy="mms.alltel.com"
+      mmsport="8080"
+      mvno_type="spn"
+      mvno_match_data="alltel2"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Alltel2"
+      mcc="310"
+      mnc="330"
+      apn="VZWINTERNET"
+      mmsc="http://mms.alltel.com/servlets/mms"
+      mmsproxy="mms.alltel.com"
+      mmsport="8080"
+      mvno_type="spn"
+      mvno_match_data="alltel2"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="pioneer"
+      carrier_id = "1185"
+      mcc="310"
+      mnc="360"
+      apn="CdmaNai"
+      mmsc="http://mms1.zsend.com"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Pioneer IMS"
+      carrier_id = "1185"
+      mcc="310"
+      mnc="360"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Pioneer IMS"
+      carrier_id = "1185"
+      mcc="310"
+      mnc="360"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Pioneer FOTA"
+      carrier_id = "1185"
+      mcc="310"
+      mnc="360"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Pioneer FOTA"
+      carrier_id = "1185"
+      mcc="310"
+      mnc="360"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Pioneer"
+      carrier_id = "1185"
+      mcc="310"
+      mnc="360"
+      apn="VZWINTERNET"
+      mmsc="http://mms1.zsend.com"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Pioneer"
+      carrier_id = "1185"
+      mcc="310"
+      mnc="360"
+      apn="VZWINTERNET"
+      mmsc="http://mms1.zsend.com"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Cingular 380 ATT"
+      carrier_id = "1187"
+      mcc="310"
+      mnc="380"
+      apn="proxy"
+      mmsc="http://mmsc.cingular.com/"
+      mmsproxy="wireless.cingular.com"
+      type="default,supl,mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="AWS MMS"
+      carrier_id = "1187"
+      mcc="310"
+      mnc="380"
+      apn="proxy"
+      mmsc="http://mmsc.mymmode.com"
+      mmsproxy="10.250.250.55"
+      mmsport="8080"
+      type="mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="AGMS Global"
+      carrier_id = "2030"
+      mcc="310"
+      mnc="380"
+      apn="agms.nl.gmm"
+      type="default"
+      mvno_type="gid"
+      mvno_match_data="50FF"
+  />
+
+   <apn carrier="GigSky"
+      carrier_id="2459"
+      mcc="310"
+      mnc="380"
+      apn="gigsky"
+      type="default"
+      mvno_type="spn"
+      mvno_match_data="GigSky"
+  />
+
+  <apn carrier="Celloneet MMS"
+      carrier_id = "1188"
+      mcc="310"
+      mnc="390"
+      apn="mms.celloneet.com"
+      user="user1@mms.celloneet.com"
+      password="celloneet"
+      mmsc="http://mms.celloneet.com/servlets/mms"
+      mmsproxy="63.99.231.135"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="ATT Nextgenphone"
+      carrier_id = "1187"
+      mcc="310"
+      mnc="410"
+      apn="nxtgenphone"
+      type="default,mms,supl,fota,hipri"
+      mmsc="http://mmsc.mobile.att.net"
+      mmsproxy="proxy.mobile.att.net"
+      mmsport="80"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="IMS"
+      carrier_id = "1187"
+      mcc="310"
+      mnc="410"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="ATT Phone"
+      carrier_id = "1187"
+      mcc="310"
+      mnc="410"
+      apn="phone"
+      type="default,mms,supl,fota,hipri"
+      mmsc="http://mmsc.mobile.att.net"
+      mmsproxy="proxy.mobile.att.net"
+      mmsport="80"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="ATT WAP"
+      carrier_id = "1187"
+      mcc="310"
+      mnc="410"
+      apn="wap.cingular"
+      proxy="wireless.cingular.com"
+      port="80"
+      server="cingulargprs.com"
+      mmsc="http://mmsc.cingular.com/"
+      mmsproxy="wireless.cingular.com"
+      type="default,supl,mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="Defense Mobile"
+      carrier_id = "2029"
+      mcc="310"
+      mnc="410"
+      apn="PRODATA"
+      mmsc="http://mmsc.mobile.att.net"
+      mmsproxy="proxy.mobile.att.net"
+      mmsport="80"
+      type="default,mms,supl"
+      protocol="IP"
+      mtusize="1410"
+      mvno_type="gid"
+      mvno_match_data="60FF"
+  />
+
+  <apn carrier="TFDATA"
+      carrier_id = "2022"
+      mcc="310"
+      mnc="410"
+      apn="tfdata"
+      type="default,mms,supl,hipri,fota"
+      protocol="IP"
+      roaming_protocol="IP"
+      mmsc="http://mms-tf.net"
+      mmsproxy="mms3.tracfone.com"
+      mmsport="80"
+      mvno_type="gid"
+      mvno_match_data="deff"
+  />
+
+  <apn carrier="TFDATA"
+      carrier_id = "2022"
+      mcc="310"
+      mnc="410"
+      apn="tfdata"
+      type="default,mms,supl,hipri,fota"
+      protocol="IP"
+      roaming_protocol="IP"
+      mmsc="http://mms-tf.net"
+      mmsproxy="mms3.tracfone.com"
+      mmsport="80"
+      mvno_type="gid"
+      mvno_match_data="ddff"
+  />
+
+  <apn carrier="CBW Data"
+      carrier_id = "1190"
+      mcc="310"
+      mnc="420"
+      apn="wap.gocbw.com"
+      mmsc="http://mms.gocbw.com:8088/mms"
+      mmsproxy="216.68.79.202"
+      mmsport="80"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="gci"
+      mcc="310"
+      mnc="430"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="gci"
+      mmsc="http://mmsc.akdt.dataonair.net:6672/"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Gci IMS"
+      mcc="310"
+      mnc="430"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="gci"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Gci IMS"
+      mcc="310"
+      mnc="430"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="gci"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Gci FOTA"
+      mcc="310"
+      mnc="430"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="gci"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Gci FOTA"
+      mcc="310"
+      mnc="430"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="gci"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Gci"
+      mcc="310"
+      mnc="430"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc.akdt.dataonair.net:6672/"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="gci"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Gci"
+      mcc="310"
+      mnc="430"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc.akdt.dataonair.net:6672/"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="gci"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Viaero Connect"
+      carrier_id = "1193"
+      mcc="310"
+      mnc="450"
+      apn="internet.vedge.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Viaero MMS"
+      carrier_id = "1193"
+      mcc="310"
+      mnc="450"
+      apn="mms"
+      mmsc="http://mms.viaero.com"
+      mmsproxy="10.168.3.23"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="DataConnect"
+      carrier_id = "1893"
+      mcc="310"
+      mnc="470"
+      apn="isp.cingular"
+      type="default,supl"
+  />
+
+  <apn carrier="MediaNet"
+      carrier_id = "1893"
+      mcc="310"
+      mnc="470"
+      apn="wap.cingular"
+      user="WAP@CINGULARGPRS.COM"
+      password="CINGULAR1"
+      mmsc="http://mmsc.cingular.com"
+      mmsproxy="66.209.11.32"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="nTelos Ota"
+      carrier_id = "1893"
+      mcc="310"
+      mnc="470"
+      apn="admin.4g.ntelos.com"
+      type="admin,fota,ota"
+      bearer_bitmask="13"
+      mmsc="http://mms.ntelospcs.net"
+      server="*"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="nTelos Ota"
+      carrier_id = "1893"
+      mcc="310"
+      mnc="470"
+      apn="admin.4g.ntelos.com"
+      type="admin,fota,ota"
+      bearer_bitmask="14"
+      mmsc="http://mms.ntelospcs.net"
+      server="*"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="nTelos Wireless"
+      carrier_id = "1893"
+      mcc="310"
+      mnc="470"
+      apn="internet.4g.ntelos.com"
+      type="default,internet,supl,hipri,mms"
+      mmsc="http://mms.ntelospcs.net"
+      server="*"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="nTelos Tether"
+      carrier_id = "1893"
+      mcc="310"
+      mnc="470"
+      apn="tethering.4g.ntelos.com"
+      type="dun,pam"
+      bearer_bitmask="13"
+      mmsc="http://mms.ntelospcs.net"
+      server="*"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="nTelos Tether"
+      carrier_id = "1893"
+      mcc="310"
+      mnc="470"
+      apn="tethering.4g.ntelos.com"
+      type="dun,pam"
+      bearer_bitmask="14"
+      mmsc="http://mms.ntelospcs.net"
+      server="*"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="nTelos Wireless"
+      carrier_id = "1893"
+      mcc="310"
+      mnc="470"
+      apn="CdmaNai"
+      mmsc="http://mms.ntelospcs.net/"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="DataConnect"
+      carrier_id = "1195"
+      mcc="310"
+      mnc="480"
+      apn="isp.cingular"
+      type="default,supl"
+  />
+
+  <apn carrier="MediaNet"
+      carrier_id = "1195"
+      mcc="310"
+      mnc="480"
+      apn="wap.cingular"
+      user="WAP@CINGULARGPRS.COM"
+      password="CINGULAR1"
+      mmsc="http://mmsc.cingular.com"
+      mmsproxy="66.209.11.32"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="T-Mobile US 490"
+      carrier_id = "1"
+      mcc="310"
+      mnc="490"
+      apn="fast.t-mobile.com"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="default,supl,mms,ia"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mtu="1440"
+  />
+
+  <apn carrier="T-Mobile US 490 DUN"
+      carrier_id = "1"
+      mcc="310"
+      mnc="490"
+      apn="pcweb.tmobile.com"
+      user="none"
+      server="*"
+      password="none"
+      protocol="IP"
+      type="dun"
+      mtu="1440"
+  />
+
+  <apn carrier="MetroPCS 490"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="490"
+      apn="fast.metropcs.com"
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MetroPCS 490"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="490"
+      apn="fast.metropcs.com"
+      mmsc="http://metropcs.mmsmvno.com/mms/wapenc"
+      type="default,supl,mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="GoodCall Picture Message"
+      carrier_id = "1"
+      mcc="310"
+      mnc="490"
+      apn="good.call"
+      mmsc="http://mms.suncom.net:8088/mms"
+      mmsproxy="66.150.33.125"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Suncom MMS"
+      carrier_id = "1"
+      mcc="310"
+      mnc="490"
+      apn="mms"
+      mmsc="http://mms.suncom.net:8088/mms"
+      mmsproxy="66.150.33.125"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="T-Mobile US 530"
+      carrier_id = "1"
+      mcc="310"
+      mnc="530"
+      apn="fast.t-mobile.com"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="default,supl,mms,ia"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mtu="1440"
+  />
+
+  <apn carrier="T-Mobile US 530 DUN"
+      carrier_id = "1"
+      mcc="310"
+      mnc="530"
+      apn="pcweb.tmobile.com"
+      user="none"
+      server="*"
+      password="none"
+      protocol="IP"
+      type="dun"
+      mtu="1440"
+  />
+
+  <apn carrier="MetroPCS 530"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="530"
+      apn="fast.metropcs.com"
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MetroPCS 530"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="530"
+      apn="fast.metropcs.com"
+      mmsc="http://metropcs.mmsmvno.com/mms/wapenc"
+      type="default,supl,mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="ATT Nextgenphone"
+      carrier_id = "1187"
+      mcc="310"
+      mnc="560"
+      apn="nxtgenphone"
+      mmsc="http://mmsc.mobile.att.net"
+      mmsproxy="proxy.mobile.att.net"
+      mmsport="80"
+      type="default,mms,supl,fota,hipri"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mtu="1410"
+  />
+
+  <apn carrier="IMS"
+      carrier_id = "1187"
+      mcc="310"
+      mnc="560"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="DobsonMMS"
+      carrier_id = "1187"
+      mcc="310"
+      mnc="560"
+      apn="dobsoncellularwap"
+      mmsc="http://mmsc"
+      mmsproxy="172.23.1.252"
+      mmsport="8799"
+      type="mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="Cellular One Smartphone"
+      carrier_id = "1800"
+      mcc="310"
+      mnc="570"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Cellular One MMS"
+      carrier_id = "1800"
+      mcc="310"
+      mnc="570"
+      apn="clearsky"
+      mmsc="http://mmsc.mtpcs.csky.us:6672/"
+      mmsproxy="209.4.229.229"
+      mmsport="9201"
+      type="mms"
+  />
+
+  <apn carrier="inland"
+      carrier_id = "2011"
+      mcc="310"
+      mnc="580"
+      apn="CdmaNai"
+      mmsc="http://mms.inland3g.com/inland/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Inland IMS"
+      carrier_id = "2011"
+      mcc="310"
+      mnc="580"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Inland IMS"
+      carrier_id = "2011"
+      mcc="310"
+      mnc="580"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Inland FOTA"
+      carrier_id = "2011"
+      mcc="310"
+      mnc="580"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Inland FOTA"
+      carrier_id = "2011"
+      mcc="310"
+      mnc="580"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Inland"
+      carrier_id = "2011"
+      mcc="310"
+      mnc="580"
+      apn="VZWINTERNET"
+      mmsc="http://mms.inland3g.com/inland/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Inland"
+      carrier_id = "2011"
+      mcc="310"
+      mnc="580"
+      apn="VZWINTERNET"
+      mmsc="http://mms.inland3g.com/inland/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="CellularOne MMS"
+      carrier_id = "1"
+      mcc="310"
+      mnc="590"
+      apn="cellular1wap"
+      mmsc="http://mmsc"
+      mmsproxy="172.23.1.252"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="T-Mobile US 590"
+      carrier_id = "1"
+      mcc="310"
+      mnc="590"
+      apn="fast.t-mobile.com"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="default,supl,mms,ia"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mtu="1440"
+  />
+
+  <apn carrier="T-Mobile US 590 DUN"
+      carrier_id = "1"
+      mcc="310"
+      mnc="590"
+      apn="pcweb.tmobile.com"
+      user="none"
+      server="*"
+      password="none"
+      protocol="IP"
+      type="dun"
+      mtu="1440"
+  />
+
+  <apn carrier="MetroPCS 590"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="590"
+      apn="fast.metropcs.com"
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MetroPCS 590"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="590"
+      apn="fast.metropcs.com"
+      mmsc="http://metropcs.mmsmvno.com/mms/wapenc"
+      type="default,supl,mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="cellcom"
+      carrier_id = "1802"
+      mcc="310"
+      mnc="600"
+      apn="CdmaNai"
+      mmsc="http://mms.cellcom.com/cellcom/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Cellcom IMS"
+      carrier_id = "1802"
+      mcc="310"
+      mnc="600"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Cellcom IMS"
+      carrier_id = "1802"
+      mcc="310"
+      mnc="600"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Cellcom FOTA"
+      carrier_id = "1802"
+      mcc="310"
+      mnc="600"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Cellcom FOTA"
+      carrier_id = "1802"
+      mcc="310"
+      mnc="600"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Cellcom"
+      carrier_id = "1802"
+      mcc="310"
+      mnc="600"
+      apn="VZWINTERNET"
+      mmsc="http://mms.cellcom.com/cellcom/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Cellcom"
+      carrier_id = "1802"
+      mcc="310"
+      mnc="600"
+      apn="VZWINTERNET"
+      mmsc="http://mms.cellcom.com/cellcom/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="EpicINT"
+      carrier_id = "1803"
+      mcc="310"
+      mnc="610"
+      apn="internet.epictouch"
+      type="default,supl"
+  />
+
+  <apn carrier="EpicMMS"
+      carrier_id = "1803"
+      mcc="310"
+      mnc="610"
+      apn="mms.epictouch"
+      mmsc="http://mmsc.westlinkcom.com/servlets/mms"
+      mmsproxy="63.99.231.135"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="T-Mobile US 640"
+      carrier_id = "1"
+      mcc="310"
+      mnc="640"
+      apn="fast.t-mobile.com"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="default,supl,mms,ia"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mtu="1440"
+  />
+
+  <apn carrier="T-Mobile US 640 DUN"
+      carrier_id = "1"
+      mcc="310"
+      mnc="640"
+      apn="pcweb.tmobile.com"
+      user="none"
+      server="*"
+      password="none"
+      protocol="IP"
+      type="dun"
+  />
+
+  <apn carrier="MetroPCS 640"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="640"
+      apn="fast.metropcs.com"
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MetroPCS 640"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="640"
+      apn="fast.metropcs.com"
+      mmsc="http://metropcs.mmsmvno.com/mms/wapenc"
+      type="default,supl,mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="T-Mobile US 660"
+      carrier_id = "1"
+      mcc="310"
+      mnc="660"
+      apn="fast.t-mobile.com"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="default,supl,mms,ia"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mtu="1440"
+  />
+
+  <apn carrier="T-Mobile US 660 DUN"
+      carrier_id = "1"
+      mcc="310"
+      mnc="660"
+      apn="pcweb.tmobile.com"
+      user="none"
+      server="*"
+      password="none"
+      protocol="IP"
+      type="dun"
+      mtu="1440"
+  />
+
+  <apn carrier="MetroPCS 660"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="660"
+      apn="fast.metropcs.com"
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MetroPCS 660"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="660"
+      apn="fast.metropcs.com"
+      mmsc="http://metropcs.mmsmvno.com/mms/wapenc"
+      type="default,supl,mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="310"
+      mnc="69"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+      mvno_type="gid"
+      mvno_match_data="547275554B3030656E"
+  />
+
+  <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="310"
+      mnc="69"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+	  mvno_type="gid"
+      mvno_match_data="54727555533030656E"
+  />
+
+  <apn carrier="Limitless"
+      carrier_id = "1808"
+      mcc="310"
+      mnc="690"
+      apn="limitless.us4g.com"
+      mmsc="http://mms.limitless.csky.us:6672/"
+      mmsproxy="209.4.229.79"
+      mmsport="9401"
+  />
+
+  <apn carrier="Rogers Internet"
+      carrier_id = "1811"
+      mcc="310"
+      mnc="720"
+      apn="internet.com"
+      user=""
+      password=""
+      proxy="10.128.1.69"
+      port="80"
+      type="default"
+  />
+
+  <apn carrier="Rogers Media"
+      carrier_id = "1811"
+      mcc="310"
+      mnc="720"
+      apn="media.com"
+      user="media"
+      password="mda01"
+      proxy="10.128.1.69"
+      port="80"
+      type="mms"
+  />
+
+  <apn carrier="appalachian"
+      carrier_id = "1813"
+      mcc="310"
+      mnc="750"
+      apn="CdmaNai"
+      mmsc="http://mms.ekn.com"
+      mmsproxy=""
+      mmsport="80"
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Appalachian IMS"
+      carrier_id = "1813"
+      mcc="310"
+      mnc="750"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Appalachian IMS"
+      carrier_id = "1813"
+      mcc="310"
+      mnc="750"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Appalachian FOTA"
+      carrier_id = "1813"
+      mcc="310"
+      mnc="750"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Appalachian FOTA"
+      carrier_id = "1813"
+      mcc="310"
+      mnc="750"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Appalachian"
+      carrier_id = "1813"
+      mcc="310"
+      mnc="750"
+      apn="VZWINTERNET"
+      mmsc="http://mms.ekn.com"
+      mmsproxy=""
+      mmsport="80"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Appalachian"
+      carrier_id = "1813"
+      mcc="310"
+      mnc="750"
+      apn="VZWINTERNET"
+      mmsc="http://mms.ekn.com"
+      mmsproxy=""
+      mmsport="80"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+  <apn carrier="Web 2"
+      carrier_id = "1815"
+      mcc="310"
+      mnc="770"
+      apn="i2.iwireless.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Web 1"
+      carrier_id = "1815"
+      mcc="310"
+      mnc="770"
+      apn="wap1.iwireless.com"
+      proxy="209.4.229.31"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Picture Messaging"
+      carrier_id = "1815"
+      mcc="310"
+      mnc="770"
+      apn="wap1.iwireless.com"
+      mmsc="http://mmsc.iwireless.dataonair.net:6672"
+      mmsproxy="209.4.229.31"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="T-Mobile US 800"
+      carrier_id = "1"
+      mcc="310"
+      mnc="800"
+      apn="fast.t-mobile.com"
+      mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc"
+      type="default,supl,mms,ia"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mtu="1440"
+  />
+
+  <apn carrier="T-Mobile US 800 DUN"
+      carrier_id = "1"
+      mcc="310"
+      mnc="800"
+      apn="pcweb.tmobile.com"
+      user="none"
+      server="*"
+      password="none"
+      protocol="IP"
+      type="dun"
+      mtu="1440"
+  />
+
+  <apn carrier="MetroPCS 800"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="800"
+      apn="fast.metropcs.com"
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="MetroPCS 800"
+      carrier_id = "1949"
+      mcc="310"
+      mnc="800"
+      apn="fast.metropcs.com"
+      mmsc="http://metropcs.mmsmvno.com/mms/wapenc"
+      type="default,supl,mms"
+      protocol="IPV6"
+      roaming_protocol="IP"
+      mvno_match_data="6D"
+      mvno_type="gid"
+  />
+
+  <apn carrier="nepa"
+      carrier_id = "2325"
+      mcc="310"
+      mnc="820"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="nepa"
+      mmsc="http://mmsc.c1nepa.csky.us:6672/"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Nepa IMS"
+      carrier_id = "2325"
+      mcc="310"
+      mnc="820"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="nepa"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Nepa IMS"
+      carrier_id = "2325"
+      mcc="310"
+      mnc="820"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="nepa"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Nepa FOTA"
+      carrier_id = "2325"
+      mcc="310"
+      mnc="820"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="nepa"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Nepa FOTA"
+      carrier_id = "2325"
+      mcc="310"
+      mnc="820"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="nepa"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Nepa"
+      carrier_id = "2325"
+      mcc="310"
+      mnc="820"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc.c1nepa.csky.us:6672/"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="nepa"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Nepa"
+      carrier_id = "2325"
+      mcc="310"
+      mnc="820"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc.c1nepa.csky.us:6672/"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="nepa"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "1821"
+      mcc="310"
+      mnc="840"
+      apn="isp"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1821"
+      mcc="310"
+      mnc="840"
+      apn="mms"
+      mmsc="http://mms.edgemobile.net/mmsc"
+      mmsproxy="12.108.12.13"
+      mmsport="3128"
+      type="mms"
+  />
+
+  <apn carrier="Edge MMS Prepay"
+      carrier_id = "1821"
+      mcc="310"
+      mnc="840"
+      apn="ppmms"
+      mmsc="http://mms.edgemobile.net/mmsc"
+      mmsproxy="12.108.12.13"
+      mmsport="3128"
+      type="mms"
+  />
+
+  <apn carrier="DTC dtcwap"
+      carrier_id = "1825"
+      mcc="310"
+      mnc="880"
+      apn="wapdtcw.com"
+      type="default"
+      proxy="204.181.155.218"
+      port="8080"
+  />
+
+  <apn carrier="DTC MMS"
+      carrier_id = "1825"
+      mcc="310"
+      mnc="880"
+      apn="mms.adv.com"
+      mmsc="http://mms.iot1.com/advantage/mms.php"
+      type="mms"
+  />
+
+  <apn carrier="midrivers"
+      carrier_id = "1827"
+      mcc="310"
+      mnc="900"
+      apn="CdmaNai"
+      mmsc="http://mmsc.midrivers.csky.us:6672/"
+      mmsproxy="209.4.229.27"
+      mmsport="9401"
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Midrivers IMS"
+      carrier_id = "1827"
+      mcc="310"
+      mnc="900"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Midrivers IMS"
+      carrier_id = "1827"
+      mcc="310"
+      mnc="900"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Midrivers FOTA"
+      carrier_id = "1827"
+      mcc="310"
+      mnc="900"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Midrivers FOTA"
+      carrier_id = "1827"
+      mcc="310"
+      mnc="900"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Midrivers"
+      carrier_id = "1827"
+      mcc="310"
+      mnc="900"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc.midrivers.csky.us:6672/"
+      mmsproxy="209.4.229.27"
+      mmsport="9401"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Midrivers"
+      carrier_id = "1827"
+      mcc="310"
+      mnc="900"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc.midrivers.csky.us:6672/"
+      mmsproxy="209.4.229.27"
+      mmsport="9401"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+  <apn carrier="WOW_WAP"
+      carrier_id = "1828"
+      mcc="310"
+      mnc="910"
+      apn="wap.firstcellular.com"
+      mmsc="mms.firstcellular.net/mmsc"
+      mmsproxy="10.101.1.5"
+      mmsport="3128"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="jamesvalley"
+      carrier_id = "1829"
+      mcc="310"
+      mnc="920"
+      apn="CdmaNai"
+      mmsc="http://m.iot1.com/jamesvalley/mms.php"
+      mmsproxy="m.iot1.com"
+      mmsport="9201"
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Jamesvalley IMS"
+      carrier_id = "1829"
+      mcc="310"
+      mnc="920"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Jamesvalley IMS"
+      carrier_id = "1829"
+      mcc="310"
+      mnc="920"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Jamesvalley FOTA"
+      carrier_id = "1829"
+      mcc="310"
+      mnc="920"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Jamesvalley FOTA"
+      carrier_id = "1829"
+      mcc="310"
+      mnc="920"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Jamesvalley"
+      carrier_id = "1829"
+      mcc="310"
+      mnc="920"
+      apn="VZWINTERNET"
+      mmsc="http://m.iot1.com/jamesvalley/mms.php"
+      mmsproxy="m.iot1.com"
+      mmsport="9201"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Jamesvalley"
+      carrier_id = "1829"
+      mcc="310"
+      mnc="920"
+      apn="VZWINTERNET"
+      mmsc="http://m.iot1.com/jamesvalley/mms.php"
+      mmsproxy="m.iot1.com"
+      mmsport="9201"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="coppervalley"
+      carrier_id = "1830"
+      mcc="310"
+      mnc="930"
+      apn="CdmaNai"
+      mmsc="http://cvwmms.com/servlets/mms"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Coppervalley IMS"
+      carrier_id = "1830"
+      mcc="310"
+      mnc="930"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Coppervalley IMS"
+      carrier_id = "1830"
+      mcc="310"
+      mnc="930"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Coppervalley FOTA"
+      carrier_id = "1830"
+      mcc="310"
+      mnc="930"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Coppervalley FOTA"
+      carrier_id = "1830"
+      mcc="310"
+      mnc="930"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Copper Valley"
+      carrier_id = "1830"
+      mcc="310"
+      mnc="930"
+      apn="VZWINTERNET"
+      mmsc="http://cvwmms.com/servlets/mms"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Copper Valley"
+      carrier_id = "1830"
+      mcc="310"
+      mnc="930"
+      apn="VZWINTERNET"
+      mmsc="http://cvwmms.com/servlets/mms"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="nntcwire"
+      carrier_id = "2324"
+      mcc="310"
+      mnc="960"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="nntcwire"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Nntcwire IMS"
+      carrier_id = "2324"
+      mcc="310"
+      mnc="960"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="nntcwire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Nntcwire IMS"
+      carrier_id = "2324"
+      mcc="310"
+      mnc="960"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="nntcwire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Nntcwire FOTA"
+      carrier_id = "2324"
+      mcc="310"
+      mnc="960"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="nntcwire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Nntcwire FOTA"
+      carrier_id = "2324"
+      mcc="310"
+      mnc="960"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="nntcwire"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Nntcwire"
+      carrier_id = "2324"
+      mcc="310"
+      mnc="960"
+      apn="VZWINTERNET"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="nntcwire"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Nntcwire"
+      carrier_id = "2324"
+      mcc="310"
+      mnc="960"
+      apn="VZWINTERNET"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="nntcwire"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="silverstar"
+      carrier_id = "2323"
+      mcc="310"
+      mnc="960"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="silverstar"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Silverstar IMS"
+      carrier_id = "2323"
+      mcc="310"
+      mnc="960"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="silverstar"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Silverstar IMS"
+      carrier_id = "2323"
+      mcc="310"
+      mnc="960"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="silverstar"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Silverstar FOTA"
+      carrier_id = "2323"
+      mcc="310"
+      mnc="960"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="silverstar"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Silverstar FOTA"
+      carrier_id = "2323"
+      mcc="310"
+      mnc="960"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="silverstar"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Silverstar"
+      carrier_id = "2323"
+      mcc="310"
+      mnc="960"
+      apn="VZWINTERNET"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="silverstar"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Silverstar"
+      carrier_id = "2323"
+      mcc="310"
+      mnc="960"
+      apn="VZWINTERNET"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="silverstar"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="snakeriver"
+      carrier_id = "2322"
+      mcc="310"
+      mnc="960"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="snakeriver"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Snakeriver IMS"
+      carrier_id = "2322"
+      mcc="310"
+      mnc="960"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="snakeriver"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Snakeriver IMS"
+      carrier_id = "2322"
+      mcc="310"
+      mnc="960"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="snakeriver"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Snakeriver FOTA"
+      carrier_id = "2322"
+      mcc="310"
+      mnc="960"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="snakeriver"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Snakeriver FOTA"
+      carrier_id = "2322"
+      mcc="310"
+      mnc="960"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="snakeriver"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Snakeriver"
+      carrier_id = "2322"
+      mcc="310"
+      mnc="960"
+      apn="VZWINTERNET"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="snakeriver"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Snakeriver"
+      carrier_id = "2322"
+      mcc="310"
+      mnc="960"
+      apn="VZWINTERNET"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="snakeriver"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="southcentral"
+      carrier_id = "2321"
+      mcc="310"
+      mnc="960"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="southcentral"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Southcentral IMS"
+      carrier_id = "2321"
+      mcc="310"
+      mnc="960"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="southcentral"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Southcentral IMS"
+      carrier_id = "2321"
+      mcc="310"
+      mnc="960"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="southcentral"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Southcentral FOTA"
+      carrier_id = "2321"
+      mcc="310"
+      mnc="960"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="southcentral"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Southcentral FOTA"
+      carrier_id = "2321"
+      mcc="310"
+      mnc="960"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="southcentral"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Southcentral"
+      carrier_id = "2321"
+      mcc="310"
+      mnc="960"
+      apn="VZWINTERNET"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="southcentral"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Southcentral"
+      carrier_id = "2321"
+      mcc="310"
+      mnc="960"
+      apn="VZWINTERNET"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="southcentral"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="strata"
+      carrier_id = "2320"
+      mcc="310"
+      mnc="960"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="strata"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Strata IMS"
+      carrier_id = "2320"
+      mcc="310"
+      mnc="960"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="strata"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Strata IMS"
+      carrier_id = "2320"
+      mcc="310"
+      mnc="960"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="strata"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Strata FOTA"
+      carrier_id = "2320"
+      mcc="310"
+      mnc="960"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="strata"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Strata FOTA"
+      carrier_id = "2320"
+      mcc="310"
+      mnc="960"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="strata"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="strata"
+      carrier_id = "2320"
+      mcc="310"
+      mnc="960"
+      apn="VZWINTERNET"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="strata"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="strata"
+      carrier_id = "2320"
+      mcc="310"
+      mnc="960"
+      apn="VZWINTERNET"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="strata"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="syringa"
+      mcc="310"
+      mnc="960"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="syringa"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Syringa IMS"
+      mcc="310"
+      mnc="960"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="syringa"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Syringa IMS"
+      mcc="310"
+      mnc="960"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="syringa"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Syringa FOTA"
+      mcc="310"
+      mnc="960"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="syringa"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Syringa FOTA"
+      mcc="310"
+      mnc="960"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="syringa"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Syringa"
+      mcc="310"
+      mnc="960"
+      apn="VZWINTERNET"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="syringa"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Syringa"
+      mcc="310"
+      mnc="960"
+      apn="VZWINTERNET"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="syringa"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="thumbcellular"
+      carrier_id = "1241"
+      mcc="311"
+      mnc="050"
+      apn="CdmaNai"
+      mmsc="http://mms.thumbcell.com/thumb/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Thumb IMS"
+      carrier_id = "1241"
+      mcc="311"
+      mnc="050"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Thumb IMS"
+      carrier_id = "1241"
+      mcc="311"
+      mnc="050"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Thumb FOTA"
+      carrier_id = "1241"
+      mcc="311"
+      mnc="050"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Thumb FOTA"
+      carrier_id = "1241"
+      mcc="311"
+      mnc="050"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Thumbcellular"
+      carrier_id = "1241"
+      mcc="311"
+      mnc="050"
+      apn="VZWINTERNET"
+      mmsc="http://mms.thumbcell.com/thumb/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Thumbcellular"
+      carrier_id = "1241"
+      mcc="311"
+      mnc="050"
+      apn="VZWINTERNET"
+      mmsc="http://mms.thumbcell.com/thumb/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="elementmobile"
+      carrier_id = "2319"
+      mcc="311"
+      mnc="070"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="elementmobile"
+      mmsc="http://mms.elementmobile.net"
+      mmsproxy=""
+      mmsport="8080"
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Elementmobile IMS"
+      carrier_id = "2319"
+      mcc="311"
+      mnc="070"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="elementmobile"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Elementmobile IMS"
+      carrier_id = "2319"
+      mcc="311"
+      mnc="070"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="elementmobile"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Elementmobile FOTA"
+      carrier_id = "2319"
+      mcc="311"
+      mnc="070"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="elementmobile"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Elementmobile FOTA"
+      carrier_id = "2319"
+      mcc="311"
+      mnc="070"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="elementmobile"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Elementmobile"
+      carrier_id = "2319"
+      mcc="311"
+      mnc="070"
+      apn="VZWINTERNET"
+      mmsc="http://mms.elementmobile.net"
+      mmsproxy=""
+      mmsport="8080"
+      mvno_type="spn"
+      mvno_match_data="elementmobile"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Elementmobile"
+      carrier_id = "2319"
+      mcc="311"
+      mnc="070"
+      apn="VZWINTERNET"
+      mmsc="http://mms.elementmobile.net"
+      mmsproxy=""
+      mmsport="8080"
+      mvno_type="spn"
+      mvno_match_data="elementmobile"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="PINE WAP"
+      carrier_id = "1244"
+      mcc="311"
+      mnc="080"
+      apn="PINE"
+      mmsc="http://69.8.34.146/mms/"
+      mmsproxy="69.8.34.146"
+      mmsport="9401"
+      type="default,mms"
+  />
+
+  <apn carrier="NexTech Wireless"
+      carrier_id = "2255"
+      mcc="311"
+      mnc="100"
+      authtype="3"
+      type="mms"
+      mmsc="http://mms.ntwls.net/nex-tech/mms.php"
+      server="*"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="sprocket"
+      carrier_id = "2318"
+      mcc="311"
+      mnc="140"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="sprocket"
+      mmsc="http://mms.sprocketwireless.com"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Sprocket IMS"
+      carrier_id = "2318"
+      mcc="311"
+      mnc="140"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="sprocket"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Sprocket IMS"
+      carrier_id = "2318"
+      mcc="311"
+      mnc="140"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="sprocket"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Sprocket FOTA"
+      carrier_id = "2318"
+      mcc="311"
+      mnc="140"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="sprocket"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Sprocket FOTA"
+      carrier_id = "2318"
+      mcc="311"
+      mnc="140"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="sprocket"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Sprocket"
+      carrier_id = "2318"
+      mcc="311"
+      mnc="140"
+      apn="VZWINTERNET"
+      mmsc="http://mms.sprocketwireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="sprocket"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Sprocket"
+      carrier_id = "2318"
+      mcc="311"
+      mnc="140"
+      apn="VZWINTERNET"
+      mmsc="http://mms.sprocketwireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="sprocket"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="ISP"
+      carrier_id = "1833"
+      mcc="311"
+      mnc="190"
+      apn="isp.cellular1.net"
+      type="default,supl"
+  />
+
+  <apn carrier="Tether"
+      carrier_id = "1833"
+      mcc="311"
+      mnc="190"
+      apn="broadband.cellular1.net"
+      type="dun"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1833"
+      mcc="311"
+      mnc="190"
+      apn="mms.cellular1.net"
+      mmsc="http://mms.cellular1.net"
+      mmsproxy="10.10.0.97"
+      mmsport="9201"
+      type="mms"
+  />
+
+  <apn carrier="Farmers GPRS"
+      carrier_id = "1835"
+      mcc="311"
+      mnc="210"
+      apn="internet.farmerswireless.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Farmers MMS"
+      carrier_id = "1835"
+      mcc="311"
+      mnc="210"
+      apn="mms.farmers.com"
+      mmsc="172.16.0.37:8514"
+      type="mms"
+  />
+
+  <apn carrier="U.S. Cellular"
+      carrier_id = "1952"
+      mcc="311"
+      mnc="220"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      authtype="3"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      carrier_id = "1952"
+      mcc="311"
+      mnc="220"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      carrier_id = "1952"
+      mcc="311"
+      mnc="220"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="221"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="221"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      carrier_id = "1952"
+      mcc="311"
+      mnc="220"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="221"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="221"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="221"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="222"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="222"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="222"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="223"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="223"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="223"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="224"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="224"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="224"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="225"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="225"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      carrier_enabled="true"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="225"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      carrier_enabled="true"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="226"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="226"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="226"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="227"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="227"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="227"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="228"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="228"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="228"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="229"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="229"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="229"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="CSpire ota"
+      carrier_id = "1836"
+      mcc="311"
+      mnc="230"
+      apn="admin.cs4glte.com"
+      server="*"
+      mmsport=""
+      mmsproxy=""
+      mmsc="http://pix.cspire.com"
+      type="admin,fota,ota"
+      bearer_bitmask="14"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="CSpire ota"
+      carrier_id = "1836"
+      mcc="311"
+      mnc="230"
+      apn="admin.cs4glte.com"
+      server="*"
+      mmsport=""
+      mmsproxy=""
+      mmsc="http://pix.cspire.com"
+      type="admin,fota,ota"
+      bearer_bitmask="13"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="CSpire internet"
+      carrier_id = "1836"
+      mcc="311"
+      mnc="230"
+      apn="internet.cs4glte.com"
+      server="*"
+      mmsport=""
+      mmsproxy=""
+      mmsc="http://pix.cspire.com"
+      type="default,internet,mms"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="CSpire tether"
+      carrier_id = "1836"
+      mcc="311"
+      mnc="230"
+      apn="tethering.cs4glte.com"
+      server="*"
+      mmsport=""
+      mmsproxy=""
+      mmsc="http://pix.cspire.com"
+      type="dun,pam"
+      bearer_bitmask="13"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="CSpire tether"
+      carrier_id = "1836"
+      mcc="311"
+      mnc="230"
+      apn="tethering.cs4glte.com"
+      server="*"
+      mmsport=""
+      mmsproxy=""
+      mmsc="http://pix.cspire.com"
+      type="dun,pam"
+      bearer_bitmask="14"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="CSpire"
+      carrier_id = "1836"
+      mcc="311"
+      mnc="230"
+      apn="CdmaNai"
+      mmsc="http://pix.cspire.com/servlets/mms"
+      mmsproxy="66.175.144.91"
+      mmsport="80"
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="leaco"
+      carrier_id = "1842"
+      mcc="311"
+      mnc="310"
+      apn="CdmaNai"
+      mmsc="http://204.181.155.217/mms/"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Leaco IMS"
+      carrier_id = "1842"
+      mcc="311"
+      mnc="310"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Leaco IMS"
+      carrier_id = "1842"
+      mcc="311"
+      mnc="310"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Leaco FOTA"
+      carrier_id = "1842"
+      mcc="311"
+      mnc="310"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Leaco FOTA"
+      carrier_id = "1842"
+      mcc="311"
+      mnc="310"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Leaco"
+      carrier_id = "1842"
+      mcc="311"
+      mnc="310"
+      apn="VZWINTERNET"
+      mmsc="http://204.181.155.217/mms/"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Leaco"
+      carrier_id = "1842"
+      mcc="311"
+      mnc="310"
+      apn="VZWINTERNET"
+      mmsc="http://204.181.155.217/mms/"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="illinoisvalley"
+      carrier_id = "1263"
+      mcc="311"
+      mnc="340"
+      apn="CdmaNai"
+      mmsc="http://mms.iot1.com/ivc/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Illinois IMS"
+      carrier_id = "1263"
+      mcc="311"
+      mnc="340"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Illinois IMS"
+      carrier_id = "1263"
+      mcc="311"
+      mnc="340"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Illinois FOTA"
+      carrier_id = "1263"
+      mcc="311"
+      mnc="340"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Illinois FOTA"
+      carrier_id = "1263"
+      mcc="311"
+      mnc="340"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Illinois valley"
+      carrier_id = "1263"
+      mcc="311"
+      mnc="340"
+      apn="VZWINTERNET"
+      mmsc="http://mms.iot1.com/ivc/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Illinois valley"
+      carrier_id = "1263"
+      mcc="311"
+      mnc="340"
+      apn="VZWINTERNET"
+      mmsc="http://mms.iot1.com/ivc/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="nemont"
+      carrier_id = "2317"
+      mcc="311"
+      mnc="350"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="nemont"
+      mmsc="http://mms.nemont.mobi/mms/"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Nemont IMS"
+      carrier_id = "2317"
+      mcc="311"
+      mnc="350"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="nemont"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Nemont IMS"
+      carrier_id = "2317"
+      mcc="311"
+      mnc="350"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="nemont"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Nemont FOTA"
+      carrier_id = "2317"
+      mcc="311"
+      mnc="350"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="nemont"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Nemont FOTA"
+      carrier_id = "2317"
+      mcc="311"
+      mnc="350"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="nemont"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Nemont"
+      carrier_id = "2317"
+      mcc="311"
+      mnc="350"
+      apn="VZWINTERNET"
+      mmsc="http://mms.nemont.mobi/mms/"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="nemont"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Nemont"
+      carrier_id = "2317"
+      mcc="311"
+      mnc="350"
+      apn="VZWINTERNET"
+      mmsc="http://mms.nemont.mobi/mms/"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="nemont"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="GCI WEB"
+      carrier_id = "1843"
+      mcc="311"
+      mnc="370"
+      apn="web.gci"
+      type="default,supl"
+  />
+
+  <apn carrier="GCI MMS"
+      carrier_id = "1843"
+      mcc="311"
+      mnc="370"
+      apn="mms.gci"
+      proxy="24.237.158.34"
+      port="9201"
+      mmsc="http://mmsc.gci.net"
+      mmsproxy="24.237.158.34"
+      mmsport="9201"
+      type="mms"
+  />
+
+  <apn carrier="Ericsson Test-SIM Internet"
+      carrier_id = "1845"
+      mcc="311"
+      mnc="390"
+      apn="VZWINTERNET"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      type="default,dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      profile_id="0"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Ericsson Test-SIM Internet"
+      carrier_id = "1845"
+      mcc="311"
+      mnc="390"
+      apn="VZWINTERNET"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      type="default,dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      profile_id="0"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Ericsson Test-SIM FOTA"
+      carrier_id = "1845"
+      mcc="311"
+      mnc="390"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      profile_id="3"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Ericsson Test-SIM FOTA"
+      carrier_id = "1845"
+      mcc="311"
+      mnc="390"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      profile_id="3"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Ericsson Test-SIM IMS"
+      carrier_id = "1845"
+      mcc="311"
+      mnc="390"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      profile_id="2"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Ericsson Test-SIM IMS"
+      carrier_id = "1845"
+      mcc="311"
+      mnc="390"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      profile_id="2"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Ericsson Test-SIM CBS"
+      carrier_id = "1845"
+      mcc="311"
+      mnc="390"
+      apn="VZWAPP"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      type="cbs,mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      profile_id="4"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="Ericsson Test-SIM CBS"
+      carrier_id = "1845"
+      mcc="311"
+      mnc="390"
+      apn="VZWAPP"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      type="cbs,mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      profile_id="4"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <apn carrier="chatmobrsa2"
+      carrier_id = "1846"
+      mcc="311"
+      mnc="410"
+      apn="CdmaNai"
+      mmsc="http://mmsc.hawkeyeswitch.net/mms/"
+      mmsproxy=""
+      mmsport="80"
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Chatmobrsa2 IMS"
+      carrier_id = "1846"
+      mcc="311"
+      mnc="410"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Chatmobrsa2 IMS"
+      carrier_id = "1846"
+      mcc="311"
+      mnc="410"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Chatmobrsa2 FOTA"
+      carrier_id = "1846"
+      mcc="311"
+      mnc="410"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Chatmobrsa2 FOTA"
+      carrier_id = "1846"
+      mcc="311"
+      mnc="410"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Chatmobrsa2"
+      carrier_id = "1846"
+      mcc="311"
+      mnc="410"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc.hawkeyeswitch.net/mms/"
+      mmsproxy=""
+      mmsport="80"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Chatmobrsa2"
+      carrier_id = "1846"
+      mcc="311"
+      mnc="410"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc.hawkeyeswitch.net/mms/"
+      mmsproxy=""
+      mmsport="80"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="northwestcell"
+      carrier_id = "1847"
+      mcc="311"
+      mnc="420"
+      apn="CdmaNai"
+      mmsc="http://mms.nwmcell.com/mms/"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="NW IMS"
+      carrier_id = "1847"
+      mcc="311"
+      mnc="420"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="NW IMS"
+      carrier_id = "1847"
+      mcc="311"
+      mnc="420"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="NW FOTA"
+      carrier_id = "1847"
+      mcc="311"
+      mnc="420"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="NW FOTA"
+      carrier_id = "1847"
+      mcc="311"
+      mnc="420"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Northwestcell"
+      carrier_id = "1847"
+      mcc="311"
+      mnc="420"
+      apn="VZWINTERNET"
+      mmsc="http://mms.nwmcell.com/mms/"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Northwestcell"
+      carrier_id = "1847"
+      mcc="311"
+      mnc="420"
+      apn="VZWINTERNET"
+      mmsc="http://mms.nwmcell.com/mms/"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="chatmobrsa1"
+      mcc="311"
+      mnc="430"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="chatmobrsa1"
+      mmsc="http://mmsc.hawkeyeswitch.net/mms/"
+      mmsproxy=""
+      mmsport="80"
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Chatmobrsa1 IMS"
+      mcc="311"
+      mnc="430"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="chatmobrsa1"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Chatmobrsa1 IMS"
+      mcc="311"
+      mnc="430"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="chatmobrsa1"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Chatmobrsa1 FOTA"
+      mcc="311"
+      mnc="430"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="chatmobrsa1"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Chatmobrsa1 FOTA"
+      mcc="311"
+      mnc="430"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="chatmobrsa1"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Chatmobrsa1"
+      mcc="311"
+      mnc="430"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc.hawkeyeswitch.net/mms/"
+      mmsproxy=""
+      mmsport="80"
+      mvno_type="spn"
+      mvno_match_data="chatmobrsa1"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Chatmobrsa1"
+      mcc="311"
+      mnc="430"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc.hawkeyeswitch.net/mms/"
+      mmsproxy=""
+      mmsport="80"
+      mvno_type="spn"
+      mvno_match_data="chatmobrsa1"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="bluegrass"
+      carrier_id = "1849"
+      mcc="311"
+      mnc="440"
+      apn="CdmaNai"
+      mmsc="http://mms.iot1.com/bluegrass/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Bluegrass IMS"
+      carrier_id = "1849"
+      mcc="311"
+      mnc="440"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Bluegrass IMS"
+      carrier_id = "1849"
+      mcc="311"
+      mnc="440"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Bluegrass FOTA"
+      carrier_id = "1849"
+      mcc="311"
+      mnc="440"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Bluegrass FOTA"
+      carrier_id = "1849"
+      mcc="311"
+      mnc="440"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Bluegrass"
+      carrier_id = "1849"
+      mcc="311"
+      mnc="440"
+      apn="VZWINTERNET"
+      mmsc="http://mms.iot1.com/bluegrass/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Bluegrass"
+      carrier_id = "1849"
+      mcc="311"
+      mnc="440"
+      apn="VZWINTERNET"
+      mmsc="http://mms.iot1.com/bluegrass/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="ptci"
+      carrier_id = "1850"
+      mcc="311"
+      mnc="450"
+      apn="CdmaNai"
+      mmsc="http://mmsc.ptci.net"
+      mmsproxy=""
+      mmsport="6672"
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Ptci IMS"
+      carrier_id = "1850"
+      mcc="311"
+      mnc="450"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Ptci IMS"
+      carrier_id = "1850"
+      mcc="311"
+      mnc="450"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Ptci FOTA"
+      carrier_id = "1850"
+      mcc="311"
+      mnc="450"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Ptci FOTA"
+      carrier_id = "1850"
+      mcc="311"
+      mnc="450"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Ptci"
+      carrier_id = "1850"
+      mcc="311"
+      mnc="450"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc.ptci.net"
+      mmsproxy=""
+      mmsport="6672"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Ptci"
+      carrier_id = "1850"
+      mcc="311"
+      mnc="450"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc.ptci.net"
+      mmsproxy=""
+      mmsport="6672"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <!-- Need two APNs for CDMA technologies: a default that is used normally -->
+  <!-- and a second APN to be used when DUN is required.  Even though the -->
+  <!-- parameters appear the same, the profileID sent to the radio when requesting -->
+  <!-- a DUN connection will be different -->
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="Verizon"
+      carrier_id = "1839"
+      mcc="311"
+      mnc="480"
+      apn="internet"
+      authtype="3"
+      type="default,mms,supl,fota,cbs"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      user_visible="false"
+  />
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="Verizon"
+      carrier_id = "1839"
+      mcc="311"
+      mnc="480"
+      apn="internet"
+      authtype="3"
+      type="default,mms,supl,fota,cbs,dun"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      profile_id="1"
+      user_visible="false"
+  />
+
+  <!-- bearer 1, 2, 3, 9, 10, 11, 13, 14, 15 -->
+  <apn carrier="Verizon"
+      carrier_id = "1839"
+      mcc="311"
+      mnc="480"
+      apn="VZWINTERNET"
+      type="default,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="1|2|3|9|10|11|13|14|15"
+      profile_id="0"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+  />
+
+  <!-- bearer 1, 2, 3, 9, 10, 11, 13, 14, 15 -->
+  <apn carrier="Verizon"
+      carrier_id = "1839"
+      mcc="311"
+      mnc="480"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="1|2|3|9|10|11|13|14|15"
+      profile_id="3"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+      user_visible="false"
+  />
+
+  <!-- bearer 1, 2, 3, 9, 10, 11, 13, 14, 15 -->
+  <apn carrier="Verizon"
+      carrier_id = "1839"
+      mcc="311"
+      mnc="480"
+      apn="IMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="1|2|3|9|10|11|13|14|15"
+      profile_id="2"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+      user_visible="false"
+  />
+
+  <!-- bearer 1, 2, 3, 9, 10, 11, 13, 14, 15 -->
+  <apn carrier="Verizon"
+      carrier_id = "1839"
+      mcc="311"
+      mnc="480"
+      apn="VZWAPP"
+      type="cbs,mms"
+      mmsc="http://mms.vtext.com/servlets/mms"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="1|2|3|9|10|11|13|14|15"
+      profile_id="4"
+      modem_cognitive="true"
+      max_conns="1023"
+      max_conns_time="300"
+      user_visible="false"
+  />
+
+  <apn carrier="24-7 WAP"
+      carrier_id = "1854"
+      mcc="311"
+      mnc="500"
+      apn="wap"
+      mmsc="http://mmsc.ctc.csky.us:6672"
+      mmsproxy="09.4.229.46"
+      mmsport="9201"
+  />
+
+  <apn carrier="Mosaic WAP"
+      carrier_id = "2316"
+      mcc="311"
+      mnc="500"
+      apn="wap"
+      type="default,mms"
+      mmsc="http://mmsc.ctc.csky.us:6672/"
+      mmsproxy="209.4.229.46"
+      mmsport="9201"
+      mvno_type="spn"
+      mvno_match_data="Mosaic Mobile"
+  />
+
+  <apn carrier="Mosaic WAP AT&amp;T"
+      carrier_id = "2316"
+      mcc="311"
+      mnc="500"
+      apn="wap"
+      type="default,mms"
+      mmsc="http://mmsc.ctc.csky.us:6672/"
+      mmsproxy="209.4.229.46"
+      mmsport="9201"
+      mvno_type="spn"
+      mvno_match_data="Mosaic RPA"
+  />
+
+  <apn carrier="Mosaic WAP T-Mobile"
+      carrier_id = "2316"
+      mcc="311"
+      mnc="500"
+      apn="wap"
+      type="default,mms"
+      mmsc="http://mmsc.ctc.csky.us:6672/"
+      mmsproxy="209.4.229.46"
+      mmsport="9201"
+      mvno_type="spn"
+      mvno_match_data="Mosaic RPT"
+  />
+
+  <apn carrier="Mosaic WAP Other networks"
+      carrier_id = "2316"
+      mcc="311"
+      mnc="500"
+      apn="wap"
+      type="default,mms"
+      mmsc="http://mmsc.ctc.csky.us:6672/"
+      mmsproxy="209.4.229.46"
+      mmsport="9201"
+      mvno_type="spn"
+      mvno_match_data="Mosaic RPO"
+  />
+
+  <apn carrier="Norvado"
+      carrier_id = "2315"
+      mcc="311"
+      mnc="500"
+      apn="wap"
+      type="default,mms"
+      mmsc="http://mmsc.ctc.csky.us:6672/"
+      mmsproxy="209.4.229.46"
+      mmsport="9201"
+      mvno_type="spn"
+      mvno_match_data="Norvado Wireless"
+  />
+
+  <apn carrier="Norvado AT&amp;T"
+      carrier_id = "2315"
+      mcc="311"
+      mnc="500"
+      apn="wap"
+      type="default,mms"
+      mmsc="http://mmsc.ctc.csky.us:6672/"
+      mmsproxy="209.4.229.46"
+      mmsport="9201"
+      mvno_type="spn"
+      mvno_match_data="Norvado Wireless RPA"
+  />
+
+  <apn carrier="Norvado T-Mobile"
+      carrier_id = "2315"
+      mcc="311"
+      mnc="500"
+      apn="wap"
+      type="default,mms"
+      mmsc="http://mmsc.ctc.csky.us:6672/"
+      mmsproxy="209.4.229.46"
+      mmsport="9201"
+      mvno_type="spn"
+      mvno_match_data="Norvado Wireless RPT"
+  />
+
+  <apn carrier="Norvado Other networks"
+      carrier_id = "2315"
+      mcc="311"
+      mnc="500"
+      apn="wap"
+      type="default,mms"
+      mmsc="http://mmsc.ctc.csky.us:6672/"
+      mmsproxy="209.4.229.46"
+      mmsport="9201"
+      mvno_type="spn"
+      mvno_match_data="Norvado Wireless RPO"
+  />
+
+  <apn carrier="Blaze"
+      carrier_id = "1857"
+      mcc="311"
+      mnc="530"
+      apn="mms.mymobiletxt.com"
+      type="default,mms"
+      mmsc="http://mms2.mymobiletxt.net"
+  />
+
+  <apn carrier="Duet Internet"
+      carrier_id = "1857"
+      mcc="311"
+      mnc="530"
+      apn="wap.mymobiletxt.com"
+      type="default,mms"
+      protocol="IP"
+      mmsc="http://172.16.16.103/mms/"
+      mmsproxy="172.16.16.102"
+      mmsport="8080"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      carrier_id = "1952"
+      mcc="311"
+      mnc="580"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      carrier_id = "1952"
+      mcc="311"
+      mnc="580"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      carrier_id = "1952"
+      mcc="311"
+      mnc="580"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="581"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="581"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="581"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="582"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="582"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="582"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="583"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="583"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="583"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="584"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="584"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="584"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="585"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="585"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="585"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="586"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="586"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="586"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="587"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="587"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="587"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="588"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="588"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="588"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="589"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+      mtu="1422"
+  />
+
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="589"
+      apn="usccinternet"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+      mtu="1422"
+  />
+
+  <!-- bearer 4, 5, 6, 7, 8, 12 -->
+  <apn carrier="U.S. Cellular"
+      mcc="311"
+      mnc="589"
+      mmsc="http://mmsc1.uscc.net/mmsc/MMS"
+      type="default,mms,dun,hipri,fota"
+      authtype="3"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="4|5|6|7|8|12"
+      mtu="1422"
+  />
+
+  <apn carrier="gsc"
+      carrier_id = "2288"
+      mcc="311"
+      mnc="590"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="gsc"
+      mmsc="http://mmsc1.gscdata.com"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Gsc IMS"
+      carrier_id = "2288"
+      mcc="311"
+      mnc="590"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="gsc"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Gsc IMS"
+      carrier_id = "2288"
+      mcc="311"
+      mnc="590"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="gsc"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Gsc FOTA"
+      carrier_id = "2288"
+      mcc="311"
+      mnc="590"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="gsc"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Gsc FOTA"
+      carrier_id = "2288"
+      mcc="311"
+      mnc="590"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="gsc"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Gsc"
+      carrier_id = "2288"
+      mcc="311"
+      mnc="590"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc1.gscdata.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="gsc"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Gsc"
+      carrier_id = "2288"
+      mcc="311"
+      mnc="590"
+      apn="VZWINTERNET"
+      mmsc="http://mmsc1.gscdata.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="gsc"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="cox"
+      carrier_id = "1910"
+      mcc="311"
+      mnc="600"
+      apn="CdmaNai"
+      mmsc="http://mms.cox.net/cox/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Cox IMS"
+      carrier_id = "1910"
+      mcc="311"
+      mnc="600"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Cox IMS"
+      carrier_id = "1910"
+      mcc="311"
+      mnc="600"
+      apn="VZWIMS"
+      type="ims,ia"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Cox FOTA"
+      carrier_id = "1910"
+      mcc="311"
+      mnc="600"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Cox FOTA"
+      carrier_id = "1910"
+      mcc="311"
+      mnc="600"
+      apn="VZWADMIN"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Cox"
+      carrier_id = "1910"
+      mcc="311"
+      mnc="600"
+      apn="VZWINTERNET"
+      mmsc="http://mms.cox.net/cox/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Cox"
+      carrier_id = "1910"
+      mcc="311"
+      mnc="600"
+      apn="VZWINTERNET"
+      mmsc="http://mms.cox.net/cox/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="srtcomm"
+      carrier_id = "2158"
+      mcc="311"
+      mnc="610"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="srtcomm"
+      mmsc="http://mms.iot1.com/srt/mms.php"
+      mmsproxy="mms.iot1.com"
+      mmsport="9201"
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Srtcomm IMS"
+      carrier_id = "2158"
+      mcc="311"
+      mnc="610"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="srtcomm"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Srtcomm IMS"
+      carrier_id = "2158"
+      mcc="311"
+      mnc="610"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="srtcomm"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Srtcomm FOTA"
+      carrier_id = "2158"
+      mcc="311"
+      mnc="610"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="srtcomm"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Srtcomm FOTA"
+      carrier_id = "2158"
+      mcc="311"
+      mnc="610"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="srtcomm"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Srtcomm"
+      carrier_id = "2158"
+      mcc="311"
+      mnc="610"
+      apn="VZWINTERNET"
+      mmsc="http://mms.iot1.com/srt/mms.php"
+      mmsproxy="mms.iot1.com"
+      mmsport="9201"
+      mvno_type="spn"
+      mvno_match_data="srtcomm"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Srtcomm"
+      carrier_id = "2158"
+      mcc="311"
+      mnc="610"
+      apn="VZWINTERNET"
+      mmsc="http://mms.iot1.com/srt/mms.php"
+      mmsproxy="mms.iot1.com"
+      mmsport="9201"
+      mvno_type="spn"
+      mvno_match_data="srtcomm"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="unitedwireless"
+      carrier_id = "2159"
+      mcc="311"
+      mnc="650"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="unitedwireless"
+      mmsc="http://mms.unitedwireless.com/united/mms.php"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="United IMS"
+      carrier_id = "2159"
+      mcc="311"
+      mnc="650"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="unitedwireless"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="United IMS"
+      carrier_id = "2159"
+      mcc="311"
+      mnc="650"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="unitedwireless"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="United FOTA"
+      carrier_id = "2159"
+      mcc="311"
+      mnc="650"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="unitedwireless"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="United FOTA"
+      carrier_id = "2159"
+      mcc="311"
+      mnc="650"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="unitedwireless"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Unitedwireless"
+      carrier_id = "2159"
+      mcc="311"
+      mnc="650"
+      apn="VZWINTERNET"
+      mmsc="http://mms.unitedwireless.com/united/mms.php"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="unitedwireless"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Unitedwireless"
+      carrier_id = "2159"
+      mcc="311"
+      mnc="650"
+      apn="VZWINTERNET"
+      mmsc="http://mms.unitedwireless.com/united/mms.php"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="unitedwireless"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Pine Belt"
+      carrier_id = "2160"
+      mcc="311"
+      mnc="670"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="Pine Belt"
+      carrier_id = "2160"
+      mcc="311"
+      mnc="670"
+      apn="lte.ota.pinebelt.net"
+      type="fota"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="Pine Belt"
+      carrier_id = "2160"
+      mcc="311"
+      mnc="670"
+      apn="lte.internet.pinebelt.net"
+      mmsc="http://mmsc.pinebelt.net:6672/"
+      mmsproxy=""
+      mmsport=""
+      type="default,mms,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="Pine Belt"
+      carrier_id = "2160"
+      mcc="311"
+      mnc="670"
+      apn="lte.tether.pinebelt.net"
+      mmsc="http://mmsc.pinebelt.net:6672/"
+      mmsproxy=""
+      mmsport=""
+      type="dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="TelAlaska Cellular"
+      carrier_id = "2256"
+      mcc="311"
+      mnc="740"
+      apn="akcell.mobi"
+      type="default"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Cleartalk"
+      carrier_id = "2257"
+      mcc="311"
+      mnc="750"
+      apn="CdmaNai"
+      authtype="3"
+      type="default,mms,supl,dun"
+      mmsc="http://mms.cleartalk.us/cleartalk/mms.php"
+      protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+  <apn carrier="ClearTalk LTE"
+      carrier_id = "2257"
+      mcc="311"
+      mnc="750"
+      apn="home.netamerica.com"
+      type="default,mms,supl,dun"
+      bearer_bitmask="14"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      mmsc="http://mms.cleartalk.us/cleartalk/mms.php"
+      mtu="1428"
+    />
+
+  <apn carrier="Sprint"
+      carrier_id = "1788"
+      mcc="311"
+      mnc="882"
+      apn="internet.curiosity.sprint.com"
+      type="default"
+      protocol="IPV4V6"
+      network_type_bitmask="13"
+  />
+  <apn carrier="Sprint"
+      carrier_id = "1788"
+      mcc="311"
+      mnc="882"
+      apn="arm.ericsson.iot"
+      type="admin"
+      protocol="IPV4V6"
+      network_type_bitmask="13"
+  />
+
+  <apn carrier="MobileNation"
+      carrier_id = "2258"
+      mcc="311"
+      mnc="910"
+      apn="mymn4g.net"
+      server="*"
+      mmsport="8081"
+      mmsproxy="mms.mymn3g.net"
+      mmsc="http://mms.mymn3g.net"
+      type="default,internet,admin,fota,dun,mms"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="charitonvalley"
+      mcc="311"
+      mnc="920"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="charitonvalley"
+      mmsc="http://mms.cvalley.net"
+      mmsproxy=""
+      mmsport="80"
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Chariton IMS"
+      mcc="311"
+      mnc="920"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="charitonvalley"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Chariton IMS"
+      mcc="311"
+      mnc="920"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="charitonvalley"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Chariton FOTA"
+      mcc="311"
+      mnc="920"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="charitonvalley"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Chariton FOTA"
+      mcc="311"
+      mnc="920"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="charitonvalley"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Chariton valley"
+      mcc="311"
+      mnc="920"
+      apn="VZWINTERNET"
+      mmsc="http://mms.cvalley.net"
+      mmsproxy=""
+      mmsport="80"
+      mvno_type="spn"
+      mvno_match_data="charitonvalley"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Chariton valley"
+      mcc="311"
+      mnc="920"
+      apn="VZWINTERNET"
+      mmsc="http://mms.cvalley.net"
+      mmsproxy=""
+      mmsport="80"
+      mvno_type="spn"
+      mvno_match_data="charitonvalley"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Syringa Wireless"
+      carrier_id = "2259"
+      mcc="311"
+      mnc="930"
+      apn="internet.syringawireless.com"
+      server="*"
+      mmsport="80"
+      mmsproxy=""
+      mmsc="http://mms.rinawireless.com"
+      type="default,internet,admin,fota,dun,mms"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="custer"
+      carrier_id = "2162"
+      mcc="312"
+      mnc="040"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="custer"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Custer IMS"
+      carrier_id = "2162"
+      mcc="312"
+      mnc="040"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="custer"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Custer IMS"
+      carrier_id = "2162"
+      mcc="312"
+      mnc="040"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="custer"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Custer FOTA"
+      carrier_id = "2162"
+      mcc="312"
+      mnc="040"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="custer"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Custer FOTA"
+      carrier_id = "2162"
+      mcc="312"
+      mnc="040"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="custer"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Custer"
+      carrier_id = "2162"
+      mcc="312"
+      mnc="040"
+      apn="VZWINTERNET"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="custer"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Custer"
+      carrier_id = "2162"
+      mcc="312"
+      mnc="040"
+      apn="VZWINTERNET"
+      mmsc="http://mms.rinawireless.com"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="custer"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="chatmobility"
+      mcc="312"
+      mnc="160"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="chatmobility"
+      mmsc="http://mms.chatmobility.com/mms/"
+      mmsproxy=""
+      mmsport="80"
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Chatmobility IMS"
+      mcc="312"
+      mnc="160"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="chatmobility"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Chatmobility IMS"
+      mcc="312"
+      mnc="160"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="chatmobility"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="chatmobility FOTA"
+      mcc="312"
+      mnc="160"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="chatmobility"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="chatmobility FOTA"
+      mcc="312"
+      mnc="160"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="chatmobility"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="chatmobility"
+      mcc="312"
+      mnc="160"
+      apn="VZWINTERNET"
+      mmsc="http://mms.chatmobility.com/mms/"
+      mmsproxy=""
+      mmsport="80"
+      mvno_type="spn"
+      mvno_match_data="chatmobility"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="chatmobility"
+      mcc="312"
+      mnc="160"
+      apn="VZWINTERNET"
+      mmsc="http://mms.chatmobility.com/mms/"
+      mmsproxy=""
+      mmsport="80"
+      mvno_type="spn"
+      mvno_match_data="chatmobility"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="NexTech Ota"
+      carrier_id = "2260"
+      mcc="312"
+      mnc="420"
+      apn="admin.lte.ntwls.com"
+      server="*"
+      mmsport=""
+      mmsproxy=""
+      mmsc="http://mms.ntwls.net/nex-tech/mms.php"
+      type="admin,fota,ota"
+      bearer_bitmask="14"
+      protocol="IP"
+  />
+
+  <apn carrier="NexTech Ota"
+      carrier_id = "2260"
+      mcc="312"
+      mnc="420"
+      apn="admin.lte.ntwls.com"
+      server="*"
+      mmsport=""
+      mmsproxy=""
+      mmsc="http://mms.ntwls.net/nex-tech/mms.php"
+      type="admin,fota,ota"
+      bearer_bitmask="13"
+      protocol="IP"
+  />
+
+  <apn carrier="NexTech Wireless"
+      carrier_id = "2260"
+      mcc="312"
+      mnc="420"
+      apn="internet.lte.ntwls.com"
+      server="*"
+      mmsport=""
+      mmsproxy=""
+      mmsc="http://mms.ntwls.net/nex-tech/mms.php"
+      type="default,internet,supl,hipri,mms"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="NexTech Tether"
+      carrier_id = "2260"
+      mcc="312"
+      mnc="420"
+      apn="modem.lte.ntwls.com"
+      server="*"
+      mmsport=""
+      mmsproxy=""
+      mmsc="http://mms.ntwls.net/nex-tech/mms.php"
+      type="dun,pam"
+      bearer_bitmask="14"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="NexTech Tether"
+      carrier_id = "2260"
+      mcc="312"
+      mnc="420"
+      apn="modem.lte.ntwls.com"
+      server="*"
+      mmsport=""
+      mmsproxy=""
+      mmsc="http://mms.ntwls.net/nex-tech/mms.php"
+      type="dun,pam"
+      bearer_bitmask="13"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="Blue Wireless"
+      carrier_id = "2261"
+      mcc="312"
+      mnc="570"
+      apn="Blue Hotspot"
+      server="*"
+      mmsport="8514"
+      mmsproxy=""
+      user="%M@dun.bluehandset.com"
+      password="wirelessblue"
+      mmsc="http://mms.blueunlimited.com"
+      type="default,dun,mms"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="openmobile"
+      mcc="330"
+      mnc="000"
+      apn="CdmaNai"
+      mvno_type="spn"
+      mvno_match_data="openmobile"
+      mmsc="http://mms.openmobilepr.com:1981/"
+      mmsproxy=""
+      mmsport=""
+      type="mms"
+      carrier_enabled="false"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="6"
+  />
+
+  <apn carrier="Openmobile IMS"
+      mcc="330"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="openmobile"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Openmobile IMS"
+      mcc="330"
+      mnc="000"
+      apn="VZWIMS"
+      type="ims,ia"
+      mvno_type="spn"
+      mvno_match_data="openmobile"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Openmobile FOTA"
+      mcc="330"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="openmobile"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Openmobile FOTA"
+      mcc="330"
+      mnc="000"
+      apn="VZWADMIN"
+      type="fota"
+      mvno_type="spn"
+      mvno_match_data="openmobile"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Openmobile"
+      mcc="330"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://mms.openmobilepr.com:1981/"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="openmobile"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="13"
+  />
+
+  <apn carrier="Openmobile"
+      mcc="330"
+      mnc="000"
+      apn="VZWINTERNET"
+      mmsc="http://mms.openmobilepr.com:1981/"
+      mmsproxy=""
+      mmsport=""
+      mvno_type="spn"
+      mvno_match_data="openmobile"
+      type="default,mms,dun,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Puerto Rico:Claro:LTE"
+      carrier_id = "1955"
+      mcc="330"
+      mnc="110"
+      apn="lte.claropr.com"
+      type="default"
+      authtype="1"
+  />
+
+  <apn carrier="Puerto Rico:Claro:Banda Ancha"
+      carrier_id = "1955"
+      mcc="330"
+      mnc="110"
+      apn="lte.claropr.com"
+      type="dun"
+      authtype="1"
+  />
+
+  <apn carrier="MMS CLARO"
+      carrier_id = "1955"
+      mcc="330"
+      mnc="110"
+      apn="mmslte.claropr.com"
+      mmsproxy="10.50.38.3"
+      mmsport="8799"
+      mmsc="http://mmsg.claropr.com:10021/mmsc"
+      authtype='1'
+      type="mms"
+  />
+
+
+  <apn carrier="Internet"
+      carrier_id = "1913"
+      mcc="334"
+      mnc="020"
+      apn="internet.itelcel.com"
+      user="webgprs"
+      password="webgprs2002"
+      authtype="1"
+      type="default,supl"
+  />
+
+
+  <apn carrier="Mensajes Multimedia"
+      carrier_id = "1913"
+      mcc="334"
+      mnc="020"
+      apn="mms.itelcel.com"
+      user="mmsgprs"
+      password="mmsgprs2003"
+      mmsc="http://mms.itelcel.com/servlets/mms"
+      mmsproxy="148.233.151.240"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+
+  <apn carrier="Movistar INTERNET"
+      carrier_id = "1914"
+      mcc="334"
+      mnc="03"
+      apn="internet.movistar.mx"
+      user="movistar"
+      password="movistar"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "1914"
+      mcc="334"
+      mnc="03"
+      apn="mms.movistar.mx"
+      user="movistar"
+      password="movistar"
+      mmsc="http://mms.movistar.mx"
+      mmsproxy="10.2.20.1"
+      mmsport="80"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Movistar INTERNET"
+      carrier_id = "1914"
+      mcc="334"
+      mnc="030"
+      apn="internet.movistar.mx"
+      user="movistar"
+      password="movistar"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "1914"
+      mcc="334"
+      mnc="030"
+      apn="mms.movistar.mx"
+      user="movistar"
+      password="movistar"
+      mmsc="http://mms.movistar.mx"
+      mmsproxy="10.2.20.1"
+      mmsport="80"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Iusacell Internet"
+      carrier_id = "1915"
+      mcc="334"
+      mnc="050"
+      apn="web.iusacellgsm.mx"
+      user="iusacellgsm"
+      password="iusacellgsm"
+      type="default,supl"
+  />
+
+  <apn carrier="Iusacell MMS"
+      carrier_id = "1915"
+      mcc="334"
+      mnc="050"
+      apn="mms.iusacellgsm.mx"
+      user="mmsiusacellgsm"
+      password="mmsiusacellgsm"
+      mmsc="http://mms.iusacell3g.com/"
+      type="mms"
+  />
+
+  <apn carrier="Modem"
+      mcc="334"
+      mnc="50"
+      authtype="1"
+      type="dun"
+      user="iusacellgsm"
+      password="iusacellgsm"
+      apn="modem.iusacellgsm.mx"
+  />
+
+  <apn carrier='Localización'
+      carrier_id = "1912"
+      mcc='334'
+      mnc='090'
+      apn='location.nexteldata.com.mx'
+      server='http://supl.nexteldata.com.mx'
+      authtype='0'
+      type='supl'
+      port='7275'
+  />
+
+  <apn carrier='MMS'
+      carrier_id = "1912"
+      mcc='334'
+      mnc='090'
+      apn='mms.nexteldata.com.mx'
+      authtype='0'
+      mmsc='http://3gmms.nexteldata.com.mx'
+      mmsproxy='129.192.129.104'
+      mmsport='8080'
+      type='mms'
+  />
+
+  <apn carrier='Internet'
+      carrier_id = "1912"
+      mcc='334'
+      mnc='090'
+      apn='modem.nexteldata.com.mx'
+      authtype='0'
+      type='dun'
+  />
+
+  <apn carrier='Navegación'
+      carrier_id = "1912"
+      mcc='334'
+      mnc='090'
+      apn='wap.nexteldata.com.mx'
+      authtype='0'
+      type='default'
+  />
+
+  <apn carrier="INTERNET Digicel"
+      carrier_id = "1577"
+      mcc="338"
+      mnc="05"
+      apn="web"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Digicel"
+      carrier_id = "1577"
+      mcc="338"
+      mnc="05"
+      apn="wap"
+      mmsproxy="172.16.7.12"
+      mmsport="8080"
+      mmsc="http://mms.digicelgroup.com"
+      type="mms"
+  />
+
+  <apn carrier="INTERNET Digicel"
+      carrier_id = "1577"
+      mcc="338"
+      mnc="050"
+      apn="web"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Digicel"
+      carrier_id = "1577"
+      mcc="338"
+      mnc="050"
+      apn="wap"
+      mmsproxy="172.16.7.12"
+      mmsport="8080"
+      mmsc="http://mms.digicelgroup.com"
+      type="mms"
+  />
+
+  <apn carrier="Lime Internet Postpaid"
+      carrier_id = "2224"
+      mcc="338"
+      mnc="18"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Lime Postpaid MMS"
+      carrier_id = "2224"
+      mcc="338"
+      mnc="18"
+      apn="multimedia"
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      mmsc="http://mmsc"
+      type="mms"
+  />
+
+  <apn carrier="Lime Internet Prepaid"
+      carrier_id = "2224"
+      mcc="338"
+      mnc="18"
+      apn="ppinternet"
+      type="default,supl"
+  />
+
+  <apn carrier="Lime Prepaid MMS"
+      carrier_id = "2224"
+      mcc="338"
+      mnc="18"
+      apn="ppmms"
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      mmsc="http://mmsc"
+      type="mms"
+  />
+
+  <apn carrier="Lime Internet Postpaid"
+      carrier_id = "2224"
+      mcc="338"
+      mnc="180"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Lime Postpaid MMS"
+      carrier_id = "2224"
+      mcc="338"
+      mnc="180"
+      apn="multimedia"
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      mmsc="http://mmsc"
+      type="mms"
+  />
+
+  <apn carrier="Lime Internet Prepaid"
+      carrier_id = "2224"
+      mcc="338"
+      mnc="180"
+      apn="ppinternet"
+      type="default,supl"
+  />
+
+  <apn carrier="Lime Prepaid MMS"
+      carrier_id = "2224"
+      mcc="338"
+      mnc="180"
+      apn="ppmms"
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      mmsc="http://mmsc"
+      type="mms"
+  />
+
+  <apn carrier="Claro Web"
+      carrier_id = "2263"
+      mcc="338"
+      mnc="070"
+      apn="internet.ideasclaro.com.jm"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Claro MMS"
+      carrier_id = "2263"
+      mcc="338"
+      mnc="070"
+      apn="mms.ideasclaro.com.jm"
+      user=""
+      password=""
+      mmsproxy="190.80.147.118"
+      mmsport="8080"
+      mmsc="http://mms.ideasclaro.com.jm/mms/wapenc"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Lime Internet Postpaid"
+      carrier_id = "2224"
+      mcc="338"
+      mnc="180"
+      apn="internet"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Lime Postpaid MMS"
+      carrier_id = "2224"
+      mcc="338"
+      mnc="180"
+      apn="multimedia"
+      user=""
+      password=""
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      mmsc="http://mmsc"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Orange World Caraïbe"
+      carrier_id = "742"
+      mcc="340"
+      mnc="01"
+      apn="orangeweb"
+      user="orange"
+      password="orange"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange MMS Caraïbe"
+      carrier_id = "742"
+      mcc="340"
+      mnc="01"
+      apn="orangewap"
+      user="orange"
+      password="orange"
+      mmsc="http://193.251.160.246/servlets/mms"
+      mmsproxy="10.0.0.10"
+      mmsport="8082"
+      type="mms"
+  />
+
+  <apn carrier="Orangeweb"
+      carrier_id = "742"
+      mcc="340"
+      mnc="01"
+      apn="orangeweb"
+      user="orange"
+      password="orange"
+      authtype="1"
+      type="dun"
+  />
+
+  <apn carrier="Digicel Web"
+      carrier_id = "745"
+      mcc="340"
+      mnc="20"
+      apn="web.digicelfr.com"
+      mmsc="http://mmc.digiceltt.com/servlets/mms"
+      mmsproxy="172.20.6.12"
+      mmsport="8080"
+      type="default,mms,supl"
+  />
+
+  <apn carrier="Lime Internet Postpaid"
+      mcc="342"
+      mnc="60"
+      apn="internet"
+      user=""
+      password=""
+      type="default,supl"
+  />
+
+  <apn carrier="Lime Postpaid MMS"
+      mcc="342"
+      mnc="60"
+      apn="multimedia"
+      user=""
+      password=""
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      mmsc="http://mmsc"
+      type="mms"
+  />
+
+  <apn carrier='Barbado:Lime:Internet'
+      carrier_id = "1360"
+      mcc='342'
+      mnc='600'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='default'
+  />
+
+  <apn carrier="Barbados:Lime:Mms"
+      carrier_id = "1360"
+      mcc="342"
+      mnc="600"
+      apn="multimedia"
+      authtype="1"
+      mmsc="http://mmsc"
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier='Barbado:Lime:Modem'
+      carrier_id = "1360"
+      mcc='342'
+      mnc='600'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='dun'
+  />
+
+  <apn carrier="Lime Internet Postpaid"
+      mcc="344"
+      mnc="92"
+      apn="internet"
+      user=""
+      password=""
+      type="default,supl"
+  />
+
+  <apn carrier="Lime Postpaid MMS"
+      mcc="344"
+      mnc="92"
+      apn="multimedia"
+      user=""
+      password=""
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      mmsc="http://mmsc"
+      type="mms"
+  />
+
+  <apn carrier='Antigua:Lime:Internet'
+      carrier_id = "1325"
+      mcc='344'
+      mnc='920'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='default'
+  />
+
+  <apn carrier='Antigua:Lime:Mms'
+      carrier_id = "1325"
+      mcc='344'
+      mnc='920'
+      apn='multimedia'
+      authtype='1'
+      mmsc='http://mmsc'
+      mmsproxy='10.20.5.34'
+      mmsport='8799'
+      type='mms'
+  />
+
+  <apn carrier='Antigua:Lime:Modem'
+      carrier_id = "1325"
+      mcc='344'
+      mnc='920'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='dun'
+  />
+
+  <apn carrier="Lime Internet Postpaid"
+      mcc="346"
+      mnc="14"
+      apn="internet"
+      user=""
+      password=""
+      type="default,supl"
+  />
+
+  <apn carrier="Lime Postpaid MMS"
+      mcc="346"
+      mnc="14"
+      apn="multimedia"
+      user=""
+      password=""
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      mmsc="http://mmsc"
+      type="mms"
+  />
+
+  <apn carrier='Cayman Islands:Lime:Internet'
+      carrier_id = "1587"
+      mcc='346'
+      mnc='140'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='default'
+  />
+
+  <apn carrier='Cayman Islands:Lime:Modem'
+      carrier_id = "1587"
+      mcc='346'
+      mnc='140'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='dun'
+  />
+
+  <apn carrier='Cayman Islands:Mms'
+      carrier_id = "1587"
+      mcc='346'
+      mnc='140'
+      apn='multimedia'
+      authtype='1'
+      mmsc='http://mmsc'
+      mmsproxy='10.20.5.34'
+      mmsport='8799'
+      type='mms'
+  />
+
+  <apn carrier="Lime Internet Postpaid"
+      mcc="348"
+      mnc="17"
+      apn="internet"
+      user=""
+      password=""
+      type="default,supl"
+  />
+
+  <apn carrier="Lime Postpaid MMS"
+      mcc="348"
+      mnc="17"
+      apn="multimedia"
+      user=""
+      password=""
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      mmsc="http://mmsc"
+      type="mms"
+  />
+
+  <apn carrier='Bvi:Digicel:Internet'
+      carrier_id = "2356"
+      mcc='348'
+      mnc='77'
+      apn='wap.digicelbvi.com'
+      authtype='1'
+      type='default'
+  />
+
+  <apn carrier='Bvi:Digicel:Mms'
+      carrier_id = "2356"
+      mcc='348'
+      mnc='77'
+      apn='wap.digicelbvi.com'
+      authtype='1'
+      mmsc='http://mmc.digiceljamaica.com/servlets/mms'
+      mmsproxy='172.16.7.12'
+      mmsport='9201'
+      type='mms'
+      user='wapbvi'
+      password='wapbvi'
+  />
+
+  <apn carrier='Bvi:Digicel:Modem'
+      carrier_id = "2356"
+      mcc='348'
+      mnc='77'
+      apn='wap.digicelbvi.com'
+      port='8080'
+      authtype='1'
+      proxy='172.16.7.12'
+      mmsc='http://wapdigicel.com'
+      type='dun'
+      user='wapbvi'
+      password='wapbvi'
+  />
+
+  <apn carrier='Bvi:Lime:Internet'
+      carrier_id = "2289"
+      mcc='348'
+      mnc='170'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='default'
+  />
+
+  <apn carrier='Bvi:Lime:Mms'
+      carrier_id = "2289"
+      mcc='348'
+      mnc='170'
+      apn='multimedia'
+      authtype='1'
+      mmsc='http://mmsc'
+      mmsproxy='10.20.5.34'
+      mmsport='8799'
+      type='mms'
+  />
+
+  <apn carrier='Bvi:Lime:Modem'
+      carrier_id = "2289"
+      mcc='348'
+      mnc='170'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='dun'
+  />
+
+  <apn carrier="Lime Internet Postpaid"
+      mcc="352"
+      mnc="11"
+      apn="internet"
+      user=""
+      password=""
+      type="default,supl"
+  />
+
+  <apn carrier="Lime Postpaid MMS"
+      mcc="352"
+      mnc="11"
+      apn="multimedia"
+      user=""
+      password=""
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      mmsc="http://mmsc"
+      type="mms"
+  />
+
+  <apn carrier='Grenada:Lime:Internet'
+      carrier_id = "2223"
+      mcc='352'
+      mnc='110'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='default'
+  />
+
+  <apn carrier='Grenada:Lime:Mms'
+      carrier_id = "2223"
+      mcc='352'
+      mnc='110'
+      apn='multimedia'
+      authtype='1'
+      mmsc='http://mmsc'
+      mmsproxy='10.20.5.34'
+      mmsport='8799'
+      type='mms'
+  />
+
+  <apn carrier='Grenada:Lime:Modem'
+      carrier_id = "2223"
+      mcc='352'
+      mnc='110'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='dun'
+  />
+
+  <apn carrier="Lime Internet Postpaid"
+      mcc="354"
+      mnc="86"
+      apn="internet"
+      user=""
+      password=""
+      type="default,supl"
+  />
+
+  <apn carrier="Lime Postpaid MMS"
+      mcc="354"
+      mnc="86"
+      apn="multimedia"
+      user=""
+      password=""
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      mmsc="http://mmsc"
+      type="mms"
+  />
+
+  <apn carrier='Monserrat:Lime:Internet'
+      carrier_id = "2292"
+      mcc='354'
+      mnc='860'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='default'
+  />
+
+  <apn carrier='Monserrat:Lime:Mms'
+      carrier_id = "2292"
+      mcc='354'
+      mnc='860'
+      apn='multimedia'
+      authtype='1'
+      mmsc='http://mmsc'
+      mmsproxy='10.20.5.34'
+      mmsport='8799'
+      type='mms'
+  />
+
+  <apn carrier='Monserrat:Lime:Modem'
+      carrier_id = "2292"
+      mcc='354'
+      mnc='860'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='dun'
+  />
+
+  <apn carrier="Lime Internet Postpaid"
+      mcc="356"
+      mnc="11"
+      apn="internet"
+      user=""
+      password=""
+      type="default,supl"
+  />
+
+  <apn carrier="Lime Postpaid MMS"
+      mcc="356"
+      mnc="11"
+      apn="multimedia"
+      user=""
+      password=""
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      mmsc="http://mmsc"
+      type="mms"
+  />
+
+  <apn carrier='St Kitts And Nevis:Lime:Internet'
+      mcc='356'
+      mnc='110'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='default'
+  />
+
+  <apn carrier='St Kitts And Nevis:Lime:Mms'
+      mcc='356'
+      mnc='110'
+      apn='multimedia'
+      authtype='1'
+      mmsc='http://mmsc'
+      mmsproxy='10.20.5.34'
+      mmsport='8799'
+      type='mms'
+  />
+
+  <apn carrier='St Kitts And Nevis:Lime:Modem'
+      mcc='356'
+      mnc='110'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='dun'
+  />
+
+  <apn carrier="Lime Internet Postpaid"
+      mcc="358"
+      mnc="11"
+      apn="internet"
+      user=""
+      password=""
+      type="default,supl"
+  />
+
+  <apn carrier="Lime Postpaid MMS"
+      mcc="358"
+      mnc="11"
+      apn="multimedia"
+      user=""
+      password=""
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      mmsc="http://mmsc"
+      type="mms"
+  />
+
+  <apn carrier="Lime Internet Postpaid"
+      mcc="360"
+      mnc="11"
+      apn="internet"
+      user=""
+      password=""
+      type="default,supl"
+  />
+
+  <apn carrier='St Lucia:Lime:Internet'
+      carrier_id = "2293"
+      mcc='358'
+      mnc='110'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='default'
+  />
+
+  <apn carrier='St Lucia:Lime:Mms'
+      carrier_id = "2293"
+      mcc='358'
+      mnc='110'
+      apn='multimedia'
+      authtype='1'
+      mmsc='http://mmsc'
+      mmsproxy='10.20.5.34'
+      mmsport='8799'
+      type='mms'
+  />
+
+  <apn carrier='St Lucia:Lime:Modem'
+      carrier_id = "2293"
+      mcc='358'
+      mnc='110'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='dun'
+  />
+
+  <apn carrier="Lime Postpaid MMS"
+      mcc="360"
+      mnc="11"
+      apn="multimedia"
+      user=""
+      password=""
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      mmsc="http://mmsc"
+      type="mms"
+  />
+
+  <apn carrier='St Vincent:Lime:Internet'
+      carrier_id = "2294"
+      mcc='360'
+      mnc='110'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='default'
+  />
+
+  <apn carrier='St Vincent:Lime:Mms'
+      carrier_id = "2294"
+      mcc='360'
+      mnc='110'
+      apn='multimedia'
+      authtype='1'
+      mmsc='http://mmsc'
+      mmsproxy='10.20.5.34'
+      mmsport='8799'
+      type='mms'
+  />
+
+  <apn carrier='St Vincent:Lime:Modem'
+      carrier_id = "2294"
+      mcc='360'
+      mnc='110'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='dun'
+  />
+
+  <apn carrier='Curacao:Digicel:Internet'
+      carrier_id = "1332"
+      mcc='362'
+      mnc='69'
+      apn='web.digicelcuracao.com'
+      authtype='1'
+      type='default'
+  />
+
+  <apn carrier='Curacao:Digicel:Mms'
+      carrier_id = "1332"
+      mcc='362'
+      mnc='69'
+      apn='wap'
+      authtype='1'
+      mmsc='http://mms.digicelgroup.com'
+      mmsproxy='172.16.7.12'
+      mmsport='9201'
+      type='mms'
+  />
+
+  <apn carrier='Curacao:Digicel:Modem'
+      carrier_id = "1332"
+      mcc='362'
+      mnc='69'
+      apn='wap'
+      port='8080'
+      authtype='1'
+      proxy='172.16.7.12'
+      mmsc='http://wapdigicel.com'
+      type='dun'
+  />
+
+  <apn carrier="INTERNET Aruba"
+      carrier_id = "2163"
+      mcc="363"
+      mnc="02"
+      apn="web.digicelaruba.com"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Digicel"
+      carrier_id = "2163"
+      mcc="363"
+      mnc="02"
+      apn="wap"
+      user=""
+      password=""
+      mmsproxy="172.16.7.12"
+      mmsport="8080"
+      mmsc="http://mms.digicelgroup.com"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="INTERNET Aruba"
+      carrier_id = "2163"
+      mcc="363"
+      mnc="020"
+      apn="web.digicelaruba.com"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Digicel"
+      carrier_id = "2163"
+      mcc="363"
+      mnc="020"
+      apn="wap"
+      user=""
+      password=""
+      mmsproxy="172.16.7.12"
+      mmsport="8080"
+      mmsc="http://mms.digicelgroup.com"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Be Aliv"
+      carrier_id = "2130"
+      mcc="364"
+      mnc="49"
+      apn="pda.newcomobile.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Be Aliv IMS"
+      carrier_id = "2130"
+      mcc="364"
+      mnc="49"
+      apn="ims"
+      type="ims"
+  />
+
+  <apn carrier="Lime Internet Postpaid"
+      mcc="365"
+      mnc="84"
+      apn="internet"
+      user=""
+      password=""
+      type="default,supl"
+  />
+
+  <apn carrier="Lime Postpaid MMS"
+      mcc="365"
+      mnc="84"
+      apn="multimedia"
+      user=""
+      password=""
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      mmsc="http://mmsc"
+      type="mms"
+  />
+
+  <apn carrier='Anguilla:Lime:Internet'
+      carrier_id = "2295"
+      mcc='365'
+      mnc='840'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='default'
+  />
+
+  <apn carrier='Anguilla:Lime:Mms'
+      carrier_id = "2295"
+      mcc='365'
+      mnc='840'
+      apn='multimedia'
+      authtype='1'
+      mmsc='http://mmsc'
+      mmsproxy='10.20.5.34'
+      mmsport='8799'
+      type='mms'
+  />
+
+  <apn carrier='Anguilla:Lime:Modem'
+      carrier_id = "2295"
+      mcc='365'
+      mnc='840'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='dun'
+  />
+
+  <apn carrier="Lime Internet Postpaid"
+      mcc="366"
+      mnc="11"
+      apn="internet"
+      user=""
+      password=""
+      type="default,supl"
+  />
+
+  <apn carrier="Lime Postpaid MMS"
+      mcc="366"
+      mnc="11"
+      apn="multimedia"
+      user=""
+      password=""
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      mmsc="http://mmsc"
+      type="mms"
+  />
+
+  <apn carrier='Dominica:Lime:Internet'
+      carrier_id = "2290"
+      mcc='366'
+      mnc='110'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='default'
+  />
+
+  <apn carrier='Dominica:Lime:Mms'
+      carrier_id = "2290"
+      mcc='366'
+      mnc='110'
+      apn='multimedia'
+      authtype='1'
+      mmsc='http://mmsc'
+      mmsproxy='10.20.5.34'
+      mmsport='8799'
+      type='mms'
+  />
+
+  <apn carrier='Dominica:Lime:Modem'
+      carrier_id = "2290"
+      mcc='366'
+      mnc='110'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='dun'
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "1444"
+      mcc="368"
+      mnc="01"
+      apn="internet"
+      type="default,supl"
+  />
+
+
+  <apn carrier="Cubacel MMS"
+      carrier_id = "1444"
+      mcc="368"
+      mnc="01"
+      apn="mms"
+      mmsproxy="200.13.145.52"
+      mmsport="8080"
+      mmsc="http://mms.cubacel.cu"
+      type="mms"
+  />
+
+  <apn carrier="Orange Internet (LTE)"
+      carrier_id = "658"
+      mcc="370"
+      mnc="01"
+      apn="orangeinternet"
+      type="ia,default,supl"
+  />
+
+  <apn carrier="Orange net (3G)"
+      carrier_id = "658"
+      mcc="370"
+      mnc="01"
+      apn="orangenet.com.do"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange MMS"
+      carrier_id = "658"
+      mcc="370"
+      mnc="01"
+      apn="orangeworld"
+      user="orange"
+      password="orange"
+      mmsproxy="172.16.126.70"
+      mmsport="8080"
+      mmsc="http://mms.orange.com.do/servlets/mms"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Internet Móvil Claro"
+      carrier_id = "1467"
+      mcc="370"
+      mnc="02"
+      apn="internet.ideasclaro.com.do"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1467"
+      mcc="370"
+      mnc="02"
+      apn="internet.ideasclaro.com.do"
+      mmsc="http://mms.ideasclaro.com.do/mms/wapenc"
+      type="mms"
+  />
+
+  <apn carrier="Internet Móvil Claro"
+      carrier_id = "1467"
+      mcc="370"
+      mnc="020"
+      apn="internet.ideasclaro.com.do"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1467"
+      mcc="370"
+      mnc="020"
+      apn="internet.ideasclaro.com.do"
+      mmsc="http://mms.ideasclaro.com.do/mms/wapenc"
+      type="mms"
+  />
+
+  <apn carrier="Viva Edge (GSM)"
+      carrier_id = "1469"
+      mcc="370"
+      mnc="04"
+      apn="edge.viva.net.do"
+      proxy="192.168.16.10"
+      port="9401"
+      user="viva"
+      password="viva"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Viva MMS"
+      carrier_id = "1469"
+      mcc="370"
+      mnc="04"
+      apn="mms.viva.net.do"
+      user="viva"
+      password="viva"
+      mmsproxy="192.168.16.10"
+      mmsport="9401"
+      mmsc="http://10.200.16.4/mms/wapenc"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Wind Telecom"
+      carrier_id = "2437"
+      mcc="370"
+      mnc="05"
+      apn="smart.wind4g.com.do"
+      type="default"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier='Haiti:Digicel:Internet'
+      carrier_id = "1532"
+      mcc='372'
+      mnc='02'
+      apn='wap.digicelha.com'
+      authtype='1'
+      type='default'
+  />
+
+  <apn carrier='Haiti:Digicel:Mms'
+      carrier_id = "1532"
+      mcc='372'
+      mnc='02'
+      apn='wap.digicelha.com'
+      authtype='1'
+      mmsc='http://mmc.digicelhaiti.com/servlets/mms'
+      mmsproxy='172.20.200.12'
+      mmsport='9201'
+      type='mms'
+      user='wapha'
+      password='wap01ha'
+  />
+
+  <apn carrier='Haiti:Digicel:Modem'
+      carrier_id = "1532"
+      mcc='372'
+      mnc='02'
+      apn='wap.digicelha.com'
+      port='8080'
+      authtype='1'
+      proxy='172.20.200.12'
+      mmsc='http://wapdigicel.com'
+      type='dun'
+      user='wapha'
+      password='wap01ha'
+  />
+
+  <apn carrier='NATCOM INTERNET'
+      carrier_id = "1533"
+      mcc="372"
+      mnc="03"
+      apn="natcom"
+      type="default,supl"
+  />
+
+  <apn carrier="Bmobile internet"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="12"
+      apn="internet"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Bmobile mms"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="12"
+      apn="mms"
+      user=""
+      password=""
+      mmsproxy="192.168.210.104"
+      mmsport="8080"
+      mmsc="http://192.168.210.104/mmrelay.app"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Bmobile internet"
+      mcc="374"
+      mnc="120"
+      apn="internet"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Bmobile mms"
+      mcc="374"
+      mnc="120"
+      apn="mms"
+      user=""
+      password=""
+      mmsproxy="192.168.210.104"
+      mmsport="8080"
+      mmsc="http://192.168.210.104/mmrelay.app"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Bmobile internet"
+      mcc="374"
+      mnc="121"
+      apn="internet"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Bmobile mms"
+      mcc="374"
+      mnc="121"
+      apn="mms"
+      user=""
+      password=""
+      mmsproxy="192.168.210.104"
+      mmsport="8080"
+      mmsc="http://192.168.210.104/mmrelay.app"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Bmobile internet"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="122"
+      apn="internet"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Bmobile mms"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="122"
+      apn="mms"
+      user=""
+      password=""
+      mmsproxy="192.168.210.104"
+      mmsport="8080"
+      mmsc="http://192.168.210.104/mmrelay.app"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Bmobile internet"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="123"
+      apn="internet"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Bmobile mms"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="123"
+      apn="mms"
+      user=""
+      password=""
+      mmsproxy="192.168.210.104"
+      mmsport="8080"
+      mmsc="http://192.168.210.104/mmrelay.app"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Bmobile internet"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="124"
+      apn="internet"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Bmobile mms"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="124"
+      apn="mms"
+      user=""
+      password=""
+      mmsproxy="192.168.210.104"
+      mmsport="8080"
+      mmsc="http://192.168.210.104/mmrelay.app"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Bmobile internet"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="125"
+      apn="internet"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Bmobile mms"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="125"
+      apn="mms"
+      user=""
+      password=""
+      mmsproxy="192.168.210.104"
+      mmsport="8080"
+      mmsc="http://192.168.210.104/mmrelay.app"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Bmobile internet"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="126"
+      apn="internet"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Bmobile mms"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="126"
+      apn="mms"
+      user=""
+      password=""
+      mmsproxy="192.168.210.104"
+      mmsport="8080"
+      mmsc="http://192.168.210.104/mmrelay.app"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Bmobile internet"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="127"
+      apn="internet"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Bmobile mms"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="127"
+      apn="mms"
+      user=""
+      password=""
+      mmsproxy="192.168.210.104"
+      mmsport="8080"
+      mmsc="http://192.168.210.104/mmrelay.app"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Bmobile internet"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="128"
+      apn="internet"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Bmobile mms"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="128"
+      apn="mms"
+      user=""
+      password=""
+      mmsproxy="192.168.210.104"
+      mmsport="8080"
+      mmsc="http://192.168.210.104/mmrelay.app"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Bmobile internet"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="129"
+      apn="internet"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Bmobile mms"
+      carrier_id = "1739"
+      mcc="374"
+      mnc="129"
+      apn="mms"
+      user=""
+      password=""
+      mmsproxy="192.168.210.104"
+      mmsport="8080"
+      mmsc="http://192.168.210.104/mmrelay.app"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="INTERNET Trinidad"
+      carrier_id = "1740"
+      mcc="374"
+      mnc="13"
+      apn="web.digiceltt.com"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Trinidad"
+      carrier_id = "1740"
+      mcc="374"
+      mnc="13"
+      apn="wap.digiceltt.com"
+      user="wap"
+      password="wap"
+      mmsproxy="172.20.6.12"
+      mmsport="8080"
+      mmsc="http://mmc.digiceltt.com/servlets/mms"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="INTERNET Trinidad"
+      carrier_id = "1740"
+      mcc="374"
+      mnc="130"
+      apn="web.digiceltt.com"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Trinidad"
+      carrier_id = "1740"
+      mcc="374"
+      mnc="130"
+      apn="wap.digiceltt.com"
+      user="wap"
+      password="wap"
+      mmsproxy="172.20.6.12"
+      mmsport="8080"
+      mmsc="http://mmc.digiceltt.com/servlets/mms"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Lime Internet Postpaid"
+      mcc="376"
+      mnc="35"
+      apn="internet"
+      user=""
+      password=""
+      type="default,supl"
+  />
+
+  <apn carrier="Lime Postpaid MMS"
+      mcc="376"
+      mnc="35"
+      apn="multimedia"
+      user=""
+      password=""
+      mmsproxy="10.20.5.34"
+      mmsport="8799"
+      mmsc="http://mmsc"
+      type="mms"
+  />
+
+  <apn carrier='Turks And Caicos:Lime:Internet'
+      carrier_id = "2291"
+      mcc='376'
+      mnc='350'
+      apn='internet'
+      authtype='1'
+      type='default'
+  />
+
+  <apn carrier='Turks And Caicos:Lime:Mms'
+      carrier_id = "2291"
+      mcc='376'
+      mnc='350'
+      apn='multimedia'
+      authtype='1'
+      mmsc='http://mmsc'
+      mmsproxy='10.20.5.34'
+      mmsport='8799'
+      type='mms'
+  />
+
+  <apn carrier='Turks And Caicos:Lime:Modem'
+      carrier_id = "2291"
+      mcc='376'
+      mnc='350'
+      apn='internet'
+      authtype='1'
+      mmsc='http://www.time4lime.com/'
+      type='dun'
+  />
+
+  <apn carrier="Azercell"
+      carrier_id = "1354"
+      mcc="400"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Bakcell"
+      carrier_id = "495"
+      mcc="400"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="FONEX"
+      carrier_id = "1355"
+      mcc="400"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Nar Mobile"
+      carrier_id = "1356"
+      mcc="400"
+      mnc="04"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Beeline Internet"
+      carrier_id = "1588"
+      mcc="401"
+      mnc="01"
+      apn="internet.beeline.kz"
+      user="@internet.beeline"
+      password="beeline"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Beeline MMS"
+      carrier_id = "1588"
+      mcc="401"
+      mnc="01"
+      apn="mms.beeline.kz"
+      user="@mms.beeline"
+      password="beeline"
+      authtype="1"
+      mmsc="http://mms.beeline.kz/mms/wapenc"
+      mmsproxy="172.27.6.93"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="DOS Internet"
+      carrier_id = "1588"
+      mcc="401"
+      mnc="01"
+      apn="internet.dos.kz"
+      type="default,supl"
+  />
+
+  <apn carrier="izi"
+       carrier_id = "2436"
+       mcc="401"
+       mnc="01"
+       apn="izi.me"
+       type="default,supl"
+       mvno_type="imsi"
+       mvno_match_data="40101568"
+   />
+
+  <apn carrier="Kcell Internet"
+      carrier_id = "1589"
+      mcc="401"
+      mnc="02"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Kcell MMS"
+      carrier_id = "1589"
+      mcc="401"
+      mnc="02"
+      apn="mms"
+      mmsc="http://mms.kcell.kz/post"
+      mmsproxy="195.47.255.7"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="ALTEL INTERNET"
+      carrier_id = "2164"
+      mcc="401"
+      mnc="07"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Tele2 Internet"
+      carrier_id = "1986"
+      mcc="401"
+      mnc="77"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Tele2 MMS"
+      carrier_id = "1986"
+      mcc="401"
+      mnc="77"
+      apn="mms"
+      mmsc="http://mms.tele2.kz/mms/wapenc"
+      mmsproxy="10.1.26.10"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="B-Mobile"
+      carrier_id = "564"
+      mcc="402"
+      mnc="11"
+      apn="default"
+      type="default,supl"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="TashiCell"
+      carrier_id = "2165"
+      mcc="402"
+      mnc="77"
+      apn="ticlnet"
+      user=""
+      password=""
+      proxy=""
+      port=""
+      type="default,supl"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="01"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="01"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="01"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="02"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="02"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="02"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="03"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="03"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="03"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="404"
+      mnc="04"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="04"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="04"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="05"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="05"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="05"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="404"
+      mnc="07"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="07"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="07"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="09"
+      apn="mms"
+      mmsc="http://10.239.221.47/mms/"
+      mmsproxy="10.239.221.7"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Reliance Net"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="09"
+      apn="smartnet"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance WAP"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="09"
+      apn="smartwap"
+      proxy="10.239.221.7"
+      port="8080"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobile Office"
+      mcc="404"
+      mnc="10"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      mcc="404"
+      mnc="10"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      mcc="404"
+      mnc="10"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="11"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="11"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="11"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="404"
+      mnc="12"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="12"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="12"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="13"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="13"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="13"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="14"
+      apn="mmsc"
+      mmsc="http://10.11.12.180"
+      mmsproxy="10.11.12.13"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="404"
+      mnc="14"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="14"
+      apn="imis"
+      proxy="10.11.12.13"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="15"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="15"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="15"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="16"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="16"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="16"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS-Postpaid"
+      mcc="404"
+      mnc="17"
+      apn="aircelwebpost"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Postpaid"
+      mcc="404"
+      mnc="17"
+      apn="aircelwappost"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Prepaid"
+      mcc="404"
+      mnc="17"
+      apn="aircelwap"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-GPRS-Prepaid"
+      mcc="404"
+      mnc="17"
+      apn="aircelweb"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel Internet (40417)"
+      mcc="404"
+      mnc="17"
+      apn="aircelgprs"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="404"
+      mnc="17"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="18"
+      apn="mms"
+      mmsc="http://10.239.221.47/mms/"
+      mmsproxy="10.239.221.7"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Reliance Net"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="18"
+      apn="smartnet"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance WAP"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="18"
+      apn="smartwap"
+      proxy="10.239.221.7"
+      port="8080"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance Internet (40418)"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="18"
+      apn="rcomnet"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="404"
+      mnc="19"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="19"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="19"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="20"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="20"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="20"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Loop Mobile MMS"
+      carrier_id = "1545"
+      mcc="404"
+      mnc="21"
+      apn="mizone"
+      password="mmsc"
+      mmsc="http://mms.loopmobile.in:8080"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Loop Mobile"
+      carrier_id = "1545"
+      mcc="404"
+      mnc="21"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="404"
+      mnc="22"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="22"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="22"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="404"
+      mnc="24"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="24"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="24"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS-Postpaid"
+      mcc="404"
+      mnc="25"
+      apn="aircelwebpost"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Postpaid"
+      mcc="404"
+      mnc="25"
+      apn="aircelwappost"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Prepaid"
+      mcc="404"
+      mnc="25"
+      apn="aircelwap"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-GPRS-Prepaid"
+      mcc="404"
+      mnc="25"
+      apn="aircelweb"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel Internet (40425)"
+      mcc="404"
+      mnc="25"
+      apn="aircelgprs"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="404"
+      mnc="25"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="27"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="27"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="27"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-GPRS-Postpaid"
+      mcc="404"
+      mnc="28"
+      apn="aircelwebpost"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Postpaid"
+      mcc="404"
+      mnc="28"
+      apn="aircelwappost"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Prepaid"
+      mcc="404"
+      mnc="28"
+      apn="aircelwap"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-GPRS-Prepaid"
+      mcc="404"
+      mnc="28"
+      apn="aircelweb"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel Internet (40428)"
+      mcc="404"
+      mnc="28"
+      apn="aircelgprs"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="404"
+      mnc="28"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS-Postpaid"
+      mcc="404"
+      mnc="29"
+      apn="aircelwebpost"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Postpaid"
+      mcc="404"
+      mnc="29"
+      apn="myaircelpost"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Prepaid"
+      mcc="404"
+      mnc="29"
+      apn="myaircel"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-GPRS-Prepaid"
+      mcc="404"
+      mnc="29"
+      apn="aircelweb"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel Internet (40429)"
+      mcc="404"
+      mnc="29"
+      apn="aircelgprs"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Aircel WAP (40429)"
+      mcc="404"
+      mnc="29"
+      apn="aircelwap"
+      type="default,supl"
+      proxy="172.17.83.69"
+      port="8080"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="404"
+      mnc="29"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="30"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="30"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="30"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="31"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="31"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="31"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS-Postpaid"
+      mcc="404"
+      mnc="33"
+      apn="aircelwebpost"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Postpaid"
+      mcc="404"
+      mnc="33"
+      apn="myaircelpost"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Prepaid"
+      mcc="404"
+      mnc="33"
+      apn="myaircel"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-GPRS-Prepaid"
+      mcc="404"
+      mnc="33"
+      apn="aircelweb"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel Internet (40433)"
+      mcc="404"
+      mnc="33"
+      apn="aircelgprs"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Aircel WAP (40433)"
+      mcc="404"
+      mnc="33"
+      apn="aircelwap"
+      type="default,supl"
+      proxy="172.17.83.69"
+      port="8080"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="404"
+      mnc="33"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="34"
+      apn="bsnlnet"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="34"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="34"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS-Postpaid"
+      mcc="404"
+      mnc="35"
+      apn="aircelwebpost"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Postpaid"
+      mcc="404"
+      mnc="35"
+      apn="aircelwappost"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Prepaid"
+      mcc="404"
+      mnc="35"
+      apn="aircelwap"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-GPRS-Prepaid"
+      mcc="404"
+      mnc="35"
+      apn="aircelweb"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel Internet (40435)"
+      mcc="404"
+      mnc="35"
+      apn="aircelgprs"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="404"
+      mnc="35"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="36"
+      apn="mms"
+      mmsc="http://10.239.221.47/mms/"
+      mmsproxy="10.239.221.7"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Reliance Net"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="36"
+      apn="smartnet"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance WAP"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="36"
+      apn="smartwap"
+      proxy="10.239.221.7"
+      port="8080"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance Internet (40436)"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="36"
+      apn="rcomnet"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Aircel-GPRS-Postpaid"
+      mcc="404"
+      mnc="37"
+      apn="aircelwebpost"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Postpaid"
+      mcc="404"
+      mnc="37"
+      apn="aircelwappost"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Prepaid"
+      mcc="404"
+      mnc="37"
+      apn="aircelwap"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-GPRS-Prepaid"
+      mcc="404"
+      mnc="37"
+      apn="aircelweb"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel Internet (40437)"
+      mcc="404"
+      mnc="37"
+      apn="aircelgprs"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="404"
+      mnc="37"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="38"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="38"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="38"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="40"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="40"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="40"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS-Postpaid"
+      carrier_id = "1550"
+      mcc="404"
+      mnc="41"
+      apn="aircelgprs.po"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-GPRS-Prepaid"
+      carrier_id = "1550"
+      mcc="404"
+      mnc="41"
+      apn="aircelgprs.pr"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Postpaid"
+      carrier_id = "1550"
+      mcc="404"
+      mnc="41"
+      apn="aircelwap.po"
+      proxy="192.168.35.201"
+      port="8081"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Prepaid"
+      carrier_id = "1550"
+      mcc="404"
+      mnc="41"
+      apn="aircelwap.pr"
+      proxy="192.168.35.201"
+      port="8081"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel Internet (40441)"
+      carrier_id = "1550"
+      mcc="404"
+      mnc="41"
+      apn="aircelgprs"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Aircel WAP (40441)"
+      carrier_id = "1550"
+      mcc="404"
+      mnc="41"
+      apn="aircelwap"
+      type="default,supl"
+      proxy="172.17.83.69"
+      port="8080"
+  />
+
+  <apn carrier="Aircel-MMS-Postpaid"
+      carrier_id = "1550"
+      mcc="404"
+      mnc="41"
+      apn="aircelmms.po"
+      mmsc="http://mmsc/mmrelay.app"
+      mmsproxy="192.168.35.196"
+      mmsport="8081"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-MMS-Prepaid"
+      carrier_id = "1550"
+      mcc="404"
+      mnc="41"
+      apn="aircelmms.pr"
+      mmsc="http://mmsc/mmrelay.app"
+      mmsproxy="192.168.35.196"
+      mmsport="8081"
+      type="mms"
+  />
+
+  <apn carrier="Aircel MMS (40441)"
+      carrier_id = "1550"
+      mcc="404"
+      mnc="41"
+      apn="aircelmms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      mmsc="http://172.17.83.67/servlets/mms"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Aircel-GPRS-Postpaid"
+      carrier_id = "1551"
+      mcc="404"
+      mnc="42"
+      apn="aircelgprs.po"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-GPRS-Prepaid"
+      carrier_id = "1551"
+      mcc="404"
+      mnc="42"
+      apn="aircelgprs.pr"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Postpaid"
+      carrier_id = "1551"
+      mcc="404"
+      mnc="42"
+      apn="aircelwap.po"
+      proxy="192.168.35.201"
+      port="8081"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Prepaid"
+      carrier_id = "1551"
+      mcc="404"
+      mnc="42"
+      apn="aircelwap.pr"
+      proxy="192.168.35.201"
+      port="8081"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel Internet (40442)"
+      carrier_id = "1551"
+      mcc="404"
+      mnc="42"
+      apn="aircelgprs"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Aircel-MMS-Postpaid"
+      carrier_id = "1551"
+      mcc="404"
+      mnc="42"
+      apn="aircelmms.po"
+      mmsc="http://mmsc/mmrelay.app"
+      mmsproxy="192.168.35.196"
+      mmsport="8081"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-MMS-Prepaid"
+      carrier_id = "1551"
+      mcc="404"
+      mnc="42"
+      apn="aircelmms.pr"
+      mmsc="http://mmsc/mmrelay.app"
+      mmsproxy="192.168.35.196"
+      mmsport="8081"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="43"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="43"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="43"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="404"
+      mnc="44"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="44"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="44"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="45"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="45"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="45"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="46"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="46"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="46"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="49"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="49"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="49"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="50"
+      apn="mms"
+      mmsc="http://10.239.221.47/mms/"
+      mmsproxy="10.239.221.7"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Reliance Net"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="50"
+      apn="smartnet"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance WAP"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="50"
+      apn="smartwap"
+      proxy="10.239.221.7"
+      port="8080"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="51"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="51"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="51"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="52"
+      apn="mms"
+      mmsc="http://10.239.221.47/mms/"
+      mmsproxy="10.239.221.7"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Reliance Net"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="52"
+      apn="smartnet"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance WAP"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="52"
+      apn="smartwap"
+      proxy="10.239.221.7"
+      port="8080"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="53"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="53"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="53"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="54"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="54"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="54"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="55"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="55"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="55"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="404"
+      mnc="56"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="56"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="56"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="57"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="57"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="57"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="58"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="58"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="58"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="59"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="59"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="59"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="60"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="60"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="60"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="62"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="62"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="62"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="64"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="64"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="64"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="66"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="66"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="66"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="67"
+      apn="mms"
+      mmsc="http://10.239.221.47/mms/"
+      mmsproxy="10.239.221.7"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Reliance Net"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="67"
+      apn="smartnet"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance WAP"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="67"
+      apn="smartwap"
+      proxy="10.239.221.7"
+      port="8080"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MTNL"
+      carrier_id = "1556"
+      mcc="404"
+      mnc="68"
+      apn="mtnl.net"
+      authtype="0"
+      user="mtnl"
+      password="mtnl123"
+      mmsc="http://mtnlmms/"
+      mmsproxy="10.10.10.10"
+      mmsport="9401"
+      type="default,mms,supl,agps,fota,dun"
+  />
+
+  <apn carrier="MTNL"
+      carrier_id = "1556"
+      mcc="404"
+      mnc="69"
+      apn="mtnl.net"
+      authtype="0"
+      user="mtnl"
+      password="mtnl123"
+      mmsc="http://mtnlmms/"
+      mmsproxy="10.10.10.10"
+      mmsport="9401"
+      type="default,mms,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1557"
+      mcc="404"
+      mnc="70"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1557"
+      mcc="404"
+      mnc="70"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1557"
+      mcc="404"
+      mnc="70"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="71"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="71"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="71"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="72"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="72"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="72"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="73"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="73"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="73"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="74"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="74"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="74"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="75"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="75"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="75"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="76"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="76"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="76"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="77"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="77"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="77"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="404"
+      mnc="78"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="78"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="78"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="79"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="79"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="79"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="80"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="80"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="80"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnlmms"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="81"
+      apn="bsnlmms"
+      mmsc="http://bsnlmmsc.in:8514"
+      mmsproxy="10.210.10.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="bsnlnet"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="81"
+      apn="bsnlnet"
+      type="default,supl"
+  />
+
+  <apn carrier="bsnllive"
+      carrier_id = "1549"
+      mcc="404"
+      mnc="81"
+      apn="bsnllive"
+      proxy="10.220.67.131"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="404"
+      mnc="82"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="82"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="82"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1559"
+      mcc="404"
+      mnc="83"
+      apn="mms"
+      mmsc="http://10.239.221.47/mms/"
+      mmsproxy="10.239.221.7"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Reliance Net"
+      carrier_id = "1559"
+      mcc="404"
+      mnc="83"
+      apn="smartnet"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance WAP"
+      carrier_id = "1559"
+      mcc="404"
+      mnc="83"
+      apn="smartwap"
+      proxy="10.239.221.7"
+      port="8080"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="84"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="84"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="84"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="85"
+      apn="mms"
+      mmsc="http://10.239.221.47/mms/"
+      mmsproxy="10.239.221.7"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Reliance Net"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="85"
+      apn="smartnet"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance WAP"
+      carrier_id = "1543"
+      mcc="404"
+      mnc="85"
+      apn="smartwap"
+      proxy="10.239.221.7"
+      port="8080"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="86"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="86"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="86"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="404"
+      mnc="87"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="87"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="87"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="88"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="88"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="404"
+      mnc="88"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="404"
+      mnc="89"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="89"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="404"
+      mnc="89"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="90"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="90"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="90"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS-Postpaid"
+      mcc="404"
+      mnc="91"
+      apn="aircelwebpost"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Postpaid"
+      mcc="404"
+      mnc="91"
+      apn="aircelwappost"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet-Prepaid"
+      mcc="404"
+      mnc="91"
+      apn="aircelwap"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-GPRS-Prepaid"
+      mcc="404"
+      mnc="91"
+      apn="aircelweb"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="404"
+      mnc="91"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="92"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="92"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="92"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="93"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="93"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="93"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="94"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="94"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="94"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="95"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="95"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="95"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="96"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="96"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="96"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="97"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="97"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="97"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="98"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="98"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="404"
+      mnc="98"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="01"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="01"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="01"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="03"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="03"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="03"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="04"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="04"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="04"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="05"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="05"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="05"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="06"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="06"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="06"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="07"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="07"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="07"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="08"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="08"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="08"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="09"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="09"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="09"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="10"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="10"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="10"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="11"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="11"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="11"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="12"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="12"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="12"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="13"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="13"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="13"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="14"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="14"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="14"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="15"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="15"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="15"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="17"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="17"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="17"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="18"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="18"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="18"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="19"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="19"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="19"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="20"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="20"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="20"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="21"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="21"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="21"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="22"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="22"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="22"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Reliance MMS"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="23"
+      apn="rcommms"
+      mmsc="http://mmsc.rcom.co.in/mms/"
+      mmsproxy="10.239.221.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Netconnect"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="23"
+      apn="rcomnet"
+      type="default,supl"
+  />
+
+  <apn carrier="RelianceMbWorld"
+      carrier_id = "1543"
+      mcc="405"
+      mnc="23"
+      apn="rcomwap"
+      proxy="10.239.221.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="025"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="025"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="025"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="026"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="026"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="026"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="027"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="027"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="027"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="028"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="028"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="028"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="029"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="029"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="029"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="030"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="030"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="030"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="031"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="031"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="031"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="032"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="032"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="032"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="033"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="033"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="033"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="034"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="034"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="034"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="035"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="035"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="035"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="036"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="036"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="036"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="037"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="037"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="037"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="038"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="038"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="038"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="039"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="039"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="039"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="040"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="040"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="040"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="041"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="041"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="041"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="042"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="042"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="042"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="043"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="043"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="043"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="044"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="044"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="044"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="045"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="045"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="045"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="046"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="046"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="046"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="TATA DOCOMO INTERNET"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="047"
+      apn="TATA.DOCOMO.INTERNET"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO DIVE-IN"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="047"
+      apn="TATA.DOCOMO.DIVE.IN"
+      proxy="10.124.94.7"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="TATA DOCOMO MMS"
+      carrier_id = "1982"
+      mcc="405"
+      mnc="047"
+      apn="TATA.DOCOMO.MMS"
+      mmsc="http://mmsc/"
+      mmsproxy="10.124.26.94"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="51"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="51"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="51"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="52"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="52"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="52"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="53"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="53"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="53"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="54"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="54"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="54"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="55"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="55"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="55"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Mobile Office"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="56"
+      apn="airtelgprs.com"
+      type="default,supl"
+  />
+
+  <apn carrier="AIRTEL LIVE"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="56"
+      apn="airtelfun.com"
+      proxy="100.1.200.99"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1961"
+      mcc="405"
+      mnc="56"
+      apn="airtelmms.com"
+      authtype="1"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsproxy="100.1.201.172"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="66"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="66"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="66"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="67"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="67"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="67"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="405"
+      mnc="70"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="70"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="70"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="750"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="750"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="750"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="751"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="751"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="751"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="752"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="752"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="752"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="753"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="753"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="753"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="754"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="754"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="754"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="755"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="755"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="755"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone_MMS"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="756"
+      apn="portalnmms"
+      mmsc="http://mms1.live.vodafone.in/mms/"
+      mmsproxy="10.10.1.100"
+      mmsport="9401"
+      type="mms"
+  />
+
+  <apn carrier="Vodafonemobileconnect"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="756"
+      apn="www"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone live"
+      carrier_id = "2378"
+      mcc="405"
+      mnc="756"
+      apn="portalnmms"
+      proxy="10.10.1.100"
+      port="9401"
+      type="default,supl"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="405"
+      mnc="799"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="799"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="799"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS"
+      mcc="405"
+      mnc="800"
+      apn="aircelgprs"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet"
+      mcc="405"
+      mnc="800"
+      apn="aircelwap"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="405"
+      mnc="800"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS"
+      mcc="405"
+      mnc="801"
+      apn="aircelgprs"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet"
+      mcc="405"
+      mnc="801"
+      apn="aircelwap"
+      proxy="192.168.35.201"
+      port="8081"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="405"
+      mnc="801"
+      apn="aircelmms"
+      mmsc="http://mmsc/mmrelay.app"
+      mmsproxy="192.168.35.196"
+      mmsport="8081"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS"
+      mcc="405"
+      mnc="802"
+      apn="aircelgprs"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet"
+      mcc="405"
+      mnc="802"
+      apn="aircelwap"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="405"
+      mnc="802"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS"
+      mcc="405"
+      mnc="803"
+      apn="aircelgprs"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet"
+      mcc="405"
+      mnc="803"
+      apn="aircelwap"
+      proxy="192.168.35.201"
+      port="8081"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="405"
+      mnc="803"
+      apn="aircelmms"
+      mmsc="http://mmsc/mmrelay.app"
+      mmsproxy="192.168.35.196"
+      mmsport="8081"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS"
+      mcc="405"
+      mnc="804"
+      apn="aircelgprs"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet"
+      mcc="405"
+      mnc="804"
+      apn="aircelwap"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="405"
+      mnc="804"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS"
+      mcc="405"
+      mnc="805"
+      apn="aircelgprs"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet"
+      mcc="405"
+      mnc="805"
+      apn="aircelwap"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="405"
+      mnc="805"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS"
+      mcc="405"
+      mnc="806"
+      apn="aircelgprs"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet"
+      mcc="405"
+      mnc="806"
+      apn="aircelwap"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="405"
+      mnc="806"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS"
+      mcc="405"
+      mnc="807"
+      apn="aircelgprs"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet"
+      mcc="405"
+      mnc="807"
+      apn="aircelwap"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="405"
+      mnc="807"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS"
+      mcc="405"
+      mnc="808"
+      apn="aircelgprs"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet"
+      mcc="405"
+      mnc="808"
+      apn="aircelwap"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="405"
+      mnc="808"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS"
+      mcc="405"
+      mnc="809"
+      apn="aircelgprs"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet"
+      mcc="405"
+      mnc="809"
+      apn="aircelwap"
+      proxy="192.168.35.201"
+      port="8081"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="405"
+      mnc="809"
+      apn="aircelmms"
+      mmsc="http://mmsc/mmrelay.app"
+      mmsproxy="192.168.35.196"
+      mmsport="8081"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS"
+      mcc="405"
+      mnc="810"
+      apn="aircelgprs"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet"
+      mcc="405"
+      mnc="810"
+      apn="aircelwap"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="405"
+      mnc="810"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS"
+      mcc="405"
+      mnc="811"
+      apn="aircelgprs"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet"
+      mcc="405"
+      mnc="811"
+      apn="aircelwap"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="405"
+      mnc="811"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Aircel-GPRS"
+      mcc="405"
+      mnc="812"
+      apn="aircelgprs"
+      type="default,supl"
+  />
+
+  <apn carrier="Pocket Internet"
+      mcc="405"
+      mnc="812"
+      apn="aircelwap"
+      proxy="172.17.83.69"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Aircel-MMS"
+      mcc="405"
+      mnc="812"
+      apn="aircelmms"
+      mmsc="http://10.50.1.166/servlets/mms"
+      mmsproxy="172.17.83.69"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="813"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="813"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="813"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="814"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="814"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="814"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="815"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="815"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="815"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="816"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="816"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="816"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="817"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="817"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="817"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="818"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="818"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="818"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="819"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="819"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="819"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="820"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="820"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="820"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="821"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="821"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="821"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="822"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="822"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="822"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="823"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="823"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="824"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="824"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="825"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="825"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="826"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="826"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="827"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="827"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="828"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="828"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="829"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="829"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="830"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="830"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      mcc="405"
+      mnc="831"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      mcc="405"
+      mnc="831"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="832"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="832"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="833"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="833"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="834"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="834"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="835"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="835"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="836"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="836"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="837"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="837"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="838"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="838"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      mcc="405"
+      mnc="839"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      mcc="405"
+      mnc="839"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="840"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="840"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="841"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="841"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="842"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="842"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="843"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="843"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="844"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="844"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="844"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="405"
+      mnc="845"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="845"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="845"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="405"
+      mnc="846"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="846"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="846"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="405"
+      mnc="847"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="847"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="847"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="405"
+      mnc="848"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="848"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="848"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="405"
+      mnc="849"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="849"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="849"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="405"
+      mnc="850"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="850"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="850"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="405"
+      mnc="851"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="851"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="851"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="405"
+      mnc="852"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="852"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="852"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Idea_Internet"
+      carrier_id = "802"
+      mcc="405"
+      mnc="853"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA GPRS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="853"
+      apn="imis"
+      proxy="10.4.42.15"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="853"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Loop Internet (405854)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="854"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405854)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="854"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405855)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="855"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405855)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="855"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405856)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="856"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405856)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="856"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405857)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="857"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405857)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="857"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405858)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="858"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405858)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="858"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405859)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="859"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405859)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="859"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405860)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="860"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405860)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="860"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405861)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="861"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405861)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="861"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405862)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="862"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405862)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="862"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405863)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="863"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405863)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="863"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405864)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="864"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405864)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="864"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405865)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="865"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405865)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="865"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405866)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="866"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405866)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="866"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405867)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="867"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405867)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="867"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405868)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="868"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405868)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="868"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405869)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="869"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405869)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="869"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405870)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="870"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405870)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="870"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405871)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="871"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405871)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="871"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405872)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="872"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405872)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="872"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405873)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="873"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405873)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="873"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop Internet (405874)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="874"
+      apn="www"
+      type="default,supl,agps,fota,dun"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Loop MMS (405874)"
+      carrier_id = "2018"
+      mcc="405"
+      mnc="874"
+      apn="mizone"
+      mmsproxy="10.0.0.10"
+      mmsport="9401"
+      mmsc="http://mms.loopmobile.in:8080/"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+      carrier_enabled="true"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="875"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="875"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="875"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="876"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="876"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="876"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="877"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="877"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="877"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="878"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="878"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="878"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="879"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="879"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="879"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="880"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="880"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="880"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="STEL"
+      carrier_id = "2265"
+      mcc="405"
+      mnc="881"
+      apn="gprs.stel.in"
+      type="default,supl"
+  />
+
+  <apn carrier="STEL"
+      carrier_id = "2265"
+      mcc="405"
+      mnc="882"
+      apn="gprs.stel.in"
+      type="default,supl"
+  />
+
+  <apn carrier="STEL"
+      carrier_id = "2265"
+      mcc="405"
+      mnc="883"
+      apn="gprs.stel.in"
+      type="default,supl"
+  />
+
+  <apn carrier="STEL"
+      carrier_id = "2265"
+      mcc="405"
+      mnc="884"
+      apn="gprs.stel.in"
+      type="default,supl"
+  />
+
+  <apn carrier="STEL"
+      carrier_id = "2265"
+      mcc="405"
+      mnc="885"
+      apn="gprs.stel.in"
+      type="default,supl"
+  />
+
+  <apn carrier="STEL"
+      carrier_id = "2265"
+      mcc="405"
+      mnc="886"
+      apn="gprs.stel.in"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA"
+      carrier_id = "802"
+      mcc="405"
+      mnc="908"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="908"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="IDEA"
+      carrier_id = "802"
+      mcc="405"
+      mnc="909"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="909"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="IDEA"
+      carrier_id = "802"
+      mcc="405"
+      mnc="910"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="910"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="IDEA"
+      carrier_id = "802"
+      mcc="405"
+      mnc="911"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="IDEA MMS"
+      carrier_id = "802"
+      mcc="405"
+      mnc="911"
+      apn="mmsc"
+      mmsc="http://10.4.42.21:8002/"
+      mmsproxy="10.4.42.15"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Cheers"
+      carrier_id = "2266"
+      mcc="405"
+      mnc="912"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Cheers"
+      carrier_id = "2266"
+      mcc="405"
+      mnc="913"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Cheers"
+      carrier_id = "2266"
+      mcc="405"
+      mnc="914"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Cheers"
+      carrier_id = "2266"
+      mcc="405"
+      mnc="915"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Cheers"
+      carrier_id = "2266"
+      mcc="405"
+      mnc="916"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Cheers"
+      carrier_id = "2266"
+      mcc="405"
+      mnc="917"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Cheers"
+      carrier_id = "2266"
+      mcc="405"
+      mnc="918"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Cheers"
+      carrier_id = "2266"
+      mcc="405"
+      mnc="919"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Cheers"
+      carrier_id = "2266"
+      mcc="405"
+      mnc="920"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Cheers"
+      carrier_id = "2266"
+      mcc="405"
+      mnc="921"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Cheers"
+      carrier_id = "2266"
+      mcc="405"
+      mnc="922"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Cheers"
+      carrier_id = "2266"
+      mcc="405"
+      mnc="923"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Cheers"
+      mcc="405"
+      mnc="924"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="925"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="925"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="925"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="926"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="926"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="926"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="927"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="927"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="927"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="928"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="928"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="928"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Uninor Internet"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="929"
+      apn="uninor"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor Wap"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="929"
+      apn="uninor"
+      proxy="10.58.10.58"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Uninor MMS"
+      carrier_id = "2002"
+      mcc="405"
+      mnc="929"
+      apn="uninor"
+      mmsc="http://10.58.2.120"
+      mmsproxy="10.58.10.59"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Cheers"
+      carrier_id = "2266"
+      mcc="405"
+      mnc="930"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Cheers"
+      mcc="405"
+      mnc="931"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Videocon MMS"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="932"
+      apn="vgprs.com"
+      mmsc="http://10.202.4.119:10021/mmsc/"
+      mmsproxy="10.202.5.145"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Videocon"
+      carrier_id = "2264"
+      mcc="405"
+      mnc="932"
+      apn="vinternet.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobilink WAP GPRS"
+      carrier_id = "1656"
+      mcc="410"
+      mnc="01"
+      apn="connect.mobilinkworld.com"
+      user="Mobilink"
+      password="Mobilink"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobilink MMS"
+      carrier_id = "1656"
+      mcc="410"
+      mnc="01"
+      apn="mms.mobilinkworld.com"
+      user="Mobilink"
+      password="Mobilink"
+      mmsc="http://mms/"
+      mmsproxy="172.25.20.12"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Ufone WAP"
+      carrier_id = "1657"
+      mcc="410"
+      mnc="03"
+      apn="Ufone.internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Ufone MMS"
+      carrier_id = "1657"
+      mcc="410"
+      mnc="03"
+      apn="Ufone.mms"
+      mmsc="http://www.ufonemms.com:80/"
+      mmsproxy="172.16.13.27"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="ZONG WAP"
+      carrier_id = "1980"
+      mcc="410"
+      mnc="04"
+      apn="zonginternet"
+      type="default,supl"
+  />
+
+  <apn carrier="ZONG MMS"
+      carrier_id = "1980"
+      mcc="410"
+      mnc="04"
+      apn="zongmms"
+      mmsc="http://10.81.6.11:8080"
+      mmsproxy="10.81.6.33"
+      mmsport="8000"
+      type="mms"
+  />
+
+  <apn carrier="Telenor WAP"
+      carrier_id = "1975"
+      mcc="410"
+      mnc="06"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Telenor MMS"
+      carrier_id = "1975"
+      mcc="410"
+      mnc="06"
+      apn="mms"
+      user="Telenor"
+      password="Telenor"
+      mmsc="http://mmstelenor"
+      mmsproxy="172.18.19.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Warid WAP"
+      carrier_id = "1656"
+      mcc="410"
+      mnc="07"
+      apn="Wap.warid"
+      type="default,supl"
+  />
+
+  <apn carrier="Warid MMS"
+      carrier_id = "1656"
+      mcc="410"
+      mnc="07"
+      apn="mms.warid"
+      mmsc="http://10.4.0.132/servlets/MMS"
+      mmsproxy="10.4.2.1"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier='Consumer Cellular'
+      mcc='410'
+      mnc='310'
+      apn='att.mvno'
+      type='default,mms,supl,hipri,fota'
+      protocol='IP'
+      roaming_protocol='IP'
+      mmsc='http://mms.fido.ca'
+      mmsproxy='mmsproxy.fido.ca'
+      mmsport='80'
+      mvno_type='gid'
+      mvno_match_data='2AC9'
+  />
+
+  <apn carrier="AWCC"
+      carrier_id = "452"
+      mcc="412"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Roshan"
+      carrier_id = "453"
+      mcc="412"
+      mnc="20"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="MTN"
+      carrier_id = "455"
+      mcc="412"
+      mnc="40"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Etisalat"
+      carrier_id = "2221"
+      mcc="412"
+      mnc="50"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobitel"
+      carrier_id = "1931"
+      mcc="413"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Dialog"
+      carrier_id = "1599"
+      mcc="413"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Etisalat"
+      carrier_id = "1600"
+      mcc="413"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel"
+      carrier_id = "1932"
+      mcc="413"
+      mnc="05"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Hutch"
+      carrier_id = "1933"
+      mcc="413"
+      mnc="08"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="MPT"
+      carrier_id = "1611"
+      mcc="414"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Ooredoo Internet"
+      carrier_id = "1996"
+      mcc="414"
+      mnc="05"
+      apn="Internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Alfa Internet"
+      carrier_id = "1920"
+      mcc="415"
+      mnc="01"
+      user="mic1"
+      password="mic1"
+      apn="internet.mic1.com.lb"
+      type="default,supl"
+  />
+
+  <apn carrier="Alfawap"
+      carrier_id = "1920"
+      mcc="415"
+      mnc="01"
+      apn="wap.mic1.com.lb"
+      user="mic1"
+      password="mic1"
+      proxy="192.168.23.50"
+      port="80"
+      type="default,supl"
+  />
+
+  <apn carrier="Alfa MMS"
+      carrier_id = "1920"
+      mcc="415"
+      mnc="01"
+      user="mic1"
+      password="mic1"
+      apn="mms.mic1.com.lb"
+      mmsc="http://mms.mic1.com.lb"
+      mmsproxy="192.168.23.51"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="touch"
+      carrier_id = "1921"
+      mcc="415"
+      mnc="03"
+      apn="touch"
+      type="default,supl"
+  />
+
+  <apn carrier="touch_WAP"
+      carrier_id = "1921"
+      mcc="415"
+      mnc="03"
+      apn="wap"
+      proxy="192.168.4.11"
+      port="80"
+      type="default,supl"
+  />
+
+  <apn carrier="touch_MMS"
+      carrier_id = "1921"
+      mcc="415"
+      mnc="03"
+      user="touch"
+      apn="mms"
+      mmsc="http://mms:8088/mms/"
+      mmsproxy="192.168.4.103"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="Zain JO Internet"
+      carrier_id = "1578"
+      mcc="416"
+      mnc="01"
+      apn="zain"
+      user="zain"
+      password="zain"
+      authtype="1"
+      type="default,supl"
+  />
+
+
+  <apn carrier="Zain JO WAP"
+      carrier_id = "1578"
+      mcc="416"
+      mnc="01"
+      apn="zain"
+      user="zain"
+      password="zain"
+      authtype="1"
+      proxy="192.168.55.10"
+      port="80"
+      type="default,supl"
+  />
+
+
+  <apn carrier="Zain JO Streaming"
+      carrier_id = "1578"
+      mcc="416"
+      mnc="01"
+      apn="Zain"
+      user="zain"
+      password="zain"
+      authtype="1"
+      type="default,supl"
+  />
+
+
+  <apn carrier="Zain JO MMS"
+      carrier_id = "1578"
+      mcc="416"
+      mnc="01"
+      apn="zain"
+      user="zain"
+      password="zain"
+      authtype="1"
+      mmsc="http://mms.jo.zain.com"
+      mmsproxy="192.168.55.10"
+      mmsport="80"
+      type="mms"
+  />
+
+
+  <apn carrier="Umniah internet"
+      carrier_id = "1580"
+      mcc="416"
+      mnc="03"
+      apn="net"
+      type="default,supl"
+  />
+
+  <apn carrier="Umniah WAP"
+      carrier_id = "1580"
+      mcc="416"
+      mnc="03"
+      apn="wap"
+      proxy="10.1.1.10"
+      port="8080"
+      type="default,supl"
+  />
+
+
+  <apn carrier="Umniah MMS"
+      carrier_id = "1580"
+      mcc="416"
+      mnc="03"
+      apn="mms"
+      mmsc="http://mms.umniah.com/"
+      mmsproxy="10.1.1.10"
+      mmsport="8080"
+      type="mms"
+  />
+
+
+  <apn carrier="Orange MMS"
+      carrier_id = "849"
+      mcc="416"
+      mnc="770"
+      apn="mms.orange.jo"
+      user="mmc"
+      password="mmc"
+      authtype="1"
+      mmsc="http://172.16.1.96/servlets/mms"
+      mmsproxy="172.16.1.2"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Orange Internet"
+      carrier_id = "849"
+      mcc="416"
+      mnc="770"
+      apn="net.orange.jo"
+      user="net"
+      password="net"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange WAP"
+      carrier_id = "849"
+      mcc="416"
+      mnc="770"
+      apn="wap.orange.jo"
+      user="wap"
+      password="wap"
+      authtype="1"
+      proxy="172.16.1.2"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange MMS"
+      carrier_id = "849"
+      mcc="416"
+      mnc="77"
+      apn="mms.orange.jo"
+      user="mmc"
+      password="mmc"
+      authtype="1"
+      mmsc="http://172.16.1.96/servlets/mms"
+      mmsproxy="172.16.1.2"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Orange Internet"
+      carrier_id = "849"
+      mcc="416"
+      mnc="77"
+      apn="net.orange.jo"
+      user="net"
+      password="net"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange WAP"
+      carrier_id = "849"
+      mcc="416"
+      mnc="77"
+      apn="wap.orange.jo"
+      user="wap"
+      password="wap"
+      authtype="1"
+      proxy="172.16.1.2"
+      port="8080"
+      type="default,supl"
+  />
+
+
+  <apn carrier="Syriatel Net"
+      carrier_id = "1088"
+      mcc="417"
+      mnc="01"
+      apn="net.syriatel.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Syriatel MMS"
+      carrier_id = "1088"
+      mcc="417"
+      mnc="01"
+      apn="mms.syriatel.com"
+      mmsc="http://mymms.syriatel.com/"
+      mmsproxy="172.20.5.6"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="MTN WAP"
+      carrier_id = "1089"
+      mcc="417"
+      mnc="02"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="MTN MMS"
+      carrier_id = "1089"
+      mcc="417"
+      mnc="02"
+      apn="mms"
+      mmsc="http://mms/"
+      mmsproxy="10.110.0.134"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Asiacell Internet"
+      carrier_id = "1969"
+      mcc="418"
+      mnc="05"
+      apn="net.asiacell.com"
+      type="default"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1969"
+      mcc="418"
+      mnc="05"
+      apn="wap.asiacell.com"
+      mmsc="http://mvas.asiacell.com/uportal"
+      mmsproxy="192.168.107.50"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="SanaTel"
+      carrier_id = "2166"
+      mcc="418"
+      mnc="08"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="ZAIN-GPRS"
+      carrier_id = "1971"
+      mcc="418"
+      mnc="20"
+      apn="internet"
+      user="atheer"
+      password="atheer"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Zain-MMS"
+      carrier_id = "1971"
+      mcc="418"
+      mnc="20"
+      apn="MMS"
+      user="atheer"
+      password="atheer"
+      authtype="1"
+      mmsc="http://mms:8002/"
+      mmsproxy="172.29.11.12"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="ZAIN-GPRS"
+      carrier_id = "1971"
+      mcc="418"
+      mnc="30"
+      apn="internet"
+      user="atheer"
+      password="atheer"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Zain-MMS"
+      carrier_id = "1971"
+      mcc="418"
+      mnc="30"
+      apn="MMS"
+      user="atheer"
+      password="atheer"
+      authtype="1"
+      mmsc="http://mms:8002/"
+      mmsproxy="172.29.11.12"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Korek 9595"
+      carrier_id = "1983"
+      mcc="418"
+      mnc="40"
+      apn="internet.korek.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Korek 9191"
+      carrier_id = "1983"
+      mcc="418"
+      mnc="40"
+      apn="net.korek.com"
+      user="korek"
+      password="korek"
+      type="default,supl"
+  />
+
+  <apn carrier="Korek 9494"
+      carrier_id = "1983"
+      mcc="418"
+      mnc="40"
+      apn="internet.korek.com"
+      type="default,supl"
+  />
+
+  <apn carrier="KOREK MMS"
+      carrier_id = "1983"
+      mcc="418"
+      mnc="40"
+      apn="mms.korek.com"
+      user="korek"
+      password="korek"
+      authtype="1"
+      mmsc="http://mms.korektel.com/mms/wapenc"
+      mmsproxy="192.168.18.187"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Mobitel"
+      carrier_id = "2345"
+      mcc="418"
+      mnc="45"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Itisaluna"
+      carrier_id = "2234"
+      mcc="418"
+      mnc="62"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Omnnea"
+      carrier_id = "2167"
+      mcc="418"
+      mnc="92"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="MI"
+      carrier_id = "1585"
+      mcc="419"
+      mnc="02"
+      apn="pps"
+      user="pps"
+      password="pps"
+      type="default,supl"
+  />
+
+  <apn carrier="Zain WAP"
+      carrier_id = "1585"
+      mcc="419"
+      mnc="02"
+      apn="pps"
+      user="pps"
+      password="pps"
+      authtype="3"
+      proxy="10.43.4.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1585"
+      mcc="419"
+      mnc="02"
+      apn="pps"
+      user="mms"
+      password="mms"
+      authtype="3"
+      mmsc="http://mms.zain"
+      mmsproxy="176.0.0.65"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Ooredoo Action"
+      carrier_id = "1586"
+      mcc="419"
+      mnc="03"
+      apn="action.ooredoo.com"
+      authtype="1"
+      type="default"
+  />
+
+  <apn carrier="Ooredoo MMS"
+      carrier_id = "1586"
+      mcc="419"
+      mnc="03"
+      apn="mms.ooredoo.com"
+      mmsc="http://action.ooredoo.com"
+      mmsproxy="194.126.53.64"
+      mmsport="8080"
+      authtype="1"
+      type="default"
+  />
+
+  <apn carrier="VIVA - KW"
+      carrier_id = "1992"
+      mcc="419"
+      mnc="04"
+      apn="viva"
+      authtype="0"
+      mmsc="http://172.16.128.80:38090/was"
+      mmsproxy="172.16.128.228"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="STC - GPRS"
+      carrier_id = "1683"
+      mcc="420"
+      mnc="01"
+      apn="jawalnet.com.sa"
+      type="default,supl"
+  />
+
+  <apn carrier="STC MMS"
+      carrier_id = "1683"
+      mcc="420"
+      mnc="01"
+      apn="mms.net.sa"
+      mmsc="http://mms.net.sa:8002/"
+      mmsproxy="10.1.1.1"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Mobily WEB"
+      carrier_id = "1684"
+      mcc="420"
+      mnc="03"
+      apn="web1"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobily prepaid - GPRS"
+      carrier_id = "1684"
+      mcc="420"
+      mnc="03"
+      apn="wap2"
+      proxy="10.3.2.133"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobily postpaid - GPRS"
+      carrier_id = "1684"
+      mcc="420"
+      mnc="03"
+      apn="wap1"
+      proxy="10.3.2.133"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobily WEB 2"
+      carrier_id = "1684"
+      mcc="420"
+      mnc="03"
+      apn="web2"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobily MMS Postpaid"
+      carrier_id = "1684"
+      mcc="420"
+      mnc="03"
+      apn="mms1"
+      mmsc="http://10.3.3.133:9090/was"
+      mmsproxy="10.3.2.133"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Mobily MMS Prepaid"
+      carrier_id = "1684"
+      mcc="420"
+      mnc="03"
+      apn="mms2"
+      mmsc="http://10.3.3.133:9090/was"
+      mmsproxy="10.3.2.133"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="zain-Internet Wap"
+      carrier_id = "1972"
+      mcc="420"
+      mnc="04"
+      apn="zain"
+      authtype="0"
+      type="default,supl"
+  />
+
+  <apn carrier="zain-mms"
+      carrier_id = "1972"
+      mcc="420"
+      mnc="04"
+      apn="zainmms"
+      mmsc="http://10.122.200.12:8002"
+      mmsproxy="10.122.200.10"
+      mmsport="8080"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="SabaFon"
+      carrier_id = "1877"
+      mcc="421"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Sabafon MMS"
+      carrier_id = "1877"
+      mcc="421"
+      mnc="01"
+      apn="mms"
+      type="mms"
+      user="wap"
+      password="wap"
+      authtype="0"
+      mmsproxy="192.168.30.174"
+      mmsc="http://mms.sabafon.com/"
+      mmsport="8080"
+  />
+
+  <apn carrier="MTN"
+      carrier_id = "1878"
+      mcc="421"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="MTN MMS YE"
+      carrier_id = "1878"
+      mcc="421"
+      mnc="02"
+      apn="fast-mms"
+      type="mms"
+      user="mms"
+      authtype="0"
+      mmsproxy="192.168.97.1"
+      mmsc="http://192.168.97.1/mmsc"
+      mmsport="3130"
+  />
+
+  <apn carrier="YemenMobile"
+      carrier_id = "2349"
+      mcc="421"
+      mnc="03"
+      apn="ymobile"
+      user="ymobile"
+      password="ymobile"
+      authtype="3"
+      type="default,supl"
+  />
+
+  <apn carrier="HiTS-UNITEL"
+      carrier_id = "2168"
+      mcc="421"
+      mnc="04"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="YemenMobile"
+      carrier_id = "2349"
+      mcc="421"
+      mnc="11"
+      apn="ymdata"
+      authtype="0"
+      type="default,mms,supl,fota,cbs,dun"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="YemenMobile"
+      carrier_id = "2349"
+      mcc="421"
+      mnc="11"
+      apn="ymims"
+      authtype="0"
+      type="ims"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="Oman Mobile MMS"
+      carrier_id = "970"
+      mcc="422"
+      mnc="02"
+      apn="mms"
+      user="mms"
+      password="mms"
+      authtype="1"
+      mmsc="http://mmsc.omanmobile.om:10021/mmsc"
+      mmsproxy="192.168.203.35"
+      mmsport="8080"
+      type="mms"
+  />
+
+
+  <apn carrier="Oman Mobile Internet"
+      carrier_id = "970"
+      mcc="422"
+      mnc="02"
+      apn="taif"
+      user="taif"
+      password="taif"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Nawras MMS"
+      carrier_id = "971"
+      mcc="422"
+      mnc="03"
+      apn="mms.nawras.com.om"
+      user="test"
+      password="test"
+      authtype="1"
+      mmsc="http://10.128.240.16/servlets/mms"
+      mmsproxy="10.128.240.19"
+      mmsport="8080"
+      type="mms"
+  />
+
+
+  <apn carrier="Nawras Internet"
+      carrier_id = "971"
+      mcc="422"
+      mnc="03"
+      apn="isp.nawras.com.om"
+      user="test"
+      password="test"
+      authtype="1"
+      type="default,supl"
+  />
+
+
+  <apn carrier="Etisalat Data Package"
+      carrier_id = "451"
+      mcc="424"
+      mnc="02"
+      apn="etisalat.ae"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Weyak Wap"
+      carrier_id = "451"
+      mcc="424"
+      mnc="02"
+      apn="etisalat"
+      proxy="10.12.0.32"
+      port="8080"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Etisalat MMS"
+      carrier_id = "451"
+      mcc="424"
+      mnc="02"
+      apn="etisalat"
+      mmsc="http://mms/servlets/mms"
+      mmsproxy="10.12.0.32"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="du Internet"
+      carrier_id = "1970"
+      mcc="424"
+      mnc="03"
+      apn="du"
+      type="default,supl"
+  />
+
+  <apn carrier="du WAP"
+      carrier_id = "1970"
+      mcc="424"
+      mnc="03"
+      apn="du"
+      proxy="10.19.18.4"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="du MMS"
+      carrier_id = "1970"
+      mcc="424"
+      mnc="03"
+      apn="du"
+      mmsc="http://mms.du.ae:8002"
+      mmsproxy="10.19.18.4"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="3G Portal"
+      carrier_id = "796"
+      mcc="425"
+      mnc="01"
+      apn="uwap.orange.co.il"
+      mmsc="http://192.168.220.15/servlets/mms"
+      mmsproxy="192.118.11.55"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Cellcom Internet"
+      carrier_id = "797"
+      mcc="425"
+      mnc="02"
+      apn="sphone"
+      type="default,supl"
+  />
+
+  <apn carrier="Cellcom MMS"
+      carrier_id = "797"
+      mcc="425"
+      mnc="02"
+      apn="mms"
+      mmsc="http://mms.cellcom.co.il"
+      mmsproxy="vwapm2.ain.co.il"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Multimedia Pelephone"
+      carrier_id = "798"
+      mcc="425"
+      mnc="03"
+      apn="mms.pelephone.net.il"
+      user="pcl@3g"
+      password="pcl"
+      authtype="3"
+      mmsc="http://mmsu.pelephone.net.il"
+      mmsproxy="10.170.252.104"
+      mmsport="9093"
+      type="mms"
+  />
+
+  <apn carrier="Sphone Pelephone"
+      carrier_id = "798"
+      mcc="425"
+      mnc="03"
+      apn="sphone.pelephone.net.il"
+      user="pcl@3g"
+      password="pcl"
+      authtype="2"
+      type="default,supl"
+  />
+
+  <apn carrier="Jawwal WAP"
+      mcc="425"
+      mnc="05"
+      apn="wap"
+      proxy="213.244.118.129"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Jawwal MMS"
+      mcc="425"
+      mnc="05"
+      apn="mms"
+      mmsc="http://mms.jawwal.ps/servlets/mms"
+      mmsproxy="213.244.118.129"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Internet"
+      mcc="425"
+      mnc="06"
+      apn="internet"
+      proxy="10.100.129.111"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Wataniya_mms"
+      mcc="425"
+      mnc="06"
+      apn="mms"
+      mmsc="http://mms.wataniya.ps/servlets/mms"
+      mmsproxy="10.100.129.111"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Internet HOT mobile"
+      carrier_id = "1991"
+      mcc="425"
+      mnc="07"
+      apn="net.hotm"
+      type="default,supl"
+  />
+
+  <apn carrier="PC HOT mobile"
+      carrier_id = "1991"
+      mcc="425"
+      mnc="07"
+      apn="pc.hotm"
+      type="dun"
+      authtype="0"
+  />
+
+  <apn carrier="MMS HOT mobile"
+      carrier_id = "1991"
+      mcc="425"
+      mnc="07"
+      apn="mms.hotm"
+      mmsc="http://mms.hotmobile.co.il"
+      mmsproxy="80.246.131.99"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="GolanTelecom Internet"
+      carrier_id = "1990"
+      mcc="425"
+      mnc="08"
+      apn="internet.golantelecom.net.il"
+      type="default,supl"
+  />
+
+  <apn carrier="GolanTelecom MMS"
+      carrier_id = "1990"
+      mcc="425"
+      mnc="08"
+      apn="mms.golantelecom.net.il"
+      mmsc="http://mmsc.golantelecom.co.il"
+      mmsproxy="10.224.228.81"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="3G Portal"
+      carrier_id = "796"
+      mcc="425"
+      mnc="10"
+      apn="uwap.orange.co.il"
+      mmsc="http://192.168.220.15/servlets/mms"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="YouPhone"
+      carrier_id = "2169"
+      mcc="425"
+      mnc="14"
+      apn="data.youphone.co.il"
+      mmsc="http://192.168.220.15/servlets/mms"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Home Cellular Internet"
+      carrier_id = "2170"
+      mcc="425"
+      mnc="15"
+      apn="hcminternet"
+      type="default,supl"
+  />
+
+  <apn carrier="Home Cellular MMS"
+      carrier_id = "2170"
+      mcc="425"
+      mnc="15"
+      apn="hcmMMS"
+      mmsc="http://82.166.164.229:9000/mmsc"
+      mmsproxy="82.166.164.229"
+      mmsport="8898"
+      type="mms"
+  />
+
+  <apn carrier="Rami Levi 3G"
+      carrier_id = "2171"
+      mcc="425"
+      mnc="16"
+      apn="internet.rl"
+      type="default,supl"
+  />
+
+  <apn carrier="Rami Levi Multimedia"
+      carrier_id = "2171"
+      mcc="425"
+      mnc="16"
+      apn="mms.pelephone.net.il"
+      mmsc="http://mmsu.pelephone.net.il"
+      mmsproxy="10.170.252.104"
+      mmsport="9093"
+      type="mms"
+  />
+
+  <apn carrier="Annatel"
+      carrier_id = "2454"
+      mcc="425"
+      mnc="26"
+      apn="annatel"
+      type="default,supl"
+  />
+
+  <apn carrier="Batelco Internet"
+      carrier_id = "1372"
+      mcc="426"
+      mnc="01"
+      apn="internet.batelco.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Batelco WAP"
+      carrier_id = "1372"
+      mcc="426"
+      mnc="01"
+      apn="wap.batelco.com"
+      user="wap"
+      password="wap"
+      authtype="0"
+      proxy="192.168.1.2"
+      port="80"
+      type="default,supl"
+  />
+
+  <apn carrier="Batelco MMS"
+      carrier_id = "1372"
+      mcc="426"
+      mnc="01"
+      apn="mms.batelco.com"
+      user="mms"
+      password="mms"
+      authtype="0"
+      mmsc="http://192.168.36.10/servlets/mms"
+      mmsproxy="192.168.1.2"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="Zain BH Internet"
+      carrier_id = "2014"
+      mcc="426"
+      mnc="02"
+      apn="internet"
+      user="internet"
+      password="internet"
+      authtype="0"
+      type="default,supl"
+  />
+
+  <apn carrier="Zain BH WAP"
+      carrier_id = "2014"
+      mcc="426"
+      mnc="02"
+      apn="wap"
+      user="wap"
+      password="wap"
+      authtype="0"
+      proxy="172.18.85.33"
+      port="80"
+      type="default,supl"
+  />
+
+
+  <apn carrier="Zain BH MMS"
+      carrier_id = "2014"
+      mcc="426"
+      mnc="02"
+      apn="mms"
+      user="mms"
+      password="mms"
+      authtype="0"
+      mmsc="http://172.18.83.129:80/"
+      mmsproxy="172.18.85.34"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="VIVAGPRS"
+      carrier_id = "2015"
+      mcc="426"
+      mnc="04"
+      apn="viva.bh"
+      type="default,supl"
+  />
+
+  <apn carrier="VIVAWAP"
+      carrier_id = "2015"
+      mcc="426"
+      mnc="04"
+      apn="vivawap.bh"
+      proxy="172.18.142.36"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="VIVAMMS"
+      carrier_id = "2015"
+      mcc="426"
+      mnc="04"
+      apn="vivawap.bh"
+      mmsc="http://mms.viva.com.bh:38090"
+      mmsproxy="172.18.142.36"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "1675"
+      mcc="427"
+      mnc="01"
+      apn="data"
+      type="default,supl"
+      authtype="1"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1675"
+      mcc="427"
+      mnc="01"
+      apn="data"
+      mmsc="http://mmsr.ooredoomms.qa"
+      mmsproxy="10.23.8.3"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Voda internet"
+      carrier_id = "2393"
+      mcc="427"
+      mnc="02"
+      apn="web.vodafone.com.qa"
+      type="default,supl"
+  />
+
+  <apn carrier="VFQ MMS"
+      carrier_id = "2393"
+      mcc="427"
+      mnc="02"
+      apn="vodafone.com.qa"
+      mmsc="http://mms.vodafone.com.qa/mmsc"
+      mmsproxy="10.101.97.102"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="Unitel"
+      carrier_id = "2347"
+      mcc="428"
+      mnc="88"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Skytel"
+      carrier_id = "2172"
+      mcc="428"
+      mnc="91"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="G.Mobile"
+      carrier_id = "2173"
+      mcc="428"
+      mnc="98"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="MobiCom"
+      carrier_id = "1612"
+      mcc="428"
+      mnc="99"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Namaste / NT Mobile"
+      carrier_id = "962"
+      mcc="429"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Ncell"
+      carrier_id = "1923"
+      mcc="429"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Sky/C-Phone"
+      carrier_id = "962"
+      mcc="429"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="SmartCell"
+      carrier_id = "1924"
+      mcc="429"
+      mnc="04"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="MCI-GPRS"
+      carrier_id = "1562"
+      mcc="432"
+      mnc="11"
+      apn="mcinet"
+      type="default,supl"
+  />
+
+  <apn carrier="MCCI MMS"
+      carrier_id = "1562"
+      mcc="432"
+      mnc="11"
+      apn="mcinet"
+      mmsc="http://192.168.193.134:38090/was"
+      mmsproxy="192.168.194.73"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="MCI-GPRS"
+      carrier_id = "1563"
+      mcc="432"
+      mnc="14"
+      apn="mcinet"
+      type="default,supl"
+  />
+
+  <apn carrier="MCCI MMS"
+      carrier_id = "1563"
+      mcc="432"
+      mnc="14"
+      apn="MCI-GPRS"
+      mmsport="38090"
+      mmsc="http://192.168.193.134"
+      type="mms"
+  />
+
+  <apn carrier="MCI-GPRS"
+      carrier_id = "1564"
+      mcc="432"
+      mnc="19"
+      apn="mcinet"
+      type="default,supl"
+  />
+
+  <apn carrier="MCCI MMS"
+      carrier_id = "1564"
+      mcc="432"
+      mnc="19"
+      apn="MCI-GPRS"
+      mmsport="38090"
+      mmsc="http://192.168.193.134"
+      type="mms"
+  />
+
+  <apn carrier="rightel"
+      carrier_id = "1987"
+      mcc="432"
+      mnc="20"
+      apn="rightel"
+      type="default,supl"
+  />
+
+  <apn carrier="RighTel-MMS"
+      carrier_id = "1987"
+      mcc="432"
+      mnc="20"
+      apn="RighTel-WAP"
+      mmsc="http://10.200.40.55:38090/was"
+      mmsproxy="10.200.39.10"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Irancell-GPRS"
+      carrier_id = "1967"
+      mcc="432"
+      mnc="35"
+      apn="mtnirancell"
+      proxy="10.131.26.138"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Irancell-MMS"
+      carrier_id = "1967"
+      mcc="432"
+      mnc="35"
+      apn="mtnirancell"
+      mmsc="http://mms:8002"
+      mmsproxy="10.131.26.138"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="MCI-GPRS"
+      carrier_id = "2352"
+      mcc="432"
+      mnc="70"
+      apn="mcinet"
+      type="default,supl"
+  />
+
+  <apn carrier="MCCI MMS"
+      carrier_id = "2352"
+      mcc="432"
+      mnc="70"
+      apn="mcinet"
+      mmsc="http://192.168.193.134:38090/was"
+      mmsproxy="192.168.194.73"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="MCI-GPRS"
+      carrier_id = "2358"
+      mcc="432"
+      mnc="93"
+      apn="mcinet"
+      type="default,supl"
+  />
+
+  <apn carrier="MCCI MMS"
+      carrier_id = "2358"
+      mcc="432"
+      mnc="93"
+      apn="MCI-GPRS"
+      mmsport="38090"
+      mmsc="http://192.168.193.134"
+      type="mms"
+  />
+
+  <apn carrier="Beeline-UZB Internet"
+      carrier_id = "1867"
+      mcc="434"
+      mnc="04"
+      apn="internet.beeline.uz"
+      user="beeline"
+      password="beeline"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Beeline-UZB MMS"
+      carrier_id = "1867"
+      mcc="434"
+      mnc="04"
+      apn="mms.beeline.uz"
+      user="beeline"
+      password="beeline"
+      authtype="1"
+      mmsc="http://mms"
+      mmsproxy="172.30.30.166"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="UCELL Internet"
+      carrier_id = "1868"
+      mcc="434"
+      mnc="05"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="UCELL MMS"
+      carrier_id = "1868"
+      mcc="434"
+      mnc="05"
+      apn="mms"
+      mmsc="http://mmsc:8002/"
+      mmsproxy="10.64.164.10"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Perfectum Mobile"
+      carrier_id = "2235"
+      mcc="434"
+      mnc="06"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="MTS-UZB Internet"
+      carrier_id = "1869"
+      mcc="434"
+      mnc="07"
+      apn="net.mts.uz"
+      user="mts"
+      password="mts"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MTS-UZB MMS"
+      carrier_id = "1869"
+      mcc="434"
+      mnc="07"
+      apn="mms.mts.uz"
+      mmsc="http://mmsc/was"
+      mmsproxy="10.10.0.10"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Tcell"
+      carrier_id = "1724"
+      mcc="436"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Tcell"
+      carrier_id = "1725"
+      mcc="436"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Megafon"
+      carrier_id = "1726"
+      mcc="436"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Babilon-M"
+      carrier_id = "1727"
+      mcc="436"
+      mnc="04"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Tacom"
+      carrier_id = "1728"
+      mcc="436"
+      mnc="05"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Tcell"
+      carrier_id = "2174"
+      mcc="436"
+      mnc="12"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Beeline"
+      carrier_id = "867"
+      mcc="437"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Fonex"
+      carrier_id = "2175"
+      mcc="437"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="MegaCom"
+      carrier_id = "2176"
+      mcc="437"
+      mnc="05"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="O!"
+      carrier_id = "2177"
+      mcc="437"
+      mnc="09"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="MTS (BARASH Communication)"
+      carrier_id = "1729"
+      mcc="438"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="TM-Cell"
+      carrier_id = "1730"
+      mcc="438"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="IIJmio (TypeI)"
+      mcc="440"
+      mnc="03"
+      apn="iijmio.jp"
+      user="mio@iij"
+      password="iij"
+      authtype="3"
+      protocol="IPV4V6"
+      type="default"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="vmobile.jp"
+      mcc="440"
+      mnc="03"
+      apn="vmobile.jp"
+      user="vmobile@jp"
+      password="vmobile"
+      authtype="3"
+      protocol="IPV4V6"
+      type="default"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="spモード"
+      mcc="440"
+      mnc="10"
+      apn="spmode.ne.jp"
+      type="default,supl"
+      authtype="0"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="lte_ims"
+      mcc="440"
+      mnc="10"
+      apn="ims"
+      type="ims"
+      authtype="0"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+      bearer_bitmask="14"
+  />
+
+  <apn carrier="Emergency"
+      mcc="440"
+      mnc="10"
+      apn=""
+      type="Emergency"
+      protocol="IPV6"
+      roaming_protocol="IPV6"
+  />
+
+  <apn carrier="楽天(rakuten.jp)"
+      carrier_id="2429"
+      mcc="440"
+      mnc="11"
+      apn="rakuten.jp"
+      type="default,supl,dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="IMS"
+      carrier_id="2429"
+      mcc="440"
+      mnc="11"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="SBM"
+      carrier_id = "1894"
+      mcc="440"
+      mnc="20"
+      apn=""
+      type="ia"
+      protocol="IP"
+  />
+
+  <apn carrier="IMS"
+      carrier_id = "1894"
+      mcc="440"
+      mnc="20"
+      apn="IMS"
+      type="ims"
+      protocol="IPV6"
+  />
+
+  <apn carrier="Application"
+      carrier_id = "1894"
+      mcc="440"
+      mnc="20"
+      apn="plus.acs.jp"
+      user="ym"
+      password="ym"
+      mmsproxy="andmms.plusacs.ne.jp"
+      mmsport="8080"
+      mmsc="http://mms-s"
+      type="default,mms,supl,hipri"
+      authtype="2"
+  />
+
+  <apn carrier="RATEL"
+      carrier_id = "1894"
+      mcc="440"
+      mnc="20"
+      apn="ratel.com"
+      user="ratel@ratel.com"
+      server=""
+      password="ratel"
+      authtype="3"
+      protocol="IPV4V6"
+      type="default,supl"
+  />
+
+  <apn carrier="RATEL"
+      carrier_id = "1581"
+      mcc="440"
+      mnc="51"
+      apn="ratel.com"
+      user="ratel@ratel.com"
+      server=""
+      password="ratel"
+      authtype="3"
+      protocol="IPV4V6"
+      type="default,supl"
+  />
+
+  <apn carrier="Rakuten"
+      carrier_id = "2109"
+      mcc="440"
+      mnc="51"
+      apn="a.rmobile.jp"
+      user="rakuten@vdm"
+      server=""
+      password="0000"
+      authtype="3"
+      type="default,supl"
+  />
+
+  <apn carrier="SKT IA"
+      carrier_id = "1891"
+      mcc="450"
+      mnc="05"
+      apn=""
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="SKT IMS"
+      carrier_id = "1891"
+      mcc="450"
+      mnc="05"
+      apn="IMS"
+      type="ims"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="SKT LTE INTERNET"
+      carrier_id = "1891"
+      mcc="450"
+      mnc="05"
+      apn="lte.sktelecom.com"
+      type="default,mms,supl,fota,cbs"
+      mmsc="http://omms.nate.com:9082/oma_mms"
+      mmsproxy="smart.nate.com"
+      mmsport="9093"
+      server="*"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="LG uplus IA"
+      carrier_id = "1892"
+      mcc="450"
+      mnc="06"
+      apn=""
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="LG uplus IMS"
+      carrier_id = "1892"
+      mcc="450"
+      mnc="06"
+      apn="IMS"
+      type="ims"
+      mmsc="http://omammsc.uplus.co.kr:9084"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="LG uplus"
+      carrier_id = "1892"
+      mcc="450"
+      mnc="06"
+      apn="internet.lguplus.co.kr"
+      type="default,mms,supl,fota,cbs"
+      mmsc="http://omammsc.uplus.co.kr:9084"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="KT IA"
+      carrier_id = "1890"
+      mcc="450"
+      mnc="08"
+      apn=""
+      type="ia"
+      protocol="IPV4V6"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="KT IMS"
+      carrier_id = "1890"
+      mcc="450"
+      mnc="08"
+      apn="IMS"
+      type="ims"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="KT"
+      carrier_id = "1890"
+      mcc="450"
+      mnc="08"
+      apn="lte.ktfwing.com"
+      type="default,mms,supl,fota,cbs"
+      mmsc="http://mmsc.ktfwing.com:9082"
+      port="80"
+      server="*"
+  />
+
+  <apn carrier="Mobi-wap-gprs 2"
+      carrier_id = "1299"
+      mcc="452"
+      mnc="01"
+      apn="m-wap"
+      user="mms"
+      password="mms"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobi-wap-gprs 1"
+      carrier_id = "1299"
+      mcc="452"
+      mnc="01"
+      apn="m-wap"
+      user="mms"
+      password="mms"
+      authtype="1"
+      proxy="203.162.21.107"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobi-gprs-mms"
+      carrier_id = "1299"
+      mcc="452"
+      mnc="01"
+      apn="m-i090"
+      user="mms"
+      password="mms"
+      authtype="1"
+      mmsc="http://203.162.21.114/mmsc"
+      mmsproxy="203.162.21.114"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Vina-wap-gprs"
+      carrier_id = "1300"
+      mcc="452"
+      mnc="02"
+      apn="m3-world"
+      user="mms"
+      password="mms"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Vina-gprs-mms"
+      carrier_id = "1300"
+      mcc="452"
+      mnc="02"
+      apn="m3-mms"
+      user="mms"
+      password="mms"
+      authtype="1"
+      mmsc="http://mms.vinaphone.com.vn"
+      mmsproxy="10.1.10.46"
+      mmsport="8000"
+      type="mms"
+  />
+
+  <apn carrier="Viettel-wap-gprs 1"
+      carrier_id = "1899"
+      mcc="452"
+      mnc="04"
+      apn="v-internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Viettel-wap-gprs 2"
+      carrier_id = "1899"
+      mcc="452"
+      mnc="04"
+      apn="v-wap"
+      proxy="192.168.233.10"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Viettel-gprs-mms"
+      carrier_id = "1899"
+      mcc="452"
+      mnc="04"
+      apn="v-mms"
+      mmsc="http://mms.viettelmobile.com.vn/mms/wapenc"
+      mmsproxy="192.168.233.10"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Vietnamobile_GPRS3"
+      carrier_id = "1994"
+      mcc="452"
+      mnc="05"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Vietnamobile_GPRS1"
+      carrier_id = "1994"
+      mcc="452"
+      mnc="05"
+      apn="wap"
+      proxy="10.10.128.44"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Vietnamobile_GPRS2"
+      carrier_id = "1994"
+      mcc="452"
+      mnc="05"
+      apn="wap"
+      type="default,supl"
+  />
+
+  <apn carrier="Vietnamobile_MMS"
+      carrier_id = "1994"
+      mcc="452"
+      mnc="05"
+      apn="mms"
+      mmsc="http://10.10.128.58/servlets/mms"
+      mmsproxy="10.10.128.44"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Gmobile-wap-gprs2"
+      carrier_id = "2178"
+      mcc="452"
+      mnc="07"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Gmobile-wap-gprs"
+      carrier_id = "2178"
+      mcc="452"
+      mnc="07"
+      apn="internet"
+      proxy="10.16.70.199"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Gmobile-gprs-mms"
+      carrier_id = "2178"
+      mcc="452"
+      mnc="07"
+      apn="mms"
+      mmsc="http://mms"
+      mmsproxy="10.16.70.199"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Gmobile MMS"
+      carrier_id = "2178"
+      mcc="452"
+      mnc="07"
+      apn="mms"
+      user="mms"
+      password="mms"
+      authtype="2"
+      mmsc="http://mms"
+      mmsproxy="10.16.70.199"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="e-internet"
+      carrier_id = "2179"
+      mcc="452"
+      mnc="08"
+      apn="e-internet"
+      type="default,supl"
+  />
+
+  <apn carrier="e-wap"
+      carrier_id = "2179"
+      mcc="452"
+      mnc="08"
+      apn="e-wap"
+      proxy="10.18.2.183"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="e-mms"
+      carrier_id = "2179"
+      mcc="452"
+      mnc="08"
+      apn="e-mms"
+      mmsc="http://10.18.2.172:38090"
+      mmsproxy="10.18.2.183"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="1O1O"
+      carrier_id = "1526"
+      mcc="454"
+      mnc="00"
+      apn="mobile"
+      mmsproxy="192.168.59.51"
+      mmsport="8080"
+      mmsc="http://192.168.58.171:8002"
+      authtype="3"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="one2free"
+      carrier_id = "1526"
+      mcc="454"
+      mnc="00"
+      apn="mobile"
+      mmsproxy="192.168.59.51"
+      mmsport="8080"
+      mmsc="http://192.168.58.171:8002"
+      authtype="3"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="NWMOBILE"
+      carrier_id = "1526"
+      mcc="454"
+      mnc="00"
+      apn="NWMOBILE"
+      mmsproxy="192.168.59.61"
+      mmsport="8080"
+      mmsc="http://192.168.58.171:8002"
+      authtype="3"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="1O1O"
+      carrier_id = "759"
+      mcc="454"
+      mnc="02"
+      apn="mobile"
+      mmsproxy="192.168.59.51"
+      mmsport="8080"
+      mmsc="http://192.168.58.171:8002"
+      authtype="3"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="one2free"
+      carrier_id = "759"
+      mcc="454"
+      mnc="02"
+      apn="mobile"
+      mmsproxy="192.168.59.51"
+      mmsport="8080"
+      mmsc="http://192.168.58.171:8002"
+      authtype="3"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="NWMOBILE"
+      carrier_id = "759"
+      mcc="454"
+      mnc="02"
+      apn="NWMOBILE"
+      mmsproxy="192.168.59.61"
+      mmsport="8080"
+      mmsc="http://192.168.58.171:8002"
+      authtype="3"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="3 LTE"
+      carrier_id = "760"
+      mcc="454"
+      mnc="03"
+      apn="mobile.lte.three.com.hk"
+      mmsc="http://mms.um.three.com.hk:10021/mmsc"
+      mmsproxy="mms.three.com.hk"
+      mmsport="8799"
+      authtype="1"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="3"
+      carrier_id = "760"
+      mcc="454"
+      mnc="03"
+      apn="mobile.three.com.hk"
+      mmsc="http://mms.um.three.com.hk:10021/mmsc"
+      mmsproxy="mms.three.com.hk"
+      mmsport="8799"
+      authtype="1"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="3(2G) MMS"
+      carrier_id = "1960"
+      mcc="454"
+      mnc="04"
+      apn="mms-g.three.com.hk"
+      mmsc="http://10.30.15.51:10021/mmsc"
+      mmsproxy="10.30.15.53"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="3(2G) GPRS"
+      carrier_id = "1960"
+      mcc="454"
+      mnc="04"
+      apn="web-g.three.com.hk"
+      proxy="10.30.3.151"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="SmarTone"
+      carrier_id = "761"
+      mcc="454"
+      mnc="06"
+      apn="SmarTone"
+      mmsc="http://mms.smartone.com/server"
+      mmsproxy="10.9.9.9"
+      mmsport="8080"
+      authtype="3"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="454"
+      mnc="08"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+  />
+
+  <apn carrier="one2free"
+      carrier_id = "765"
+      mcc="454"
+      mnc="10"
+      apn="hkcsl"
+      mmsc="http://192.168.58.171:8002"
+      mmsproxy="192.168.59.51"
+      mmsport="8080"
+      authtype="3"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="CMHK MMS"
+      carrier_id = "767"
+      mcc="454"
+      mnc="12"
+      apn="cmhk"
+      mmsc="http://mms.hk.chinamobile.com/mms"
+      type="mms"
+  />
+
+  <apn carrier="CMHK Data"
+      carrier_id = "767"
+      mcc="454"
+      mnc="12"
+      apn="cmhk"
+      type="default,supl"
+  />
+
+  <apn carrier="CMHK MMS"
+      carrier_id = "767"
+      mcc="454"
+      mnc="13"
+      apn="cmhk"
+      mmsc="http://mms.hk.chinamobile.com/mms"
+      type="mms"
+  />
+
+  <apn carrier="CMHK Data"
+      carrier_id = "767"
+      mcc="454"
+      mnc="13"
+      apn="cmhk"
+      type="default,supl"
+  />
+
+  <apn carrier="SmarTone"
+      carrier_id = "768"
+      mcc="454"
+      mnc="15"
+      apn="SmarTone"
+      mmsproxy="10.9.9.9"
+      mmsport="8080"
+      mmsc="http://mms.smartone.com/server"
+      authtype="3"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="PCCW-HKT"
+      carrier_id = "769"
+      mcc="454"
+      mnc="16"
+      apn="pccw"
+      mmsc="http://3gmms.pccwmobile.com:8080/was"
+      mmsproxy="10.140.14.10"
+      mmsport="8080"
+      authtype="1"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="SmarTone"
+      carrier_id = "761"
+      mcc="454"
+      mnc="17"
+      apn="SmarTone"
+      mmsproxy="10.9.9.9"
+      mmsport="8080"
+      mmsc="http://mms.smartone.com/server"
+      authtype="3"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="1O1O"
+      carrier_id = "770"
+      mcc="454"
+      mnc="18"
+      apn="mobile"
+      mmsproxy="192.168.59.51"
+      mmsport="8080"
+      mmsc="http://192.168.58.171:8002"
+      authtype="3"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="one2free"
+      carrier_id = "770"
+      mcc="454"
+      mnc="18"
+      apn="mobile"
+      mmsproxy="192.168.59.51"
+      mmsport="8080"
+      mmsc="http://192.168.58.171:8002"
+      authtype="3"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="NWMOBILE"
+      carrier_id = "770"
+      mcc="454"
+      mnc="18"
+      apn="NWMOBILE"
+      mmsproxy="192.168.59.61"
+      mmsport="8080"
+      mmsc="http://192.168.58.171:8002"
+      authtype="3"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="PCCW-HKT"
+      carrier_id = "1526"
+      mcc="454"
+      mnc="19"
+      apn="pccw"
+      mmsc="http://3gmms.pccwmobile.com:8080/was"
+      mmsproxy="10.140.14.10"
+      mmsport="8080"
+      authtype="1"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="SmarTone Macau"
+      carrier_id = "1613"
+      mcc="455"
+      mnc="00"
+      apn="smartgprs"
+      mmsc="http://momms.smartone.com/dmog/mo"
+      mmsproxy="10.9.9.29"
+      mmsport="8080"
+      authtype="3"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="CTM Data"
+      carrier_id = "1614"
+      mcc="455"
+      mnc="01"
+      apn="ctm-mobile"
+      type="default,supl"
+  />
+
+  <apn carrier="CTM MMS"
+      carrier_id = "1614"
+      mcc="455"
+      mnc="01"
+      apn="ctmmms"
+      mmsc="http://mms.wap.ctm.net:8002"
+      mmsproxy="192.168.99.3"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="CTM (Prepaid)"
+      carrier_id = "1614"
+      mcc="455"
+      mnc="01"
+      apn="ctmprepaid"
+      mmsc="http://mms.wap.ctm.net:8002"
+      mmsproxy="192.168.99.3"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="3 Macau"
+      carrier_id = "1615"
+      mcc="455"
+      mnc="03"
+      apn="mobile.three.com.mo"
+      mmsc="http://mms.three.com.mo:10021/mmsc"
+      mmsproxy="mms.three.com.mo"
+      mmsport="8080"
+      authtype="1"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="CTM Data"
+      carrier_id = "1614"
+      mcc="455"
+      mnc="04"
+      apn="ctm-mobile"
+      type="default,supl"
+  />
+
+  <apn carrier="CTM MMS"
+      carrier_id = "1614"
+      mcc="455"
+      mnc="04"
+      apn="ctmmms"
+      mmsc="http://mms.wap.ctm.net:8002"
+      mmsproxy="192.168.99.3"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="CTM (Prepaid)"
+      carrier_id = "1614"
+      mcc="455"
+      mnc="04"
+      apn="ctmprepaid"
+      mmsc="http://mms.wap.ctm.net:8002"
+      mmsproxy="192.168.99.3"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="3 Macau"
+      mcc="455"
+      mnc="05"
+      apn="mobile.three.com.mo"
+      mmsc="http://mms.three.com.mo:10021/mmsc"
+      mmsproxy="mms.three.com.mo"
+      mmsport="8080"
+      authtype="1"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Cellcard"
+      carrier_id = "868"
+      mcc="456"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Smart"
+      carrier_id = "869"
+      mcc="456"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="qb"
+      carrier_id = "2180"
+      mcc="456"
+      mnc="04"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Star-Cell"
+      carrier_id = "869"
+      mcc="456"
+      mnc="05"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Smart"
+      carrier_id = "869"
+      mcc="456"
+      mnc="06"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Metfone"
+      carrier_id = "2181"
+      mcc="456"
+      mnc="08"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Beeline"
+      mcc="456"
+      mnc="09"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Excell"
+      carrier_id = "2236"
+      mcc="456"
+      mnc="11"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Cellcard"
+      carrier_id = "871"
+      mcc="456"
+      mnc="18"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="LTC"
+      carrier_id = "1590"
+      mcc="457"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="ETL"
+      carrier_id = "1591"
+      mcc="457"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Unitel"
+      carrier_id = "2346"
+      mcc="457"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Beeline"
+      carrier_id = "1592"
+      mcc="457"
+      mnc="08"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="中国移动 (China Mobile) GPRS"
+      carrier_id = "1435"
+      mcc="460"
+      mnc="00"
+      apn="cmnet"
+      type="default,supl"
+  />
+
+  <apn carrier="中国移动 (China Mobile) WAP"
+      carrier_id = "1435"
+      mcc="460"
+      mnc="00"
+      apn="cmwap"
+      proxy="10.0.0.172"
+      port="80"
+      type="default,supl"
+  />
+
+  <apn carrier="中国移动彩信 (China Mobile)"
+      carrier_id = "1435"
+      mcc="460"
+      mnc="00"
+      apn="cmwap"
+      proxy="10.0.0.172"
+      port="80"
+      mmsc="http://mmsc.monternet.com"
+      mmsproxy="10.0.0.172"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="沃3G连接互联网 (China Unicom)"
+      carrier_id = "1436"
+      mcc="460"
+      mnc="01"
+      apn="3gnet"
+      type="default,supl"
+  />
+
+  <apn carrier="沃3G手机上网 (China Unicom)"
+      carrier_id = "1436"
+      mcc="460"
+      mnc="01"
+      apn="3gwap"
+      proxy="10.0.0.172"
+      port="80"
+      type="default,supl"
+  />
+
+  <apn carrier="联通2GNET上网 (China Unicom)"
+      carrier_id = "1436"
+      mcc="460"
+      mnc="01"
+      apn="uninet"
+      type="default,supl"
+  />
+
+  <apn carrier="联通彩信 (China Unicom)"
+      carrier_id = "1436"
+      mcc="460"
+      mnc="01"
+      apn="3gwap"
+      mmsc="http://mmsc.myuni.com.cn"
+      mmsproxy="10.0.0.172"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="联通2g彩信 (China Unicom)"
+      carrier_id = "1436"
+      mcc="460"
+      mnc="01"
+      apn="uniwap"
+      mmsc="http://mmsc.myuni.com.cn"
+      mmsproxy="10.0.0.172"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="中国移动 (China Mobile) GPRS"
+      carrier_id = "1435"
+      mcc="460"
+      mnc="02"
+      apn="cmnet"
+      type="default,supl"
+  />
+
+  <apn carrier="中国移动 (China Mobile) WAP"
+      carrier_id = "1435"
+      mcc="460"
+      mnc="02"
+      apn="cmwap"
+      proxy="10.0.0.172"
+      port="80"
+      type="default,supl"
+  />
+
+  <apn carrier="中国移动彩信 (China Mobile)"
+      carrier_id = "1435"
+      mcc="460"
+      mnc="02"
+      apn="cmwap"
+      proxy="10.0.0.172"
+      port="80"
+      mmsc="http://mmsc.monternet.com"
+      mmsproxy="10.0.0.172"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="中国移动 (China Mobile) GPRS"
+      carrier_id = "1435"
+      mcc="460"
+      mnc="07"
+      apn="cmnet"
+      type="default,supl"
+  />
+
+  <apn carrier="中国移动 (China Mobile) GPRS"
+      carrier_id = "1435"
+      mcc="460"
+      mnc="08"
+      apn="cmnet"
+      type="default,supl"
+  />
+
+  <apn carrier="中国移动 (China Mobile) WAP"
+      carrier_id = "1435"
+      mcc="460"
+      mnc="07"
+      apn="cmwap"
+      proxy="10.0.0.172"
+      port="80"
+      type="default,supl"
+  />
+
+  <apn carrier="中国移动彩信 (China Mobile)"
+      carrier_id = "1435"
+      mcc="460"
+      mnc="07"
+      apn="cmwap"
+      proxy="10.0.0.172"
+      port="80"
+      mmsc="http://mmsc.monternet.com"
+      mmsproxy="10.0.0.172"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="中国移动 (China Mobile) WAP"
+      carrier_id = "1435"
+      mcc="460"
+      mnc="08"
+      apn="cmwap"
+      proxy="10.0.0.172"
+      port="80"
+      type="default,supl"
+  />
+
+  <apn carrier="中国移动彩信 (China Mobile)"
+      carrier_id = "1435"
+      mcc="460"
+      mnc="08"
+      apn="cmwap"
+      proxy="10.0.0.172"
+      port="80"
+      mmsc="http://mmsc.monternet.com"
+      mmsproxy="10.0.0.172"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="China Unicom 3G"
+      apn="3gnet"
+      carrier_id = "1436"
+      mcc="460"
+      mnc="09"
+      port="80"
+      type="default, supl"/>
+
+  <apn carrier="China Unicom wap"
+      apn="3gwap"
+      carrier_id = "1436"
+      mcc="460"
+      mnc="09"
+      proxy="10.0.0.172"
+      port="80"
+      mmsproxy="10.0.0.172"
+      mmsport="80"
+      mmsc="http://mmsc.myuni.com.cn"
+      type="default, mms"/>
+
+  <apn carrier="ctlte"
+      carrier_id = "2237"
+      mcc="460"
+      mnc="11"
+      apn="ctlte"
+      user=""
+      password=""
+      authtype="0"
+      server="*"
+      proxy=""
+      port="80"
+      mmsc=""
+      mmsproxy=""
+      mmsport=""
+      type="default,hipri,supl,fota,cbs"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="CTWAP"
+      carrier_id = "2237"
+      mcc="460"
+      mnc="11"
+      apn="ctwap"
+      user=""
+      password=""
+      authtype="0"
+      server="*"
+      proxy=""
+      port="80"
+      mmsc="http://mmsc.vnet.mobi"
+      mmsproxy="10.0.0.200"
+      mmsport="80"
+      type="mms"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="CTNET"
+      carrier_id = "2237"
+      mcc="460"
+      mnc="03"
+      apn="ctnet"
+      user="ctnet@mycdma.cn"
+      password="vnet.mobi"
+      authtype="3"
+      server="*"
+      proxy=""
+      port="80"
+      mmsc=""
+      mmsproxy=""
+      mmsport=""
+      type="default,hipri,fota,cbs"
+      protocol="IP"
+  />
+
+  <apn carrier="CTWAP"
+      carrier_id = "2237"
+      mcc="460"
+      mnc="03"
+      apn="ctwap"
+      user="ctwap@mycdma.cn"
+      password="vnet.mobi"
+      authtype="3"
+      server="*"
+      proxy=""
+      port="80"
+      mmsc="http://mmsc.vnet.mobi"
+      mmsproxy="10.0.0.200"
+      mmsport="80"
+      type="default,mms,hipri,supl,fota,cbs"
+      protocol="IP"
+  />
+
+  <apn carrier="CTNET"
+      carrier_id = "2237"
+      mcc="204"
+      mnc="04"
+      apn="ctnet"
+      user=""
+      password=""
+      authtype="0"
+      server="*"
+      proxy=""
+      port=""
+      mmsc=""
+      mmsproxy=""
+      mmsport=""
+      type="default,hipri,supl,fota,cbs"
+      mvno_type="spn"
+      mvno_match_data="中国电信"
+      protocol="IP"
+  />
+
+  <apn carrier="遠傳電信(Far EasTone) (MMS)"
+      carrier_id = "1881"
+      mcc="466"
+      mnc="01"
+      apn="fetnet01"
+      mmsc="http://mms"
+      mmsproxy="210.241.199.199"
+      mmsport="9201"
+      type="mms"
+  />
+
+  <apn carrier="遠傳電信(Far EasTone) (Internet)"
+      carrier_id = "1881"
+      mcc="466"
+      mnc="01"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="和信電訊(KGT-Online) (Internet)"
+      carrier_id = "1881"
+      mcc="466"
+      mnc="88"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="和信電訊(KGT-Online) (MMS)"
+      carrier_id = "1881"
+      mcc="466"
+      mnc="88"
+      apn="kgtmms"
+      mmsc="http://mms.kgtmms.net.tw/mms/wapenc"
+      mmsproxy="172.28.33.5"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="VIBO-vibo"
+      carrier_id = "1886"
+      mcc="466"
+      mnc="89"
+      apn="vibo"
+      type="default,supl"
+  />
+
+  <apn carrier="T Star-internet"
+      carrier_id = "1886"
+      mcc="466"
+      mnc="89"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="VIBOONE"
+      carrier_id = "1886"
+      mcc="466"
+      mnc="89"
+      apn="viboone"
+      type="default,supl"
+  />
+
+  <apn carrier="T Star-MMS"
+      carrier_id = "1886"
+      mcc="466"
+      mnc="89"
+      apn="internet"
+      mmsc="http://mms.vibo.net.tw"
+      mmsproxy="172.24.128.36"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="中華電信(Chunghwa) (Internet)"
+      carrier_id = "1884"
+      mcc="466"
+      mnc="92"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="中華電信(Chunghwa) (MMS)"
+      carrier_id = "1884"
+      mcc="466"
+      mnc="92"
+      apn="emome"
+      mmsc="http://mms.emome.net:8002"
+      mmsproxy="10.1.1.1"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="台灣大哥大(TW Mobile) (Internet)"
+      carrier_id = "1887"
+      mcc="466"
+      mnc="93"
+      apn="Internet"
+      type="default,supl"
+  />
+
+  <apn carrier="台灣大哥大(TW Mobile) (MMS)"
+      carrier_id = "1887"
+      mcc="466"
+      mnc="93"
+      apn="MMS"
+      mmsc="http://mms.catch.net.tw"
+      mmsproxy="10.1.1.2"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="台灣大哥大(TW Mobile) (Internet)"
+      carrier_id = "1888"
+      mcc="466"
+      mnc="97"
+      apn="Internet"
+      type="default,supl"
+  />
+
+  <apn carrier="台灣大哥大(TW Mobile) (MMS)"
+      carrier_id = "1888"
+      mcc="466"
+      mnc="97"
+      apn="MMS"
+      mmsc="http://mms.catch.net.tw"
+      mmsproxy="10.1.1.2"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="台灣大哥大(TW Mobile) (Internet)"
+      carrier_id = "1889"
+      mcc="466"
+      mnc="99"
+      apn="Internet"
+      type="default,supl"
+  />
+
+  <apn carrier="台灣大哥大(TW Mobile) (MMS)"
+      carrier_id = "1889"
+      mcc="466"
+      mnc="99"
+      apn="mms"
+      mmsc="http://mms.catch.net.tw"
+      mmsproxy="10.1.1.2"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="GP-INTERNET"
+      carrier_id = "1362"
+      mcc="470"
+      mnc="01"
+      apn="gpinternet"
+      authtype="0"
+      type="default,supl,agps,fota,dun"
+  />
+
+  <apn carrier="GP-MMS"
+      carrier_id = "1362"
+      mcc="470"
+      mnc="01"
+      apn="gpmms"
+      authtype="0"
+      mmsc="http://mms.gpsurf.net/servlets/mms"
+      mmsproxy="10.128.1.2"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Dhiraagu"
+      carrier_id = "1624"
+      mcc="472"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="OoredooData"
+      carrier_id = "2033"
+      mcc="472"
+      mnc="02"
+      apn="OoredooData"
+      type="default"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "2033"
+      mcc="472"
+      mnc="02"
+      apn="OoredooData"
+      mmsc="http://mms.ooredoo.mv"
+      mmsproxy="172.24.10.20"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="DiGi Internet"
+      carrier_id = "1630"
+      mcc="502"
+      mnc="10"
+      apn="diginet"
+      type="default,supl"
+  />
+
+  <apn carrier="DiGi MMS"
+      carrier_id = "1630"
+      mcc="502"
+      mnc="10"
+      apn="digimms"
+      user="mms"
+      password="mms"
+      mmsc="http://mms.digi.com.my/servlets/mms"
+      mmsproxy="203.92.128.160"
+      mmsport="80"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Maxis Internet"
+      carrier_id = "1628"
+      mcc="502"
+      mnc="12"
+      apn="max4g"
+      user="maxis"
+      password="wap"
+      mmsproxy="202.75.133.49"
+      mmsport="80"
+      mmsc="http://172.16.74.100:10021/mmsc"
+      authtype="1"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Celcom Internet"
+      carrier_id = "1633"
+      mcc="502"
+      mnc="13"
+      apn="celcom4g"
+      mmsproxy="10.128.1.242"
+      mmsport="8080"
+      mmsc="http://mms.celcom.net.my"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="DiGi Internet"
+      carrier_id = "1630"
+      mcc="502"
+      mnc="143"
+      apn="diginet"
+      type="default,supl"
+  />
+
+  <apn carrier="DiGi MMS"
+      carrier_id = "1630"
+      mcc="502"
+      mnc="143"
+      apn="digimms"
+      user="mms"
+      password="mms"
+      mmsc="http://mms.digi.com.my/servlets/mms"
+      mmsproxy="203.92.128.160"
+      mmsport="80"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Celcom Internet"
+      carrier_id = "1633"
+      mcc="502"
+      mnc="145"
+      apn="celcom4g"
+      mmsproxy="10.128.1.242"
+      mmsport="8080"
+      mmsc="http://mms.celcom.net.my"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="DiGi Internet"
+      carrier_id = "1630"
+      mcc="502"
+      mnc="146"
+      apn="diginet"
+      type="default,supl"
+  />
+
+  <apn carrier="DiGi MMS"
+      carrier_id = "1630"
+      mcc="502"
+      mnc="146"
+      apn="digimms"
+      user="mms"
+      password="mms"
+      mmsc="http://mms.digi.com.my/servlets/mms"
+      mmsproxy="203.92.128.160"
+      mmsport="80"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Celcom Internet"
+      carrier_id = "1633"
+      mcc="502"
+      mnc="148"
+      apn="celcom4g"
+      mmsproxy="10.128.1.242"
+      mmsport="8080"
+      mmsc="http://mms.celcom.net.my"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="DiGi MMS"
+      carrier_id = "1630"
+      mcc="502"
+      mnc="16"
+      apn="digimms"
+      user="mms"
+      password="mms"
+      mmsc="http://mms.digi.com.my/servlets/mms"
+      mmsproxy="203.92.128.160"
+      mmsport="80"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="DiGi Internet"
+      carrier_id = "1630"
+      mcc="502"
+      mnc="16"
+      apn="diginet"
+      type="default,supl"
+  />
+
+  <apn carrier="Maxis Internet"
+      carrier_id = "1631"
+      mcc="502"
+      mnc="17"
+      apn="max4g"
+      user="maxis"
+      password="wap"
+      mmsproxy="202.75.133.49"
+      mmsport="80"
+      mmsc="http://172.16.74.100:10021/mmsc"
+      authtype="1"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="U Mobile Internet"
+      carrier_id = "1632"
+      mcc="502"
+      mnc="18"
+      apn="my3g"
+      mmsproxy="10.30.5.11"
+      mmsport="8080"
+      mmsc="http://10.30.3.11/servlets/mms"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Celcom Internet"
+      carrier_id = "1633"
+      mcc="502"
+      mnc="19"
+      apn="celcom4g"
+      mmsproxy="10.128.1.242"
+      mmsport="8080"
+      mmsc="http://mms.celcom.net.my"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Telstra IMS"
+      carrier_id = "1345"
+      mcc="505"
+      mnc="01"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="Telstra Internet"
+      carrier_id = "1345"
+      mcc="505"
+      mnc="01"
+      apn="telstra.wap"
+      type="default,supl"
+      protocol="IPV4"
+      roaming_protocol="IPV4"
+  />
+
+  <apn carrier="Telstra MMS"
+      carrier_id = "1345"
+      mcc="505"
+      mnc="01"
+      apn="telstra.mms"
+      type="mms"
+      mmsc="http://mmsc.telstra.com:8002/"
+      mmsproxy="10.1.1.180"
+      mmsport="80"
+      protocol="IPV4"
+      roaming_protocol="IPV4"
+  />
+
+  <apn carrier="Telstra Tethering"
+      carrier_id = "1345"
+      mcc="505"
+      mnc="01"
+      apn="telstra.internet"
+      type="dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4"
+  />
+
+  <apn carrier="Telstra HOS"
+      carrier_id = "1345"
+      mcc="505"
+      mnc="01"
+      apn="hos"
+      protocol="IPV4"
+      roaming_protocol="IPV4"
+   />
+
+  <apn carrier="Optus Yes Internet"
+      carrier_id = "30"
+      mcc="505"
+      mnc="02"
+      apn="yesinternet"
+      type="default,supl"
+  />
+
+  <apn carrier="Optus MMS"
+      carrier_id = "30"
+      mcc="505"
+      mnc="02"
+      apn="mms"
+      mmsc="http://mmsc.optus.com.au:8002/"
+      mmsproxy="61.88.190.10"
+      mmsport="8070"
+      type="mms"
+  />
+
+  <apn carrier="Virgin Internet"
+      carrier_id = "2145"
+      mcc="505"
+      mnc="02"
+      apn="yesinternet"
+      type="default,supl"
+      mvno_match_data="505029"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Virgin MMS"
+      carrier_id = "2145"
+      mcc="505"
+      mnc="02"
+      apn="mms"
+      mmsc="http://mmsc.optus.com.au:8002/"
+      mmsproxy="61.88.190.10"
+      mmsport="8070"
+      type="mms"
+      mvno_match_data="505029"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Vodafone live!"
+      carrier_id = "15"
+      mcc="505"
+      mnc="03"
+      apn="live.vodafone.com"
+      mmsc="http://pxt.vodafone.net.au/pxtsend"
+      mmsproxy="10.202.2.60"
+      mmsport="8080"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Planet 3"
+      carrier_id = "1348"
+      mcc="505"
+      mnc="06"
+      apn="3services"
+      authtype="0"
+      mmsc="http://mmsc.three.net.au:10021/mmsc"
+      mmsproxy="10.176.57.25"
+      mmsport="8799"
+      protocol="IP"
+  />
+
+  <apn carrier="VF AU PXT"
+      mcc="505"
+      mnc="07"
+      apn="live.vodafone.com"
+      mmsc="http://pxt.vodafone.net.au/pxtsend"
+      mmsproxy="10.202.2.60"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="VF Internet"
+      mcc="505"
+      mnc="07"
+      apn="vfinternet.au"
+      type="default,supl"
+  />
+
+  <apn carrier="3Internet"
+      carrier_id = "1351"
+      mcc="505"
+      mnc="12"
+      apn="3netaccess"
+      type="default,supl"
+  />
+
+  <apn carrier="3"
+      carrier_id = "1351"
+      mcc="505"
+      mnc="12"
+      apn="3services"
+      mmsc="http://mmsc.three.net.au:10021/mmsc"
+      mmsproxy="10.176.57.25"
+      mmsport="8799"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Truphone"
+      carrier_id = "2143"
+      mcc="505"
+      mnc="38"
+      apn="truphone.com"
+      mmsc="http://mmsc.truphone.com:1981/mm1"
+      type="default,supl,mms,dun"
+  />
+
+  <apn carrier="Telstra IMS"
+      carrier_id = "1345"
+      mcc="505"
+      mnc="71"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="Telstra Internet"
+      carrier_id = "1345"
+      mcc="505"
+      mnc="71"
+      apn="telstra.wap"
+      type="default,supl"
+      protocol="IPV4"
+      roaming_protocol="IPV4"
+  />
+
+  <apn carrier="Telstra MMS"
+      carrier_id = "1345"
+      mcc="505"
+      mnc="71"
+      apn="telstra.mms"
+      type="mms"
+      mmsc="http://mmsc.telstra.com:8002/"
+      mmsproxy="10.1.1.180"
+      mmsport="80"
+      protocol="IPV4"
+      roaming_protocol="IPV4"
+  />
+
+  <apn carrier="Telstra Tethering"
+      carrier_id = "1345"
+      mcc="505"
+      mnc="71"
+      apn="telstra.internet"
+      type="dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4"
+  />
+
+  <apn carrier="Telstra HOS"
+      carrier_id = "1345"
+      mcc="505"
+      mnc="71"
+      apn="hos"
+      protocol="IPV4"
+      roaming_protocol="IPV4"
+  />
+
+  <apn carrier="Telstra IMS"
+      carrier_id = "1345"
+      mcc="505"
+      mnc="72"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="Telstra Internet"
+      carrier_id = "1345"
+      mcc="505"
+      mnc="72"
+      apn="telstra.wap"
+      type="default,supl"
+      protocol="IPV4"
+      roaming_protocol="IPV4"
+  />
+
+  <apn carrier="Telstra MMS"
+      carrier_id = "1345"
+      mcc="505"
+      mnc="72"
+      apn="telstra.mms"
+      type="mms"
+      mmsc="http://mmsc.telstra.com:8002/"
+      mmsproxy="10.1.1.180"
+      mmsport="80"
+      protocol="IPV4"
+      roaming_protocol="IPV4"
+  />
+
+  <apn carrier="Telstra Tethering"
+      carrier_id = "1345"
+      mcc="505"
+      mnc="72"
+      apn="telstra.internet"
+      type="dun"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4"
+  />
+
+  <apn carrier="Telstra HOS"
+      carrier_id = "1345"
+      mcc="505"
+      mnc="72"
+      apn="hos"
+      protocol="IPV4"
+      roaming_protocol="IPV4"
+  />
+
+  <apn carrier="VF AU PXT"
+      carrier_id = "492"
+      mcc="505"
+      mnc="88"
+      apn="live.vodafone.com"
+      mmsc="http://pxt.vodafone.net.au/pxtsend"
+      mmsproxy="10.202.2.60"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="VF Internet"
+      carrier_id = "492"
+      mcc="505"
+      mnc="88"
+      apn="vfinternet.au"
+      type="default,supl"
+  />
+
+  <apn carrier="Optus Internet"
+      carrier_id = "30"
+      mcc="505"
+      mnc="90"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Optus MMS"
+      carrier_id = "30"
+      mcc="505"
+      mnc="90"
+      apn="mms"
+      mmsc="http://mmsc.optus.com.au:8002/"
+      mmsproxy="61.88.190.10"
+      mmsport="8070"
+      type="mms"
+  />
+
+  <apn carrier="Vodafone Live!"
+      carrier_id = "1349"
+      mcc="505"
+      mnc="99"
+      apn="live.vodafone.com"
+      mmsc="http://pxt.vodafone.net.au/pxtsend"
+      mmsproxy="10.202.2.60"
+      mmsport="8080"
+  />
+
+  <apn carrier="indosatgprs"
+      carrier_id = "1537"
+      mcc="510"
+      mnc="01"
+      apn="indosatgprs"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Indosat MMS"
+      carrier_id = "1537"
+      mcc="510"
+      mnc="01"
+      apn="indosatmms"
+      user="indosat"
+      password="indosat"
+      authtype="1"
+      mmsc="http://mmsc.indosat.com"
+      mmsproxy="10.19.19.19"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="AXIS-SNS"
+      carrier_id = "788"
+      mcc="510"
+      mnc="08"
+      apn="AXIS"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="AXISwap"
+      carrier_id = "788"
+      mcc="510"
+      mnc="08"
+      apn="AXIS"
+      user="axis"
+      password="123456"
+      proxy="10.8.3.8"
+      port="8080"
+      type="default,supl"
+      authtype="1"
+  />
+
+  <apn carrier="AXISmms"
+      carrier_id = "788"
+      mcc="510"
+      mnc="08"
+      apn="AXISmms"
+      user="axis"
+      password="123456"
+      mmsc="http://mmsc.axis"
+      mmsproxy="10.8.3.8"
+      mmsport="8080"
+      type="mms"
+      authtype="1"
+  />
+
+  <apn carrier="internet"
+      carrier_id = "787"
+      mcc="510"
+      mnc="10"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="TSEL-WAP"
+      carrier_id = "787"
+      mcc="510"
+      mnc="10"
+      apn="telkomsel"
+      user="wap"
+      password="wap123"
+      authtype="1"
+      proxy="10.1.89.130"
+      port="8000"
+      type="default,supl"
+  />
+
+  <apn carrier="TSEL-MMS"
+      carrier_id = "787"
+      mcc="510"
+      mnc="10"
+      apn="mms"
+      user="wap"
+      password="wap123"
+      authtype="1"
+      mmsc="http://mms.telkomsel.com"
+      mmsproxy="10.1.89.150"
+      mmsport="8000"
+      type="mms"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "788"
+      mcc="510"
+      mnc="11"
+      apn="internet"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="XL-MMS"
+      carrier_id = "788"
+      mcc="510"
+      mnc="11"
+      apn="www.xlmms.net"
+      user="xlgprs"
+      password="proxl"
+      authtype="1"
+      mmsc="http://mmc.xl.net.id/servlets/mms"
+      mmsproxy="202.152.240.50"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Indosat-SNS"
+      carrier_id = "789"
+      mcc="510"
+      mnc="21"
+      apn="indosatgprs"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Indosat GPRS"
+      carrier_id = "789"
+      mcc="510"
+      mnc="21"
+      apn="indosatgprs"
+      user="indosat"
+      password="indosat"
+      authtype="1"
+      proxy="10.19.19.19"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Indosat MMS"
+      carrier_id = "789"
+      mcc="510"
+      mnc="21"
+      apn="indosatmms"
+      user="indosat"
+      password="indosat"
+      authtype="1"
+      mmsc="http://mmsc.indosat.com"
+      mmsproxy="10.19.19.19"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="3-SNS"
+      carrier_id = "1966"
+      mcc="510"
+      mnc="89"
+      apn="3gprs"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="3GPRS"
+      carrier_id = "1966"
+      mcc="510"
+      mnc="89"
+      apn="3gprs"
+      user="3gprs"
+      password="3gprs"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="3MMS"
+      carrier_id = "1966"
+      mcc="510"
+      mnc="89"
+      apn="3mms"
+      user="3mms"
+      password="3mms"
+      authtype="1"
+      mmsc="http://mms.three.co.id"
+      mmsproxy="10.4.0.10"
+      mmsport="3128"
+      type="mms"
+  />
+
+  <apn carrier="Telin"
+      carrier_id = "2182"
+      mcc="514"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Timor Telecom"
+      carrier_id = "2183"
+      mcc="514"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Viettel Timor-Leste"
+      carrier_id = "2268"
+      mcc="514"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="myGlobe Internet"
+      carrier_id = "1653"
+      mcc="515"
+      mnc="02"
+      apn="internet.globe.com.ph"
+      type="default,supl"
+  />
+
+  <apn carrier="myGlobe INET"
+      carrier_id = "1653"
+      mcc="515"
+      mnc="02"
+      apn="http.globe.com.ph"
+      type="default,supl"
+  />
+
+  <apn carrier="myGlobe Connect"
+      carrier_id = "1653"
+      mcc="515"
+      mnc="02"
+      apn="www.globe.com.ph"
+      proxy="203.177.42.214"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="myGlobe MMS"
+      carrier_id = "1653"
+      mcc="515"
+      mnc="02"
+      apn="mms.globe.com.ph"
+      mmsc="http://192.40.100.22:10021/mmsc"
+      mmsproxy="203.177.42.214"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="SMARTLTE"
+      carrier_id = "1654"
+      mcc="515"
+      mnc="03"
+      apn="smartlte"
+      type="default,supl"
+  />
+
+  <apn carrier="SMART INTERNET"
+      carrier_id = "1654"
+      mcc="515"
+      mnc="03"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Smart GPRS"
+      carrier_id = "1654"
+      mcc="515"
+      mnc="03"
+      apn="Smart1"
+      proxy="10.102.61.46"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Smart MMS"
+      carrier_id = "1654"
+      mcc="515"
+      mnc="03"
+      apn="mms"
+      mmsc="http://10.102.61.238:8002"
+      mmsproxy="10.102.61.46"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Sun Internet"
+      carrier_id = "1655"
+      mcc="515"
+      mnc="05"
+      apn="minternet"
+      type="default,supl"
+  />
+
+  <apn carrier="SUN WAP GPRS"
+      carrier_id = "1655"
+      mcc="515"
+      mnc="05"
+      apn="wap"
+      proxy="202.138.159.78"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Sun SBW"
+      carrier_id = "1655"
+      mcc="515"
+      mnc="05"
+      apn="fbband"
+      type="default,supl"
+  />
+
+  <apn carrier="Sun Streaming"
+      carrier_id = "1655"
+      mcc="515"
+      mnc="05"
+      apn="minternet"
+      type="default,supl"
+  />
+
+  <apn carrier="SUN MMS"
+      carrier_id = "1655"
+      mcc="515"
+      mnc="05"
+      apn="mms"
+      mmsc="http://mmscenter.suncellular.com.ph"
+      mmsproxy="202.138.159.78"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Redinternet"
+      carrier_id = "2184"
+      mcc="515"
+      mnc="18"
+      apn="redinternet"
+      type="default,supl"
+  />
+
+  <apn carrier="Redmms"
+      carrier_id = "2184"
+      mcc="515"
+      mnc="18"
+      apn="real.globe.com.ph"
+      mmsc="http://10.102.61.193:8002/mmsc"
+      mmsproxy="10.138.3.35"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="CAT3G INTERNET"
+      carrier_id = "1096"
+      mcc="520"
+      mnc="00"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="CAT3G MMS"
+      carrier_id = "1096"
+      mcc="520"
+      mnc="00"
+      apn="catmms"
+      mmsc="http://mms.cat3g.com:8002/"
+      mmsproxy="10.4.7.39"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="TRUE-H INTERNET"
+      carrier_id = "2336"
+      mcc="520"
+      mnc="00"
+      apn="internet"
+      user="true"
+      password="true"
+      authtype="1"
+      type="default,supl"
+      mvno_match_data="01"
+      mvno_type="gid"
+  />
+
+  <apn carrier="TRUE-H MMS"
+      carrier_id = "2336"
+      mcc="520"
+      mnc="00"
+      apn="hmms"
+      user="true"
+      password="true"
+      authtype="1"
+      mmsc="http://mms.trueh.com:8002/"
+      mmsproxy="10.4.7.39"
+      mmsport="8080"
+      type="mms"
+      mvno_match_data="01"
+      mvno_type="gid"
+  />
+
+  <apn carrier="AIS Internet"
+      carrier_id = "1097"
+      mcc="520"
+      mnc="01"
+      apn="internet"
+      authtype="0"
+      type="default,supl"
+  />
+
+  <apn carrier="AIS MMS"
+      carrier_id = "1097"
+      mcc="520"
+      mnc="01"
+      apn="multimedia"
+      mmsc="http://mms.mobilelife.co.th"
+      mmsproxy="203.170.229.34"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="AIS Internet"
+      carrier_id = "1098"
+      mcc="520"
+      mnc="03"
+      apn="internet"
+      authtype="0"
+      type="default,supl"
+  />
+
+  <apn carrier="AIS MMS"
+      carrier_id = "1098"
+      mcc="520"
+      mnc="03"
+      apn="multimedia"
+      mmsc="http://mms.mobilelife.co.th"
+      mmsproxy="203.170.229.34"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="TRUE-H INTERNET"
+      carrier_id = "1997"
+      mcc="520"
+      mnc="04"
+      apn="internet"
+      user="true"
+      password="true"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="TRUE-H MMS"
+      carrier_id = "1997"
+      mcc="520"
+      mnc="04"
+      apn="hmms"
+      user="true"
+      password="true"
+      authtype="1"
+      mmsc="http://mms.trueh.com:8002/"
+      mmsproxy="10.4.7.39"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="dtac Internet"
+      carrier_id = "1897"
+      mcc="520"
+      mnc="05"
+      apn="www.dtac.co.th"
+      type="default,supl"
+  />
+
+  <apn carrier="dtac MMS"
+      carrier_id = "1897"
+      mcc="520"
+      mnc="05"
+      apn="mms"
+      mmsc="http://mms2.dtac.co.th:8002/"
+      mmsproxy="10.10.10.10"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="TOT 3G Internet"
+      carrier_id = "1723"
+      mcc="520"
+      mnc="15"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="TOT 3G MMS"
+      carrier_id = "1723"
+      mcc="520"
+      mnc="15"
+      apn="mms"
+      mmsc="http://mms.tot3g.net:8002"
+      mmsproxy="192.168.0.72"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="dtac MMS"
+      carrier_id = "1896"
+      mcc="520"
+      mnc="18"
+      apn="mms"
+      mmsc="http://mms.dtac.co.th:8002/"
+      mmsproxy="203.155.200.133"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="dtac Internet"
+      carrier_id = "1896"
+      mcc="520"
+      mnc="18"
+      apn="www.dtac.co.th"
+      type="default,supl"
+  />
+
+  <apn carrier="TRUE INTERNET"
+      carrier_id = "1898"
+      mcc="520"
+      mnc="99"
+      apn="internet"
+      user="true"
+      password="true"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="TRUE MMS"
+      carrier_id = "1898"
+      mcc="520"
+      mnc="99"
+      apn="hmms"
+      user="true"
+      password="true"
+      authtype="1"
+      mmsc="http://mms.truelife.com:8002/"
+      mmsproxy="10.4.7.39"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="SingTel (PostPaid)"
+      carrier_id = "31"
+      mcc="525"
+      mnc="01"
+      apn="e-ideas"
+      mmsproxy="165.21.42.84"
+      mmsport="8080"
+      mmsc="http://mms.singtel.com:10021/mmsc"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="SingTel (PrePaid)"
+      carrier_id = "31"
+      mcc="525"
+      mnc="01"
+      apn="hicard"
+      mmsproxy="165.21.42.84"
+      mmsport="8080"
+      mmsc="http://mms.singtel.com:10021/mmsc"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="SingTel (PostPaid)"
+      carrier_id = "31"
+      mcc="525"
+      mnc="02"
+      apn="e-ideas"
+      mmsproxy="165.21.42.84"
+      mmsport="8080"
+      mmsc="http://mms.singtel.com:10021/mmsc"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="SingTel (PrePaid)"
+      carrier_id = "31"
+      mcc="525"
+      mnc="02"
+      apn="hicard"
+      mmsproxy="165.21.42.84"
+      mmsport="8080"
+      mmsc="http://mms.singtel.com:10021/mmsc"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Sunsurf Mobile"
+      carrier_id = "1706"
+      mcc="525"
+      mnc="03"
+      apn="sunsurf"
+      type="default,supl"
+  />
+
+  <apn carrier="M1 MMS(3G)"
+      carrier_id = "1706"
+      mcc="525"
+      mnc="03"
+      apn="miworld"
+      user="65"
+      password="user123"
+      mmsc="http://mmsgw:8002"
+      mmsproxy="172.16.14.10"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Sunsurf Mobile"
+      carrier_id = "2238"
+      mcc="525"
+      mnc="04"
+      apn="sunsurf"
+      type="default,supl"
+  />
+
+  <apn carrier="M1 MMS(3G)"
+      carrier_id = "2238"
+      mcc="525"
+      mnc="04"
+      apn="miworld"
+      user="65"
+      password="user123"
+      authtype="1"
+      mmsc="http://mmsgw:8002"
+      mmsproxy="172.16.14.10"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="SH Data Postpaid"
+      carrier_id = "1707"
+      mcc="525"
+      mnc="05"
+      apn="shwap"
+      type="default,supl"
+  />
+
+  <apn carrier="SH MMS Postpaid"
+      carrier_id = "1707"
+      mcc="525"
+      mnc="05"
+      apn="shmms"
+      mmsc="http://mms.starhubgee.com.sg:8002/"
+      mmsproxy="10.12.1.80"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="B-Mobile"
+      carrier_id = "2350"
+      mcc="528"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="DSTCom"
+      carrier_id = "1379"
+      mcc="528"
+      mnc="11"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="VFNZ Gateway"
+      carrier_id = "2364"
+      mcc="530"
+      mnc="01"
+      apn="live.vodafone.com"
+      mmsc="http://pxt.vodafone.net.nz/pxtsend"
+      mmsproxy="172.30.38.3"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="VFNZ Internet"
+      carrier_id = "2364"
+      mcc="530"
+      mnc="01"
+      apn="vodafone"
+      type="default,supl"
+  />
+
+  <apn carrier="Data"
+      carrier_id = "968"
+      mcc="530"
+      mnc="05"
+      apn="Internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Content"
+      carrier_id = "968"
+      mcc="530"
+      mnc="05"
+      apn="Internet"
+      proxy="210.55.11.73"
+      port="80"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "968"
+      mcc="530"
+      mnc="05"
+      apn="Internet"
+      mmsc="http://lsmmsc.xtra.co.nz"
+      mmsproxy="210.55.11.73"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="Default"
+      carrier_id = "2105"
+      mcc="530"
+      mnc="05"
+      apn="wapaccess.co.nz"
+      type="default,supl"
+      mvno_match_data="Skinny"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Content"
+      carrier_id = "2105"
+      mcc="530"
+      mnc="05"
+      apn="wapaccess.co.nz"
+      proxy="210.55.11.73"
+      port="80"
+      type="default,supl"
+      mvno_match_data="Skinny"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Data"
+      carrier_id = "2105"
+      mcc="530"
+      mnc="05"
+      apn="wapaccess.co.nz"
+      type="default,supl"
+      mvno_match_data="Skinny"
+      mvno_type="spn"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "2105"
+      mcc="530"
+      mnc="05"
+      apn="wapaccess.co.nz"
+      mmsc="http://mms.mmsaccess.co.nz"
+      mmsproxy="210.55.11.73"
+      mmsport="80"
+      type="mms"
+      mvno_match_data="Skinny"
+      mvno_type="spn"
+  />
+
+  <apn carrier="2Degrees Internet"
+      carrier_id = "969"
+      mcc="530"
+      mnc="24"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="2Degrees MMS"
+      carrier_id = "969"
+      mcc="530"
+      mnc="24"
+      apn="mms"
+      mmsc="http://mms.2degreesmobile.net.nz:48090"
+      mmsproxy="118.148.1.118"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Digicel"
+      mcc="536"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="BeMobile"
+      carrier_id = "1649"
+      mcc="537"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="PNG WAP"
+      carrier_id = "1651"
+      mcc="537"
+      mnc="03"
+      apn="wap.digicelpng.com"
+      proxy="10.149.83.116"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="PNG WEB"
+      carrier_id = "1651"
+      mcc="537"
+      mnc="03"
+      apn="internet.digicelpng.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Papua New Guinea:Digicel:Modem"
+      carrier_id = "1651"
+      mcc="537"
+      mnc="03"
+      apn="wap.digicel.com.pg"
+      type="dun"
+      authtype="1"
+      mmsc="http://wapdigicel.com"
+      proxy="10.149.122.12"
+      port="8080"
+  />
+
+  <apn carrier="PNG MMS"
+      carrier_id = "1651"
+      mcc="537"
+      mnc="03"
+      apn="wap.digicelpng.com"
+      mmsc="http://mms.digicelpng.com:8990"
+      mmsproxy="10.149.83.116"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="EMnify"
+      carrier_id = "2326"
+      mcc="537"
+      mnc="03"
+      apn="em"
+      mvno_match_data="5370309"
+      mvno_type="imsi"
+      type="default,supl"
+  />
+
+  <apn carrier="U-Call"
+      carrier_id = "1733"
+      mcc="539"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Shoreline Communication"
+      carrier_id = "1734"
+      mcc="539"
+      mnc="43"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Digicel"
+      carrier_id = "2220"
+      mcc="539"
+      mnc="88"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Tonga:Digicel:Modem"
+      carrier_id = "2220"
+      mcc="539"
+      mnc="88"
+      apn="wap"
+      type="dun"
+      authtype="1"
+      mmsc="http://wapdigicel.com"
+      proxy="172.16.7.12"
+      port="8080"
+  />
+
+  <apn carrier="Tonga:Digicel:Mms"
+      carrier_id = "2220"
+      mcc="539"
+      mnc="88"
+      apn="wap"
+      type="mms"
+      authtype="1"
+      mmsproxy="172.16.7.12"
+      mmsc="http://mms.digicelgroup.com"
+      mmsport="9201"
+  />
+
+  <apn carrier="BREEZE"
+      carrier_id = "2185"
+      mcc="540"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="BeMobile"
+      carrier_id = "2123"
+      mcc="540"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="AIL"
+      carrier_id = "2239"
+      mcc="541"
+      mnc="00"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="SMILE"
+      carrier_id = "1301"
+      mcc="541"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Digicel"
+      carrier_id = "2219"
+      mcc="541"
+      mnc="05"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Vanatu:Digicel:Modem"
+      carrier_id = "2219"
+      mcc="541"
+      mnc="05"
+      apn="wap"
+      type="dun"
+      authtype="1"
+      mmsc="http://wapdigicel.com"
+      proxy="172.16.7.12"
+      port="8080"
+  />
+
+  <apn carrier="Vanatu:Digicel:Mms"
+      carrier_id = "2219"
+      mcc="541"
+      mnc="05"
+      apn="wap"
+      type="mms"
+      authtype="1"
+      mmsproxy="172.16.7.12"
+      mmsc="http://mms.digicelgroup.com"
+      mmsport="9201"
+  />
+
+  <apn carrier="Vodafone"
+      carrier_id = "1481"
+      mcc="542"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Digicel"
+      carrier_id = "2186"
+      mcc="542"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Fiji:Digicel:Modem"
+      carrier_id = "2186"
+      mcc="542"
+      mnc="02"
+      apn="wap"
+      type="dun"
+      authtype="1"
+      mmsc="http://wapdigicel.com"
+      proxy="172.16.7.12"
+      port="8080"
+  />
+
+  <apn carrier="Fiji:Digicel:Mms"
+      carrier_id = "2186"
+      mcc="542"
+      mnc="02"
+      apn="wap"
+      type="mms"
+      authtype="1"
+      mmsproxy="172.16.7.12"
+      mmsc="http://mms.digicelgroup.com"
+      mmsport="9201"
+  />
+
+  <apn carrier="Bluesky"
+      carrier_id = "1957"
+      mcc="544"
+      mnc="11"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Kiribati - TSKL"
+      carrier_id = "2240"
+      mcc="545"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Kiribati - Frigate Net"
+      carrier_id = "2187"
+      mcc="545"
+      mnc="09"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobilis"
+      carrier_id = "943"
+      mcc="546"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Vini"
+      carrier_id = "1648"
+      mcc="547"
+      mnc="20"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Telecom Cook"
+      carrier_id = "1426"
+      mcc="548"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Digicel"
+      carrier_id = "1302"
+      mcc="549"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Bluesky"
+      carrier_id = "1876"
+      mcc="549"
+      mnc="27"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="FSMTC"
+      carrier_id = "1482"
+      mcc="550"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="MINTA"
+      mcc="551"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="PNCC"
+      carrier_id = "1671"
+      mcc="552"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Palau Mobile"
+      carrier_id = "2188"
+      mcc="552"
+      mnc="80"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobinil Web"
+      carrier_id = "675"
+      mcc="602"
+      mnc="01"
+      apn="mobinilweb"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobinil WAP"
+      carrier_id = "675"
+      mcc="602"
+      mnc="01"
+      apn="mobinilwap"
+      proxy="62.241.155.45"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobinil MMS"
+      carrier_id = "675"
+      mcc="602"
+      mnc="01"
+      apn="mobinilmms"
+      mmsc="http://10.7.13.24:8002"
+      mmsproxy="62.241.155.45"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="vodafone internet"
+      carrier_id = "2380"
+      mcc="602"
+      mnc="02"
+      apn="internet.vodafone.net"
+      user="internet"
+      password="internet"
+      authtype="3"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone WAP"
+      carrier_id = "2380"
+      mcc="602"
+      mnc="02"
+      apn="wap.vodafone.com.eg"
+      user="wap"
+      password="wap"
+      authtype="3"
+      proxy="163.121.178.2"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodafone MMS"
+      carrier_id = "2380"
+      mcc="602"
+      mnc="02"
+      apn="mms.vodafone.com.eg"
+      user="mms"
+      password="mms"
+      authtype="1"
+      mmsc="http://mms.vodafone.com.eg/servlets/mms"
+      mmsproxy="163.121.178.2"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Etisalat WAP"
+      carrier_id = "1968"
+      mcc="602"
+      mnc="03"
+      apn="etisalat"
+      proxy="10.71.130.29"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Etisalat MMS"
+      carrier_id = "1968"
+      mcc="602"
+      mnc="03"
+      apn="etisalat"
+      mmsc="http://10.71.131.7:38090"
+      mmsproxy="10.71.130.29"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="mobilis wap"
+      carrier_id = "1470"
+      mcc="603"
+      mnc="01"
+      apn="wap"
+      proxy="172.25.49.2"
+      port="8080"
+      user="wap"
+      password="wap"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobilis internet"
+      carrier_id = "1470"
+      mcc="603"
+      mnc="01"
+      apn="internet"
+      user="internet"
+      password="internet"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobilis mms"
+      carrier_id = "1470"
+      mcc="603"
+      mnc="01"
+      apn="mms"
+      user="mms"
+      password="mms"
+      authtype="1"
+      mmsc="http://172.25.49.9/servlets/mms"
+      mmsproxy="172.25.49.2"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="djezzy.internet"
+      carrier_id = "1471"
+      mcc="603"
+      mnc="02"
+      apn="djezzy.internet"
+      type="default,supl"
+  />
+
+  <apn carrier="djezzy.mms"
+      carrier_id = "1471"
+      mcc="603"
+      mnc="02"
+      apn="djezzy.mms"
+      user="mms"
+      password="mms"
+      mmsc="http://172.24.97.152:6021/mmsc"
+      mmsproxy="172.24.97.158"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="Ooredoo internet"
+      carrier_id = "1977"
+      mcc="603"
+      mnc="03"
+      apn="internet"
+      type="default,supl"
+      authtype="1"
+  />
+
+  <apn carrier="Ooredoo mms"
+      carrier_id = "1977"
+      mcc="603"
+      mnc="03"
+      apn="ooredoomms"
+      user="mms"
+      password="mms"
+      mmsc="http://10.10.111.1"
+      mmsproxy="192.168.52.3"
+      mmsport="3128"
+      type="mms"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "902"
+      mcc="604"
+      mnc="00"
+      apn="internet.orange.ma"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Imedia"
+      carrier_id = "902"
+      mcc="604"
+      mnc="00"
+      apn="wap.meditel.ma"
+      proxy="10.8.8.8"
+      port="8080"
+      user="MEDIWAP"
+      password="MEDIWAP"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="GPRS MMS"
+      carrier_id = "902"
+      mcc="604"
+      mnc="00"
+      apn="mms.meditel.ma"
+      user="MEDIMMS"
+      password="MEDIMMS"
+      authtype="1"
+      mmsc="http://mms.meditel.ma:8088/mms"
+      mmsproxy="10.8.8.9"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="MobileZone"
+      carrier_id = "903"
+      mcc="604"
+      mnc="01"
+      apn="wap.iamgprs.ma"
+      proxy="212.217.54.133"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Internet Mobile"
+      carrier_id = "903"
+      mcc="604"
+      mnc="01"
+      apn="www.iamgprs1.ma"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS IAM"
+      carrier_id = "903"
+      mcc="604"
+      mnc="01"
+      apn="mmsiam"
+      mmsc="http://mms:8002/"
+      mmsproxy="10.16.35.50"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="WEB"
+      carrier_id = "1985"
+      mcc="604"
+      mnc="02"
+      apn="www.wana.ma"
+      type="default,supl"
+  />
+
+  <apn carrier="WAP"
+      carrier_id = "1985"
+      mcc="604"
+      mnc="02"
+      apn="www.wana.ma"
+      proxy="10.86.0.10"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1985"
+      mcc="604"
+      mnc="02"
+      apn="mms.wana.ma"
+      mmsc="http://mms.wana.ma:38090"
+      mmsproxy="10.86.0.10"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="weborange"
+      carrier_id = "1936"
+      mcc="605"
+      mnc="01"
+      apn="weborange"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Orange"
+      carrier_id = "1936"
+      mcc="605"
+      mnc="01"
+      apn="mms.otun"
+      mmsc="http://mms.orange.tn"
+      mmsproxy="10.12.1.52"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "1731"
+      mcc="605"
+      mnc="02"
+      apn="internet.tn"
+      type="default,supl"
+  />
+
+  <apn carrier="Internet Portail"
+      carrier_id = "1731"
+      mcc="605"
+      mnc="02"
+      apn="gprs.tn"
+      user="gprs"
+      password="gprs"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Tunisie Telecom MMS"
+      carrier_id = "1731"
+      mcc="605"
+      mnc="02"
+      apn="mms.tn"
+      user="mms@tt1"
+      password="mms"
+      authtype="1"
+      mmsc="http://192.168.0.3:19090/was"
+      mmsproxy="192.168.0.2"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Ooredoo TN Internet"
+      carrier_id = "1732"
+      mcc="605"
+      mnc="03"
+      apn="internet.ooredoo.tn"
+      type="default"
+  />
+
+  <apn carrier="Ooredoo TN MMS"
+      carrier_id = "1732"
+      mcc="605"
+      mnc="03"
+      apn="mms.ooredoo.tn"
+      mmsc="http://mmsc.ooredoo.tn"
+      mmsproxy="10.3.2.100"
+      mmsport="80"
+      type="mms"
+  />
+
+  <apn carrier="Libyana"
+      carrier_id = "1973"
+      mcc="606"
+      mnc="00"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Libyana MMS"
+      carrier_id = "1973"
+      mcc="606"
+      mnc="00"
+      apn="mms"
+      type="mms"
+      authtype="0"
+      mmsproxy="192.168.8.148"
+      mmsc="http://62.240.62.180:80"
+      mmsport="8000"
+  />
+
+  <apn carrier="Madar"
+      carrier_id = "2006"
+      mcc="606"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Al-Jeel Phone"
+      carrier_id = "2189"
+      mcc="606"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Libya Phone"
+      carrier_id = "2348"
+      mcc="606"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Hatef Libya"
+      carrier_id = "2190"
+      mcc="606"
+      mnc="06"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Gamcel"
+      carrier_id = "736"
+      mcc="607"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Africel"
+      carrier_id = "737"
+      mcc="607"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Comium"
+      carrier_id = "738"
+      mcc="607"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="QCell"
+      carrier_id = "2191"
+      mcc="607"
+      mnc="04"
+      apn="default"
+      type="default,supl"
+  />
+
+    <apn carrier="Orange MMS SN"
+      carrier_id = "1721"
+      mcc="608"
+      mnc="01"
+      apn="mms"
+      user="mms"
+      password="mms"
+      mmsc="http://mmsalize/servlets/mms"
+      mmsproxy="172.16.30.9"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Orange Wap SN"
+      carrier_id = "1721"
+      mcc="608"
+      mnc="01"
+      apn="wap"
+      user="wap"
+      password="wap"
+      proxy="172.16.30.9"
+      port="8080"
+      type="default"
+  />
+
+  <apn carrier="Orange Web SN"
+      carrier_id = "1721"
+      mcc="608"
+      mnc="01"
+      apn="internet"
+      user="internet"
+      password="internet"
+      type="default"
+  />
+
+  <apn carrier="Tigo Internet SN"
+      carrier_id = "1722"
+      mcc="608"
+      mnc="02"
+      apn="web.sentel.com"
+      type="default,supl"
+  />
+
+  <apn carrier="Expresso Internet SN"
+      carrier_id = "2192"
+      mcc="608"
+      mnc="03"
+      apn="expresso"
+      user="wap"
+      password="wap"
+      proxy="10.71.123.69"
+      port="8080"
+      type="default"
+  />
+
+  <apn carrier="Mattel"
+      carrier_id = "1616"
+      mcc="609"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Chinguitel"
+      carrier_id = "1617"
+      mcc="609"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Mauritel"
+      carrier_id = "1618"
+      mcc="609"
+      mnc="10"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange 3G/4G"
+      carrier_id = "2034"
+      mcc="610"
+      mnc="02"
+      apn="internet"
+      authtype="1"
+      user="internet"
+      password="internet"
+      type="default"
+  />
+
+  <apn carrier="Orange ML MMS"
+      carrier_id = "2034"
+      mcc="610"
+      mnc="02"
+      apn="mms"
+      user="mms"
+      password="mms"
+      mmsc="http://10.109.6.2/servlets/mms"
+      mmsproxy="10.109.4.35"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Orange Wap ML"
+      carrier_id = "2034"
+      mcc="610"
+      mnc="02"
+      apn="wap"
+      user="wap"
+      password="wap"
+      proxy="10.109.4.35"
+      port="8080"
+      type="default"
+  />
+
+  <apn carrier="Orange S.A."
+      carrier_id = "739"
+      mcc="611"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Sotelgui"
+      carrier_id = "740"
+      mcc="611"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Telecel Guinee"
+      carrier_id = "2193"
+      mcc="611"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="MTN"
+      carrier_id = "2225"
+      mcc="611"
+      mnc="04"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Cellcom"
+      carrier_id = "741"
+      mcc="611"
+      mnc="05"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Moov Internet CI"
+      carrier_id = "1420"
+      mcc="612"
+      mnc="02"
+      apn="moov"
+      user="web"
+      password="web"
+      proxy="10.172.11.17"
+      port="8080"
+      type="default"
+  />
+
+  <apn carrier="Oweb"
+      carrier_id = "1421"
+      mcc="612"
+      mnc="03"
+      apn="orangeciweb"
+      user="web"
+      password="web"
+      authtype="1"
+      type="default"
+  />
+
+  <apn carrier="OWORLD CI"
+      carrier_id = "1421"
+      mcc="612"
+      mnc="03"
+      apn="orangeciwap"
+      user="wap"
+      password="wap"
+      proxy="172.20.4.33"
+      port="8080"
+      type="default"
+  />
+
+  <apn carrier="Omms CI"
+      carrier_id = "1421"
+      mcc="612"
+      mnc="03"
+      apn="orangecimms"
+      user="mms"
+      password="mms"
+      mmsc="http://172.20.6.1/servlets/mms"
+      mmsproxy="172.20.4.33"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Koz Internet CI"
+      carrier_id = "1422"
+      mcc="612"
+      mnc="04"
+      apn="gprs.koz.ci"
+      user="web"
+      password="web"
+      proxy="10.20.3.10"
+      port="8080"
+      type="default"
+  />
+
+  <apn carrier="MTN Internet CI"
+      carrier_id = "1423"
+      mcc="612"
+      mnc="05"
+      apn="web.mtn.ci"
+      user="vide"
+      password="vide"
+      type="default"
+  />
+
+  <apn carrier="Telmob"
+      carrier_id = "1946"
+      mcc="613"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel"
+      carrier_id = "1368"
+      mcc="613"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Telecel Faso"
+      carrier_id = "1369"
+      mcc="613"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange MMS"
+      apn="orange.mms"
+      user="orange"
+      password="orange"
+      mmsc="http://10.10.10.35:38090/was"
+      mmsproxy="10.10.10.36"
+      mmsport="8080"
+      carrier_id = "1943"
+      mcc="614"
+      mnc="04"
+      type="mms"
+  />
+
+  <apn carrier="Orange Internet"
+      apn="orange.ne"
+      carrier_id = "1943"
+      mcc="614"
+      mnc="04"
+      type="default"
+  />
+
+  <apn carrier="Togo Cell"
+      carrier_id = "1095"
+      mcc="615"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Moov"
+      carrier_id = "1947"
+      mcc="615"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Libercom"
+      carrier_id = "1376"
+      mcc="616"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Moov"
+      carrier_id = "1377"
+      mcc="616"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="MTN"
+      carrier_id = "1378"
+      mcc="616"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="BBCOM"
+      carrier_id = "1944"
+      mcc="616"
+      mnc="04"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Glo"
+      carrier_id = "1945"
+      mcc="616"
+      mnc="05"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange MMS"
+      apn="orangemms"
+      user="mmsc"
+      password="mmsc"
+      mmsc="http://10.2.1.20:8514"
+      mmsproxy="10.2.1.20"
+      mmsport="8080"
+      carrier_id = "1621"
+      mcc="617"
+      mnc="01"
+      type="mms"
+  />
+
+  <apn carrier="Orange Internet"
+      apn="orange"
+      carrier_id = "1621"
+      mcc="617"
+      mnc="01"
+      type="default"
+  />
+
+  <apn carrier="Lonestar Cell"
+      carrier_id = "2194"
+      mcc="618"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Libercell"
+      carrier_id = "2195"
+      mcc="618"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Comium"
+      carrier_id = "1601"
+      mcc="618"
+      mnc="04"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange"
+      carrier_id = "2035"
+      mcc="618"
+      mnc="07"
+      apn="Orange"
+      type="default,supl"
+  />
+
+  <apn carrier="LIBTELCO"
+      carrier_id = "2196"
+      mcc="618"
+      mnc="20"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel"
+      carrier_id = "1716"
+      mcc="619"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Tigo"
+      carrier_id = "1717"
+      mcc="619"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Africell"
+      carrier_id = "1718"
+      mcc="619"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Comium"
+      carrier_id = "1074"
+      mcc="619"
+      mnc="04"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Africell"
+      carrier_id = "1075"
+      mcc="619"
+      mnc="05"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Mobitel"
+      carrier_id = "1076"
+      mcc="619"
+      mnc="25"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Glo"
+      mcc="620"
+      mnc="0"
+      apn="glowap"
+      authtype="0"
+      type="default,supl,agps,fota,dun"
+  />
+
+  <apn carrier="Glo mms"
+      mcc="620"
+      mnc="0"
+      apn="glo mms"
+      authtype="0"
+      mmsc="http://mms.gloworld.com/mms"
+      mmsproxy="10.161.85.4"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="MTN Internet GH"
+      apn="internet"
+      carrier_id = "1515"
+      mcc="620"
+      mnc="01"
+      type="default"
+  />
+
+  <apn carrier="MTN MMS"
+      carrier_id = "1515"
+      mcc="620"
+      mnc="01"
+      apn="mtn mms"
+      type="mms"
+      authtype="0"
+      mmsproxy="172.17.3.7"
+      mmsc="http://172.17.3.7"
+      mmsport="8080"
+  />
+
+  <apn carrier="Vodafone Internet GH"
+      apn="browse"
+      carrier_id = "2383"
+      mcc="620"
+      mnc="02"
+      type="default"
+  />
+
+  <apn carrier="Vodafone_mms"
+      carrier_id = "2383"
+      mcc="620"
+      mnc="02"
+      apn="mms"
+      type="mms"
+      authtype="0"
+      mmsproxy="172.24.97.1"
+      mmsc="http://mms.vodaphone.com.gh/mms"
+      mmsport="9201"
+  />
+
+  <apn carrier="Tigo Internet GH"
+      apn="web.tigo.com.gh"
+      carrier_id = "2108"
+      mcc="620"
+      mnc="03"
+      type="default"
+  />
+
+  <apn carrier="Tigo mms"
+      carrier_id = "2108"
+      mcc="620"
+      mnc="03"
+      apn="mms.tigo.com.gh"
+      type="mms"
+      authtype="0"
+      mmsproxy="10.4.1.7"
+      mmsc="http://mms/"
+      mmsport="8080"
+  />
+
+  <apn carrier="Airtel Internet GH"
+      apn="wap"
+      carrier_id = "2108"
+      mcc="620"
+      mnc="06"
+      proxy="10.93.85.88"
+      port="9201"
+      type="default"
+  />
+
+  <apn carrier="Airtel mms"
+      carrier_id = "2108"
+      mcc="620"
+      mnc="06"
+      apn="mms/airtel mms"
+      type="mms"
+      authtype="0"
+      mmsproxy="100.1.201.172"
+      mmsc="http://100.1.201.171:10021/mmsc"
+      mmsport="8799"
+  />
+
+  <apn carrier="Glo Internet GH"
+      apn="glowap"
+      carrier_id = "2222"
+      mcc="620"
+      mnc="07"
+      user="glo"
+      password="glo"
+      authtype="1"
+      proxy="10.161.85.4"
+      port="8799"
+      type="default"
+  />
+
+  <apn carrier="Airtel Internet"
+      carrier_id = "1638"
+      mcc="621"
+      mnc="20"
+      apn="internet.ng.zain.com"
+      user="internet"
+      password="internet"
+      authtype="1"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel MMS"
+      carrier_id = "1638"
+      mcc="621"
+      mnc="20"
+      apn="mms.ng.zain.com"
+      user="mms"
+      password="mms"
+      authtype="1"
+      mmsc="http://10.210.3.239:9800/mm1"
+      mmsproxy="172.18.254.5"
+      type="mms"
+  />
+
+  <apn carrier="Airtel WAP"
+      carrier_id = "1638"
+      mcc="621"
+      mnc="20"
+      apn="wap.ng.zain.com"
+      user="wap"
+      password="wap"
+      authtype="1"
+      proxy="172.18.254.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="MTN-WEB"
+      carrier_id = "1639"
+      mcc="621"
+      mnc="30"
+      apn="internet"
+      user="web"
+      password="web"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MTN ACESS"
+      carrier_id = "1639"
+      mcc="621"
+      mnc="30"
+      apn="web.gprs.mtnnigeria.net"
+      user="web"
+      password="web"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MTN MMS"
+      carrier_id = "1639"
+      mcc="621"
+      mnc="30"
+      apn="web.gprs.mtnnigeria.net"
+      mmsc="http://10.199.212.8/servlets/mms"
+      mmsproxy="10.199.212.2"
+      type="mms"
+  />
+
+  <apn carrier="Glo Direct"
+      carrier_id = "2115"
+      mcc="621"
+      mnc="50"
+      apn="glosecure"
+      user="gprs"
+      password="gprs"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Glo MMS"
+      carrier_id = "2115"
+      mcc="621"
+      mnc="50"
+      apn="glomms"
+      user="mms"
+      password="mms"
+      authtype="1"
+      mmsc="http://mms.gloworld.com/mmsc"
+      mmsproxy="10.100.82.4"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="etisalat WAP"
+      carrier_id = "1979"
+      mcc="621"
+      mnc="60"
+      apn="etisalat"
+      proxy="10.71.170.5"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="etisalat MMS"
+      carrier_id = "1979"
+      mcc="621"
+      mnc="60"
+      apn="etisalat"
+      mmsc="http://10.71.170.30:38090/was"
+      type="mms"
+  />
+
+  <apn carrier="Airtel"
+      carrier_id = "1093"
+      mcc="622"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Tawali"
+      carrier_id = "1094"
+      mcc="622"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Tigo"
+      carrier_id = "2227"
+      mcc="622"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Salam"
+      carrier_id = "2197"
+      mcc="622"
+      mnc="04"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="CTP"
+      carrier_id = "1408"
+      mcc="623"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="TC"
+      carrier_id = "1409"
+      mcc="623"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Internet browsing"
+      carrier_id = "1410"
+      mcc="623"
+      mnc="03"
+      apn="orangeca3g"
+      type="default,supl"
+  />
+
+  <apn carrier="Nationlink"
+      carrier_id = "2198"
+      mcc="623"
+      mnc="04"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="CVMOVEL"
+      carrier_id = "1445"
+      mcc="625"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="T+"
+      carrier_id = "1446"
+      mcc="625"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="CSTmovel"
+      carrier_id = "1086"
+      mcc="626"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange GQ"
+      carrier_id = "746"
+      mcc="627"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange GQ MMS"
+      carrier_id = "746"
+      mcc="627"
+      mnc="01"
+      apn="orangemms"
+      type="mms"
+      user="mms"
+      password="mms"
+      authtype="0"
+      mmsproxy="192.168.17.2"
+      mmsc="http://192.168.17.34/servlets/mms"
+      mmsport="8080"
+  />
+
+  <apn carrier="Hits GQ"
+      carrier_id = "2199"
+      mcc="627"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Libertis"
+      carrier_id = "1488"
+      mcc="628"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Moov"
+      carrier_id = "1489"
+      mcc="628"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel"
+      carrier_id = "1490"
+      mcc="628"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Azur"
+      carrier_id = "2200"
+      mcc="628"
+      mnc="04"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel"
+      carrier_id = "1411"
+      mcc="629"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Libertis Telecom"
+      carrier_id = "1412"
+      mcc="629"
+      mnc="10"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodacom Internet CD"
+      carrier_id = "1405"
+      mcc="630"
+      mnc="01"
+      apn="vodanet"
+      port="8080"
+      type="default"
+  />
+
+  <apn carrier="Vodacom MMS"
+      carrier_id = "1405"
+      mcc="630"
+      mnc="01"
+      apn="vodalive"
+      type="mms"
+      authtype="0"
+      mmsproxy="172.24.97.1"
+      mmsc="http://172.24.97.1/mmsc"
+      mmsport="8080"
+  />
+
+  <apn carrier="Tigo Internet CD"
+      carrier_id = "2036"
+      mcc="630"
+      mnc="89"
+      apn="tigo.web"
+      type="default"
+  />
+
+  <apn carrier="UNITEL"
+      carrier_id = "1334"
+      mcc="631"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="MOVICEL"
+      carrier_id = "2201"
+      mcc="631"
+      mnc="04"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Areeba"
+      carrier_id = "1524"
+      mcc="632"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange Bissau"
+      carrier_id = "1948"
+      mcc="632"
+      mnc="03"
+      apn="4Gogb"
+      type="default,supl"
+  />
+
+  <apn carrier="Guinetel"
+      carrier_id = "2241"
+      mcc="632"
+      mnc="07"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Cable &amp; Wireless"
+      carrier_id = "1685"
+      mcc="633"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Mediatech International"
+      carrier_id = "1686"
+      mcc="633"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel"
+      carrier_id = "1687"
+      mcc="633"
+      mnc="10"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Zain SD"
+      carrier_id = "1688"
+      mcc="634"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="MTN"
+      carrier_id = "1689"
+      mcc="634"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Sudani One"
+      carrier_id = "2202"
+      mcc="634"
+      mnc="07"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Privet Network"
+      carrier_id = "2242"
+      mcc="634"
+      mnc="09"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="MTN"
+      carrier_id = "1682"
+      mcc="635"
+      mnc="10"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Rwandatel"
+      carrier_id = "2243"
+      mcc="635"
+      mnc="12"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Tigo"
+      carrier_id = "2203"
+      mcc="635"
+      mnc="13"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel"
+      carrier_id = "2204"
+      mcc="635"
+      mnc="14"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="ETH-MTN"
+      carrier_id = "681"
+      mcc="636"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Telesom"
+      carrier_id = "2205"
+      mcc="637"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Somafone"
+      carrier_id = "2244"
+      mcc="637"
+      mnc="04"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Nationlink"
+      carrier_id = "2206"
+      mcc="637"
+      mnc="10"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Hormuud"
+      carrier_id = "2245"
+      mcc="637"
+      mnc="25"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Golis"
+      carrier_id = "1082"
+      mcc="637"
+      mnc="30"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Unittel"
+      carrier_id = "2246"
+      mcc="637"
+      mnc="57"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Nationlink Telecom"
+      mcc="637"
+      mnc="60"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Somtel"
+      carrier_id = "2207"
+      mcc="637"
+      mnc="71"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Telcom"
+      carrier_id = "2208"
+      mcc="637"
+      mnc="82"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Evatis"
+      carrier_id = "1462"
+      mcc="638"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="safaricom GPRS"
+      carrier_id = "865"
+      mcc="639"
+      mnc="02"
+      apn="safaricom"
+      user="saf"
+      password="data"
+      authtype="1"
+      proxy="172.22.2.38"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="safaricom mms"
+      carrier_id = "865"
+      mcc="639"
+      mnc="02"
+      apn="safaricom"
+      user="saf"
+      password="data"
+      authtype="1"
+      mmsproxy="172.22.2.38"
+      mmsport="8080"
+      mmsc="http://mms.gprs.safaricom.com"
+      type="mms"
+  />
+
+
+  <apn carrier="Airtel Internet"
+      carrier_id = "866"
+      mcc="639"
+      mnc="03"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel mms"
+      carrier_id = "866"
+      mcc="639"
+      mnc="03"
+      apn="mms"
+      mmsc="http://mms.ke.airtel.com:8002"
+      mmsproxy="172.30.9.8"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Airtel"
+      carrier_id = "866"
+      mcc="639"
+      mnc="03"
+      apn="ke.celtel.com"
+      type="default,supl"
+  />
+
+  <apn carrier="mms"
+      carrier_id = "866"
+      mcc="639"
+      mnc="03"
+      apn="ke.celtel.com"
+      mmsproxy="172.30.8.50"
+      mmsport="8080"
+      mmsc="http://mms.ke.celtel.com/servlets/mms"
+      type="mms"
+  />
+
+  <apn carrier="Yu Internet"
+      carrier_id = "2209"
+      mcc="639"
+      mnc="05"
+      apn="Internet"
+      proxy="10.4.16.6"
+      port="8080"
+      mmsproxy="10.4.16.6"
+      mmsport="8080"
+      mmsc="http://10.4.16.22/servlets/mms"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Yu WAP"
+      carrier_id = "2209"
+      mcc="639"
+      mnc="05"
+      apn="Yu internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Yu mms"
+      carrier_id = "2209"
+      mcc="639"
+      mnc="05"
+      apn="Yu"
+      mmsproxy="10.4.16.6"
+      mmsport="8080"
+      mmsc="http://10.4.16.22/servlets/mms"
+      type="mms"
+  />
+
+  <apn carrier="Orange Internet"
+      carrier_id = "2210"
+      mcc="639"
+      mnc="07"
+      apn="bew.orange.co.ke"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange MMS"
+      carrier_id = "2210"
+      mcc="639"
+      mnc="07"
+      apn="mms.orange.co.ke"
+      mmsproxy="10.36.17.130"
+      mmsport="8080"
+      mmsc="http://10.36.16.5/servlets/mms"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Vodacom WAP"
+      carrier_id = "1744"
+      mcc="640"
+      mnc="04"
+      apn="Wap"
+      proxy="10.154.0.8"
+      port="9401"
+      type="default,supl"
+      mvno_match_data="VodaCom Tanzania"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Vodacom MMS"
+      carrier_id = "1744"
+      mcc="640"
+      mnc="04"
+      apn="mms"
+      mmsc="http://10.154.0.12/mms/"
+      type="mms"
+      mvno_match_data="VodaCom Tanzania"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Airtel Internet UG"
+      apn="internet"
+      carrier_id = "1753"
+      mcc="641"
+      mnc="01"
+      type="default"
+  />
+
+  <apn carrier="MTN-WEB"
+      apn="internet"
+      carrier_id = "1754"
+      mcc="641"
+      mnc="10"
+      type="default"
+  />
+
+  <apn carrier="UTL Internet UG"
+      apn="utweb"
+      carrier_id = "1755"
+      mcc="641"
+      mnc="11"
+      proxy="10.76.101.51"
+      port="8080"
+      type="default"
+  />
+
+  <apn carrier="Orange Internet UG"
+      carrier_id = "1756"
+      mcc="641"
+      mnc="14"
+      apn="orange.ug"
+      type="default"
+  />
+
+  <apn carrier="Orange MMS"
+      carrier_id = "1756"
+      mcc="641"
+      mnc="14"
+      apn="orangemms"
+      mmsc="http://mms/"
+      type="mms"
+  />
+
+  <apn carrier="Warid Telecom Internet UG"
+      apn="web.waridtel.co.ug"
+      carrier_id = "1757"
+      mcc="641"
+      mnc="22"
+      proxy="10.5.27.80"
+      port="8080"
+      type="default"
+  />
+
+  <apn carrier="Spacetel"
+      carrier_id = "1373"
+      mcc="642"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Tempo"
+      carrier_id = "1374"
+      mcc="642"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Onatel"
+      carrier_id = "1375"
+      mcc="642"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Smart Mobile"
+      carrier_id = "2355"
+      mcc="642"
+      mnc="07"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="HiTs Telecom"
+      carrier_id = "2211"
+      mcc="642"
+      mnc="08"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Leo"
+      carrier_id = "2212"
+      mcc="642"
+      mnc="82"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="mCel"
+      carrier_id = "1634"
+      mcc="643"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Movitel"
+      carrier_id = "2213"
+      mcc="643"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Vodacom"
+      carrier_id = "2381"
+      mcc="643"
+      mnc="04"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel"
+      carrier_id = "1319"
+      mcc="645"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="MTN"
+      carrier_id = "1320"
+      mcc="645"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="ZAMTEL"
+      carrier_id = "1321"
+      mcc="645"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange MG Internet"
+      carrier_id = "1606"
+      mcc="646"
+      mnc="02"
+      apn="orangenet"
+      type="default,supl,agps,fota,dun"
+      authtype="0"
+  />
+
+  <apn carrier="Orange World re"
+      carrier_id = "1676"
+      mcc="647"
+      mnc="00"
+      apn="orangerun"
+      user="orange"
+      password="orange"
+      type="default,supl"
+  />
+
+  <apn carrier="Orange MMS Réunion"
+      carrier_id = "1676"
+      mcc="647"
+      mnc="00"
+      apn="orangerun.acte"
+      user="orange"
+      password="orange"
+      mmsc="http://mms.orange.re"
+      mmsproxy="192.168.10.200"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="OnlyWap"
+      carrier_id = "1677"
+      mcc="647"
+      mnc="02"
+      apn="onlywap"
+      user="only"
+      password="only"
+      authtype="1"
+      proxy="10.4.85.50"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="OnlyMMS"
+      carrier_id = "1677"
+      mcc="647"
+      mnc="02"
+      apn="onlymms"
+      user="only"
+      password="only"
+      authtype="1"
+      mmsc="http://10.4.85.50:8514"
+      mmsproxy="10.4.85.50"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Free Re"
+      carrier_id = "2127"
+      mcc="647"
+      mnc="03"
+      apn="free.re"
+      mmsc="http://mms.free.re"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Full Internet SRR"
+      carrier_id = "1008"
+      mcc="647"
+      mnc="10"
+      apn="sl2sfr"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1008"
+      mcc="647"
+      mnc="10"
+      apn="mmssfr"
+      user="mms"
+      password="mms"
+      mmsc="http://mms"
+      mmsproxy="10.0.224.145"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="GPRS SRR"
+      carrier_id = "1008"
+      mcc="647"
+      mnc="10"
+      apn="wapsfr"
+      user="wap"
+      password="wap"
+      proxy="10.0.224.161"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Coriolis WAP"
+      carrier_id = "2135"
+      mcc="647"
+      mnc="10"
+      apn="fnetcoriolis"
+      type="default,supl"
+      mvno_match_data="12"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Coriolis MMS"
+      carrier_id = "2135"
+      mcc="647"
+      mnc="10"
+      mmsc="http://mmscoriolis"
+      mmsproxy="10.143.156.6"
+      mmsport="8080"
+      apn="mmscoriolis"
+      type="mms"
+      mvno_match_data="12"
+      mvno_type="gid"
+  />
+
+  <apn carrier="Telecel"
+      carrier_id = "1879"
+      mcc="648"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Econet"
+      carrier_id = "1880"
+      mcc="648"
+      mnc="04"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="MTC"
+      carrier_id = "941"
+      mcc="649"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="switch"
+      carrier_id = "2214"
+      mcc="649"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Leo"
+      carrier_id = "942"
+      mcc="649"
+      mnc="03"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="TNM"
+      carrier_id = "1625"
+      mcc="650"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Airtel"
+      carrier_id = "1626"
+      mcc="650"
+      mnc="10"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="VCL Internet GPRS"
+      carrier_id = "2392"
+      mcc="651"
+      mnc="01"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="VCL MMS GPRS"
+      carrier_id = "2392"
+      mcc="651"
+      mnc="01"
+      apn="mms"
+      mmsc="http://mmsc.vodacom4me.co.ls"
+      mmsproxy="10.113.63.11"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Swazi MTN"
+      carrier_id = "1091"
+      mcc="653"
+      mnc="10"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="HURI - SNPT"
+      carrier_id = "872"
+      mcc="654"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="LTE.Vodacom"
+      carrier_id = "24"
+      mcc="655"
+      mnc="01"
+      apn="lte.vodacom.za"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS.Vodacom"
+      carrier_id = "24"
+      mcc="655"
+      mnc="01"
+      apn="lte.vodacom.za"
+      mmsc="http://mmsc.vodacom4me.co.za"
+      mmsproxy="196.6.128.13"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Smart.Vodacom"
+      carrier_id = "24"
+      mcc="655"
+      mnc="01"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS.Vodacom"
+      carrier_id = "24"
+      mcc="655"
+      mnc="01"
+      apn="mms.vodacom.net"
+      mmsc="http://mmsc.vodacom4me.co.za"
+      mmsproxy="196.6.128.13"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Telkom Mobile Internet"
+      carrier_id = "1965"
+      mcc="655"
+      mnc="02"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Telkom Mobile MMS"
+      carrier_id = "1965"
+      mcc="655"
+      mnc="02"
+      apn="mms"
+      mmsc="http://mms.8ta.com:38090/was"
+      mmsproxy="41.151.254.162"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Cell C GPRS"
+      carrier_id = "1308"
+      mcc="655"
+      mnc="07"
+      apn="internet"
+      proxy="196.31.116.250"
+      port="8080"
+      type="default,supl"
+  />
+
+  <apn carrier="Cell C MMS"
+      carrier_id = "1308"
+      mcc="655"
+      mnc="07"
+      apn="mms"
+      mmsc="http://mms.cmobile.co.za/"
+      mmsproxy="196.31.116.250"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="VIRGIN_INTERNET_1"
+      carrier_id = "2335"
+      mcc="655"
+      mnc="07"
+      apn="vdata"
+      proxy="196.31.116.241"
+      port="8080"
+      type="default,supl"
+      mvno_match_data="6550710"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="VIRGIN_INTERNET_2"
+      carrier_id = "2335"
+      mcc="655"
+      mnc="07"
+      apn="vdata"
+      proxy="196.31.116.241"
+      port="9201"
+      type="default,supl"
+      mvno_match_data="6550710"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Virgin_MMS_1"
+      carrier_id = "2335"
+      mcc="655"
+      mnc="07"
+      apn="vmms"
+      mmsc="http://mms.virginmobile.co.za"
+      mmsproxy="196.31.116.242"
+      mmsport="8080"
+      type="mms"
+      mvno_match_data="6550710"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="Virgin_MMS_2"
+      carrier_id = "2335"
+      mcc="655"
+      mnc="07"
+      apn="vmms"
+      mmsc="http://mms.virginmobile.co.za"
+      mmsproxy="196.31.116.242"
+      mmsport="9201"
+      type="mms"
+      mvno_match_data="6550710"
+      mvno_type="imsi"
+  />
+
+  <apn carrier="MTN GPRS"
+      carrier_id = "1309"
+      mcc="655"
+      mnc="10"
+      apn="myMTN"
+      user="mtnwap"
+      password="mtnwap"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MTN MMS"
+      carrier_id = "1309"
+      mcc="655"
+      mnc="10"
+      apn="myMTN"
+      user="mtnmms"
+      password="mtnmms"
+      authtype="1"
+      mmsc="http://mms.mtn.co.za/mms/wapenc"
+      mmsproxy="196.11.240.241"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Eritel"
+      carrier_id = "2247"
+      mcc="657"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="DigiCell"
+      carrier_id = "570"
+      mcc="702"
+      mnc="67"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Smart"
+      carrier_id = "2354"
+      mcc="702"
+      mnc="99"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Internet CLARO"
+      carrier_id = "1520"
+      mcc="704"
+      mnc="01"
+      apn="internet.ideasclaro"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS CLARO"
+      carrier_id = "1520"
+      mcc="704"
+      mnc="01"
+      apn="mms.ideasclaro"
+      mmsproxy="216.230.133.66"
+      mmsport="8080"
+      mmsc="http://mms.ideasclaro.com:8002"
+      type="mms"
+  />
+
+  <apn carrier="Broadband TIGO"
+      carrier_id = "1521"
+      mcc="704"
+      mnc="02"
+      apn="broadband.tigo.gt"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS TIGO"
+      carrier_id = "1521"
+      mcc="704"
+      mnc="02"
+      apn="mms.tigo.gt"
+      mmsproxy="10.16.17.12"
+      mmsport="8888"
+      mmsc="http://mms"
+      type="mms"
+  />
+
+  <apn carrier="Movistar INTERNET"
+      carrier_id = "1522"
+      mcc="704"
+      mnc="03"
+      apn="internet.movistar.gt"
+      user="movistargt"
+      password="movistargt"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "1522"
+      mcc="704"
+      mnc="03"
+      apn="mms.movistar.gt"
+      user="movistargt"
+      password="movistargt"
+      mmsproxy="10.12.22.1"
+      mmsport="80"
+      mmsc="http://mms.movistar.gt"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Movistar INTERNET"
+      carrier_id = "1522"
+      mcc="704"
+      mnc="030"
+      apn="internet.movistar.gt"
+      user="movistargt"
+      password="movistargt"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "1522"
+      mcc="704"
+      mnc="030"
+      apn="mms.movistar.gt"
+      user="movistargt"
+      password="movistargt"
+      mmsproxy="10.12.22.1"
+      mmsport="80"
+      mmsc="http://mms.movistar.gt"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Internet CLARO"
+      carrier_id = "1954"
+      mcc="706"
+      mnc="01"
+      apn="internet.ideasclaro"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS CLARO"
+      carrier_id = "1954"
+      mcc="706"
+      mnc="01"
+      apn="mms.ideasclaro"
+      mmsproxy="216.230.133.66"
+      mmsport="8080"
+      mmsc="http://mms.ideasclaro.com:8002"
+      type="mms"
+  />
+
+  <apn carrier="Digicel Internet"
+      carrier_id = "1087"
+      mcc="706"
+      mnc="02"
+      apn="web.digicelsv.com"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1087"
+      mcc="706"
+      mnc="02"
+      apn="wap.digicelsv.com"
+      mmsproxy="172.26.5.12"
+      mmsport="8080"
+      mmsc="http://mmc.digiceljamaica.com/servlets/mms"
+      type="mms"
+  />
+
+  <apn carrier="Internet Tigo"
+      carrier_id = "1998"
+      mcc="706"
+      mnc="03"
+      apn="internet.tigo.sv"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Tigo"
+      carrier_id = "1998"
+      mcc="706"
+      mnc="03"
+      apn="mms.tigo.sv"
+      mmsproxy="10.16.17.12"
+      mmsport="8888"
+      mmsc="http://mms"
+      type="mms"
+  />
+
+  <apn carrier="Movistar INTERNET"
+      carrier_id = "2009"
+      mcc="706"
+      mnc="04"
+      apn="internet.movistar.sv"
+      user="movistarsv"
+      password="movistarsv"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "2009"
+      mcc="706"
+      mnc="04"
+      apn="mms.movistar.sv"
+      user="movistarsv"
+      password="movistarsv"
+      mmsproxy="10.12.20.1"
+      mmsport="80"
+      mmsc="http://mms.movistar.sv"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Movistar INTERNET"
+      carrier_id = "2009"
+      mcc="706"
+      mnc="040"
+      apn="internet.movistar.sv"
+      user="movistarsv"
+      password="movistarsv"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "2009"
+      mcc="706"
+      mnc="040"
+      apn="mms.movistar.sv"
+      user="movistarsv"
+      password="movistarsv"
+      mmsproxy="10.12.20.1"
+      mmsport="80"
+      mmsc="http://mms.movistar.sv"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Internet Claro"
+      carrier_id = "773"
+      mcc="708"
+      mnc="001"
+      apn="internet.ideasclaro"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Claro"
+      carrier_id = "773"
+      mcc="708"
+      mnc="001"
+      apn="mms.ideasclaro"
+      mmsproxy="10.6.32.2"
+      mmsport="8080"
+      mmsc="http://10.6.32.27/servlets/mms"
+      type="mms"
+  />
+
+  <apn carrier="INTERNET TIGO"
+      carrier_id = "1528"
+      mcc="708"
+      mnc="02"
+      apn="internet.tigo.hn"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS TIGO"
+      carrier_id = "1528"
+      mcc="708"
+      mnc="02"
+      apn="mms.tigo.hn"
+      mmsproxy="10.16.17.12"
+      mmsport="8888"
+      mmsc="http://mms"
+      type="mms"
+  />
+
+  <apn carrier='Honduras:Digicel:Internet'
+      carrier_id = "2248"
+      mcc='708'
+      mnc='04'
+      apn='web.digicelhn.com'
+      authtype='1'
+      type='default'
+  />
+
+  <apn carrier='Honduras:Digicel:Mms'
+      carrier_id = "2248"
+      mcc='708'
+      mnc='04'
+      apn='wap.digicelhn.com'
+      authtype='1'
+      mmsc='http://mms.digicelsv.com/servlets/mms'
+      mmsproxy='172.26.5.12'
+      mmsport='9201'
+      type='mms'
+  />
+
+  <apn carrier='Honduras:Digicel:Modem'
+      carrier_id = "2248"
+      mcc='708'
+      mnc='04'
+      apn='wap.digicelhn.com'
+      port='8080'
+      authtype='1'
+      proxy='172.26.5.12'
+      mmsc='http://www.digicelive.com'
+      type='dun'
+  />
+
+  <apn carrier="INTERNET TIGO"
+      carrier_id = "1528"
+      mcc="708"
+      mnc="020"
+      apn="internet.tigo.hn"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS TIGO"
+      carrier_id = "1528"
+      mcc="708"
+      mnc="020"
+      apn="mms.tigo.hn"
+      mmsproxy="10.16.17.12"
+      mmsport="8888"
+      mmsc="http://mms"
+      type="mms"
+  />
+
+  <apn carrier='Honduras:Digicel:Internet:2'
+      carrier_id = "2248"
+      mcc='708'
+      mnc='040'
+      apn='web.digicelhn.com'
+      authtype='1'
+      type='default'
+  />
+
+  <apn carrier='Honduras:Digicel:Mms:2'
+      carrier_id = "2248"
+      mcc='708'
+      mnc='040'
+      apn='wap.digicelhn.com'
+      authtype='1'
+      mmsc='http://mms.digicelsv.com/servlets/mms'
+      mmsproxy='172.26.5.12'
+      mmsport='9201'
+      type='mms'
+  />
+
+  <apn carrier="Enitel WEB"
+      carrier_id = "1641"
+      mcc="710"
+      mnc="21"
+      apn="internet.ideasalo.ni"
+      user="internet"
+      password="internet"
+      authtype="1"
+      type="default,supl"
+  />
+
+
+  <apn carrier="Enitel MMS"
+      carrier_id = "1641"
+      mcc="710"
+      mnc="21"
+      apn="mms.indeasalo.ni"
+      user="mms"
+      password="mms"
+      mmsproxy="10.6.32.2"
+      mmsport="8080"
+      mmsc="http://10.6.32.27/servlets/mms"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Movistar INTERNET"
+      carrier_id = "2010"
+      mcc="710"
+      mnc="30"
+      apn="internet.movistar.ni"
+      user="movistarni"
+      password="movistarni"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "2010"
+      mcc="710"
+      mnc="30"
+      apn="mms.movistar.ni"
+      user="movistarni"
+      password="movistarni"
+      mmsproxy="10.12.23.1"
+      mmsport="80"
+      mmsc="http://mms.movistar.ni"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Yota Nicaragua Internet"
+      carrier_id = "2458"
+      mcc="710"
+      mnc="70"
+      apn="internet"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar INTERNET"
+      carrier_id = "2010"
+      mcc="710"
+      mnc="300"
+      apn="internet.movistar.ni"
+      user="movistarni"
+      password="movistarni"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "2010"
+      mcc="710"
+      mnc="300"
+      apn="mms.movistar.ni"
+      user="movistarni"
+      password="movistarni"
+      mmsproxy="10.12.23.1"
+      mmsport="80"
+      mmsc="http://mms.movistar.ni"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Enitel WEB"
+      carrier_id = "1642"
+      mcc="710"
+      mnc="73"
+      apn="internet.ideasalo.ni"
+      user="internet"
+      password="internet"
+      authtype="1"
+      type="default,supl"
+  />
+
+
+  <apn carrier="Enitel MMS"
+      carrier_id = "1642"
+      mcc="710"
+      mnc="73"
+      apn="mms.indeasalo.ni"
+      user="mms"
+      password="mms"
+      mmsproxy="10.6.32.2"
+      mmsport="8080"
+      mmsc="http://10.6.32.27/servlets/mms"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Enitel WEB"
+      carrier_id = "1642"
+      mcc="710"
+      mnc="730"
+      apn="internet.ideasalo.ni"
+      user="internet"
+      password="internet"
+      authtype="1"
+      type="default,supl"
+  />
+
+
+  <apn carrier="Enitel MMS"
+      carrier_id = "1642"
+      mcc="710"
+      mnc="730"
+      apn="mms.indeasalo.ni"
+      user="mms"
+      password="mms"
+      mmsproxy="10.6.32.2"
+      mmsport="8080"
+      mmsc="http://10.6.32.27/servlets/mms"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="KOLBI 3G"
+      carrier_id = "627"
+      mcc="712"
+      mnc="01"
+      apn="kolbi3g"
+      type="default,supl"
+  />
+
+  <apn carrier="Costar Rica:Kolbi:Modem"
+      carrier_id = "627"
+      mcc="712"
+      mnc="01"
+      apn="kolbi"
+      type="dun"
+      authtype="1"
+      mmsc="http://mimundokolbi.ice.cr"
+      mmsport="8080"
+  />
+
+  <apn carrier="Kolbi_Multimedia"
+      carrier_id = "627"
+      mcc="712"
+      mnc="01"
+      apn="kolbimundo"
+      mmsproxy="10.184.202.24"
+      mmsport="8080"
+      mmsc="http://mmsice"
+      type="mms"
+  />
+
+  <apn carrier="KOLBI 3G"
+      carrier_id = "627"
+      mcc="712"
+      mnc="02"
+      apn="kolbi3g"
+      type="default,supl"
+  />
+
+  <apn carrier="Kolbi_Multimedia"
+      carrier_id = "627"
+      mcc="712"
+      mnc="02"
+      apn="kolbimundo"
+      mmsproxy="10.184.202.24"
+      mmsport="8080"
+      mmsc="http://mmsice"
+      type="mms"
+  />
+
+  <apn carrier="Internet CLARO CR"
+      carrier_id = "1953"
+      mcc="712"
+      mnc="03"
+      apn="internet.ideasclaro"
+      user=""
+      password=""
+      type="default,supl"
+  />
+
+  <apn carrier="MMS CLARO CR"
+      carrier_id = "1953"
+      mcc="712"
+      mnc="03"
+      apn="mms.ideasclaro"
+      user=""
+      password=""
+      mmsproxy="216.230.133.66"
+      mmsport="8080"
+      mmsc="http://mms.ideasclaro.com:8002"
+      type="mms"
+  />
+
+  <apn carrier="Movistar INTERNET"
+      carrier_id = "2003"
+      mcc="712"
+      mnc="04"
+      apn="internet.movistar.cr"
+      user="movistarcr"
+      password="movistarcr"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "2003"
+      mcc="712"
+      mnc="04"
+      apn="mms.movistar.cr"
+      user="movistarcr"
+      password="movistarcr"
+      mmsproxy="10.221.79.83"
+      mmsport="80"
+      mmsc="http://mms.movistar.cr"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Internet Tuyo"
+      carrier_id = "2267"
+      mcc="712"
+      mnc="019"
+      apn="tm7datos"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Tuyo"
+      carrier_id = "2267"
+      mcc="712"
+      mnc="019"
+      apn="tm7mms"
+      mmsproxy="10.186.181.5"
+      mmsport="3128"
+      mmsc="http://mmsc.tuyomovil.com:1981"
+      type="mms"
+  />
+
+  <apn carrier="Internet Tuyo"
+      carrier_id = "2267"
+      mcc="712"
+      mnc="190"
+      apn="tm7datos"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Tuyo"
+      carrier_id = "2267"
+      mcc="712"
+      mnc="190"
+      apn="tm7mms"
+      mmsproxy="10.186.181.5"
+      mmsport="3128"
+      mmsc="http://mmsc.tuyomovil.com:1981"
+      type="mms"
+  />
+
+  <apn carrier="Internet Fullmovil"
+      mcc="712"
+      mnc="20"
+      apn="datos.fullmovil.cr"
+      type="default,supl"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "973"
+      mcc="714"
+      mnc="01"
+      apn="apn01.cwpanama.com.pa"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "973"
+      mcc="714"
+      mnc="01"
+      apn="apn02.cwpanama.com.pa"
+      mmsproxy="172.25.3.5"
+      mmsport="8080"
+      mmsc="http://mms.zonamovil.com.pa"
+      type="mms"
+  />
+
+  <apn carrier="Movistar INTERNET"
+      carrier_id = "974"
+      mcc="714"
+      mnc="02"
+      apn="internet.movistar.pa"
+      user="movistarpa"
+      password="movistarpa"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "974"
+      mcc="714"
+      mnc="02"
+      apn="mms.movistar.pa"
+      user="movistarpamms"
+      password="movistarpa"
+      mmsproxy="10.12.21.1"
+      mmsport="80"
+      mmsc="http://mms.movistar.pa"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Movistar INTERNET"
+      carrier_id = "974"
+      mcc="714"
+      mnc="020"
+      apn="internet.movistar.pa"
+      user="movistarpa"
+      password="movistarpa"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "974"
+      mcc="714"
+      mnc="020"
+      apn="mms.movistar.pa"
+      user="movistarpamms"
+      password="movistarpa"
+      mmsproxy="10.12.21.1"
+      mmsport="80"
+      mmsc="http://mms.movistar.pa"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="WEB Claro"
+      carrier_id = "1925"
+      mcc="714"
+      mnc="03"
+      apn="web.claro.com.pa"
+      user="CLAROWEB"
+      password="CLAROWEB"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Claro"
+      carrier_id = "1925"
+      mcc="714"
+      mnc="03"
+      apn="mms.claro.com.pa"
+      user="CLAROMMS"
+      password="CLAROMMS"
+      mmsproxy="10.240.3.129"
+      mmsport="8799"
+      mmsc="http://www.claro.com.pa/mms/"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Digicel Internet"
+      carrier_id = "1926"
+      mcc="714"
+      mnc="04"
+      apn="web.digicelpanama.com"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1926"
+      mcc="714"
+      mnc="04"
+      apn="wap.digicelpanama.com"
+      mmsproxy="172.27.99.99"
+      mmsport="8080"
+      mmsc="http://mmc.digicelpanama.com/servlets/mms"
+      type="mms"
+  />
+
+  <apn carrier='Panama:Digicel:Internet:2'
+      carrier_id = "1926"
+      mcc='714'
+      mnc='040'
+      apn='web.digicelpanama.com'
+      authtype='1'
+      type='default'
+  />
+
+  <apn carrier='Panama:Digicel:Mms:2'
+      carrier_id = "1926"
+      mcc='714'
+      mnc='040'
+      apn='wap.digicelpanama.com'
+      authtype='1'
+      mmsc='http://mmc.digicelpanama.com/servlets/mms'
+      mmsproxy='172.27.99.99'
+      mmsport='9201'
+      type='mms'
+  />
+
+  <apn carrier="Movistar INTERNET"
+      carrier_id = "1929"
+      mcc="716"
+      mnc="06"
+      apn="movistar.pe"
+      user="movistar@datos"
+      password="movistar"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "1929"
+      mcc="716"
+      mnc="06"
+      apn="mms.movistar.pe"
+      user="movistar@mms"
+      password="movistar"
+      mmsproxy="200.4.196.118"
+      mmsport="8080"
+      mmsc="http://mmsc.telefonicamovistar.com.pe:8088/mms/"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="CLARO DATOS"
+      carrier_id = "1647"
+      mcc="716"
+      mnc="10"
+      apn="claro.pe"
+      user="claro"
+      password="claro"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="CLARO MMS"
+      carrier_id = "1647"
+      mcc="716"
+      mnc="10"
+      apn="mms.claro.pe"
+      user="claro"
+      password="claro"
+      mmsproxy="192.168.231.30"
+      mmsport="80"
+      mmsc="http://claro/servlets/mms"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Bitel - Internet"
+      carrier_id = "2359"
+      mcc="716"
+      mnc="15"
+      apn="bitel"
+      authtype="1"
+      type="default,supl"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Bitel - MMS"
+      carrier_id = "2359"
+      mcc="716"
+      mnc="15"
+      apn="bitel-mms"
+      mmsc="http://181.176.241.99:8080"
+      mmsproxy="10.121.144.3"
+      mmsport="8000"
+      authtype="1"
+      type="mms"
+      protocol="IP"
+      roaming_protocol="IP"
+  />
+
+  <apn carrier="Entel PE"
+      carrier_id = "1930"
+      mcc="716"
+      mnc="17"
+      apn="entel.pe"
+      authtype="0"
+      type="default,dun"
+      protocol="IP"
+  />
+
+  <apn carrier="Entel MMS"
+      carrier_id = "1930"
+      mcc="716"
+      mnc="17"
+      apn="mms.entel.pe"
+      mmsc="http://mms.entel.pe"
+      mmsproxy="10.0.215.74"
+      mmsport="8080"
+      authtype="0"
+      type="mms"
+      protocol="IP"
+  />
+
+  <apn carrier="Entel Location"
+      carrier_id = "1930"
+      mcc="716"
+      mnc="17"
+      apn="location.entel.pe"
+      port="7275"
+      server="http://location.entel.pe"
+      authtype="0"
+      type="supl"
+      protocol="IP"
+  />
+
+  <apn carrier="Servicio_WEB"
+    carrier_id="2249"
+    mcc="722"
+    mnc="01"
+    apn="internet.movil"
+    user="internet"
+    password="internet"
+    authtype="1"
+    type="default"
+    protocol="IPV4V6"
+    roaming_protocol="IPV4V6"
+    mvno_type="spn"
+    mvno_match_data="Tuenti"
+  />
+
+  <apn carrier="Movistar INTERNET"
+      carrier_id = "1337"
+      mcc="722"
+      mnc="07"
+      apn="wap.gprs.unifon.com.ar"
+      user="wap"
+      password="wap"
+      authtype="1"
+      type="default,supl"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "1337"
+      mcc="722"
+      mnc="07"
+      apn="mms.gprs.unifon.com.ar"
+      user="mms"
+      password="mms"
+      mmsproxy="200.68.32.239"
+      mmsport="8080"
+      mmsc="http://mms.movistar.com.ar"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Claro AR"
+      carrier_id = "1338"
+      mcc="722"
+      mnc="31"
+      apn="igprs.claro.com.ar"
+      mmsc="http://mms.claro.com.ar"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Claro AR"
+      carrier_id = "1338"
+      mcc="722"
+      mnc="310"
+      apn="igprs.claro.com.ar"
+      mmsc="http://mms.claro.com.ar"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Personal Datos"
+      carrier_id = "1341"
+      mcc="722"
+      mnc="34"
+      apn="datos.personal.com"
+      user="datos"
+      password="datos"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Argentina:Personal:DUN"
+      carrier_id = "1341"
+      mcc="722"
+      mnc="34"
+      apn="internet.personal.com"
+      type="dun"
+      user="internet"
+      password="internet"
+      authtype="0"
+  />
+
+  <apn carrier="Personal MMS"
+      carrier_id = "1341"
+      mcc="722"
+      mnc="34"
+      apn="mms"
+      user="mms"
+      password="mms"
+      mmsproxy="172.25.7.31"
+      mmsport="8080"
+      mmsc="http://mms.personal.com"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier='Argentina:Nuestro:MMS'
+      carrier_id = "2250"
+      mcc='722'
+      mnc='36'
+      apn='mms.nuestro.com.ar'
+      authtype='0'
+      mmsc='http://mms.nuestro.com.ar'
+      mmsproxy='172.16.0.20'
+      mmsport='8080'
+      type='mms'
+      user='mms'
+  />
+
+  <apn carrier='Argentina:Nuestro:Internet'
+      carrier_id = "2250"
+      mcc='722'
+      mnc='36'
+      apn='gprs.nuestro.com.ar'
+      authtype='0'
+      type='default'
+      user='gprs'
+  />
+
+  <apn carrier='Argentina:Personal :Datos'
+      carrier_id = "1341"
+      mcc='722'
+      mnc='340'
+      apn='datos.personal.com'
+      authtype='0'
+      type='default'
+      user='gprs'
+      password='adgj'
+  />
+
+  <apn carrier='Argentina:Personal :DUN'
+      carrier_id = "1341"
+      mcc='722'
+      mnc='340'
+      apn='internet.personal.com'
+      authtype='0'
+      type='dun'
+      user='internet'
+      password='internet'
+  />
+
+  <apn carrier='Argentina:Personal :MMS'
+      carrier_id = "1341"
+      mcc='722'
+      mnc='340'
+      apn='mms'
+      authtype='0'
+      mmsc='http://mms.personal.com'
+      mmsproxy='172.25.7.31'
+      mmsport='8080'
+      type='mms'
+      user='mms'
+      password='mms'
+  />
+
+  <apn carrier="Personal Datos"
+      carrier_id = "1341"
+      mcc="722"
+      mnc="341"
+      apn="datos.personal.com"
+      user="datos"
+      password="datos"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Argentina:Personal: DUN"
+      carrier_id = "1341"
+      mcc="722"
+      mnc="341"
+      apn="internet.personal.com"
+      type="dun"
+      user="internet"
+      password="internet"
+      authtype="0"
+  />
+
+  <apn carrier="Personal MMS"
+      carrier_id = "1341"
+      mcc="722"
+      mnc="341"
+      apn="mms"
+      user="mms"
+      password="mms"
+      mmsproxy="172.25.7.31"
+      mmsport="8080"
+      mmsc="http://mms.personal.com"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="TIM Connect"
+      carrier_id = "1385"
+      mcc="724"
+      mnc="02"
+      apn="timbrasil.br"
+      user="tim"
+      password="tim"
+      mmsc="http://mms.tim.br"
+      mmsproxy="189.40.191.96"
+      mmsport="8080"
+      authtype="1"
+      protocol="IPV4V6"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="TIM Connect"
+      carrier_id = "1385"
+      mcc="724"
+      mnc="03"
+      apn="timbrasil.br"
+      user="tim"
+      password="tim"
+      mmsc="http://mms.tim.br"
+      mmsproxy="189.40.191.96"
+      mmsport="8080"
+      authtype="1"
+      protocol="IPV4V6"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="TIM Connect"
+      carrier_id = "1385"
+      mcc="724"
+      mnc="04"
+      apn="timbrasil.br"
+      user="tim"
+      password="tim"
+      mmsc="http://mms.tim.br"
+      mmsproxy="189.40.191.96"
+      mmsport="8080"
+      authtype="1"
+      protocol="IPV4V6"
+      type="default,supl,mms"
+  />
+
+  <apn carrier="Java Session"
+      carrier_id = "529"
+      mcc="724"
+      mnc="05"
+      apn="java.claro.com.br"
+      user="claro"
+      password="claro"
+      type="default,supl"
+  />
+
+  <apn carrier="Claro Foto"
+      carrier_id = "529"
+      mcc="724"
+      mnc="05"
+      apn="mms.claro.com.br"
+      user="claro"
+      password="claro"
+      mmsc="http://mms.claro.com.br"
+      mmsproxy="200.169.126.10"
+      mmsport="8799"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Vivo MMS"
+      carrier_id = "530"
+      mcc="724"
+      mnc="06"
+      apn="mms.vivo.com.br"
+      user="vivo"
+      password="vivo"
+      mmsc="http://termnat.vivomms.com.br:8088/mms"
+      mmsproxy="200.142.130.104"
+      mmsport="80"
+      authtype="1"
+      protocol="IPV4V6"
+      type="mms"
+  />
+
+  <apn carrier="Vivo Internet"
+      carrier_id = "530"
+      mcc="724"
+      mnc="06"
+      apn="zap.vivo.com.br"
+      user="vivo"
+      password="vivo"
+      authtype="1"
+      protocol="IPV4V6"
+      type="default,supl"
+  />
+
+  <apn carrier="SCTL MMS"
+      carrier_id = "1388"
+      mcc="724"
+      mnc="07"
+      apn="mms.sercomtel.com.br"
+      user="sercomtel"
+      password="sercomtel"
+      mmsc="http://mms.claro.com.br"
+      mmsproxy="200.169.126.10"
+      mmsport="8799"
+      type="mms"
+  />
+
+  <apn carrier="SCTL GPRS"
+      carrier_id = "1388"
+      mcc="724"
+      mnc="07"
+      apn="sercomtel.com.br"
+      user="sercomtel"
+      password="sercomtel"
+      type="default,supl"
+  />
+
+  <apn carrier="Vivo Internet"
+      carrier_id = "530"
+      mcc="724"
+      mnc="10"
+      apn="zap.vivo.com.br"
+      user="vivo"
+      password="vivo"
+      authtype="1"
+      protocol="IPV4V6"
+      type="default,supl"
+  />
+
+  <apn carrier="Vivo MMS"
+      carrier_id = "530"
+      mcc="724"
+      mnc="10"
+      apn="mms.vivo.com.br"
+      user="vivo"
+      password="vivo"
+      mmsc="http://termnat.vivomms.com.br:8088/mms"
+      mmsproxy="200.142.130.104"
+      mmsport="80"
+      authtype="1"
+      protocol="IPV4V6"
+      type="mms"
+  />
+
+  <apn carrier="Vivo MMS"
+      carrier_id = "530"
+      mcc="724"
+      mnc="11"
+      apn="mms.vivo.com.br"
+      user="vivo"
+      password="vivo"
+      mmsc="http://termnat.vivomms.com.br:8088/mms"
+      mmsproxy="200.142.130.104"
+      mmsport="80"
+      authtype="1"
+      protocol="IPV4V6"
+      type="mms"
+  />
+
+  <apn carrier="Vivo Internet"
+      carrier_id = "530"
+      mcc="724"
+      mnc="11"
+      apn="zap.vivo.com.br"
+      user="vivo"
+      password="vivo"
+      authtype="1"
+      protocol="IPV4V6"
+      type="default,supl"
+  />
+
+  <apn carrier='Sercomtel:Dados'
+      carrier_id = "539"
+      mcc='724'
+      mnc='15'
+      apn='sercomtel.com.br'
+      authtype='1'
+      type='default'
+      user='sercomtel'
+      password='sercomtel'
+  />
+
+  <apn carrier='Sercomtel:MMS'
+      carrier_id = "539"
+      mcc='724'
+      mnc='15'
+      apn='mms.sercomtel.com.br'
+      authtype='1'
+      mmsc='http://mms.claro.com.br'
+      mmsproxy='200.169.126.10'
+      mmsport='8799'
+      type='mms'
+      user='sercomtel'
+      password='sercomtel'
+  />
+
+  <apn carrier='Sercomtel:Modem'
+      carrier_id = "539"
+      mcc='724'
+      mnc='15'
+      apn='sercomtel.com.br'
+      authtype='1'
+      type='dun'
+      user='sercomtel'
+      password='sercomtel'
+  />
+
+  <apn carrier="Oi GPRS Internet"
+      carrier_id = "540"
+      mcc="724"
+      mnc="16"
+      apn="gprs.oi.com.br"
+      protocol="IPV4V6"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS GPRS"
+      carrier_id = "540"
+      mcc="724"
+      mnc="16"
+      apn="mmsgprs.oi.com.br"
+      user="oimms"
+      password="oioioi"
+      mmsc="http://200.222.42.204:8002"
+      mmsproxy="192.168.10.50"
+      mmsport="3128"
+      authtype="1"
+      protocol="IPV4V6"
+      type="mms"
+  />
+
+  <apn carrier="Surf"
+      mcc="724"
+      mnc="17"
+      apn="internet.br"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Surf"
+  />
+
+  <apn carrier="LIGUE 4G Internet"
+      mcc="724"
+      mnc="18"
+      apn="iot4u.br"
+      authtype="1"
+      user="arqia"
+      password="arqia"
+      type="default"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4"
+      mvno_type="spn"
+      mvno_match_data="LIGUE"
+  />
+
+  <apn carrier="LIGUE 4G IMS"
+      mcc="724"
+      mnc="18"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4"
+      mvno_type="spn"
+      mvno_match_data="LIGUE"
+  />
+
+  <apn carrier="TelemigC GPRS"
+      carrier_id = "543"
+      mcc="724"
+      mnc="19"
+      apn="gprs.telemigcelular.com.br"
+      user="celular"
+      password="celular"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Telemig"
+      carrier_id = "543"
+      mcc="724"
+      mnc="19"
+      apn="mmsgprs.telemigcelular.com.br"
+      user="celular"
+      password="celular"
+      mmsc="http://mms.telemigcelular.com.br"
+      mmsproxy="200.192.230.142"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="LIGUE Internet"
+      mcc="724"
+      mnc="21"
+      apn="internet.ligue.vc"
+      type="default"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="LIGUE IMS"
+      mcc="724"
+      mnc="21"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+  />
+
+  <apn carrier="Vivo Internet"
+      carrier_id = "530"
+      mcc="724"
+      mnc="23"
+      apn="zap.vivo.com.br"
+      user="vivo"
+      password="vivo"
+      authtype="1"
+      protocol="IPV4V6"
+      type="default,supl"
+  />
+
+  <apn carrier="Vivo MMS"
+      carrier_id = "530"
+      mcc="724"
+      mnc="23"
+      apn="mms.vivo.com.br"
+      user="vivo"
+      password="vivo"
+      mmsc="http://termnat.vivomms.com.br:8088/mms"
+      mmsproxy="200.142.130.104"
+      mmsport="80"
+      authtype="1"
+      protocol="IPV4V6"
+      type="mms"
+  />
+
+  <apn carrier="OI:INTERNET:2"
+      carrier_id = "1389"
+      mcc="724"
+      mnc="24"
+      apn="gprs.oi.com.br"
+      authtype="1"
+      type="default,dun"
+      user="oi"
+      password="oi"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="Oi:MMS:2"
+      carrier_id = "1389"
+      mcc="724"
+      mnc="24"
+      apn="mmsgprs.oi.com.br"
+      authtype="1"
+      mmsc="http://200.222.42.204:8002"
+      mmsproxy="192.168.10.50"
+      mmsport="3128"
+      type="mms"
+      user="oimms"
+      password="oioioi"
+      protocol="IPV4V6"
+      roaming_protocol="IPV4V6"
+  />
+
+  <apn carrier="Oi GPRS Internet"
+      carrier_id = "1389"
+      mcc="724"
+      mnc="31"
+      apn="gprs.oi.com.br"
+      protocol="IPV4V6"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS GPRS"
+      carrier_id = "1389"
+      mcc="724"
+      mnc="31"
+      apn="mmsgprs.oi.com.br"
+      user="oimms"
+      password="oioioi"
+      mmsc="http://200.222.42.204:8002"
+      mmsproxy="192.168.10.50"
+      mmsport="3128"
+      authtype="1"
+      protocol="IPV4V6"
+      type="mms"
+  />
+
+  <apn carrier='CTBC:Dados:1'
+      carrier_id = "1390"
+      mcc='724'
+      mnc='32'
+      apn='ctbc.br'
+      authtype='1'
+      type='default'
+      user='CTBC'
+      password='1212'
+  />
+
+  <apn carrier='CTBC:Modem:1'
+      carrier_id = "1390"
+      mcc='724'
+      mnc='32'
+      apn='ctbc.br'
+      authtype='1'
+      type='dun'
+      user='CTBC'
+      password='1212'
+  />
+
+  <apn carrier='CTBC:MMS:1'
+      carrier_id = "1390"
+      mcc='724'
+      mnc='32'
+      apn='mms.ctbc.br'
+      authtype='1'
+      mmsc='http://mms.ctbccelular.com.br/was'
+      mmsproxy='172.29.7.70'
+      mmsport='8080'
+      type='mms'
+      user='CTBC'
+      password='1212'
+  />
+
+  <apn carrier='CTBC:Dados:2'
+      carrier_id = "1390"
+      mcc='724'
+      mnc='33'
+      apn='ctbc.br'
+      authtype='1'
+      type='default'
+      user='CTBC'
+      password='1212'
+  />
+
+  <apn carrier='CTBC:Modem:2'
+      carrier_id = "1390"
+      mcc='724'
+      mnc='33'
+      apn='ctbc.br'
+      authtype='1'
+      type='dun'
+      user='CTBC'
+      password='1212'
+  />
+
+  <apn carrier='CTBC:MMS:2'
+      carrier_id = "1390"
+      mcc='724'
+      mnc='33'
+      apn='mms.ctbc.br'
+      authtype='1'
+      mmsc='http://mms.ctbccelular.com.br/was'
+      mmsproxy='172.29.7.70'
+      mmsport='8080'
+      type='mms'
+      user='CTBC'
+      password='1212'
+  />
+
+  <apn carrier='CTBC:Dados:3'
+      carrier_id = "1390"
+      mcc='724'
+      mnc='34'
+      apn='ctbc.br'
+      authtype='1'
+      type='default'
+      user='CTBC'
+      password='1212'
+  />
+
+  <apn carrier='CTBC:Modem:3'
+      carrier_id = "1390"
+      mcc='724'
+      mnc='34'
+      apn='ctbc.br'
+      authtype='1'
+      type='dun'
+      user='CTBC'
+      password='1212'
+  />
+
+  <apn carrier='CTBC:MMS:3'
+      carrier_id = "1390"
+      mcc='724'
+      mnc='34'
+      apn='mms.ctbc.br'
+      authtype='1'
+      mmsc='http://mms.ctbccelular.com.br/was'
+      mmsproxy='172.29.7.70'
+      mmsport='8080'
+      type='mms'
+      user='CTBC'
+      password='1212'
+  />
+
+  <apn carrier='Nextel MMS'
+      carrier_id = "1383"
+      mcc='724'
+      mnc='39'
+      apn='mms.nextel3g.net.br'
+      authtype='0'
+      mmsc='http://3gmms.nextel3g.net.br'
+      mmsproxy='129.192.129.104'
+      mmsport='8080'
+      type='mms'
+      protocol='IPV4V6'
+      roaming_protocol='IPV4V6'
+  />
+
+  <apn carrier='Nextel WAP'
+      carrier_id = "1383"
+      mcc='724'
+      mnc='39'
+      apn='wap.nextel3g.net.br'
+      authtype='0'
+      type='default,dun'
+      protocol='IPV4V6'
+      roaming_protocol='IPV4V6'
+  />
+
+  <apn carrier='Porto Seguro Conecta'
+      carrier_id = "2215"
+      mcc='724'
+      mnc='54'
+      authtype='0'
+      type='default,dun'
+      apn='portoconecta.br'
+  />
+
+  <apn carrier="Internet Movil"
+      carrier_id = "1427"
+      mcc="730"
+      mnc="01"
+      apn="bam.entelpcs.cl"
+      user="entelpcs"
+      password="entelpcs"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Entel"
+      carrier_id = "1427"
+      mcc="730"
+      mnc="01"
+      apn="mms.entelpcs.cl"
+      user="entelpcs"
+      password="entelpcs"
+      mmsproxy="10.99.0.10"
+      mmsport="8080"
+      mmsc="http://mmsc.entelpcs.cl"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier='Internet Nextel'
+      carrier_id = "1430"
+      mcc='730'
+      mnc='09'
+      apn='wap.nextelmovil.cl'
+      authtype='0'
+      type='default'
+  />
+
+  <apn carrier='MMS Nextel'
+      carrier_id = "1430"
+      mcc='730'
+      mnc='09'
+      apn='mms.nextelmovil.cl'
+      authtype='0'
+      mmsc='http://3gmms.nextelmovil.cl'
+      mmsproxy='129.192.129.104'
+      mmsport='8080'
+      type='mms'
+  />
+
+  <apn carrier="Internet Movil"
+      carrier_id = "1427"
+      mcc="730"
+      mnc="10"
+      apn="bam.entelpcs.cl"
+      user="entelpcs"
+      password="entelpcs"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Entel"
+      carrier_id = "1427"
+      mcc="730"
+      mnc="10"
+      apn="mms.entelpcs.cl"
+      user="entelpcs"
+      password="entelpcs"
+      mmsproxy="10.99.0.10"
+      mmsport="8080"
+      mmsc="http://mmsc.entelpcs.cl"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Movistar APLICACIONES"
+      carrier_id = "1428"
+      mcc="730"
+      mnc="02"
+      apn="wap.tmovil.cl"
+      user="wap"
+      password="wap"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "1428"
+      mcc="730"
+      mnc="02"
+      apn="mms.tmovil.cl"
+      user="mms"
+      password="mms"
+      mmsproxy="172.17.8.10"
+      mmsport="8080"
+      mmsc="http://mms.movistar.cl"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Banda Ancha Movil"
+      carrier_id = "1429"
+      mcc="730"
+      mnc="03"
+      apn="bam.clarochile.cl"
+      user="clarochile"
+      password="clarochile"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Claro"
+      carrier_id = "1429"
+      mcc="730"
+      mnc="03"
+      apn="mms.clarochile.cl"
+      user="clarochile"
+      password="clarochile"
+      mmsproxy="172.23.200.200"
+      mmsport="8080"
+      mmsc="http://mms.clarochile.cl"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="web"
+      carrier_id = "1428"
+      mcc="730"
+      mnc="07"
+      apn="web.gtdmovil.cl"
+      user="webgtd"
+      password="webgtd"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Internet"
+      carrier_id = "2216"
+      mcc="730"
+      mnc="08"
+      apn="movil.vtr.com"
+      user="vtrmovil"
+      password="vtrmovil"
+      authtype="2"
+      type="default,supl"
+  />
+
+  <apn carrier="Wap"
+      carrier_id = "2216"
+      mcc="730"
+      mnc="08"
+      apn="wap.vtr.com"
+      proxy="192.168.94.210"
+      port="9028"
+      user=""
+      password=""
+      authtype="0"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "2216"
+      mcc="730"
+      mnc="08"
+      apn="mms.vtr.com"
+      user="mms"
+      password=""
+      mmsc="http://192.168.94.162:19090/was"
+      mmsproxy="192.168.94.210"
+      mmsport="9028"
+      authtype="0"
+      type="mms"
+  />
+
+  <apn carrier="Internet Movil"
+      carrier_id = "1427"
+      mcc="730"
+      mnc="10"
+      apn="bam.entelpcs.cl"
+      user="entelpcs"
+      password="entelpcs"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Entel PCS"
+      carrier_id = "1427"
+      mcc="730"
+      mnc="10"
+      apn="mms.entelpcs.cl"
+      user="entelpcs"
+      password="entelpcs"
+      mmsc="http://mmsc.entelpcs.cl"
+      mmsproxy="10.99.0.10"
+      mmsport="8080"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier='Movistar INTERNET'
+      mcc='732'
+      mnc='12'
+      apn='internet.movistar.com.co'
+      authtype='1'
+      type='default, dun'
+      user='movistar'
+      password='movistar'
+  />
+
+  <apn carrier='Movistar MMS'
+      mcc='732'
+      mnc='12'
+      apn='mms.movistar.com.co'
+      authtype='1'
+      mmsc='http://mms.movistar.com.co'
+      mmsproxy='192.168.222.7'
+      mmsport='9001'
+      type='mms'
+      user='movistar'
+      password='movistar'
+  />
+
+  <apn carrier="COMCEL"
+      carrier_id = "1442"
+      mcc="732"
+      mnc="101"
+      apn="internet.comcel.com.co"
+      user="COMCELWEB"
+      password="COMCELWEB"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Comcel 3GSM"
+      carrier_id = "1442"
+      mcc="732"
+      mnc="101"
+      apn="mms.comcel.com.co"
+      user="COMCELMMS"
+      password="COMCELMMS"
+      mmsproxy="198.228.90.225"
+      mmsport="8799"
+      mmsc="http://www.comcel.com.co/mms/"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="TIGO WEB"
+      carrier_id = "624"
+      mcc="732"
+      mnc="103"
+      apn="web.colombiamovil.com.co"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="TIGO Multimedia"
+      carrier_id = "624"
+      mcc="732"
+      mnc="103"
+      apn="mms.colombiamovil.com.co"
+      user="mms-cm1900"
+      password="mms-cm1900"
+      mmsproxy="190.102.206.48"
+      mmsport="8080"
+      mmsc="http://mms.ola.com.co"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Internet ETB"
+      carrier_id = "2218"
+      mcc="732"
+      mnc="103"
+      apn="moviletb.net.co"
+      type="default,dun"
+      user="etb"
+      password="etb"
+      authtype="0"
+      mvno_match_data="ETB MOVI"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Internet ETB"
+      carrier_id = "2218"
+      mcc="732"
+      mnc="103"
+      apn="moviletb.net.co"
+      type="default,dun"
+      user="etb"
+      password="etb"
+      authtype="0"
+      mvno_match_data="ETB MOVI"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Internet Éxito"
+      carrier_id = "2337"
+      mcc="732"
+      mnc="103"
+      apn="movilexito.net.co"
+      type="default,dun"
+      authtype="1"
+      mvno_match_data="movil exito"
+      mvno_type="spn"
+  />
+
+  <apn carrier="UNE"
+      carrier_id = "2338"
+      mcc="732"
+      mnc="103"
+      apn="www.une.net.co"
+      type="default,dun"
+      user="une"
+      password="une"
+      authtype="0"
+      mvno_match_data="UNE"
+      mvno_type="spn"
+  />
+
+  <apn carrier="TIGO WEB"
+      carrier_id = "624"
+      mcc="732"
+      mnc="111"
+      apn="web.colombiamovil.com.co"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="TIGO Multimedia"
+      carrier_id = "624"
+      mcc="732"
+      mnc="111"
+      apn="mms.colombiamovil.com.co"
+      user="mms-cm1900"
+      password="mms-cm1900"
+      mmsproxy="190.102.206.48"
+      mmsport="8080"
+      mmsc="http://mms.ola.com.co"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Internet ETB"
+      carrier_id = "2218"
+      mcc="732"
+      mnc="111"
+      apn="moviletb.net.co"
+      type="default,dun"
+      user="etb"
+      password="etb"
+      authtype="0"
+      mvno_match_data="ETB MOVIL"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Internet Éxito"
+      carrier_id = "2337"
+      mcc="732"
+      mnc="111"
+      apn="movilexito.net.co"
+      type="default,dun"
+      authtype="1"
+      mvno_match_data="movil exito"
+      mvno_type="spn"
+  />
+
+  <apn carrier="UNE"
+      carrier_id = "2338"
+      mcc="732"
+      mnc="111"
+      apn="www.une.net.co"
+      type="default,dun"
+      user="une"
+      password="une"
+      authtype="0"
+      mvno_match_data="UNE"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Movistar INTERNET"
+      carrier_id = "625"
+      mcc="732"
+      mnc="123"
+      apn="internet.movistar.com.co"
+      user="movistar"
+      password="movistar"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "625"
+      mcc="732"
+      mnc="123"
+      apn="mms.movistar.com.co"
+      user="movistar"
+      password="movistar"
+      mmsproxy="192.168.222.7"
+      mmsport="9001"
+      mmsc="http://mms.movistar.com.co"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Virgin Mobile"
+      carrier_id = "2339"
+      mcc="732"
+      mnc="123"
+      apn="web.vmc.net.co"
+      type="default,supl,internet"
+      authtype="1"
+      mvno_match_data="Virgin Mobile"
+      mvno_type="spn"
+  />
+
+  <apn carrier="Avantel"
+      carrier_id = "626"
+      mcc="732"
+      mnc="130"
+      apn="lte.avantel.com.co"
+      authtype="0"
+      type="default"
+  />
+
+  <apn carrier="ETB 4G"
+      carrier_id = "2218"
+      mcc="732"
+      mnc="187"
+      apn="internetmovil.etb.net.co"
+      authtype="0"
+      type="default"
+  />
+
+  <apn carrier="Digitel 412"
+      carrier_id = "1870"
+      mcc="734"
+      mnc="01"
+      apn="internet.digitel.ve"
+      type="default,supl"
+  />
+
+  <apn carrier="Venezuela:Digitel:MODEM:1"
+      carrier_id = "1870"
+      mcc="734"
+      mnc="01"
+      apn="gprsweb.digitel.ve"
+      type="dun"
+      authtype="1"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1870"
+      mcc="734"
+      mnc="01"
+      apn="expresate.digitel.ve"
+      mmsproxy="10.99.0.10"
+      mmsport="8080"
+      mmsc="http://mms.412.com.ve/servlets/mms"
+      type="mms"
+  />
+
+  <apn carrier="Digitel 412"
+      carrier_id = "1871"
+      mcc="734"
+      mnc="02"
+      apn="internet.digitel.ve"
+      type="default,supl"
+  />
+
+  <apn carrier="Venezuela:Digitel:MODEM:2"
+      carrier_id = "1871"
+      mcc="734"
+      mnc="02"
+      apn="gprsweb.digitel.ve"
+      type="dun"
+      authtype="1"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1871"
+      mcc="734"
+      mnc="02"
+      apn="expresate.digitel.ve"
+      mmsproxy="10.99.0.10"
+      mmsport="8080"
+      mmsc="http://mms.412.com.ve/servlets/mms"
+      type="mms"
+  />
+
+  <apn carrier="Digitel 412"
+      carrier_id = "1872"
+      mcc="734"
+      mnc="03"
+      apn="internet.digitel.ve"
+      type="default,supl"
+  />
+
+  <apn carrier="Venezuela:Digitel:MODEM:3"
+      carrier_id = "1872"
+      mcc="734"
+      mnc="03"
+      apn="gprsweb.digitel.ve"
+      type="dun"
+      authtype="1"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1872"
+      mcc="734"
+      mnc="03"
+      apn="expresate.digitel.ve"
+      mmsproxy="10.99.0.10"
+      mmsport="8080"
+      mmsc="http://mms.412.com.ve/servlets/mms"
+      type="mms"
+  />
+
+  <apn carrier="Movistar INTERNET"
+      carrier_id = "1873"
+      mcc="734"
+      mnc="04"
+      apn="internet.movistar.ve"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "1873"
+      mcc="734"
+      mnc="04"
+      apn="mms.movistar.ve"
+      mmsproxy="200.35.64.73"
+      mmsport="9001"
+      mmsc="http://mms.movistar.com.ve:8088/mms"
+      type="mms"
+  />
+
+  <apn carrier="Movistar WAP"
+      carrier_id = "1873"
+      mcc="734"
+      mnc="04"
+      apn="wap.movistar.ve"
+      mmsproxy="200.35.64.73"
+      mmsport="9001"
+      type="default,supl"
+  />
+
+  <apn carrier="MODEM"
+      carrier_id = "1874"
+      mcc="734"
+      mnc="06"
+      apn="int.movilnet.com.ve"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      carrier_id = "1874"
+      mcc="734"
+      mnc="06"
+      apn="mm.movilnet.com.ve"
+      mmsproxy="192.168.16.12"
+      mmsport="8080"
+      mmsc="http://mms2.movilnet.com.ve/servlets/mms"
+      type="mms"
+  />
+
+  <apn carrier="VIVA3G"
+      carrier_id = "1380"
+      mcc="736"
+      mnc="01"
+      apn="internet.nuevatel.com"
+      user=""
+      password=""
+      proxy="192.168.101.4"
+      port="3128"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="VIVAMMS"
+      carrier_id = "1380"
+      mcc="736"
+      mnc="01"
+      apn="mms.nuevatel.com"
+      user=""
+      password=""
+      mmsproxy="192.168.101.4"
+      mmsport="3128"
+      mmsc="http://mmsgw.nuevatel.com:1981"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="ENTEL WAP GPRS"
+      carrier_id = "1381"
+      mcc="736"
+      mnc="02"
+      apn="wap.movil.com.bo"
+      user=""
+      password=""
+      proxy="172.27.7.10"
+      port="8080"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="ENTEL MMS GPRS"
+      carrier_id = "1381"
+      mcc="736"
+      mnc="02"
+      apn="mms.movil.com.bo"
+      user=""
+      password=""
+      mmsproxy="172.27.7.10"
+      mmsport="8080"
+      mmsc="http://mms.movil.com.bo/servlets/mms"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="WAPTIGO"
+      carrier_id = "1382"
+      mcc="736"
+      mnc="03"
+      apn="wap.tigo.bo"
+      user=""
+      password=""
+      proxy="172.25.100.8"
+      port="8080"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MMSTIGO"
+      carrier_id = "1382"
+      mcc="736"
+      mnc="03"
+      apn="mms.tigo.bo"
+      user=""
+      password=""
+      mmsproxy="172.25.100.8"
+      mmsport="8080"
+      mmsc="http://mms"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Digicel"
+      carrier_id = "1525"
+      mcc="738"
+      mnc="01"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Guyana:Digicel:Modem"
+      carrier_id = "1525"
+      mcc="738"
+      mnc="01"
+      apn="wap.digicelgy.com"
+      type="dun"
+      user="wap"
+      password="wap"
+      authtype="1"
+      mmsc="http://www.digicelive.com"
+      proxy="172.20.6.12"
+      port="8080"
+  />
+
+  <apn carrier="Guyana:Digicel:Mms"
+      carrier_id = "1525"
+      mcc="738"
+      mnc="01"
+      apn="wap.digicelgy.com"
+      type="mms"
+      user="wap"
+      password="wap"
+      authtype="1"
+      mmsproxy="172.20.6.12"
+      mmsc="http://mmc.digicelgy.com/servlets/mms"
+      mmsport="9201"
+  />
+
+  <apn carrier="GT&amp;T Cellink Plus"
+      carrier_id = "2217"
+      mcc="738"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar INTERNET"
+      carrier_id = "1472"
+      mcc="740"
+      mnc="00"
+      apn="internet.movistar.com.ec"
+      user="movistar"
+      password="movistar"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "1472"
+      mcc="740"
+      mnc="00"
+      apn="mms.movistar.com.ec"
+      user="movistar"
+      password="movistar"
+      mmsproxy="10.3.5.50"
+      mmsport="9001"
+      mmsc="http://mms.movistar.com.ec:8088/mms/"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Internet Claro"
+      carrier_id = "1473"
+      mcc="740"
+      mnc="01"
+      apn="internet.claro.com.ec"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Claro"
+      carrier_id = "1473"
+      mcc="740"
+      mnc="01"
+      apn="mms.claro.com.ec"
+      user="portamms"
+      password="portamms2003"
+      mmsproxy="216.250.208.94"
+      mmsport="8799"
+      mmsc="http://iesmms.porta.com.ec/"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Internet Claro"
+      carrier_id = "1473"
+      mcc="740"
+      mnc="010"
+      apn="internet.claro.com.ec"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Claro"
+      carrier_id = "1473"
+      mcc="740"
+      mnc="010"
+      apn="mms.claro.com.ec"
+      user="portamms"
+      password="portamms2003"
+      mmsproxy="216.250.208.94"
+      mmsport="8799"
+      mmsc="http://iesmms.porta.com.ec/"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="CNT 3G"
+      carrier_id = "1474"
+      mcc="740"
+      mnc="02"
+      apn="internet3gsp.alegro.net.ec"
+      type="default,supl"
+  />
+
+  <apn carrier="CNT MMS"
+      carrier_id = "1474"
+      mcc="740"
+      mnc="02"
+      apn="mms.alegro.net.ec"
+      mmsproxy="10.4.85.3"
+      mmsport="8080"
+      mmsc="http://mms.alegro.net.ec/mms/"
+      type="mms"
+  />
+
+  <apn carrier="VOX INTERNET"
+      carrier_id = "1672"
+      mcc="744"
+      mnc="01"
+      apn="vox.internet"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Paraguay:Voxx:Modem"
+      carrier_id = "1672"
+      mcc="744"
+      mnc="01"
+      apn="vox.wap"
+      type="dun"
+      authtype="1"
+      mmsproxy="172.24.97.29"
+      mmsc="http://www.vox.com.py/"
+      port="8080"
+  />
+
+  <apn carrier="VOX MMS"
+      carrier_id = "1672"
+      mcc="744"
+      mnc="01"
+      apn="vox.mms"
+      user="vox"
+      password="vox"
+      mmsproxy="172.24.97.29"
+      mmsport="8080"
+      mmsc="http://mms.vox.com.py/mmsc"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Claro PY"
+      carrier_id = "1673"
+      mcc="744"
+      mnc="02"
+      apn="igprs.claro.com.py"
+      user="ctigprs"
+      password="ctigprs999"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS GPRS PY"
+      carrier_id = "1673"
+      mcc="744"
+      mnc="02"
+      apn="mms.ctimovil.com.py"
+      user="ctimms"
+      password="ctimms999"
+      mmsproxy="170.51.255.240"
+      mmsport="8080"
+      mmsc="http://mms.ctimovil.com.py"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="TIGO PY"
+      carrier_id = "1927"
+      mcc="744"
+      mnc="04"
+      apn="internet.tigo.py"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS Tigo"
+      carrier_id = "1927"
+      mcc="744"
+      mnc="04"
+      apn="mms.tigo.py"
+      user="tigo"
+      password="tigo"
+      mmsproxy="10.16.17.12"
+      mmsport="8888"
+      mmsc="http://mms"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Personal Datos Py"
+      carrier_id = "1928"
+      mcc="744"
+      mnc="05"
+      apn="internet"
+      user="personal"
+      password="personal"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Personal MMS Py"
+      carrier_id = "1928"
+      mcc="744"
+      mnc="05"
+      apn="mms"
+      user="mms"
+      password="mms"
+      mmsproxy="172.16.192.7"
+      mmsport="8080"
+      mmsc="http://mms"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Telesur"
+      carrier_id = "1083"
+      mcc="746"
+      mnc="02"
+      apn="default"
+      type="default,supl"
+  />
+
+  <apn carrier='Suriname:Digicel:Internet'
+      carrier_id = "1084"
+      mcc='746'
+      mnc='03'
+      apn='web.digicelsr.com'
+      authtype='1'
+      type='default'
+  />
+
+  <apn carrier='Suriname:Digicel:Mms'
+      carrier_id = "1084"
+      mcc='746'
+      mnc='03'
+      apn='wap.digicelsr.com'
+      authtype='1'
+      mmsc='http://mmc.digicelsr.com/servlets/mms'
+      mmsproxy='172.20.6.12'
+      mmsport='9201'
+      type='mms'
+      user='wap'
+      password='wap'
+  />
+
+  <apn carrier='Suriname:Digicel:Modem'
+      carrier_id = "1084"
+      mcc='746'
+      mnc='03'
+      apn='wap.digicelsr.com'
+      port='8080'
+      authtype='1'
+      proxy='172.20.6.12'
+      mmsc='http://wapdigicel.com'
+      type='dun'
+      user='wap'
+      password='wap'
+  />
+
+  <apn carrier="wapANCEL"
+      carrier_id = "1862"
+      mcc="748"
+      mnc="01"
+      apn="wap"
+      proxy="200.40.246.2"
+      port="3128"
+      user=""
+      password=""
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="mmsANCEL"
+      carrier_id = "1862"
+      mcc="748"
+      mnc="01"
+      apn="mms"
+      user=""
+      password=""
+      mmsproxy="200.40.246.2"
+      mmsport="3128"
+      mmsc="http://mmsc.mms.ancelutil.com.uy"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="gprsANCEL"
+      carrier_id = "1862"
+      mcc="748"
+      mnc="01"
+      apn="gprs.ancel"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar INTERNET"
+      carrier_id = "1863"
+      mcc="748"
+      mnc="07"
+      apn="webapn.movistar.com.uy"
+      user="movistar"
+      password="movistar"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="Movistar MMS"
+      carrier_id = "1863"
+      mcc="748"
+      mnc="07"
+      apn="apnmms.movistar.com.uy"
+      user="mmsuy"
+      password="mmsuy"
+      mmsproxy="10.0.2.29"
+      mmsport="8080"
+      mmsc="http://mmsc.movistar.com.uy"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Claro UY"
+      carrier_id = "1864"
+      mcc="748"
+      mnc="10"
+      apn="igprs.claro.com.uy"
+      user="ctigprs"
+      password="ctigprs999"
+      authtype="1"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS GPRS UY"
+      carrier_id = "1864"
+      mcc="748"
+      mnc="10"
+      apn="mms.ctimovil.com.uy"
+      user="ctimms"
+      password="ctimms999"
+      mmsproxy="170.51.255.240"
+      mmsport="8080"
+      mmsc="http://mms.ctimovil.com.uy"
+      authtype="1"
+      type="mms"
+  />
+
+  <apn carrier="Orange Armenia MMS"
+      carrier_id = "1940"
+      mcc="283"
+      mnc="10"
+      apn="mms"
+      mmsc="http://mms/"
+      mmsproxy="192.168.220.251"
+      mmsport="3128"
+      type="mms"
+      authtype="1"
+  />
+
+  <apn carrier="Orange Armenia Internet"
+      carrier_id = "1940"
+      mcc="283"
+      mnc="10"
+      apn="Internet"
+      type="default"
+      authtype="1"
+  />
+
+  <apn carrier="Orange BW MMS"
+      carrier_id = "567"
+      mcc="652"
+      mnc="02"
+      apn="mms.orange.co.bw"
+      mmsc="http://10.0.0.242/servlets/mms"
+      mmsproxy="10.0.0.226"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Orange WAP BW"
+      carrier_id = "567"
+      mcc="652"
+      mnc="02"
+      apn="internet.orange.co.bw"
+      proxy="10.0.0.226"
+      port="8080"
+      type="default"
+  />
+
+  <apn carrier="Orange CM"
+      carrier_id = "1434"
+      mcc="624"
+      mnc="02"
+      apn="orangecmgprs"
+      user="orange"
+      password="orange"
+      proxy="192.168.122.101"
+      port="8080"
+      mmsc="http://mms.orange.cm"
+      mmsproxy="192.168.122.101"
+      mmsport="8080"
+      type="default,mms"
+  />
+
+  <apn carrier="Orange net KE"
+      carrier_id = "2210"
+      mcc="639"
+      mnc="07"
+      apn="bew.orange.co.ke"
+      type="default"
+  />
+
+  <apn carrier="Orange RE"
+      carrier_id = "1676"
+      mcc="647"
+      mnc="00"
+      apn="orangerun"
+      user="orange"
+      password="orange"
+      type="default"
+  />
+
+  <apn carrier="Orange MG MMS"
+      carrier_id = "1606"
+      mcc="646"
+      mnc="02"
+      apn="orangemms"
+      user="mms"
+      password="orange"
+      mmsc="http://10.152.10.70.38090"
+      mmsproxy="10.150.0.115"
+      mmsport="8080"
+      type="mms"
+  />
+
+  <apn carrier="Orange World MG"
+      carrier_id = "1606"
+      mcc="646"
+      mnc="02"
+      apn="orangeworld"
+      user="world"
+      password="orange"
+      proxy="10.150.0.115"
+      port="8080"
+      type="default"
+  />
+
+  <apn carrier="CIOT Vodafone"
+      mcc="901"
+      mnc="28"
+      apn="ciot.vodafone.com"
+      user="vodafone"
+      password="vodafone"
+      type="default"
+  />
+
+  <apn carrier="mobiledata"
+      mcc="901"
+      mnc="37"
+      apn="mobiledata"
+      type="default,supl"
+  />
+
+  <apn carrier="EMnify"
+      mcc="901"
+      mnc="43"
+      apn="em"
+      type="default,supl"
+  />
+
+  <apn carrier="BICS Internet"
+      carrier_id = "2132"
+      mcc="901"
+      mnc="58"
+      apn="bicsapn"
+      type="default,supl"
+  />
+
+  <apn carrier="Sberbank-Telecom Internet"
+      carrier_id = "2251"
+      mcc="250"
+      mnc="50"
+      apn="internet.sberbank-tele.com"
+      user=""
+      password=""
+      type="default,supl"
+      mvno_type="gid"
+      mvno_match_data="FA3207"
+  />
+  <apn carrier="Sberbank-Telecom MMS"
+      carrier_id = "2251"
+      mcc="250"
+      mnc="50"
+      apn="mms.sberbank-tele.com"
+      user=""
+      password=""
+      mmsc="http://mmsc"
+      mmsproxy="10.77.36.100"
+      mmsport="8080"
+      type="mms"
+      mvno_type="gid"
+      mvno_match_data="FA3207"
+  />
+  <apn carrier="Sberbank-Telecom IMS"
+      carrier_id = "2251"
+      mcc="250"
+      mnc="50"
+      apn="ims"
+      type="ims"
+      protocol="IPV4V6"
+      mvno_type="gid"
+      mvno_match_data="FA3207"
+  />
+
+  <apn carrier="Unleashed"
+      carrier_id = "2144"
+      mcc="206"
+      mnc="30"
+      apn="web.be"
+      type="default,supl"
+  />
+
+  <apn carrier="Kena Mobile Web"
+      mcc="222"
+      mnc="07"
+      apn="web.kenamobile.it"
+      type="default"
+  />
+
+  <apn carrier="Kena Mobile MMS"
+      mcc="222"
+      mnc="07"
+      apn="mms.kenamobile.it"
+      type="mms"
+      mmsc="http://mms.kenamobile.it"
+      mmsproxy="10.248.1.12"
+      mmsport="80"
+  />
+
+  <apn carrier="Lycamobile"
+      mcc="505"
+      mnc="19"
+      apn="data.lycamobile.com.au"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      mcc="242"
+      mnc="23"
+      apn="data.lyca-mobile.no"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      mcc="228"
+      mnc="54"
+      apn="data.lycamobile.ch"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      carrier_id = "2404"
+      mcc="232"
+      mnc="08"
+      apn="data.lycamobile.at"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      mcc="206"
+      mnc="06"
+      apn="data.lycamobile.be"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      mcc="262"
+      mnc="43"
+      apn="data.lycamobile.de"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      mcc="238"
+      mnc="12"
+      apn="data.lycamobile.dk"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      mcc="214"
+      mnc="25"
+      apn="data.lycamobile.es"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      mcc="208"
+      mnc="25"
+      apn="data.lycamobile.fr"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      mcc="272"
+      mnc="13"
+      apn="data.lycamobile.ie"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      mcc="204"
+      mnc="09"
+      apn="data.lycamobile.nl"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      carrier_id = "2403"
+      mcc="260"
+      mnc="09"
+      apn="data.lycamobile.pl"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      mcc="268"
+      mnc="04"
+      apn="data.lycamobile.pt"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      mcc="226"
+      mnc="16"
+      apn="data.lycamobile.ro"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      carrier_id = "2405"
+      mcc="240"
+      mnc="12"
+      apn="data.lycamobile.se"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      mcc="222"
+      mnc="35"
+      apn="data.lycamobile.it"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      mcc="311"
+      mnc="960"
+      apn="data.lycamobile.com"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      mcc="641"
+      mnc="26"
+      apn="data.lycamobile.ug"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      mcc="294"
+      mnc="04"
+      apn="data.lycamobile.mk"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Lycamobile"
+      mcc="655"
+      mnc="53"
+      apn="data.lycamobile.co.za"
+      authtype="1"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="Lycamobile"
+  />
+
+  <apn carrier="Internet"
+      mcc="234"
+      mnc="57"
+      apn="mobile.sky"
+      authtype="0"
+      type="default,supl"
+  />
+
+  <apn carrier="MMS"
+      mcc="234"
+      mnc="57"
+      apn="mms.mobile.sky"
+      mmsc="http://185.110.178.96:38090/was"
+      mmsproxy="185.110.178.97"
+      mmsport="9028"
+      type="mms"
+  />
+
+  <apn carrier="Altan"
+      carrier_id = "2469"
+      mcc="334"
+      mnc="140"
+      apn="internet.altan"
+      type="default"
+      user=""
+      password=""
+  />
+
+  <apn carrier="Altan"
+      carrier_id = "2469"
+      mcc="334"
+      mnc="140"
+      apn="ims"
+      type="ims"
+      user=""
+      password=""
+  />
+
+  <apn carrier="IENTC"
+      carrier_id = "2470"
+      mcc="334"
+      mnc="140"
+      apn="internet.ientc.com"
+      type="default"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="IENTC"
+  />
+
+  <apn carrier="NeWWW"
+      carrier_id = "2471"
+      mcc="334"
+      mnc="140"
+      apn="internet.newww.com"
+      type="default"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="NeWWW"
+  />
+
+  <apn carrier="NeWWW"
+      carrier_id = "2471"
+      mcc="334"
+      mnc="140"
+      apn="ims"
+      type="ims"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="NeWWW"
+  />
+
+  <apn carrier="travelfy"
+      carrier_id="2472"
+      apn="travelfy"
+      type="default,supl"
+  />
+
+  <apn carrier="Internet WOM"
+    carrier_id="1430"
+    mcc="730"
+    mnc="09"
+    apn="internet"
+    type="default"
+    user=""
+    password=""
+    protocol="IPV4V6"
+    roaming_protocol="IPV4V6"
+    user_editable="false"
+  />
+
+  <apn carrier="IMS"
+    carrier_id="1430"
+    mcc="730"
+    mnc="09"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    protocol="IPV4"
+    roaming_protocol="IPV4"
+    user_editable="false"
+    user_visible="false"
+  />
+
+  <apn carrier="Megacable"
+    carrier_id="2473"
+    mcc="334"
+    mnc="140"
+    apn="mega45g.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="Mega4.5 G"
+  />
+
+  <apn carrier="Megacable"
+    carrier_id="2473"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="Mega4.5 G"
+  />
+
+  <apn carrier="Netwey"
+    carrier_id="2474"
+    mcc="334"
+    mnc="140"
+    apn="internet.netwey.com.mx"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="NETWEY"
+  />
+
+  <apn carrier="Netwey"
+    carrier_id="2474"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="NETWEY"
+  />
+
+  <apn carrier="Retemex"
+    carrier_id="2475"
+    mcc="334"
+    mnc="140"
+    apn="internet.retemex.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="RETEMEX"
+  />
+
+  <apn carrier="Retemex"
+    carrier_id="2475"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="RETEMEX"
+  />
+
+  <apn carrier="Walmart MX"
+    carrier_id="2476"
+    mcc="334"
+    mnc="140"
+    apn="internet.wm.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="BAIT"
+  />
+
+  <apn carrier="Walmart MX"
+    carrier_id="2476"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="BAIT"
+  />
+
+  <apn carrier="Iusacomm"
+    carrier_id="2477"
+    mcc="334"
+    mnc="140"
+    apn="internet.iusacomm.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="IUSATEL"
+  />
+
+  <apn carrier="Iusacomm"
+    carrier_id="2477"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="IUSATEL"
+  />
+
+  <apn carrier="CFE"
+    carrier_id="2478"
+    mcc="334"
+    mnc="140"
+    apn="internet.cfe.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="CFE TEIPT"
+  />
+
+  <apn carrier="CFE"
+    carrier_id="2478"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="CFE TEIPT"
+  />
+
+  <apn carrier="Inten"
+    carrier_id="2479"
+    mcc="334"
+    mnc="140"
+    apn="internet.inten.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="INTEN"
+  />
+
+  <apn carrier="Inteni"
+    carrier_id="2479"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="INTEN"
+  />
+
+  <apn carrier="Diveracy"
+    carrier_id="2480"
+    mcc="334"
+    mnc="140"
+    apn="internet.diveracy.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="NEMI"
+  />
+
+  <apn carrier="Diveracy"
+    carrier_id="2480"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="NEMI"
+  />
+
+  <apn carrier="Diri"
+    carrier_id="2481"
+    mcc="334"
+    mnc="140"
+    apn="internet.diri.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="DIRI"
+  />
+
+  <apn carrier="Diri"
+    carrier_id="2481"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="DIRI"
+  />
+
+  <apn carrier="Topos"
+    carrier_id="2482"
+    mcc="334"
+    mnc="140"
+    apn="internet.turbored.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="TURBORED"
+  />
+
+  <apn carrier="Topos"
+    carrier_id="2482"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="TURBORED"
+  />
+
+  <apn carrier="Guruweb"
+    carrier_id="2483"
+    mcc="334"
+    mnc="140"
+    apn="internet.gugacom.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="Gurucomm"
+  />
+
+  <apn carrier="Guruweb"
+    carrier_id="2483"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="Gurucomm"
+  />
+
+  <apn carrier="Ubix"
+    carrier_id="2484"
+    mcc="334"
+    mnc="140"
+    apn="internet.ubix.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="Ubix"
+  />
+
+  <apn carrier="Ubix"
+    carrier_id="2484"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="Ubix"
+  />
+
+  <apn carrier="Rocketel"
+    carrier_id="2485"
+    mcc="334"
+    mnc="140"
+    apn="internet.rocketel.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="PagaPhone"
+  />
+
+  <apn carrier="Rocketel"
+    carrier_id="2485"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="PagaPhone"
+  />
+
+  <apn carrier="Redpotencia"
+    carrier_id="2486"
+    mcc="334"
+    mnc="140"
+    apn="internet.edilar.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="Redpotencia"
+  />
+
+  <apn carrier="Redpotencia"
+    carrier_id="2486"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="Redpotencia"
+  />
+
+  <apn carrier="Adinteli 1"
+    carrier_id="2487"
+    mcc="334"
+    mnc="140"
+    apn="internet.plus.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="CHAMO-MOVIL"
+  />
+
+  <apn carrier="Adinteli 1"
+    carrier_id="2487"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="CHAMO-MOVIL"
+  />
+
+  <apn carrier="Adinteli 2"
+    carrier_id="2487"
+    mcc="334"
+    mnc="140"
+    apn="internet.plus.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="BYPLUS"
+  />
+
+  <apn carrier="Adinteli 2"
+    carrier_id="2487"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="BYPLUS"
+  />
+
+  <apn carrier="Izzi"
+    carrier_id="2488"
+    mcc="334"
+    mnc="140"
+    apn="internet.izzi.mx"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="izzi"
+  />
+
+  <apn carrier="Izzi"
+    carrier_id="2488"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="izzi"
+  />
+
+  <apn carrier="Adm"
+    carrier_id="2489"
+    mcc="334"
+    mnc="140"
+    apn="internet.adm.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="MISTRAL"
+  />
+
+  <apn carrier="Adm"
+    carrier_id="2489"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="MISTRAL"
+  />
+
+  <apn carrier="Ads"
+    carrier_id="2490"
+    mcc="334"
+    mnc="140"
+    apn="internet.mexfon.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="MEXFON"
+  />
+
+  <apn carrier="Ads"
+    carrier_id="2490"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="MEXFON"
+  />
+
+  <apn carrier="Yonder"
+    carrier_id="2491"
+    mcc="334"
+    mnc="140"
+    apn="internet.yotelco.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="YO"
+  />
+
+  <apn carrier="Yonder"
+    carrier_id="2491"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="YO"
+  />
+
+  <apn carrier="Arlonet"
+    carrier_id="2492"
+    mcc="334"
+    mnc="140"
+    apn="internet.arloesinet.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="Arlonet"
+  />
+
+  <apn carrier="Arlonet"
+    carrier_id="2492"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="Arlonet"
+  />
+
+  <apn carrier="Tridex"
+    carrier_id="2493"
+    mcc="334"
+    mnc="140"
+    apn="internet.valor.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="VALOR"
+  />
+
+  <apn carrier="Tridex"
+    carrier_id="2493"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="VALOR"
+  />
+
+  <apn carrier="Wimo"
+    carrier_id="2494"
+    mcc="334"
+    mnc="140"
+    apn="internet.wimo.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="WiMO"
+  />
+
+  <apn carrier="Wimoi"
+    carrier_id="2494"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="WiMO"
+  />
+
+  <apn carrier="Oui"
+    carrier_id="2495"
+    mcc="334"
+    mnc="140"
+    apn="internet.oui.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="OUI"
+  />
+
+  <apn carrier="Oui"
+    carrier_id="2495"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="OUI"
+  />
+
+  <apn carrier="Freedompop"
+    carrier_id="2496"
+    mcc="334"
+    mnc="140"
+    apn="Internet.mvne1.com"
+    type="default"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="FreedomPop"
+  />
+
+  <apn carrier="Freedompop"
+    carrier_id="2496"
+    mcc="334"
+    mnc="140"
+    apn="ims"
+    type="ims"
+    user=""
+    password=""
+    mvno_type="spn"
+    mvno_match_data="FreedomPop"
+  />
+
+  <apn carrier="IENTC"
+      carrier_id = "2470"
+      mcc="334"
+      mnc="140"
+      apn="ims"
+      type="ims"
+      user=""
+      password=""
+      mvno_type="spn"
+      mvno_match_data="IENTC"
+  />
+</apns>
diff --git a/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/call-pppd b/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/call-pppd
new file mode 100755
index 0000000..9f7f1cb
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/call-pppd
@@ -0,0 +1,34 @@
+#!/system/bin/sh
+# An unforunate wrapper script 
+# so that the exit code of pppd may be retrieved
+
+
+#PPPD_PID=""
+PPPD_EXIT=""
+
+/system/bin/setprop "net.gprs.ppp-exit" ""
+
+/system/bin/log -t pppd "Starting pppd"
+
+/system/bin/log -t pppd "PARAM1: $1"
+/system/bin/log -t pppd "PARAM2: $2"
+/system/bin/log -t pppd "PARAM3: $3"
+/system/bin/log -t pppd "PARAM4: $4"
+/system/bin/log -t pppd "PARAM5: $5"
+
+if [ $# -lt 6 ] ; then
+
+/system/bin/pppd $1 debug defaultroute noauth nodetach nocrtscts novj noipdefault usepeerdns user "$2" password "$3" connect "$4" disconnect "$5"
+
+else
+
+/system/bin/log -t pppd "PARAM6: $6"
+/system/bin/pppd $1 debug defaultroute noauth nodetach nocrtscts $2 noipdefault usepeerdns user "$3" password "$4" connect "$5" disconnect "$6"
+fi
+PPPD_EXIT=$?
+#PPPD_PID=$!
+
+#/system/bin/log -t pppd "pppd pid: $PPPD_PID"
+/system/bin/log -t pppd "pppd exited with $PPPD_EXIT"
+
+/system/bin/setprop "net.gprs.ppp-exit" "$PPPD_EXIT"
diff --git a/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/chat b/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/chat
new file mode 100755
index 0000000..69ae636
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/chat
Binary files differ
diff --git a/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/dhcpcd b/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/dhcpcd
new file mode 100755
index 0000000..b6c23ea
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/dhcpcd
Binary files differ
diff --git a/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/ip-down b/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/ip-down
new file mode 100755
index 0000000..40ffdbe
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/ip-down
Binary files differ
diff --git a/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/ip-up b/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/ip-up
new file mode 100755
index 0000000..6aa7702
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/ip-up
Binary files differ
diff --git a/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/ql-ril.conf b/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/ql-ril.conf
new file mode 100755
index 0000000..6591d53
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/bin64/ql-ril.conf
@@ -0,0 +1,42 @@
+#This file is in a state of unavailability.
+#In most cases, there is no need to open any option.
+#In special cases, please use it under the guidance of FAE.
+
+#LTE_SignalStrength=-1
+#LTE_Is_Report_SignalStrength=1
+#At_Cmds_For_Customer_Initialize=at+csq;at+cgreg?;at+cops?;at+qcfg="nwscanmodeex"
+#Icc_Constants=EF_ICCID
+#support_CDMPhone=1
+#URC_delay_mseconds=2000
+#Query_Available_Networks=1
+#Sim_Hot_Plugging=1  #0-not support; 1-support low level; 2-support high level
+#at_qcrmcall=1
+#Recovery_App=
+#ATT_Test=1
+#need_switch_CMT_to_CMTI=1
+#RevokeClientIDIndication=1
+#PS_ONLY=1
+#check_data_stall=1
+#POLL_CALL_STATE=1
+#support_fota=1 #url and local path should start with 'fota:'. such as 'fota:/data/EC200Txxxxxxx.bin'
+#autoUnlockPin=1
+#check_sms_manually=1
+#support_x55_loopback=1
+#manifest_path=/odm/etc/vintf/xxx.xml  #xxx.xml is the name of manifest,such as manifest_m50_nonpayment_cell.xml
+#usb_port_path1=
+#usb_port_path2=
+#use_dsda=1
+#RIL_REQUEST_SHUTDOWN_SUPPORT=0
+#RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE_SUPPORT=0
+#RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL_SUPPORT=0
+#RM500Voice=1
+#SetPreferredNetworkType_NR=1
+#asr_support_gps=1
+#IPv4v6_was_also_successful=1
+#usbnet=mbim
+#not_support_0b00=1
+#ue_function_mode=1 #1 data only 2 data voice 3 data_voice_roaming 4 voice only
+#active_query_network_resident=1
+#asr_zhanrui_support_ipv6=1
+#plane_mode_0=1
+#use_MTK=1
diff --git a/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/manifest.xml b/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/manifest.xml
new file mode 100755
index 0000000..866b401
--- /dev/null
+++ b/android/vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/manifest.xml
@@ -0,0 +1,12 @@
+<manifest version="1.0" type="device" target-level="4">
+    <hal format="hidl">
+        <name>android.hardware.radio</name>
+        <transport>hwbinder</transport>
+        <version>1.4</version>
+        <interface>
+            <name>IRadio</name>
+            <instance>slot1</instance>
+        </interface>
+        <fqname>@1.2::ISap/slot1</fqname>
+    </hal>
+</manifest>
diff --git a/android/vendor/aw/public/prebuild/lib/librild/radio_common.mk b/android/vendor/aw/public/prebuild/lib/librild/radio_common.mk
old mode 100644
new mode 100755
index e204028..2403104
--- a/android/vendor/aw/public/prebuild/lib/librild/radio_common.mk
+++ b/android/vendor/aw/public/prebuild/lib/librild/radio_common.mk
@@ -1,38 +1,128 @@
 LOCAL_PATH := vendor/aw/public/prebuild/lib/librild
 
-RIL_LIB_VERSION  ?= 10.0
+RIL_LIB_VERSION  ?= 12.0
 RIL_LIB_BASENAME ?= libsoftwinner-ril-$(RIL_LIB_VERSION)
 
 # 3G Data Card Packages
 PRODUCT_PACKAGES += \
-	android.hardware.radio@1.4 \
-	android.hardware.radio.config@1.1-service \
-	android.hardware.radio.config@1.1 \
+	CarrierDefaultApp \
+	CarrierConfig \
 	pppd_vendor \
 	rild \
 	chat \
-	$(RIL_LIB_BASENAME) \
+	dhcpcd \
+	libreference-ril-an12 \
+	libreference-ril-an10 \
 	radio_monitor
 
-DISABLE_RILD_OEM_HOOK := true
+#PRODUCT_PACKAGES += \
+    android.hardware.radio@1.5-radio-service \
+    android.hardware.radio.config@1.2-service \
+	android.hardware.radio.config@1.0-service \
+	android.hardware.radio@1.5
+
+PRODUCT_PACKAGES += \
+	android.hardware.radio@1.4 \
+	android.hardware.radio.config@1.1-service \
+	android.hardware.radio.config@1.1 \
+
+#PRODUCT_PACKAGES += \
+    android.hardware.radio@1.2-radio-service \
+
+#PRODUCT_PACKAGES += \
+    android.hardware.radio@1.0-radio-service \
+    android.hardware.radio@1.1-radio-service \
+    android.hardware.radio@1.2-radio-service \
+    android.hardware.radio@1.3-radio-service \
+    android.hardware.radio@1.4-radio-service \
+    android.hardware.radio@1.5-radio-service \
+    android.hardware.radio@1.6-radio-service
+
+#PRODUCT_PACKAGES += \
+    android.hardware.radio@1.0 \
+    android.hardware.radio@1.1 \
+    android.hardware.radio@1.2 \
+    android.hardware.radio@1.3 \
+    android.hardware.radio@1.4 \
+    android.hardware.radio@1.5 \
+    android.hardware.radio@1.6
+
+#PRODUCT_PACKAGES += \
+  	android.hardware.radio.config@1.0 \
+  	android.hardware.radio.config@1.1 \
+  	android.hardware.radio.config@1.2 \
+  	android.hardware.radio.config@1.3
+
+#PRODUCT_PACKAGES += \
+    android.hardware.radio.config@1.1-service	\
+    android.hardware.radio.config@1.2-service	\
+    android.hardware.radio.config@1.3-service
+
+# DISABLE_RILD_OEM_HOOK := true
 
 # 3G Data Card Configuration Flie
-PRODUCT_COPY_FILES += \
-	$(LOCAL_PATH)/config/data_call/ip-down:$(TARGET_COPY_OUT_VENDOR)/bin/etc/ppp/ip-down \
-	$(LOCAL_PATH)/config/data_call/ip-up:$(TARGET_COPY_OUT_VENDOR)/bin/etc/ppp/ip-up \
-	$(LOCAL_PATH)/config/data_call/3g_dongle.cfg:$(TARGET_COPY_OUT_VENDOR)/etc/3g_dongle.cfg \
-	$(LOCAL_PATH)/config/data_call/apns-conf_sdk.xml:$(TARGET_COPY_OUT_PRODUCT)/etc/apns-conf.xml \
+# PRODUCT_COPY_FILES += \
 	$(LOCAL_PATH)/config/initrc/env.librild.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/env.librild.rc
 
+# $(LOCAL_PATH)/config/data_call/ip-down:$(TARGET_COPY_OUT_VENDOR)/bin/etc/ppp/ip-down \
+# $(LOCAL_PATH)/config/data_call/ip-up:$(TARGET_COPY_OUT_VENDOR)/bin/etc/ppp/ip-up \
+# $(LOCAL_PATH)/config/data_call/3g_dongle.cfg:$(TARGET_COPY_OUT_VENDOR)/etc/3g_dongle.cfg \
+# $(LOCAL_PATH)/config/data_call/apns-conf_sdk.xml:$(TARGET_COPY_OUT_PRODUCT)/etc/apns-conf.xml \
+
+PRODUCT_PACKAGES += \
+    usb_dongle
+
 # Radio Monitor Configuration Flie
-PRODUCT_COPY_FILES += \
-	$(LOCAL_PATH)/config/radio_monitor/usb_modeswitch:$(TARGET_COPY_OUT_VENDOR)/bin/usb_modeswitch \
-	$(call find-copy-subdir-files,*,$(LOCAL_PATH)/config/radio_monitor/usb_modeswitch.d,$(TARGET_COPY_OUT_VENDOR)/etc/usb_modeswitch.d)
+PRODUCT_PACKAGES += usb_modeswitch
+# PRODUCT_COPY_FILES += \
+# 	$(call find-copy-subdir-files,*,$(LOCAL_PATH)/config/radio_monitor/usb_modeswitch.d,$(TARGET_COPY_OUT_VENDOR)/etc/usb_modeswitch.d)
+# 	#$(LOCAL_PATH)/config/radio_monitor/usb_modeswitch:$(TARGET_COPY_OUT_VENDOR)/bin/usb_modeswitch \
 
 # Radio parameter
 PRODUCT_PROPERTY_OVERRIDES += \
 	vendor.rild.libargs=-d/dev/ttyUSB2 \
-	vendor.rild.libpath=$(RIL_LIB_BASENAME).so \
-	ro.radio.noril=true \
+	ro.radio.noril=false \
 	ro.radio.noawril=false \
 	ro.vendor.sw.embeded.telephony=false
+
+PRODUCT_PROPERTY_OVERRIDES += \
+    vendor.rild.libpath=/vendor/lib64/libreference-ril-an10.so
+
+PRODUCT_PROPERTY_OVERRIDES += \
+    ro.telephony.default_network=9 \
+	persist.sys.pref.net.type=10 \
+    rild.libargs=-d/dev/ttyUSB2 \
+    ro.com.android.mobiledata=true \
+    ro.com.android.prov_mobiledata=true
+
+PRODUCT_PACKAGES += \
+    Telecom \
+    TeleService \
+    Telephony \
+    TelephonyProvider
+
+PRODUCT_PACKAGES += \
+	Mms \
+	ContactsCommon \
+	libril3 \
+	rild3 \
+	Stk \
+	ip-up \
+	ip-down \
+	libril \
+	librilutils
+
+PRODUCT_COPY_FILES += $(LOCAL_PATH)/quecte_ec20_modem/apns-full-conf.xml:$(TARGET_COPY_OUT_PRODUCT)/etc/apns-conf.xml
+
+DEVICE_MANIFEST_FILE += vendor/aw/public/prebuild/lib/librild/quecte_ec20_modem/manifest.xml
+
+PRODUCT_COPY_FILES += \
+    $(LOCAL_PATH)/quecte_ec20_modem/bin64/call-pppd:$(TARGET_COPY_OUT_SYSTEM)/etc/ppp/call-pppd \
+    $(LOCAL_PATH)/quecte_ec20_modem/bin64/ip-down:$(TARGET_COPY_OUT_SYSTEM)/etc/ppp/ip-down \
+    $(LOCAL_PATH)/quecte_ec20_modem/bin64/ip-up:$(TARGET_COPY_OUT_SYSTEM)/etc/ppp/ip-up \
+    $(LOCAL_PATH)/quecte_ec20_modem/bin64/ql-ril.conf:$(TARGET_COPY_OUT_VENDOR)/etc/ql-ril.conf
+
+PRODUCT_COPY_FILES += \
+    $(LOCAL_PATH)/quecte_ec20_modem/bin64/dhcpcd:$(TARGET_COPY_OUT_VENDOR)/bin/dhcpcd \
+    $(LOCAL_PATH)/quecte_ec20_modem/bin64/call-pppd:$(TARGET_COPY_OUT_SYSTEM)/etc/ppp/call-pppd \
+    $(LOCAL_PATH)/quecte_ec20_modem/bin64/chat:$(TARGET_COPY_OUT_SYSTEM)/bin/chat
diff --git a/longan/kernel/linux-4.9/drivers/usb/serial/option.c b/longan/kernel/linux-4.9/drivers/usb/serial/option.c
index 665f417..12d06a1 100644
--- a/longan/kernel/linux-4.9/drivers/usb/serial/option.c
+++ b/longan/kernel/linux-4.9/drivers/usb/serial/option.c
@@ -1970,7 +1970,8 @@
 	{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0105, 0xff),			/* Fibocom NL678 series */
 	  .driver_info = RSVD(6) },
 #if 1
-	 { USB_DEVICE(0x05C6, 0x9090) }, /* Quectel UC15 */
+	 { USB_DEVICE(0x2C7C, 0x6002) }, /* Quectel EC200 */
+         { USB_DEVICE(0x05C6, 0x9090) }, /* Quectel UC15 */
          { USB_DEVICE(0x05C6, 0x9003) }, /* Quectel UC20 */
          { USB_DEVICE(0x2C7C, 0x0125) }, /* Quectel EC25/EC20 R2.0 */
          { USB_DEVICE(0x2C7C, 0x0121) }, /* Quectel EC21 */

--
Gitblit v1.6.2